<commit_before>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2008, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

// Original version: Melonee Wise <mwise@willowgarage.com>

#include "control_toolbox/pid.h"
#include "tinyxml.h"

namespace control_toolbox {

Pid::Pid(double p, double i, double d, double i_max, double i_min) :
  p_gain_(p), i_gain_(i), d_gain_(d), i_max_(i_max), i_min_(i_min)
{
  this->reset();
}

Pid::~Pid()
{
}

void Pid::initPid(double p, double i, double d, double i_max, double i_min)
{
  this->setGains(p,i,d,i_max,i_min);
  reset();
}

void Pid::reset()
{
  p_error_last_ = 0.0;
  p_error_ = 0.0;
  d_error_ = 0.0;
  i_term_  = 0.0;
  cmd_ = 0.0;
}

void Pid::getGains(double &p, double &i, double &d, double &i_max, double &i_min)
{
  p = p_gain_;
  i = i_gain_;
  d = d_gain_;
  i_max = i_max_;
  i_min = i_min_;
}

void Pid::setGains(double p, double i, double d, double i_max, double i_min)
{
  p_gain_ = p;
  i_gain_ = i;
  d_gain_ = d;
  i_max_ = i_max;
  i_min_ = i_min;
}

bool Pid::initParam(const std::string& prefix)
{
  ros::NodeHandle node(prefix);

  if (!node.getParam("p", p_gain_)) {
    ROS_ERROR("No p gain specified for pid.  Prefix: %s", prefix.c_str());
    return false;
  }
  node.param("i", i_gain_, 0.0) ;
  node.param("d", d_gain_, 0.0) ;
  node.param("i_clamp", i_max_, 0.0) ;
  i_min_ = -i_max_;

  reset();
  return true;
}

bool Pid::initXml(TiXmlElement *config)
{
  p_gain_ = config->Attribute("p") ? atof(config->Attribute("p")) : 0.0;
  i_gain_ = config->Attribute("i") ? atof(config->Attribute("i")) : 0.0;
  d_gain_ = config->Attribute("d") ? atof(config->Attribute("d")) : 0.0;
  i_max_ = config->Attribute("iClamp") ? atof(config->Attribute("iClamp")) : 0.0;
  i_min_ = -i_max_;

  reset();
  return true;
}

bool Pid::init(const ros::NodeHandle &node)
{
  ros::NodeHandle n(node);
  if (!n.getParam("p", p_gain_)) {
    ROS_ERROR("No p gain specified for pid.  Namespace: %s", n.getNamespace().c_str());
    return false;
  }
  n.param("i", i_gain_, 0.0);
  n.param("d", d_gain_, 0.0);
  n.param("i_clamp", i_max_, 0.0);
  i_min_ = -i_max_;

  reset();
  return true;
}

double Pid::computeCommand(double error, ros::Duration dt)
{
  double p_term, d_term;
  p_error_ = error; //this is pError = pState-pTarget

  if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error))
    return 0.0;

  // Calculate proportional contribution to command
  p_term = p_gain_ * p_error_;

  //Calculate integral contribution to command
  i_term_ = i_term_ + i_gain_ * dt.toSec() * p_error_;

  // Limit i_term_ so that the limit is meaningful in the output
  i_term_ = std::max( i_min_, std::min( i_term_, i_max_) );

  // Calculate the derivative error
  if (dt.toSec() > 0.0)
  {
    d_error_ = (p_error_ - p_error_last_) / dt.toSec();
    p_error_last_ = p_error_;
  }
  // Calculate derivative contribution to command
  d_term = d_gain_ * d_error_;
  cmd_ = p_term + i_term_ + d_term;

  return cmd_;
}

double Pid::updatePid(double error, ros::Duration dt)
{
  double p_term, d_term;
  p_error_ = error; //this is pError = pState-pTarget

  if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error))
    return 0.0;

  // Calculate proportional contribution to command
  p_term = p_gain_ * p_error_;

  //Calculate integral contribution to command
  i_term_ = i_term_ + i_gain_ * dt.toSec() * p_error_;

  // Limit i_term_ so that the limit is meaningful in the output
  i_term_ = std::max( i_min_, std::min( i_term_, i_max_) );

  // Calculate the derivative error
  if (dt.toSec() > 0.0)
  {
    d_error_ = (p_error_ - p_error_last_) / dt.toSec();
    p_error_last_ = p_error_;
  }
  // Calculate derivative contribution to command
  d_term = d_gain_ * d_error_;
  cmd_ = - p_term - i_term_ - d_term;

  return cmd_;
}

double Pid::computeCommand(double error, double error_dot, ros::Duration dt)
{
  double p_term, d_term;
  p_error_ = error; //this is pError = pState-pTarget
  d_error_ = error_dot;

  if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error) || std::isnan(error_dot) || std::isinf(error_dot))
    return 0.0;

  // Calculate proportional contribution to command
  p_term = p_gain_ * p_error_;

  //Calculate integral contribution to command
  i_term_ = i_term_ + i_gain_ * dt.toSec() * p_error_;

  // Limit i_term_ so that the limit is meaningful in the output
  i_term_ = std::max( i_min_, std::min( i_term_, i_max_) );

  // Calculate derivative contribution to command
  d_term = d_gain_ * d_error_;
  cmd_ = p_term + i_term_ + d_term;

  return cmd_;
}

double Pid::updatePid(double error, double error_dot, ros::Duration dt)
{
  double p_term, d_term;
  p_error_ = error; //this is pError = pState-pTarget
  d_error_ = error_dot;

  if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error) || std::isnan(error_dot) || std::isinf(error_dot))
    return 0.0;

  // Calculate proportional contribution to command
  p_term = p_gain_ * p_error_;

  //Calculate integral contribution to command
  i_term_ = i_term_ + i_gain_ * dt.toSec() * p_error_;

  // Limit i_term_ so that the limit is meaningful in the output
  i_term_ = std::max( i_min_, std::min( i_term_, i_max_) );

  // Calculate derivative contribution to command
  d_term = d_gain_ * d_error_;
  cmd_ = - p_term - i_term_ - d_term;

  return cmd_;
}

void Pid::setCurrentCmd(double cmd)
{
  cmd_ = cmd;
}

double Pid::getCurrentCmd()
{
  return cmd_;
}

void Pid::getCurrentPIDErrors(double *pe, double *ie, double *de)
{
  *pe = p_error_;
  *ie = i_gain_ ? i_term_/i_gain_ : 0.0;
  *de = d_error_;
}

}
<commit_msg>Enforcing i_min_ <= 0 and i_max_ >= 0 in integral bound parameters, reducing duplicated code<commit_after>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2008, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

// Original version: Melonee Wise <mwise@willowgarage.com>

#include "control_toolbox/pid.h"
#include "tinyxml.h"

namespace control_toolbox {

Pid::Pid(double p, double i, double d, double i_max, double i_min) :
  p_gain_(p), i_gain_(i), d_gain_(d), i_max_(i_max), i_min_(i_min)
{
  this->reset();
}

Pid::~Pid()
{
}

void Pid::initPid(double p, double i, double d, double i_max, double i_min)
{
  this->setGains(p,i,d,i_max,i_min);
  reset();
}

void Pid::reset()
{
  p_error_last_ = 0.0;
  p_error_ = 0.0;
  d_error_ = 0.0;
  i_term_  = 0.0;
  cmd_ = 0.0;
}

void Pid::getGains(double &p, double &i, double &d, double &i_max, double &i_min)
{
  p = p_gain_;
  i = i_gain_;
  d = d_gain_;
  i_max = i_max_;
  i_min = i_min_;
}

void Pid::setGains(double p, double i, double d, double i_max, double i_min)
{
  p_gain_ = p;
  i_gain_ = i;
  d_gain_ = d;
  i_max_ = i_max;
  i_min_ = i_min;
}

bool Pid::initParam(const std::string& prefix)
{
  ros::NodeHandle nh(prefix);
  return this->init(nh);
}

bool Pid::initXml(TiXmlElement *config)
{
  p_gain_ = config->Attribute("p") ? atof(config->Attribute("p")) : 0.0;
  i_gain_ = config->Attribute("i") ? atof(config->Attribute("i")) : 0.0;
  d_gain_ = config->Attribute("d") ? atof(config->Attribute("d")) : 0.0;
  double i_clamp;
  i_clamp = config->Attribute("iClamp") ? atof(config->Attribute("iClamp")) : 0.0;
  i_max_ = std::abs(i_clamp);
  i_min_ = -std::abs(i_clamp);

  reset();
  return true;
}

bool Pid::init(const ros::NodeHandle &node)
{
  ros::NodeHandle n(node);
  if (!n.getParam("p", p_gain_)) {
    ROS_ERROR("No p gain specified for pid.  Namespace: %s", n.getNamespace().c_str());
    return false;
  }
  n.param("i", i_gain_, 0.0);
  n.param("d", d_gain_, 0.0);

  double i_clamp;
  n.param("i_clamp", i_clamp, 0.0);
  i_max_ = std::abs(i_clamp);
  i_min_ = -std::abs(i_clamp);

  reset();
  return true;
}

double Pid::computeCommand(double error, ros::Duration dt)
{
  double p_term, d_term;
  p_error_ = error; //this is pError = pState-pTarget

  if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error))
    return 0.0;

  // Calculate proportional contribution to command
  p_term = p_gain_ * p_error_;

  //Calculate integral contribution to command
  i_term_ = i_term_ + i_gain_ * dt.toSec() * p_error_;

  // Limit i_term_ so that the limit is meaningful in the output
  i_term_ = std::max( i_min_, std::min( i_term_, i_max_) );

  // Calculate the derivative error
  if (dt.toSec() > 0.0)
  {
    d_error_ = (p_error_ - p_error_last_) / dt.toSec();
    p_error_last_ = p_error_;
  }
  // Calculate derivative contribution to command
  d_term = d_gain_ * d_error_;
  cmd_ = p_term + i_term_ + d_term;

  return cmd_;
}

double Pid::updatePid(double error, ros::Duration dt)
{
  double p_term, d_term;
  p_error_ = error; //this is pError = pState-pTarget

  if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error))
    return 0.0;

  // Calculate proportional contribution to command
  p_term = p_gain_ * p_error_;

  //Calculate integral contribution to command
  i_term_ = i_term_ + i_gain_ * dt.toSec() * p_error_;

  // Limit i_term_ so that the limit is meaningful in the output
  i_term_ = std::max( i_min_, std::min( i_term_, i_max_) );

  // Calculate the derivative error
  if (dt.toSec() > 0.0)
  {
    d_error_ = (p_error_ - p_error_last_) / dt.toSec();
    p_error_last_ = p_error_;
  }
  // Calculate derivative contribution to command
  d_term = d_gain_ * d_error_;
  cmd_ = - p_term - i_term_ - d_term;

  return cmd_;
}

double Pid::computeCommand(double error, double error_dot, ros::Duration dt)
{
  double p_term, d_term;
  p_error_ = error; //this is pError = pState-pTarget
  d_error_ = error_dot;

  if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error) || std::isnan(error_dot) || std::isinf(error_dot))
    return 0.0;

  // Calculate proportional contribution to command
  p_term = p_gain_ * p_error_;

  //Calculate integral contribution to command
  i_term_ = i_term_ + i_gain_ * dt.toSec() * p_error_;

  // Limit i_term_ so that the limit is meaningful in the output
  i_term_ = std::max( i_min_, std::min( i_term_, i_max_) );

  // Calculate derivative contribution to command
  d_term = d_gain_ * d_error_;
  cmd_ = p_term + i_term_ + d_term;

  return cmd_;
}

double Pid::updatePid(double error, double error_dot, ros::Duration dt)
{
  double p_term, d_term;
  p_error_ = error; //this is pError = pState-pTarget
  d_error_ = error_dot;

  if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error) || std::isnan(error_dot) || std::isinf(error_dot))
    return 0.0;

  // Calculate proportional contribution to command
  p_term = p_gain_ * p_error_;

  //Calculate integral contribution to command
  i_term_ = i_term_ + i_gain_ * dt.toSec() * p_error_;

  // Limit i_term_ so that the limit is meaningful in the output
  i_term_ = std::max( i_min_, std::min( i_term_, i_max_) );

  // Calculate derivative contribution to command
  d_term = d_gain_ * d_error_;
  cmd_ = - p_term - i_term_ - d_term;

  return cmd_;
}

void Pid::setCurrentCmd(double cmd)
{
  cmd_ = cmd;
}

double Pid::getCurrentCmd()
{
  return cmd_;
}

void Pid::getCurrentPIDErrors(double *pe, double *ie, double *de)
{
  *pe = p_error_;
  *ie = i_gain_ ? i_term_/i_gain_ : 0.0;
  *de = d_error_;
}

}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdint.h>
#include <setjmp.h>
#include <png.h>

namespace png {

uint8_t *load(const char *path, int *width, int *height, int *channels)
{
	FILE *file = fopen(path, "rb");

	if (!file)
		return 0;

	size_t headerSize = 8;
	uint8_t header[8];
	headerSize = fread(header, 1, headerSize, file);

	if (png_sig_cmp(header, 0, headerSize))
	{
		fclose(file);
		return 0;
	}

	png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	if (!png)
	{
		fclose(file);
		return 0;
	}

	png_infop info = png_create_info_struct(png);

	if (!info)
	{
		png_destroy_read_struct(&png, NULL, NULL);
		fclose(file);
		return 0;
	}

	png_infop info_end = png_create_info_struct(png);

	if (!info_end)
	{
		png_destroy_read_struct(&png, &info, NULL);
		fclose(file);
		return 0;
	}

	if (setjmp(png_jmpbuf(png)))
	{
		png_destroy_read_struct(&png, &info, &info_end);
		fclose(file);
		return 0;
	}

	png_init_io(png, file);
	png_set_sig_bytes(png, headerSize);
	png_read_png(png, info, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);

	int color = png_get_color_type(png, info);
	*width = png_get_image_width(png, info);
	*height = png_get_image_height(png, info);

	if (color != PNG_COLOR_TYPE_RGB && color != PNG_COLOR_TYPE_RGB_ALPHA)
	{
		png_destroy_read_struct(&png, &info, &info_end);
		fclose(file);
		return 0;
	}

	png_bytep *rows = png_get_rows(png, info);

	*channels = (color == PNG_COLOR_TYPE_RGB_ALPHA ? 4 : 3);

	uint8_t *image = new uint8_t[(*width) * (*height) * (*channels)];

	for (int y = 0; y < *height; y++)
		memcpy(image + y * (*width) * (*channels), rows[y], (*width) * (*channels));

	png_destroy_read_struct(&png, &info, &info_end);
	fclose(file);

	return image;
}

bool save(const char *filename, int width, int height, unsigned char *data)
{
	FILE *png_file = fopen(filename, "wb");

	if (!png_file)
		return false;

	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	if (!png_ptr)
		return false;

	png_infop info_ptr = png_create_info_struct(png_ptr);

	if (!info_ptr)
		return false;

	png_init_io(png_ptr, png_file);

	png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	png_byte **row_ptrs = new png_byte*[height];

	for (int i = 0; i < height; i++)
		row_ptrs[i] = data + i * width * 4;

	png_set_rows(png_ptr, info_ptr, row_ptrs);
	png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

	png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(png_file);

	delete[] row_ptrs;

	return true;
}

} // namespace png
<commit_msg>Added string.h in png.cpp. Needed for memcpy.<commit_after>#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <setjmp.h>
#include <png.h>

namespace png {

uint8_t *load(const char *path, int *width, int *height, int *channels)
{
	FILE *file = fopen(path, "rb");

	if (!file)
		return 0;

	size_t headerSize = 8;
	uint8_t header[8];
	headerSize = fread(header, 1, headerSize, file);

	if (png_sig_cmp(header, 0, headerSize))
	{
		fclose(file);
		return 0;
	}

	png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	if (!png)
	{
		fclose(file);
		return 0;
	}

	png_infop info = png_create_info_struct(png);

	if (!info)
	{
		png_destroy_read_struct(&png, NULL, NULL);
		fclose(file);
		return 0;
	}

	png_infop info_end = png_create_info_struct(png);

	if (!info_end)
	{
		png_destroy_read_struct(&png, &info, NULL);
		fclose(file);
		return 0;
	}

	if (setjmp(png_jmpbuf(png)))
	{
		png_destroy_read_struct(&png, &info, &info_end);
		fclose(file);
		return 0;
	}

	png_init_io(png, file);
	png_set_sig_bytes(png, headerSize);
	png_read_png(png, info, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);

	int color = png_get_color_type(png, info);
	*width = png_get_image_width(png, info);
	*height = png_get_image_height(png, info);

	if (color != PNG_COLOR_TYPE_RGB && color != PNG_COLOR_TYPE_RGB_ALPHA)
	{
		png_destroy_read_struct(&png, &info, &info_end);
		fclose(file);
		return 0;
	}

	png_bytep *rows = png_get_rows(png, info);

	*channels = (color == PNG_COLOR_TYPE_RGB_ALPHA ? 4 : 3);

	uint8_t *image = new uint8_t[(*width) * (*height) * (*channels)];

	for (int y = 0; y < *height; y++)
		memcpy(image + y * (*width) * (*channels), rows[y], (*width) * (*channels));

	png_destroy_read_struct(&png, &info, &info_end);
	fclose(file);

	return image;
}

bool save(const char *filename, int width, int height, unsigned char *data)
{
	FILE *png_file = fopen(filename, "wb");

	if (!png_file)
		return false;

	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	if (!png_ptr)
		return false;

	png_infop info_ptr = png_create_info_struct(png_ptr);

	if (!info_ptr)
		return false;

	png_init_io(png_ptr, png_file);

	png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	png_byte **row_ptrs = new png_byte*[height];

	for (int i = 0; i < height; i++)
		row_ptrs[i] = data + i * width * 4;

	png_set_rows(png_ptr, info_ptr, row_ptrs);
	png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

	png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(png_file);

	delete[] row_ptrs;

	return true;
}

} // namespace png
<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>

#include "ppu.hpp"
#include "cpu.hpp"
#include "debug.hpp"

PPU::PPU () {}
PPU::~PPU () {}

void PPU::Initialize(CPU* _cpu, MMU* _mmu) {
	assert("CPU reference invalid" && _cpu != nullptr);
	assert("MMU reference invalid" && _mmu != nullptr);
	cpu = _cpu;
	mmu = _mmu;

	// FeedRandomToBackground ();
	// FeedPatternToBackground ();
}

void PPU::SetDisplayStatus () {
	uint8_t status = mmu->ReadByte(LCDSTAT);
	// If display is disabled, set mode to 1 and reset scanline
	if (IsDisplayEnabled() == false) {
		ResetScanline();
		ResetScanlineCounter();

		status &= 252;
		status |= 0x1;
		mmu->WriteByte(LCDSTAT, status);
		return;
	}

	uint8_t currLine = mmu->ReadByte(CURLINE);
	uint8_t currMode = status & 0x3;

	uint8_t nextMode = 0;
	bool requestInterrupt = false;

	/* If in VBLANK, set mode to 1 */
	if (currLine >= 144) {
		nextMode = 1;
		status = (status & ~0x3) | 0x1;
		requestInterrupt = ((status & 0x10) == 0x10);
	}
	/* Mode 2 */
	else if (scanlineCounter >= 376) {
		nextMode = 2;
		status = (status & ~0x3) | 0x2;
		requestInterrupt = ((status & 0x20) == 0x20);
	}
	/* Mode 3 */
	else if (scanlineCounter >= 204) {
		nextMode = 3;
		status = (status & ~0x3) | 0x3;
	}
	/* Mode 0 */
	else {
		nextMode = 0;
		status = (status & ~0x3);
		requestInterrupt = ((status & 0x8) == 0x8);
	}

	// Request an interrupt if we changed modes
	if (requestInterrupt && nextMode != currMode) {
		cpu->RequestInterrupt(1);
	}

	// Coincidence Flag
	if (currLine == mmu->ReadByte(CMPLINE)) {
		status |= 0x4;
		if ((status & 0x20) == 0x20)
			cpu->RequestInterrupt(1);
	}
	else {
		status = (status & ~0x4);
	}

	mmu->WriteByte(LCDSTAT, status);
}

void PPU::StepUpdate (uint16_t cycles) {
	SetDisplayStatus();

	if (IsDisplayEnabled() == false)
		return;

	scanlineCounter -= cycles;

	if (scanlineCounter > 0)
		return;

	uint8_t currLine = NextScanline();

	ResetScanlineCounter();

	if (currLine == 144)
		cpu->RequestInterrupt(0);

	if (currLine > 153)
		ResetScanline();
	else if (currLine < 144) {
		DrawScanline(currLine);
	}
}

uint8_t* PPU::GetDisplayBuffer () {
	return &displayBuffer[0];
}

uint8_t ComputeBitColorID (uint16_t line, uint8_t numBit) {
	return (line & (0x8000 >> numBit)) >> (14 - numBit) |
	       (line & (0x80   >> numBit)) >> (7  - numBit);
}

void PPU::DrawScanline (uint8_t line) {
	uint8_t scrollY = mmu->ReadByte(SCROLLY);
	uint8_t scrollX = mmu->ReadByte(SCROLLX);
	uint16_t bgTilesMapAddress = GetBackgroundTilesAddress();
	uint16_t tilesAddress = GetTilesAddress();

	uint8_t iScrolled = scrollY + line;
	uint8_t iTile = (iScrolled) / 8;

	for (size_t jPixel = 0; jPixel < 160; jPixel += 1) {
		uint8_t jScrolled = scrollX + jPixel;
		uint8_t jTile = (jScrolled) / 8;

		// FIXME: Getting wrong tiles
		uint16_t tileIdAddress = bgTilesMapAddress + iTile * 32 + jTile;
		uint8_t untreatedByte = mmu->ReadByte(tileIdAddress);

		int16_t tileID;
		if (tilesAddress == 0x8000)
			tileID = untreatedByte;
		else
			tileID = reinterpret_cast<int8_t&>(untreatedByte);

		// std::cout << "i: " << std::hex << (int) iTile << '\n';
		// std::cout << "j: " << std::hex << (int) jTile << '\n';
		// std::cout << "tileIdAddress: " << std::hex << (int) tileIdAddress << '\n';
		// std::cout << "tileId:        " << std::hex << (int) tileID << '\n';
		// assert(tileIdAddress != 0x9910);
		// if (tileIdAddress == 0x9910) {
		// 	while (1) {}
		// }

		uint16_t tileLocation = tilesAddress;
		if (tilesAddress == 0x8000)
			tileLocation += tileID * 16;
		else
			tileLocation += (tileID + 128) * 16;
		// if (tileIdLocation == 0x990F)
		// 	tileLocation = 0x80C0;
		uint16_t tile = mmu->ReadWord(tileLocation + (iScrolled % 8) * 2);
		// std::cout << "[" << std::hex << tileLocation << "] " << tileID << " : " << tile  << "\n";

		if (tileID != 0)
			displayBuffer[line * 160 + jPixel] = 3;

		displayBuffer[line * 160 + jPixel] = ComputeBitColorID(tile, jScrolled % 8);
	}
}

void PPU::FeedRandomToDisplay () {
	for (size_t i = 0; i < 160 * 144; i += 1) {
		int luminosity = rand() % 4;
		displayBuffer[i] = luminosity;
	}
}

uint16_t PPU::GetTilesAddress () {
	uint8_t lcdControl = mmu->ReadByte(LCDCTRL);
	if ((lcdControl & 0x10) == 0x10) {
		return 0x8000;
	} else {
		return 0x8800;
	}
}

uint16_t PPU::GetBackgroundTilesAddress () {
	uint8_t lcdControl = mmu->ReadByte(LCDCTRL);
	if ((lcdControl & 0x8) == 0x8) {
		return 0x9C00;
	} else {
		return 0x9800;
	}
}

uint8_t PPU::NextScanline () {
	uint8_t* pScanline = mmu->GetMemoryRef(CURLINE);
	(*pScanline) += 1;
	return *pScanline;
}

void PPU::ResetScanline () {
	(*mmu->GetMemoryRef(CURLINE)) = 0;
}

void PPU::ResetScanlineCounter () {
	scanlineCounter = 456;
}

bool PPU::IsDisplayEnabled () {
	return (mmu->ReadByte(LCDCTRL) & 0x80) == 0x80;
}
<commit_msg>Removed old debugging prints<commit_after>#include <iostream>
#include <algorithm>

#include "ppu.hpp"
#include "cpu.hpp"
#include "debug.hpp"

PPU::PPU () {}
PPU::~PPU () {}

void PPU::Initialize(CPU* _cpu, MMU* _mmu) {
	assert("CPU reference invalid" && _cpu != nullptr);
	assert("MMU reference invalid" && _mmu != nullptr);
	cpu = _cpu;
	mmu = _mmu;

	// FeedRandomToBackground ();
	// FeedPatternToBackground ();
}

void PPU::SetDisplayStatus () {
	uint8_t status = mmu->ReadByte(LCDSTAT);
	// If display is disabled, set mode to 1 and reset scanline
	if (IsDisplayEnabled() == false) {
		ResetScanline();
		ResetScanlineCounter();

		status &= 252;
		status |= 0x1;
		mmu->WriteByte(LCDSTAT, status);
		return;
	}

	uint8_t currLine = mmu->ReadByte(CURLINE);
	uint8_t currMode = status & 0x3;

	uint8_t nextMode = 0;
	bool requestInterrupt = false;

	/* If in VBLANK, set mode to 1 */
	if (currLine >= 144) {
		nextMode = 1;
		status = (status & ~0x3) | 0x1;
		requestInterrupt = ((status & 0x10) == 0x10);
	}
	/* Mode 2 */
	else if (scanlineCounter >= 376) {
		nextMode = 2;
		status = (status & ~0x3) | 0x2;
		requestInterrupt = ((status & 0x20) == 0x20);
	}
	/* Mode 3 */
	else if (scanlineCounter >= 204) {
		nextMode = 3;
		status = (status & ~0x3) | 0x3;
	}
	/* Mode 0 */
	else {
		nextMode = 0;
		status = (status & ~0x3);
		requestInterrupt = ((status & 0x8) == 0x8);
	}

	// Request an interrupt if we changed modes
	if (requestInterrupt && nextMode != currMode) {
		cpu->RequestInterrupt(1);
	}

	// Coincidence Flag
	if (currLine == mmu->ReadByte(CMPLINE)) {
		status |= 0x4;
		if ((status & 0x20) == 0x20)
			cpu->RequestInterrupt(1);
	}
	else {
		status = (status & ~0x4);
	}

	mmu->WriteByte(LCDSTAT, status);
}

void PPU::StepUpdate (uint16_t cycles) {
	SetDisplayStatus();

	if (IsDisplayEnabled() == false)
		return;

	scanlineCounter -= cycles;

	if (scanlineCounter > 0)
		return;

	uint8_t currLine = NextScanline();

	ResetScanlineCounter();

	if (currLine == 144)
		cpu->RequestInterrupt(0);

	if (currLine > 153)
		ResetScanline();
	else if (currLine < 144) {
		DrawScanline(currLine);
	}
}

uint8_t* PPU::GetDisplayBuffer () {
	return &displayBuffer[0];
}

uint8_t ComputeBitColorID (uint16_t line, uint8_t numBit) {
	return (line & (0x8000 >> numBit)) >> (14 - numBit) |
	       (line & (0x80   >> numBit)) >> (7  - numBit);
}

void PPU::DrawScanline (uint8_t line) {
	uint8_t scrollY = mmu->ReadByte(SCROLLY);
	uint8_t scrollX = mmu->ReadByte(SCROLLX);
	uint16_t bgTilesMapAddress = GetBackgroundTilesAddress();
	uint16_t tilesAddress = GetTilesAddress();

	uint8_t iScrolled = scrollY + line;
	uint8_t iTile = (iScrolled) / 8;

	for (size_t jPixel = 0; jPixel < 160; jPixel += 1) {
		uint8_t jScrolled = scrollX + jPixel;
		uint8_t jTile = (jScrolled) / 8;

		// FIXME: Getting wrong tiles
		uint16_t tileIdAddress = bgTilesMapAddress + iTile * 32 + jTile;
		uint8_t untreatedByte = mmu->ReadByte(tileIdAddress);

		int16_t tileID;
		if (tilesAddress == 0x8000)
			tileID = untreatedByte;
		else
			tileID = reinterpret_cast<int8_t&>(untreatedByte);

		// std::cout << "i: " << std::hex << (int) iTile << '\n';
		// std::cout << "j: " << std::hex << (int) jTile << '\n';
		// std::cout << "tileIdAddress: " << std::hex << (int) tileIdAddress << '\n';
		// std::cout << "tileId:        " << std::hex << (int) tileID << '\n';
		// assert(tileIdAddress != 0x9910);
		// if (tileIdAddress == 0x9910) {
		// 	while (1) {}
		// }

		uint16_t tileLocation = tilesAddress;
		if (tilesAddress == 0x8000)
			tileLocation += tileID * 16;
		else
			tileLocation += (tileID + 128) * 16;

		uint16_t tile = mmu->ReadWord(tileLocation + (iScrolled % 8) * 2);

		if (tileID != 0)
			displayBuffer[line * 160 + jPixel] = 3;

		displayBuffer[line * 160 + jPixel] = ComputeBitColorID(tile, jScrolled % 8);
	}
}

void PPU::FeedRandomToDisplay () {
	for (size_t i = 0; i < 160 * 144; i += 1) {
		int luminosity = rand() % 4;
		displayBuffer[i] = luminosity;
	}
}

uint16_t PPU::GetTilesAddress () {
	uint8_t lcdControl = mmu->ReadByte(LCDCTRL);
	if ((lcdControl & 0x10) == 0x10) {
		return 0x8000;
	} else {
		return 0x8800;
	}
}

uint16_t PPU::GetBackgroundTilesAddress () {
	uint8_t lcdControl = mmu->ReadByte(LCDCTRL);
	if ((lcdControl & 0x8) == 0x8) {
		return 0x9C00;
	} else {
		return 0x9800;
	}
}

uint8_t PPU::NextScanline () {
	uint8_t* pScanline = mmu->GetMemoryRef(CURLINE);
	(*pScanline) += 1;
	return *pScanline;
}

void PPU::ResetScanline () {
	(*mmu->GetMemoryRef(CURLINE)) = 0;
}

void PPU::ResetScanlineCounter () {
	scanlineCounter = 456;
}

bool PPU::IsDisplayEnabled () {
	return (mmu->ReadByte(LCDCTRL) & 0x80) == 0x80;
}
<|endoftext|>


<commit_before>#include "ray.hpp"

#include <math.h>
#include <array>
#include <algorithm>

#include "constants.hpp"
#include "box2d.hpp"

void Ray::swap(Ray & rhs)
{
  std::swap(m_origin, rhs.m_origin);
  std::swap(m_direction, rhs.m_direction);
}

Ray::Ray(Ray && rhs)
{
  swap(rhs);

  std::cout << "Move copy constructor" <<std::endl;
}

Ray & Ray::operator=(Ray && rhs)
{
  swap(rhs);

  std::cout << "Move operator=" <<std::endl;

  return *this;
}

bool Ray::operator ==(const Ray & rhs) const
{
  if (this == &rhs) { return true; }

  if (this->m_direction != rhs.direction()) { return false; }
  if (this->m_origin != rhs.origin()) { return false; }

  return true;
}

bool Ray::operator !=(const Ray & rhs) const
{
  return !(this->operator ==(rhs));
}

Ray & Ray::operator=(const Ray & rhs)
{
  Ray tmp(rhs);
  swap(tmp);
  return *this;
}

bool Ray::checkIntersection(
    Ray const & ray,
    Box2D const & box)
{
  // Check if a point inside a box.
  if (Box2D::checkInside(box, ray.origin()))
  {
    return true;
  }

  // Recalculate box points.
  // Use the point as an origin of a coordinate system for the box.
  float x_1_n = box.point1().x() - ray.origin().x();
  float x_2_n = box.point2().x() - ray.origin().x();

  float y_1_n = box.point1().y() - ray.origin().y();
  float y_2_n = box.point2().y() - ray.origin().y();

  float x_3_n = x_1_n;
  float y_3_n = y_2_n;

  float x_4_n = x_2_n;
  float y_4_n = y_1_n;

  float x_ray = ray.direction().x();
  float y_ray = ray.direction().y();

  // Check if the x coordinate is zero.
  x_ray = checkZeroDenominator(x_ray);
  x_1_n = checkZeroDenominator(x_1_n);
  x_2_n = checkZeroDenominator(x_2_n);
  x_3_n = checkZeroDenominator(x_3_n);
  x_4_n = checkZeroDenominator(x_4_n);

  // Calculate an anlge for the current point
  // and convert the angle to degrees.
  float angle_ray = convertRadianToDegrees(
        std::atan(y_ray / x_ray));
  float angle_1_n = convertRadianToDegrees(
        std::atan(y_1_n / x_1_n));
  float angle_2_n = convertRadianToDegrees(
        std::atan(y_2_n / x_2_n));
  float angle_3_n = convertRadianToDegrees(
        std::atan(y_3_n / x_3_n));
  float angle_4_n = convertRadianToDegrees(
        std::atan(y_4_n / x_4_n));

  // Correct a value of the angle if needed.
  angle_ray = recalculateAngle(x_ray, y_ray, angle_ray);
  angle_1_n = recalculateAngle(x_1_n, y_1_n, angle_1_n);
  angle_2_n = recalculateAngle(x_2_n, y_2_n, angle_2_n);
  angle_3_n = recalculateAngle(x_3_n, y_3_n, angle_3_n);
  angle_4_n = recalculateAngle(x_4_n, y_4_n, angle_4_n);

  // Combine all angles for the box points.
  std::array<float, 4> angles = {
    angle_1_n, angle_2_n, angle_3_n, angle_4_n
  };

  // Find a min and max angles for the box points.
  auto result = std::minmax_element(
        std::begin(angles), std::end(angles));

  // Compare the ray angle with the min
  // and max angles for the box points.
  if (*result.first <= angle_ray
      && angle_ray <= *result.second) {
    return true;
  }

  return false;
}

float Ray::convertRadianToDegrees(float const & angle)
{
  return angle / Constants::PI * 180;
}

float Ray::recalculateAngle(float const & x,
                            float const & y,
                            float const & angle)
{
  float angle_n = 0.0f;

  // The second quarter.
  if (y > (0.0f - Constants::kEps) &&
      x < (0.0f + Constants::kEps))
  {
    angle_n = 180.0f - abs(angle);
  }

  // The third quarter.
  if (y < 0.0f &&
      x < (0.0f + Constants::kEps))
  {
    angle_n = 180.0f + abs(angle);
  }

  // The fouth quarter.
  if (y < 0.0f &&
      x > 0.0f)
  {
    angle_n = 360.0f - abs(angle);
  }

  return angle_n;
}

float Ray::checkZeroDenominator(float const & value)
{
  float tmp = value;

  if (abs(tmp) < Constants::kEps)
  {
    tmp = Constants::kEps;
  }

  return tmp;
}

std::ostream & operator <<(std::ostream & os,
                           Ray const & rhs)
{
  os << "origin: " << rhs.origin() << "; "
     << "direction: " << rhs.direction() << std::endl;
  return os;
}
<commit_msg>fix bug in the code<commit_after>#include "ray.hpp"

#include <math.h>
#include <array>
#include <algorithm>

#include "constants.hpp"
#include "box2d.hpp"

void Ray::swap(Ray & rhs)
{
  std::swap(m_origin, rhs.m_origin);
  std::swap(m_direction, rhs.m_direction);
}

Ray::Ray(Ray && rhs)
{
  swap(rhs);

  std::cout << "Move copy constructor" <<std::endl;
}

Ray & Ray::operator=(Ray && rhs)
{
  swap(rhs);

  std::cout << "Move operator=" <<std::endl;

  return *this;
}

bool Ray::operator ==(const Ray & rhs) const
{
  if (this == &rhs) { return true; }

  if (this->m_direction != rhs.direction()) { return false; }
  if (this->m_origin != rhs.origin()) { return false; }

  return true;
}

bool Ray::operator !=(const Ray & rhs) const
{
  return !(this->operator ==(rhs));
}

Ray & Ray::operator=(const Ray & rhs)
{
  Ray tmp(rhs);
  swap(tmp);
  return *this;
}

bool Ray::checkIntersection(
    Ray const & ray,
    Box2D const & box)
{
  // Check if a point inside a box.
  if (Box2D::checkInside(box, ray.origin()))
  {
    return true;
  }

  bool is_special = false;

  // Recalculate box points.
  // Use the point as an origin of a coordinate system for the box.
  float x_1_n = box.point1().x() - ray.origin().x();
  float x_2_n = box.point2().x() - ray.origin().x();

  float y_1_n = box.point1().y() - ray.origin().y();
  float y_2_n = box.point2().y() - ray.origin().y();

  float x_3_n = x_1_n;
  float y_3_n = y_2_n;

  float x_4_n = x_2_n;
  float y_4_n = y_1_n;

  float x_ray = ray.direction().x();
  float y_ray = ray.direction().y();

  // It handels special case when rectangle intersepts x-axis
  // to the right from an origin point of a ray.
  if (x_ray < x_1_n && x_ray < x_2_n)
  {
    is_special = true;
  }

  // Check if the x coordinate is zero.
  x_ray = checkZeroDenominator(x_ray);
  x_1_n = checkZeroDenominator(x_1_n);
  x_2_n = checkZeroDenominator(x_2_n);
  x_3_n = checkZeroDenominator(x_3_n);
  x_4_n = checkZeroDenominator(x_4_n);

  // Calculate an anlge for the current point
  // and convert the angle to degrees.
  float angle_ray = convertRadianToDegrees(
        std::atan(y_ray / x_ray));
  float angle_1_n = convertRadianToDegrees(
        std::atan(y_1_n / x_1_n));
  float angle_2_n = convertRadianToDegrees(
        std::atan(y_2_n / x_2_n));
  float angle_3_n = convertRadianToDegrees(
        std::atan(y_3_n / x_3_n));
  float angle_4_n = convertRadianToDegrees(
        std::atan(y_4_n / x_4_n));

  // Correct a value of the angle if needed.
  angle_ray = recalculateAngle(x_ray, y_ray, angle_ray);
  angle_1_n = recalculateAngle(x_1_n, y_1_n, angle_1_n);
  angle_2_n = recalculateAngle(x_2_n, y_2_n, angle_2_n);
  angle_3_n = recalculateAngle(x_3_n, y_3_n, angle_3_n);
  angle_4_n = recalculateAngle(x_4_n, y_4_n, angle_4_n);

  // Combine all angles for the box points.
  std::array<float, 4> angles = {
    angle_1_n, angle_2_n, angle_3_n, angle_4_n
  };

  if (is_special)
  {
    // It finds to angles.
    // Maximum angle in the first quater
    // and the minimun angle in the fouth quater.
    float angle_max_first_quater = 0.0f;
    float angle_min_fourth_quater = 360.0f;

    for (auto const & item : angles)
    {
      if (item < 90.0f)
      {
        if (angle_max_first_quater < item)
        {
          angle_max_first_quater = item;
        }
      }
      else if (item > 270.0f)
      {
        if (angle_min_fourth_quater > item)
        {
          angle_min_fourth_quater = item;
        }
      }
    }

    // Compare the ray angle with
    // the max angle in the first quater
    // and the min angle in the fouth quater.
    if (angle_ray <= angle_max_first_quater &&
        angle_ray >= angle_min_fourth_quater) {
      return true;
    }
  }
  else
  {
    // Find a min and max angles for the box points.
    auto result = std::minmax_element(
          std::begin(angles), std::end(angles));

    // Compare the ray angle with the min
    // and max angles for the box points.
    if (*result.first <= angle_ray &&
        angle_ray <= *result.second) {
      return true;
    }
  }

  return false;
}

float Ray::convertRadianToDegrees(float const & angle)
{
  return angle / Constants::PI * 180;
}

float Ray::recalculateAngle(float const & x,
                            float const & y,
                            float const & angle)
{
  float angle_n = 0.0f;

  // The second quarter.
  if (y > (0.0f - Constants::kEps) &&
      x < (0.0f + Constants::kEps))
  {
    angle_n = 180.0f - abs(angle);
  }

  // The third quarter.
  if (y < 0.0f &&
      x < (0.0f + Constants::kEps))
  {
    angle_n = 180.0f + abs(angle);
  }

  // The fouth quarter.
  if (y < 0.0f &&
      x > 0.0f)
  {
    angle_n = 360.0f - abs(angle);
  }

  return angle_n;
}

float Ray::checkZeroDenominator(float const & value)
{
  float tmp = value;

  if (abs(tmp) < Constants::kEps)
  {
    tmp = Constants::kEps;
  }

  return tmp;
}

std::ostream & operator <<(std::ostream & os,
                           Ray const & rhs)
{
  os << "origin: " << rhs.origin() << "; "
     << "direction: " << rhs.direction() << std::endl;
  return os;
}
<|endoftext|>


<commit_before>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"
#include "db.h"
#include "nw.h"
#include "search8.h"
#include "search16.h"
#include "threads.h"
#include "util.h"

static pthread_mutex_t scan_mutex;

static ThreadRunner * search_threads = nullptr;

struct search_data
{
  BYTE ** qtable;
  WORD ** qtable_w;

  BYTE * dprofile;
  WORD * dprofile_w;

  BYTE * hearray;

  uint64_t * dir_array;

  uint64_t target_count;
  uint64_t target_index;
};

static struct search_data * sd;
static uint64_t master_next;
static uint64_t master_length;
static uint64_t remainingchunks;
static uint64_t * master_targets;
static uint64_t * master_scores;
static uint64_t * master_diffs;
static uint64_t * master_alignlengths;
static int master_bits;
static uint64_t dirbufferbytes;

queryinfo_t query;
uint64_t longestdbsequence;

void search_alloc(struct search_data * sdp);
void search_free(struct search_data * sdp);
void search_init(struct search_data * sdp);
void search_chunk(struct search_data * sdp, int64_t bits);
auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool;
void search_worker_core(int64_t t);
auto search_worker(void * vp) -> void *;

void search_alloc(struct search_data * sdp)
{
  constexpr unsigned int one_kilobyte {1024};
  constexpr unsigned int nt_per_uint64 {32};
  constexpr unsigned int bytes_per_uint64 {8};

  dirbufferbytes =
    bytes_per_uint64 * longestdbsequence * ((longestdbsequence + 3) / 4) * 4;
  sdp->qtable = static_cast<BYTE**>
    (xmalloc(longestdbsequence * sizeof(BYTE*)));
  sdp->qtable_w = static_cast<WORD**>
    (xmalloc(longestdbsequence * sizeof(WORD*)));
  sdp->dprofile = static_cast<BYTE*>
    (xmalloc(2 * one_kilobyte));  // 4 * 16 * 32
  sdp->dprofile_w = static_cast<WORD*>
    (xmalloc(2 * one_kilobyte));  // 4 * 2 * 8 * 32
  sdp->hearray = static_cast<BYTE*>
    (xmalloc(longestdbsequence * nt_per_uint64));
  sdp->dir_array = static_cast<uint64_t *>
    (xmalloc(dirbufferbytes));

  memset(sdp->hearray, 0, longestdbsequence * nt_per_uint64);
  memset(sdp->dir_array, 0, dirbufferbytes);
}

void search_free(struct search_data * sdp)
{
  xfree(sdp->qtable);
  xfree(sdp->qtable_w);
  xfree(sdp->dprofile);
  xfree(sdp->dprofile_w);
  xfree(sdp->hearray);
  xfree(sdp->dir_array);
}

void search_init(struct search_data * sdp)
{
  constexpr int byte_multiplier {64};
  constexpr int word_multiplier {32};

  for(auto i = 0U; i < query.len; i++)
  {
    int nt_value {nt_extract(query.seq, i) + 1};   // 1,  2,   3, or   4
    int byte_offset {byte_multiplier * nt_value};  // 1, 64, 128, or 192
    int word_offset {word_multiplier * nt_value};  // 1, 32,  64, or 128

    sdp->qtable[i]   = sdp->dprofile   + byte_offset;
    sdp->qtable_w[i] = sdp->dprofile_w + word_offset;
  }
}

void search_chunk(struct search_data * sdp, int64_t bits)
{
  constexpr unsigned int bit_mode_16 {16};
  if (sdp->target_count == 0) {
    return;
  }

#if 0

  for(auto i = 0ULL; i < sdp->target_count; i++)
    {
    char * dseq;
    unsigned int dlen;
    char * nwalignment;

    uint64_t seqno = master_targets[sdp->target_index + i];
    db_getsequenceandlength(seqno, & dseq, & dlen);

    nw(dseq, dlen,
       query.seq, query.len,
       score_matrix_63,
       penalty_gapopen, penalty_gapextend,
       (int64_t *)(master_scores) + sdp->target_index + i,
       (int64_t *)(master_diffs) + sdp->target_index + i,
       (int64_t *)(master_alignlengths) + sdp->target_index + i,
       & nwalignment,
       (unsigned char *) sdp->dir_array,
       (int64_t *) sdp->hearray,
       query.qno, seqno);

#if 0
    printf("\nAlignment: %s\n", nwalignment);
#endif

    xfree(nwalignment);
  }

  return;

#endif

 if (bits == bit_mode_16)
   {
    search16(sdp->qtable_w,
             static_cast<WORD>(penalty_gapopen),
             static_cast<WORD>(penalty_gapextend),
             static_cast<WORD*>(score_matrix_16),
             sdp->dprofile_w,
             reinterpret_cast<WORD*>(sdp->hearray),
             sdp->target_count,
             master_targets + sdp->target_index,
             master_scores + sdp->target_index,
             master_diffs + sdp->target_index,
             master_alignlengths + sdp->target_index,
             static_cast<uint64_t>(query.len),
             dirbufferbytes / sizeof(uint64_t),
             sdp->dir_array,
             longestdbsequence);
   }
 else {
    search8(sdp->qtable,
            static_cast<BYTE>(penalty_gapopen),
            static_cast<BYTE>(penalty_gapextend),
            static_cast<BYTE*>(score_matrix_8),
            sdp->dprofile,
            sdp->hearray,
            sdp->target_count,
            master_targets + sdp->target_index,
            master_scores + sdp->target_index,
            master_diffs + sdp->target_index,
            master_alignlengths + sdp->target_index,
            static_cast<uint64_t>(query.len),
            dirbufferbytes / sizeof(uint64_t),
            sdp->dir_array,
            longestdbsequence);
 }
}

auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool
{
  // * countref = how many sequences to search
  // * firstref = index into master_targets/scores/diffs where thread should start

  bool status {false};

  pthread_mutex_lock(&scan_mutex);

  if (master_next < master_length)
    {
      uint64_t chunksize =
        ((master_length - master_next + remainingchunks - 1) / remainingchunks);

      * countref = chunksize;
      * firstref = master_next;

      master_next += chunksize;
      remainingchunks--;
      status = true;
    }

  pthread_mutex_unlock(&scan_mutex);

  return status;
}

void search_worker_core(int64_t t)
{
  search_init(sd + t);
  while(search_getwork(& sd[t].target_count, & sd[t].target_index)) {
    search_chunk(sd + t, master_bits);
  }
}

void search_do(uint64_t query_no,
               uint64_t listlength,
               uint64_t * targets,
               uint64_t * scores,
               uint64_t * diffs,
               uint64_t * alignlengths,
               int bits)
{
  // constexpr unsigned int bit_mode_16 {16};
  constexpr unsigned int channels_8 {8};
  constexpr unsigned int bit_mode_8 {8};
  constexpr unsigned int channels_16 {16};
  query.qno = query_no;
  unsigned int query_len = 0;
  db_getsequenceandlength(query_no, &query.seq, &query_len);
  query.len = query_len;

  master_next = 0;
  master_length = listlength;
  master_targets = targets;
  master_scores = scores;
  master_diffs = diffs;
  master_alignlengths = alignlengths;
  master_bits = bits;

  auto thr = static_cast<uint64_t>(opt_threads);

  if (bits == bit_mode_8)
    {
      if (master_length <= (channels_16 - 1) * thr) {
        thr = (master_length + channels_16 - 1) / channels_16;
      }
    }
  else
    {
      if (master_length <= (channels_8 - 1) * thr) {
        thr = (master_length + channels_8 - 1) / channels_8;
      }
    }

  remainingchunks = thr;

  if (thr == 1) {
    search_worker_core(0);
  }
  else {
    search_threads->run();
  }
}

void search_begin()
{
  longestdbsequence = db_getlongestsequence();

  sd = static_cast<struct search_data *>
    (xmalloc(sizeof(search_data) * static_cast<uint64_t>(opt_threads)));

  for(auto t = 0LL; t < opt_threads; t++) {
    search_alloc(sd+t);
  }

  pthread_mutex_init(& scan_mutex, nullptr);

  /* start threads */

  search_threads
    = new ThreadRunner(static_cast<int>(opt_threads), search_worker_core);
}

void search_end()
{
  /* finish and clean up worker threads */

  delete search_threads;

  pthread_mutex_destroy(& scan_mutex);

  for(auto t = 0LL; t < opt_threads; t++) {
    search_free(sd+t);
  }
  xfree(sd);
}
<commit_msg>set pointer to nullptr after delete (recommended)<commit_after>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"
#include "db.h"
#include "nw.h"
#include "search8.h"
#include "search16.h"
#include "threads.h"
#include "util.h"

static pthread_mutex_t scan_mutex;

static ThreadRunner * search_threads = nullptr;

struct search_data
{
  BYTE ** qtable;
  WORD ** qtable_w;

  BYTE * dprofile;
  WORD * dprofile_w;

  BYTE * hearray;

  uint64_t * dir_array;

  uint64_t target_count;
  uint64_t target_index;
};

static struct search_data * sd;
static uint64_t master_next;
static uint64_t master_length;
static uint64_t remainingchunks;
static uint64_t * master_targets;
static uint64_t * master_scores;
static uint64_t * master_diffs;
static uint64_t * master_alignlengths;
static int master_bits;
static uint64_t dirbufferbytes;

queryinfo_t query;
uint64_t longestdbsequence;

void search_alloc(struct search_data * sdp);
void search_free(struct search_data * sdp);
void search_init(struct search_data * sdp);
void search_chunk(struct search_data * sdp, int64_t bits);
auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool;
void search_worker_core(int64_t t);
auto search_worker(void * vp) -> void *;

void search_alloc(struct search_data * sdp)
{
  constexpr unsigned int one_kilobyte {1024};
  constexpr unsigned int nt_per_uint64 {32};
  constexpr unsigned int bytes_per_uint64 {8};

  dirbufferbytes =
    bytes_per_uint64 * longestdbsequence * ((longestdbsequence + 3) / 4) * 4;
  sdp->qtable = static_cast<BYTE**>
    (xmalloc(longestdbsequence * sizeof(BYTE*)));
  sdp->qtable_w = static_cast<WORD**>
    (xmalloc(longestdbsequence * sizeof(WORD*)));
  sdp->dprofile = static_cast<BYTE*>
    (xmalloc(2 * one_kilobyte));  // 4 * 16 * 32
  sdp->dprofile_w = static_cast<WORD*>
    (xmalloc(2 * one_kilobyte));  // 4 * 2 * 8 * 32
  sdp->hearray = static_cast<BYTE*>
    (xmalloc(longestdbsequence * nt_per_uint64));
  sdp->dir_array = static_cast<uint64_t *>
    (xmalloc(dirbufferbytes));

  memset(sdp->hearray, 0, longestdbsequence * nt_per_uint64);
  memset(sdp->dir_array, 0, dirbufferbytes);
}

void search_free(struct search_data * sdp)
{
  xfree(sdp->qtable);
  xfree(sdp->qtable_w);
  xfree(sdp->dprofile);
  xfree(sdp->dprofile_w);
  xfree(sdp->hearray);
  xfree(sdp->dir_array);
}

void search_init(struct search_data * sdp)
{
  constexpr int byte_multiplier {64};
  constexpr int word_multiplier {32};

  for(auto i = 0U; i < query.len; i++)
  {
    int nt_value {nt_extract(query.seq, i) + 1};   // 1,  2,   3, or   4
    int byte_offset {byte_multiplier * nt_value};  // 1, 64, 128, or 192
    int word_offset {word_multiplier * nt_value};  // 1, 32,  64, or 128

    sdp->qtable[i]   = sdp->dprofile   + byte_offset;
    sdp->qtable_w[i] = sdp->dprofile_w + word_offset;
  }
}

void search_chunk(struct search_data * sdp, int64_t bits)
{
  constexpr unsigned int bit_mode_16 {16};
  if (sdp->target_count == 0) {
    return;
  }

#if 0

  for(auto i = 0ULL; i < sdp->target_count; i++)
    {
    char * dseq;
    unsigned int dlen;
    char * nwalignment;

    uint64_t seqno = master_targets[sdp->target_index + i];
    db_getsequenceandlength(seqno, & dseq, & dlen);

    nw(dseq, dlen,
       query.seq, query.len,
       score_matrix_63,
       penalty_gapopen, penalty_gapextend,
       (int64_t *)(master_scores) + sdp->target_index + i,
       (int64_t *)(master_diffs) + sdp->target_index + i,
       (int64_t *)(master_alignlengths) + sdp->target_index + i,
       & nwalignment,
       (unsigned char *) sdp->dir_array,
       (int64_t *) sdp->hearray,
       query.qno, seqno);

#if 0
    printf("\nAlignment: %s\n", nwalignment);
#endif

    xfree(nwalignment);
  }

  return;

#endif

 if (bits == bit_mode_16)
   {
    search16(sdp->qtable_w,
             static_cast<WORD>(penalty_gapopen),
             static_cast<WORD>(penalty_gapextend),
             static_cast<WORD*>(score_matrix_16),
             sdp->dprofile_w,
             reinterpret_cast<WORD*>(sdp->hearray),
             sdp->target_count,
             master_targets + sdp->target_index,
             master_scores + sdp->target_index,
             master_diffs + sdp->target_index,
             master_alignlengths + sdp->target_index,
             static_cast<uint64_t>(query.len),
             dirbufferbytes / sizeof(uint64_t),
             sdp->dir_array,
             longestdbsequence);
   }
 else {
    search8(sdp->qtable,
            static_cast<BYTE>(penalty_gapopen),
            static_cast<BYTE>(penalty_gapextend),
            static_cast<BYTE*>(score_matrix_8),
            sdp->dprofile,
            sdp->hearray,
            sdp->target_count,
            master_targets + sdp->target_index,
            master_scores + sdp->target_index,
            master_diffs + sdp->target_index,
            master_alignlengths + sdp->target_index,
            static_cast<uint64_t>(query.len),
            dirbufferbytes / sizeof(uint64_t),
            sdp->dir_array,
            longestdbsequence);
 }
}

auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool
{
  // * countref = how many sequences to search
  // * firstref = index into master_targets/scores/diffs where thread should start

  bool status {false};

  pthread_mutex_lock(&scan_mutex);

  if (master_next < master_length)
    {
      uint64_t chunksize =
        ((master_length - master_next + remainingchunks - 1) / remainingchunks);

      * countref = chunksize;
      * firstref = master_next;

      master_next += chunksize;
      remainingchunks--;
      status = true;
    }

  pthread_mutex_unlock(&scan_mutex);

  return status;
}

void search_worker_core(int64_t t)
{
  search_init(sd + t);
  while(search_getwork(& sd[t].target_count, & sd[t].target_index)) {
    search_chunk(sd + t, master_bits);
  }
}

void search_do(uint64_t query_no,
               uint64_t listlength,
               uint64_t * targets,
               uint64_t * scores,
               uint64_t * diffs,
               uint64_t * alignlengths,
               int bits)
{
  // constexpr unsigned int bit_mode_16 {16};
  constexpr unsigned int channels_8 {8};
  constexpr unsigned int bit_mode_8 {8};
  constexpr unsigned int channels_16 {16};
  query.qno = query_no;
  unsigned int query_len = 0;
  db_getsequenceandlength(query_no, &query.seq, &query_len);
  query.len = query_len;

  master_next = 0;
  master_length = listlength;
  master_targets = targets;
  master_scores = scores;
  master_diffs = diffs;
  master_alignlengths = alignlengths;
  master_bits = bits;

  auto thr = static_cast<uint64_t>(opt_threads);

  if (bits == bit_mode_8)
    {
      if (master_length <= (channels_16 - 1) * thr) {
        thr = (master_length + channels_16 - 1) / channels_16;
      }
    }
  else
    {
      if (master_length <= (channels_8 - 1) * thr) {
        thr = (master_length + channels_8 - 1) / channels_8;
      }
    }

  remainingchunks = thr;

  if (thr == 1) {
    search_worker_core(0);
  }
  else {
    search_threads->run();
  }
}

void search_begin()
{
  longestdbsequence = db_getlongestsequence();

  sd = static_cast<struct search_data *>
    (xmalloc(sizeof(search_data) * static_cast<uint64_t>(opt_threads)));

  for(auto t = 0LL; t < opt_threads; t++) {
    search_alloc(sd+t);
  }

  pthread_mutex_init(& scan_mutex, nullptr);

  /* start threads */

  search_threads
    = new ThreadRunner(static_cast<int>(opt_threads), search_worker_core);
}

void search_end()
{
  /* finish and clean up worker threads */

  delete search_threads;
  search_threads = nullptr;

  pthread_mutex_destroy(& scan_mutex);

  for(auto t = 0LL; t < opt_threads; t++) {
    search_free(sd+t);
  }
  xfree(sd);
}
<|endoftext|>


<commit_before>#include<iostream>
#include<vector>
#include<cstdio>
#include<string>
#include<thread>
#include<dirent.h>
#include<chrono>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<fcntl.h>
#include<unistd.h>
#include<cstdlib>
#include<sys/wait.h>
#include<string.h>
#include<mutex>
#define SUCCESS 0
#define FAILURE 1
#define MAX_SIZE 1024
#define CLI_ID "101"
#define TOKEN "#"
#define BCAST_PORT 6000
#define LISTENER_PORT 54545

void fs_bcast()
{
	//Current Client Socket
	int bcast_sockfd;

	bcast_sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	struct sockaddr_in new_addr;
	memset(&new_addr, 0, sizeof(new_addr));
	new_addr.sin_family = AF_INET;
	new_addr.sin_port = BCAST_PORT;
	new_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	while(1)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(5000));
		DIR *dir;
		struct dirent *ent;
		char fs_data[MAX_SIZE];
		memset(fs_data, 0, MAX_SIZE);
		strcpy(fs_data, CLI_ID);
		if ((dir = opendir ("./")) != NULL)
		{
  			while((ent = readdir (dir)) != NULL)
 			{
				if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
          			{continue;}
				else
				{
					strcat(fs_data, TOKEN);
  					strcat(fs_data, ent->d_name);
          			}
			}
		}
  		closedir (dir);
		std::cout << fs_data << std::endl;
		sendto(bcast_sockfd, fs_data, strlen(fs_data), 0, (struct sockaddr *)&new_addr, sizeof(struct sockaddr_in));
	}
}

void bcast_listener()
{
	int sockfd;
	std::cout<<"Hello"<<std::endl;
	struct sockaddr_in new_addr;
	struct sockaddr_in cli_addr;
	unsigned slen = sizeof(cli_addr);

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	memset(&new_addr, 0, sizeof(new_addr));
	new_addr.sin_family = AF_INET;
	new_addr.sin_port = LISTENER_PORT;
	new_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	int bind_status = bind(sockfd, (struct sockaddr*)&new_addr, sizeof(new_addr));

	while(1)
	{
		char bcast_buffer[1024];
		memset(bcast_buffer, 0, sizeof(bcast_buffer));
		recvfrom(sockfd, bcast_buffer, sizeof(bcast_buffer)-1, 0, (sockaddr *)&cli_addr, &slen);
		std::cout << "Listening.." <<std::endl;
		std::cout << "GOT FS" << bcast_buffer << std::endl;
	}
}

int main(int argc, char **argv)
{

	std::thread broadcaster(fs_bcast);
	std::thread listener(bcast_listener);
	broadcaster.detach();
	listener.detach();
	while(1){}
	return SUCCESS;
}

<commit_msg>Parsing config<commit_after>#include<iostream>
#include<vector>
#include<cstdio>
#include<string>
#include<thread>
#include<dirent.h>
#include<chrono>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<fcntl.h>
#include<unistd.h>
#include<cstdlib>
#include<sys/wait.h>
#include<string.h>
#include<mutex>
#include<unordered_map>
#include <iostream>
#include <fstream>
#define SUCCESS 0
#define FAILURE 1
#define MAX_SIZE 1024
#define CLI_ID "101"
#define TOKEN "#"
#define BCAST_PORT 6000
#define LISTENER_PORT 54545

char Client_id[15]={0};
char b_cast_time[10]={0};

//unordered_map<std::string,std::string> cluster_info;

void config_parser()
{
	std::fstream config_file;
	std::string line;
	config_file.open("../files/config",std::ios::in|std::ios::out);
	while(getline(config_file,line))
	{

		if(0==line.length())
			continue;
		else
			std::cout<<line<<std::endl;
	}

}

void fs_bcast()
{
	//Current Client Socket
	int bcast_sockfd;

	bcast_sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	struct sockaddr_in new_addr;
	memset(&new_addr, 0, sizeof(new_addr));
	new_addr.sin_family = AF_INET;
	new_addr.sin_port = BCAST_PORT;
	new_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	while(1)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(5000));
		DIR *dir;
		struct dirent *ent;
		char fs_data[MAX_SIZE];
		memset(fs_data, 0, MAX_SIZE);
		strcpy(fs_data, CLI_ID);
		if ((dir = opendir ("./")) != NULL)
		{
  			while((ent = readdir (dir)) != NULL)
 			{
				if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
          			{continue;}
				else
				{
					strcat(fs_data, TOKEN);
  					strcat(fs_data, ent->d_name);
          			}
			}
		}
  		closedir (dir);
		std::cout << fs_data << std::endl;
		sendto(bcast_sockfd, fs_data, strlen(fs_data), 0, (struct sockaddr *)&new_addr, sizeof(struct sockaddr_in));
	}
}

void bcast_listener()
{
	int sockfd;
	std::cout<<"Hello"<<std::endl;
	struct sockaddr_in new_addr;
	struct sockaddr_in cli_addr;
	unsigned slen = sizeof(cli_addr);

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	memset(&new_addr, 0, sizeof(new_addr));
	new_addr.sin_family = AF_INET;
	new_addr.sin_port = LISTENER_PORT;
	new_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	int bind_status = bind(sockfd, (struct sockaddr*)&new_addr, sizeof(new_addr));

	while(1)
	{
		char bcast_buffer[1024];
		memset(bcast_buffer, 0, sizeof(bcast_buffer));
		recvfrom(sockfd, bcast_buffer, sizeof(bcast_buffer)-1, 0, (sockaddr *)&cli_addr, &slen);
		std::cout << "Listening.." <<std::endl;
		std::cout << "GOT FS" << bcast_buffer << std::endl;
	}
}

int main(int argc, char **argv)
{

	std::thread broadcaster(fs_bcast);
	std::thread listener(bcast_listener);
	broadcaster.detach();
	listener.detach();
	while(1){}
	return SUCCESS;
}

<|endoftext|>


<commit_before>
// This file is part of node-lmdb, the Node.js binding for lmdb
// Copyright (c) 2013-2017 Timur Kristóf
// Licensed to you under the terms of the MIT license
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "node-lmdb.h"

using namespace v8;
using namespace node;

TxnWrap::TxnWrap(MDB_env *env, MDB_txn *txn) {
    this->env = env;
    this->txn = txn;
    this->flags = 0;
}

TxnWrap::~TxnWrap() {
    // Close if not closed already
    if (this->txn) {
        mdb_txn_abort(txn);
        this->removeFromEnvWrap();
    }
}

void TxnWrap::removeFromEnvWrap() {
    if (this->ew) {
        if (this->ew->currentWriteTxn == this) {
            this->ew->currentWriteTxn = nullptr;
        }
        else {
            auto it = std::find(ew->readTxns.begin(), ew->readTxns.end(), this);
            if (it != ew->readTxns.end()) {
                ew->readTxns.erase(it);
            }
        }

        this->ew->Unref();
        this->ew = nullptr;
    }
}

NAN_METHOD(TxnWrap::ctor) {
    Nan::HandleScope scope;

    EnvWrap *ew = Nan::ObjectWrap::Unwrap<EnvWrap>(info[0]->ToObject());
    int flags = 0;

    if (info[1]->IsObject()) {
        Local<Object> options = info[1]->ToObject();

        // Get flags from options

        setFlagFromValue(&flags, MDB_RDONLY, "readOnly", false, options);
    }

    // Check existence of current write transaction
    if (0 == (flags & MDB_RDONLY) && ew->currentWriteTxn != nullptr) {
        return Nan::ThrowError("You have already opened a write transaction in the current process, can't open a second one.");
    }

    MDB_txn *txn;
    int rc = mdb_txn_begin(ew->env, nullptr, flags, &txn);
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }

    TxnWrap* tw = new TxnWrap(ew->env, txn);
    tw->flags = flags;
    tw->ew = ew;
    tw->ew->Ref();
    tw->Wrap(info.This());

    // Set the current write transaction
    if (0 == (flags & MDB_RDONLY)) {
        ew->currentWriteTxn = tw;
    }
    else {
        ew->readTxns.push_back(tw);
    }

    return info.GetReturnValue().Set(info.This());
}

NAN_METHOD(TxnWrap::commit) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int rc = mdb_txn_commit(tw->txn);
    tw->removeFromEnvWrap();
    tw->txn = nullptr;

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

NAN_METHOD(TxnWrap::abort) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    mdb_txn_abort(tw->txn);
    tw->removeFromEnvWrap();
    tw->txn = nullptr;
}

NAN_METHOD(TxnWrap::reset) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    mdb_txn_reset(tw->txn);
}

NAN_METHOD(TxnWrap::renew) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int rc = mdb_txn_renew(tw->txn);
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

Nan::NAN_METHOD_RETURN_TYPE TxnWrap::getCommon(Nan::NAN_METHOD_ARGS_TYPE info, Local<Value> (*successFunc)(MDB_val&)) {
    Nan::HandleScope scope;

    if (info.Length() != 2 && info.Length() != 3) {
        return Nan::ThrowError("Invalid number of arguments to cursor.get");
    }

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    MDB_val key, oldkey, data;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[2], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    // Bookkeeping for old key so that we can free it even if key will point inside LMDB
    oldkey.mv_data = key.mv_data;
    oldkey.mv_size = key.mv_size;

    int rc = mdb_get(tw->txn, dw->dbi, &key, &data);

    if (freeKey) {
        freeKey(oldkey);
    }

    if (rc == MDB_NOTFOUND) {
        return info.GetReturnValue().Set(Nan::Null());
    }
    else if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
    else {
      return info.GetReturnValue().Set(successFunc(data));
    }
}

NAN_METHOD(TxnWrap::getString) {
    return getCommon(info, valToString);
}

NAN_METHOD(TxnWrap::getStringUnsafe) {
    return getCommon(info, valToStringUnsafe);
}

NAN_METHOD(TxnWrap::getBinary) {
    return getCommon(info, valToBinary);
}

NAN_METHOD(TxnWrap::getBinaryUnsafe) {
    return getCommon(info, valToBinaryUnsafe);
}

NAN_METHOD(TxnWrap::getNumber) {
    return getCommon(info, valToNumber);
}

NAN_METHOD(TxnWrap::getBoolean) {
    return getCommon(info, valToBoolean);
}

Nan::NAN_METHOD_RETURN_TYPE TxnWrap::putCommon(Nan::NAN_METHOD_ARGS_TYPE info, void (*fillFunc)(Nan::NAN_METHOD_ARGS_TYPE info, MDB_val&), void (*freeData)(MDB_val&)) {
    Nan::HandleScope scope;

    if (info.Length() != 3 && info.Length() != 4) {
        return Nan::ThrowError("Invalid number of arguments to cursor.put");
    }

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int flags = 0;
    MDB_val key, data;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[3], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    if (!info[3]->IsNull() && !info[3]->IsUndefined() && info[3]->IsObject()) {
        auto options = info[3]->ToObject();
        setFlagFromValue(&flags, MDB_NODUPDATA, "noDupData", false, options);
        setFlagFromValue(&flags, MDB_NOOVERWRITE, "noOverwrite", false, options);
        setFlagFromValue(&flags, MDB_APPEND, "append", false, options);
        setFlagFromValue(&flags, MDB_APPENDDUP, "appendDup", false, options);

        // NOTE: does not make sense to support MDB_RESERVE, because it wouldn't save the memcpy from V8 to lmdb
    }

    // Fill key and data
    fillFunc(info, data);

    // Keep a copy of the original key and data, so we can free them
    MDB_val originalKey = key;
    MDB_val originalData = data;

    int rc = mdb_put(tw->txn, dw->dbi, &key, &data, flags);

    // Free original key and data (what was supplied by the user, not what points to lmdb)
    if (freeKey) {
        freeKey(originalKey);
    }
    if (freeData) {
        freeData(originalData);
    }

    // Check result code
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

NAN_METHOD(TxnWrap::putString) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        CustomExternalStringResource::writeTo(info[2]->ToString(), &data);
    }, [](MDB_val &data) -> void {
        delete[] (uint16_t*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::putBinary) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = node::Buffer::Length(info[2]);
        data.mv_data = node::Buffer::Data(info[2]);
    }, [](MDB_val &) -> void {
        // The data is owned by the node::Buffer so we don't need to free it.
    });
}

NAN_METHOD(TxnWrap::putNumber) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = sizeof(double);
        data.mv_data = new double;
        auto numberLocal = Nan::To<v8::Number>(info[2]).ToLocalChecked();
        *((double*)data.mv_data) = numberLocal->Value();
    }, [](MDB_val &data) -> void {
        delete (double*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::putBoolean) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = sizeof(double);
        data.mv_data = new bool;
        auto booleanLocal = Nan::To<v8::Boolean>(info[2]).ToLocalChecked();
        *((bool*)data.mv_data) = booleanLocal->Value();
    }, [](MDB_val &data) -> void {
        delete (bool*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::del) {
    Nan::HandleScope scope;

    // Check argument count
    auto argCount = info.Length();
    if (argCount < 2 || argCount > 4) {
        return Nan::ThrowError("Invalid number of arguments to cursor.del, should be: (a) <dbi>, <key> (b) <dbi>, <key>, <options> (c) <dbi>, <key>, <data> (d) <dbi>, <key>, <data>, <options>");
    }

    // Unwrap native objects
    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    // Take care of options object and data handle
    Local<Value> options;
    Local<Value> dataHandle;

    if (argCount == 4) {
        options = info[3];
        dataHandle = info[2];
    }
    else if (argCount == 3) {
        if (info[2]->IsObject()) {
            options = info[2];
            dataHandle = Nan::Undefined();
        }
        else {
            options = Nan::Undefined();
            dataHandle = info[2];
        }
    }
    else if (argCount == 2) {
        options = Nan::Undefined();
        dataHandle = Nan::Undefined();
    }
    else {
        return Nan::ThrowError("Unknown arguments to cursor.del, this could be a node-lmdb bug!");
    }

    MDB_val key;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], options, dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    // Set data if dupSort true and data given
    MDB_val data;
    bool freeData = false;

    if ((dw->flags & MDB_DUPSORT) && !(dataHandle->IsUndefined())) {
        if (dataHandle->IsString()) {
            CustomExternalStringResource::writeTo(dataHandle->ToString(), &data);
            freeData = true;
        }
        else if (node::Buffer::HasInstance(dataHandle)) {
            data.mv_size = node::Buffer::Length(dataHandle);
            data.mv_data = node::Buffer::Data(dataHandle);
            freeData = true;
        }
        else if (dataHandle->IsNumber()) {
            auto numberLocal = Nan::To<v8::Number>(dataHandle).ToLocalChecked();
            data.mv_size = sizeof(double);
            data.mv_data = new double;
            *reinterpret_cast<double*>(data.mv_data) = numberLocal->Value();
            freeData = true;
        }
        else if (dataHandle->IsBoolean()) {
            auto booleanLocal = Nan::To<v8::Boolean>(dataHandle).ToLocalChecked();
            data.mv_size = sizeof(double);
            data.mv_data = new bool;
            *reinterpret_cast<bool*>(data.mv_data) = booleanLocal->Value();
            freeData = true;
        }
        else {
            Nan::ThrowError("Invalid data type.");
        }
    }

    int rc = mdb_del(tw->txn, dw->dbi, &key, freeData ? &data : nullptr);

    if (freeKey) {
        freeKey(key);
    }

    if (freeData) {
        if (dataHandle->IsString()) {
            delete[] (uint16_t*)data.mv_data;
        }
        else if (node::Buffer::HasInstance(dataHandle)) {
            // I think the data is owned by the node::Buffer so we don't need to free it - need to clarify
        }
        else if (dataHandle->IsNumber()) {
            delete (double*)data.mv_data;
        }
        else if (dataHandle->IsBoolean()) {
            delete (bool*)data.mv_data;
        }
    }

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}
<commit_msg>optimize away a memory allocation in putNumber / putBoolean<commit_after>
// This file is part of node-lmdb, the Node.js binding for lmdb
// Copyright (c) 2013-2017 Timur Kristóf
// Licensed to you under the terms of the MIT license
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "node-lmdb.h"

using namespace v8;
using namespace node;

TxnWrap::TxnWrap(MDB_env *env, MDB_txn *txn) {
    this->env = env;
    this->txn = txn;
    this->flags = 0;
}

TxnWrap::~TxnWrap() {
    // Close if not closed already
    if (this->txn) {
        mdb_txn_abort(txn);
        this->removeFromEnvWrap();
    }
}

void TxnWrap::removeFromEnvWrap() {
    if (this->ew) {
        if (this->ew->currentWriteTxn == this) {
            this->ew->currentWriteTxn = nullptr;
        }
        else {
            auto it = std::find(ew->readTxns.begin(), ew->readTxns.end(), this);
            if (it != ew->readTxns.end()) {
                ew->readTxns.erase(it);
            }
        }

        this->ew->Unref();
        this->ew = nullptr;
    }
}

NAN_METHOD(TxnWrap::ctor) {
    Nan::HandleScope scope;

    EnvWrap *ew = Nan::ObjectWrap::Unwrap<EnvWrap>(info[0]->ToObject());
    int flags = 0;

    if (info[1]->IsObject()) {
        Local<Object> options = info[1]->ToObject();

        // Get flags from options

        setFlagFromValue(&flags, MDB_RDONLY, "readOnly", false, options);
    }

    // Check existence of current write transaction
    if (0 == (flags & MDB_RDONLY) && ew->currentWriteTxn != nullptr) {
        return Nan::ThrowError("You have already opened a write transaction in the current process, can't open a second one.");
    }

    MDB_txn *txn;
    int rc = mdb_txn_begin(ew->env, nullptr, flags, &txn);
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }

    TxnWrap* tw = new TxnWrap(ew->env, txn);
    tw->flags = flags;
    tw->ew = ew;
    tw->ew->Ref();
    tw->Wrap(info.This());

    // Set the current write transaction
    if (0 == (flags & MDB_RDONLY)) {
        ew->currentWriteTxn = tw;
    }
    else {
        ew->readTxns.push_back(tw);
    }

    return info.GetReturnValue().Set(info.This());
}

NAN_METHOD(TxnWrap::commit) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int rc = mdb_txn_commit(tw->txn);
    tw->removeFromEnvWrap();
    tw->txn = nullptr;

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

NAN_METHOD(TxnWrap::abort) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    mdb_txn_abort(tw->txn);
    tw->removeFromEnvWrap();
    tw->txn = nullptr;
}

NAN_METHOD(TxnWrap::reset) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    mdb_txn_reset(tw->txn);
}

NAN_METHOD(TxnWrap::renew) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int rc = mdb_txn_renew(tw->txn);
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

Nan::NAN_METHOD_RETURN_TYPE TxnWrap::getCommon(Nan::NAN_METHOD_ARGS_TYPE info, Local<Value> (*successFunc)(MDB_val&)) {
    Nan::HandleScope scope;

    if (info.Length() != 2 && info.Length() != 3) {
        return Nan::ThrowError("Invalid number of arguments to cursor.get");
    }

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    MDB_val key, oldkey, data;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[2], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    // Bookkeeping for old key so that we can free it even if key will point inside LMDB
    oldkey.mv_data = key.mv_data;
    oldkey.mv_size = key.mv_size;

    int rc = mdb_get(tw->txn, dw->dbi, &key, &data);

    if (freeKey) {
        freeKey(oldkey);
    }

    if (rc == MDB_NOTFOUND) {
        return info.GetReturnValue().Set(Nan::Null());
    }
    else if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
    else {
      return info.GetReturnValue().Set(successFunc(data));
    }
}

NAN_METHOD(TxnWrap::getString) {
    return getCommon(info, valToString);
}

NAN_METHOD(TxnWrap::getStringUnsafe) {
    return getCommon(info, valToStringUnsafe);
}

NAN_METHOD(TxnWrap::getBinary) {
    return getCommon(info, valToBinary);
}

NAN_METHOD(TxnWrap::getBinaryUnsafe) {
    return getCommon(info, valToBinaryUnsafe);
}

NAN_METHOD(TxnWrap::getNumber) {
    return getCommon(info, valToNumber);
}

NAN_METHOD(TxnWrap::getBoolean) {
    return getCommon(info, valToBoolean);
}

Nan::NAN_METHOD_RETURN_TYPE TxnWrap::putCommon(Nan::NAN_METHOD_ARGS_TYPE info, void (*fillFunc)(Nan::NAN_METHOD_ARGS_TYPE info, MDB_val&), void (*freeData)(MDB_val&)) {
    Nan::HandleScope scope;

    if (info.Length() != 3 && info.Length() != 4) {
        return Nan::ThrowError("Invalid number of arguments to cursor.put");
    }

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int flags = 0;
    MDB_val key, data;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[3], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    if (!info[3]->IsNull() && !info[3]->IsUndefined() && info[3]->IsObject()) {
        auto options = info[3]->ToObject();
        setFlagFromValue(&flags, MDB_NODUPDATA, "noDupData", false, options);
        setFlagFromValue(&flags, MDB_NOOVERWRITE, "noOverwrite", false, options);
        setFlagFromValue(&flags, MDB_APPEND, "append", false, options);
        setFlagFromValue(&flags, MDB_APPENDDUP, "appendDup", false, options);

        // NOTE: does not make sense to support MDB_RESERVE, because it wouldn't save the memcpy from V8 to lmdb
    }

    // Fill key and data
    fillFunc(info, data);

    // Keep a copy of the original key and data, so we can free them
    MDB_val originalKey = key;
    MDB_val originalData = data;

    int rc = mdb_put(tw->txn, dw->dbi, &key, &data, flags);

    // Free original key and data (what was supplied by the user, not what points to lmdb)
    if (freeKey) {
        freeKey(originalKey);
    }
    if (freeData) {
        freeData(originalData);
    }

    // Check result code
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

NAN_METHOD(TxnWrap::putString) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        CustomExternalStringResource::writeTo(info[2]->ToString(), &data);
    }, [](MDB_val &data) -> void {
        delete[] (uint16_t*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::putBinary) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = node::Buffer::Length(info[2]);
        data.mv_data = node::Buffer::Data(info[2]);
    }, [](MDB_val &) -> void {
        // The data is owned by the node::Buffer so we don't need to free it.
    });
}

// This is used by putNumber for temporary storage
static thread_local double numberToPut = 0.0;

NAN_METHOD(TxnWrap::putNumber) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        auto numberLocal = Nan::To<v8::Number>(info[2]).ToLocalChecked();
        numberToPut = numberLocal->Value();

        data.mv_size = sizeof(double);
        data.mv_data = &numberToPut;
    }, nullptr);
}

// This is used by putBoolean for temporary storage
static thread_local bool booleanToPut = false;

NAN_METHOD(TxnWrap::putBoolean) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        auto booleanLocal = Nan::To<v8::Boolean>(info[2]).ToLocalChecked();
        booleanToPut = booleanLocal->Value();

        data.mv_size = sizeof(bool);
        data.mv_data = &booleanToPut;
    }, nullptr);
}

NAN_METHOD(TxnWrap::del) {
    Nan::HandleScope scope;

    // Check argument count
    auto argCount = info.Length();
    if (argCount < 2 || argCount > 4) {
        return Nan::ThrowError("Invalid number of arguments to cursor.del, should be: (a) <dbi>, <key> (b) <dbi>, <key>, <options> (c) <dbi>, <key>, <data> (d) <dbi>, <key>, <data>, <options>");
    }

    // Unwrap native objects
    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    // Take care of options object and data handle
    Local<Value> options;
    Local<Value> dataHandle;

    if (argCount == 4) {
        options = info[3];
        dataHandle = info[2];
    }
    else if (argCount == 3) {
        if (info[2]->IsObject()) {
            options = info[2];
            dataHandle = Nan::Undefined();
        }
        else {
            options = Nan::Undefined();
            dataHandle = info[2];
        }
    }
    else if (argCount == 2) {
        options = Nan::Undefined();
        dataHandle = Nan::Undefined();
    }
    else {
        return Nan::ThrowError("Unknown arguments to cursor.del, this could be a node-lmdb bug!");
    }

    MDB_val key;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], options, dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    // Set data if dupSort true and data given
    MDB_val data;
    bool freeData = false;

    if ((dw->flags & MDB_DUPSORT) && !(dataHandle->IsUndefined())) {
        if (dataHandle->IsString()) {
            CustomExternalStringResource::writeTo(dataHandle->ToString(), &data);
            freeData = true;
        }
        else if (node::Buffer::HasInstance(dataHandle)) {
            data.mv_size = node::Buffer::Length(dataHandle);
            data.mv_data = node::Buffer::Data(dataHandle);
            freeData = true;
        }
        else if (dataHandle->IsNumber()) {
            auto numberLocal = Nan::To<v8::Number>(dataHandle).ToLocalChecked();
            data.mv_size = sizeof(double);
            data.mv_data = new double;
            *reinterpret_cast<double*>(data.mv_data) = numberLocal->Value();
            freeData = true;
        }
        else if (dataHandle->IsBoolean()) {
            auto booleanLocal = Nan::To<v8::Boolean>(dataHandle).ToLocalChecked();
            data.mv_size = sizeof(double);
            data.mv_data = new bool;
            *reinterpret_cast<bool*>(data.mv_data) = booleanLocal->Value();
            freeData = true;
        }
        else {
            Nan::ThrowError("Invalid data type.");
        }
    }

    int rc = mdb_del(tw->txn, dw->dbi, &key, freeData ? &data : nullptr);

    if (freeKey) {
        freeKey(key);
    }

    if (freeData) {
        if (dataHandle->IsString()) {
            delete[] (uint16_t*)data.mv_data;
        }
        else if (node::Buffer::HasInstance(dataHandle)) {
            // I think the data is owned by the node::Buffer so we don't need to free it - need to clarify
        }
        else if (dataHandle->IsNumber()) {
            delete (double*)data.mv_data;
        }
        else if (dataHandle->IsBoolean()) {
            delete (bool*)data.mv_data;
        }
    }

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xerecord.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-07-10 13:33:43 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_XERECORD_HXX
#include "xerecord.hxx"
#endif

// Base classes to export Excel records =======================================

XclExpRecordBase::~XclExpRecordBase()
{
}

void XclExpRecordBase::Save( XclExpStream& rStrm )
{
}

void XclExpRecordBase::SaveRepeated( XclExpStream& rStrm, size_t nCount )
{
    for( size_t nIndex = 0; nIndex < nCount; ++nIndex )
        Save( rStrm );
}

// ----------------------------------------------------------------------------

XclExpRecord::XclExpRecord( sal_uInt16 nRecId, sal_Size nRecSize ) :
    mnRecId( nRecId ),
    mnRecSize( nRecSize )
{
}

XclExpRecord::~XclExpRecord()
{
}

void XclExpRecord::SetRecHeader( sal_uInt16 nRecId, sal_Size nRecSize )
{
    SetRecId( nRecId );
    SetRecSize( nRecSize );
}

void XclExpRecord::WriteBody( XclExpStream& rStrm )
{
}

void XclExpRecord::Save( XclExpStream& rStrm )
{
    DBG_ASSERT( mnRecId != EXC_ID_UNKNOWN, "XclExpRecord::Save - record ID uninitialized" );
    rStrm.StartRecord( mnRecId, mnRecSize );
    WriteBody( rStrm );
    rStrm.EndRecord();
}

// ----------------------------------------------------------------------------

void XclExpBoolRecord::WriteBody( XclExpStream& rStrm )
{
    rStrm << static_cast< sal_uInt16 >( mbValue ? 1 : 0 );
}

// ----------------------------------------------------------------------------

XclExpDummyRecord::XclExpDummyRecord( sal_uInt16 nRecId, const void* pRecData, sal_Size nRecSize ) :
    XclExpRecord( nRecId )
{
    SetData( pRecData, nRecSize );
}

void XclExpDummyRecord::SetData( const void* pRecData, sal_Size nRecSize )
{
    mpData = pRecData;
    SetRecSize( pRecData ? nRecSize : 0 );
}

void XclExpDummyRecord::WriteBody( XclExpStream& rStrm )
{
    rStrm.Write( mpData, GetRecSize() );
}

// ============================================================================

<commit_msg>INTEGRATION: CWS pchfix01 (1.5.216); FILE MERGED 2006/07/12 10:01:52 kaib 1.5.216.1: #i67080# Converted cxx files in sc, added initial project level pch and stripped old PCH definitions.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xerecord.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: kz $ $Date: 2006-07-21 12:00:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"

#ifndef SC_XERECORD_HXX
#include "xerecord.hxx"
#endif

// Base classes to export Excel records =======================================

XclExpRecordBase::~XclExpRecordBase()
{
}

void XclExpRecordBase::Save( XclExpStream& rStrm )
{
}

void XclExpRecordBase::SaveRepeated( XclExpStream& rStrm, size_t nCount )
{
    for( size_t nIndex = 0; nIndex < nCount; ++nIndex )
        Save( rStrm );
}

// ----------------------------------------------------------------------------

XclExpRecord::XclExpRecord( sal_uInt16 nRecId, sal_Size nRecSize ) :
    mnRecId( nRecId ),
    mnRecSize( nRecSize )
{
}

XclExpRecord::~XclExpRecord()
{
}

void XclExpRecord::SetRecHeader( sal_uInt16 nRecId, sal_Size nRecSize )
{
    SetRecId( nRecId );
    SetRecSize( nRecSize );
}

void XclExpRecord::WriteBody( XclExpStream& rStrm )
{
}

void XclExpRecord::Save( XclExpStream& rStrm )
{
    DBG_ASSERT( mnRecId != EXC_ID_UNKNOWN, "XclExpRecord::Save - record ID uninitialized" );
    rStrm.StartRecord( mnRecId, mnRecSize );
    WriteBody( rStrm );
    rStrm.EndRecord();
}

// ----------------------------------------------------------------------------

void XclExpBoolRecord::WriteBody( XclExpStream& rStrm )
{
    rStrm << static_cast< sal_uInt16 >( mbValue ? 1 : 0 );
}

// ----------------------------------------------------------------------------

XclExpDummyRecord::XclExpDummyRecord( sal_uInt16 nRecId, const void* pRecData, sal_Size nRecSize ) :
    XclExpRecord( nRecId )
{
    SetData( pRecData, nRecSize );
}

void XclExpDummyRecord::SetData( const void* pRecData, sal_Size nRecSize )
{
    mpData = pRecData;
    SetRecSize( pRecData ? nRecSize : 0 );
}

void XclExpDummyRecord::WriteBody( XclExpStream& rStrm )
{
    rStrm.Write( mpData, GetRecSize() );
}

// ============================================================================

<|endoftext|>