<commit_before>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
struct Node
{
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree;

template <typename T>
std::ostream& operator<<(std::ostream&, const BinaryTree<T>&);

template <typename T>
class BinaryTree
{
private:
	Node<T>*root;
	int count = 0;
public:
	BinaryTree();
	~BinaryTree();
	Node<T>* root_();
	unsigned int getCount()const;
	Node<T> *findNode(const T&, Node<T>*)const;
	void insertNode(const T&x);
	void deleteNode(Node<T>* temp);
	bool removeElement(Node<T>* parent, Node<T>* current, const T& val);
	bool deleteValue(const T& value);
	void write(const std::string& filename)const;
	friend std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);
};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template <typename T>
unsigned int BinaryTree<T>::getCount()const
{
	return count;
}

template<typename T>
Node<T>* BinaryTree<T>::findNode(const T& data, Node<T>* temp) const
{
	if (temp == 0 || data == temp->data)
		return temp;
	if (data > temp->data)
		return findNode(data, temp->right);
	else
		return findNode(data, temp->left);
}

template<typename T>
void BinaryTree<T>::insertNode(const T&x)
{
	if (findNode(x, root_())) return;
	Node<T>* Tree = new Node<T>;
	Tree->data = x;
	Tree->left = Tree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = Tree;
	else
	{
		if (x < buff->data)
			buff->left = Tree;
		else
			buff->right = Tree;
	}
	++count;
}

template<typename T>
void BinaryTree<T>::write(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << count << "\t";
	output(file_1, root);
	file_1.close();
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
		return;
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template <typename T>
std::ostream& output(std::ostream& out, const Node<T>* node, unsigned int level)
{
	if (!node)
		return out;
	output(out, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		out << "\t";
	out << node->data << std::endl;
	output(out, node->left, level + 1);
	return out;
}

template<typename T>
bool BinaryTree<T>::removeElement(Node<T>* parent, Node<T>* current, const T& val)
{
	if (!current) return false;
	if (current->data == val)
	{
		if (current->left == NULL || current->right == NULL) {
			Node<T>* temp = current->left;
			if (current->right) temp = current->right;
			if (parent) {
				if (parent->left == current) {
					parent->left = temp;
				}
				else {
					parent->right = temp;
				}
			}
			else {
				this->root = temp;
			}
		}
		/*else {
			Node<T>* validSubs = current->right;
			while (validSubs->left) {
				validSubs = validSubs->left;
			}
			T temp = current->data;
			current->data = validSubs->data;
			validSubs->data = temp;
			return removeElement(current, current->right, temp);
		}*/
		else {
			Node<T>* validSubs = current->left;
			while (validSubs->right) {
				validSubs = validSubs->right;
			}
			validSubs->right = current->right->left;
			current->right->left = current->left;
			if (parent->left == current)
				parent->left = current->right;
			else
				parent->right = current->right;
		}
		delete current;
		count--;
		return true;
	}
	if (current->data > val)
		return removeElement(current, current->left, val);
	else
		return removeElement(current, current->right, val);
}

template<typename T>
bool BinaryTree<T>::deleteValue(const T& value)
{
	return this->removeElement(NULL, root, value);
}

template <typename T>
std::ostream& operator<<(std::ostream& out, const BinaryTree<T>& temp)
{
	output(out, temp.root, 0);
	return out;
}
<commit_msg>Create matrix.hpp<commit_after>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
struct Node
{
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree;

template <typename T>
std::ostream& operator<<(std::ostream&, const BinaryTree<T>&);

template <typename T>
class BinaryTree
{
private:
	Node<T>*root;
	int count = 0;
public:
	BinaryTree();
	~BinaryTree();
	Node<T>* root_();
	unsigned int getCount()const;
	Node<T> *findNode(const T&, Node<T>*)const;
	void insertNode(const T&x);
	void deleteNode(Node<T>* temp);
	bool removeElement(Node<T>* parent, Node<T>* current, const T& val);
	bool deleteValue(const T& value);
	void write(const std::string& filename)const;
	friend std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);
};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template <typename T>
unsigned int BinaryTree<T>::getCount()const
{
	return count;
}

template<typename T>
Node<T>* BinaryTree<T>::findNode(const T& data, Node<T>* temp) const
{
	if (temp == 0 || data == temp->data)
		return temp;
	if (data > temp->data)
		return findNode(data, temp->right);
	else
		return findNode(data, temp->left);
}

template<typename T>
void BinaryTree<T>::insertNode(const T&x)
{
	if (findNode(x, root_())) return;
	Node<T>* Tree = new Node<T>;
	Tree->data = x;
	Tree->left = Tree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = Tree;
	else
	{
		if (x < buff->data)
			buff->left = Tree;
		else
			buff->right = Tree;
	}
	++count;
}

template<typename T>
void BinaryTree<T>::write(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << count << "\t";
	output(file_1, root);
	file_1.close();
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
		return;
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template <typename T>
std::ostream& output(std::ostream& out, const Node<T>* node, unsigned int level)
{
	if (!node)
		return out;
	output(out, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		out << "\t";
	out << node->data << std::endl;
	output(out, node->left, level + 1);
	return out;
}

template<typename T>
bool BinaryTree<T>::removeElement(Node<T>* parent, Node<T>* current, const T& val)
{
	if (!current) return false;
	if (current->data == val)
	{
		if (current->left == NULL || current->right == NULL) {
			Node<T>* temp = current->left;
			if (current->right) temp = current->right;
			if (parent) {
				if (parent->left == current) {
					parent->left = temp;
				}
				else {
					parent->right = temp;
				}
			}
			else {
				this->root = temp;
			}
		}
		/*else {
			Node<T>* validSubs = current->right;
			while (validSubs->left) {
				validSubs = validSubs->left;
			}
			T temp = current->data;
			current->data = validSubs->data;
			validSubs->data = temp;
			return removeElement(current, current->right, temp);
		}*/
		else {
			Node<T>* validSubs = current->left;
			while (validSubs->right) {
				validSubs = validSubs->right;
			}
			validSubs->right = current->right->left;
			current->right->left = nullptr;
			current->right->left = current->left;
			if (parent->left == current)
				parent->left = current->right;
			else
				parent->right = current->right;
		}
		delete current;
		count--;
		return true;
	}
	if (current->data > val)
		return removeElement(current, current->left, val);
	else
		return removeElement(current, current->right, val);
}

template<typename T>
bool BinaryTree<T>::deleteValue(const T& value)
{
	return this->removeElement(NULL, root, value);
}

template <typename T>
std::ostream& operator<<(std::ostream& out, const BinaryTree<T>& temp)
{
	output(out, temp.root, 0);
	return out;
}
<|endoftext|>


<commit_before>#ifdef _MSC_VER
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4996)
#endif

#ifdef NDEBUG
#undef NDEBUG
#endif

#include <stdlib.h>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <vw/FileIO.h>
#include <vw/Image.h>
#include <vw/Math.h>
#include <vw/Stereo.h>
#include <vw/Cartography.h>
using namespace vw;
using namespace vw::stereo;
using namespace vw::cartography;

#include "stereo.h"
#include "DEM.h"
#include "nff_terrain.h"
#include "OrthoRasterizer.h"

// Allows FileIO to correctly read/write these pixel types
namespace vw {
  template<> struct PixelFormatID<Vector3>   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
}

class PointTransFunc : public ReturnFixedType<Vector3> {
  Matrix3x3 m_trans;
public:
  PointTransFunc(Matrix3x3 trans) : m_trans(trans) {}
  Vector3 operator() (Vector3 const& pt) const { return m_trans*pt; }
};

int main( int argc, char *argv[] ) {
  set_debug_level(VerboseDebugMessage+11);

  std::string input_file_name, out_prefix, output_file_type, texture_filename;
  unsigned cache_size, max_triangles;
  float dem_spacing, default_value=0;
  unsigned simplemesh_h_step, simplemesh_v_step;
  int debug_level;
  double semi_major, semi_minor;
  std::string reference_spheroid;
  double phi_rot, omega_rot, kappa_rot;
  std::string rot_order;
  double proj_lat=0, proj_lon=0, proj_scale=1;
  double z_offset;
  unsigned utm_zone;

  po::options_description desc("Options");
  desc.add_options()
    ("help", "Display this help message")
    ("default-value", po::value<float>(&default_value), "Explicitly set the default (missing pixel) value.  By default, the min z value is used.")
    ("use-alpha", "Create images that have an alpha channel")
    ("dem-spacing,s", po::value<float>(&dem_spacing)->default_value(0), "Set the DEM post size (if this value is 0, the post spacing size is computed for you)")
    ("normalized,n", "Also write a normalized version of the DEM (for debugging)")
    ("orthoimage", po::value<std::string>(&texture_filename), "Write an orthoimage based on the texture file given as an argument to this command line option")
    ("grayscale", "Use grayscale image processing for creating the orthoimage")
    ("offset-files", "Also write a pair of ascii offset files (for debugging)")
    ("cache", po::value<unsigned>(&cache_size)->default_value(1024), "Cache size, in megabytes")
    ("input-file", po::value<std::string>(&input_file_name), "Explicitly specify the input file")
    ("texture-file", po::value<std::string>(&texture_filename), "Specify texture filename")
    ("output-prefix,o", po::value<std::string>(&out_prefix)->default_value("terrain"), "Specify the output prefix")
    ("output-filetype,t", po::value<std::string>(&output_file_type)->default_value("tif"), "Specify the output file")
    ("debug-level,d", po::value<int>(&debug_level)->default_value(vw::DebugMessage-1), "Set the debugging output level. (0-50+)")
    ("xyz-to-lonlat", "Convert from xyz coordinates to longitude, latitude, altitude coordinates.")
    ("reference-spheroid,r", po::value<std::string>(&reference_spheroid)->default_value(""),"Set a reference surface to a hard coded value (one of [moon , mars].  This will override manually set datum information.")
    ("semi-major-axis", po::value<double>(&semi_major)->default_value(0),"Set the dimensions of the datum.")
    ("semi-minor-axis", po::value<double>(&semi_minor)->default_value(0),"Set the dimensions of the datum.")
    ("z-offset", po::value<double>(&z_offset)->default_value(0), "Add a vertical offset to the DEM")

    ("sinusoidal", "Save using a sinusoidal projection")
    ("mercator", "Save using a Mercator projection")
    ("transverse-mercator", "Save using a transverse Mercator projection")
    ("orthographic", "Save using an orthographic projection")
    ("stereographic", "Save using a stereographic projection")
    ("lambert-azimuthal", "Save using a Lambert azimuthal projection")
    ("utm", po::value<unsigned>(&utm_zone), "Save using a UTM projection with the given zone")
    ("proj-lat", po::value<double>(&proj_lat), "The center of projection latitude (if applicable)")
    ("proj-lon", po::value<double>(&proj_lon), "The center of projection longitude (if applicable)")
    ("proj-scale", po::value<double>(&proj_scale), "The projection scale (if applicable)")

    ("rotation-order", po::value<std::string>(&rot_order)->default_value("xyz"),"Set the order of an euler angle rotation applied to the 3D points prior to DEM rasterization")
    ("phi-rotation", po::value<double>(&phi_rot)->default_value(0),"Set a rotation angle phi")
    ("omega-rotation", po::value<double>(&omega_rot)->default_value(0),"Set a rotation angle omega")
    ("kappa-rotation", po::value<double>(&kappa_rot)->default_value(0),"Set a rotation angle kappa");

  po::positional_options_description p;
  p.add("input-file", 1);

  po::variables_map vm;
  po::store( po::command_line_parser( argc, argv ).options(desc).positional(p).run(), vm );
  po::notify( vm );

  // Set the Vision Workbench debug level
  set_debug_level(debug_level);
  Cache::system_cache().resize( cache_size*1024*1024 );

  if( vm.count("help") ) {
    std::cout << desc << std::endl;
    return 1;
  }

  if( vm.count("input-file") != 1 ) {
    std::cout << "Error: Must specify exactly one pointcloud file and one texture file!" << std::endl;
    std::cout << desc << std::endl;
    return 1;
  }

  DiskImageView<Vector3> point_disk_image(input_file_name);
  ImageViewRef<Vector3> point_image = point_disk_image;

  // Apply an (optional) rotation to the 3D points before building the mesh.
  if (phi_rot != 0 || omega_rot != 0 || kappa_rot != 0) {
    std::cout << "Applying rotation sequence: " << rot_order << "      Angles: " << phi_rot << "   " << omega_rot << "  " << kappa_rot << "\n";
    Matrix3x3 rotation_trans = math::euler_to_rotation_matrix(phi_rot,omega_rot,kappa_rot,rot_order);
    point_image = per_pixel_filter(point_image, PointTransFunc(rotation_trans));
  }

  if (vm.count("xyz-to-lonlat") ) {
    std::cout << "Reprojecting points into longitude, latitude, altitude.\n";
    point_image = cartography::xyz_to_lon_lat_radius(point_image);
  }

  // Select a cartographic DATUM.  There are several hard coded datums
  // that can be used here, or the user can specify their own.
  cartography::Datum datum;
  if ( reference_spheroid != "" ) {
    if (reference_spheroid == "mars") {
      const double MOLA_PEDR_EQUATORIAL_RADIUS = 3396000.0;
      std::cout << "Re-referencing altitude values using standard MOLA spherical radius: " << MOLA_PEDR_EQUATORIAL_RADIUS << "\n";
      datum = cartography::Datum("Mars Datum",
                                 "MOLA PEDR Spheroid",
                                 "Prime Meridian",
                                 MOLA_PEDR_EQUATORIAL_RADIUS,
                                 MOLA_PEDR_EQUATORIAL_RADIUS,
                                 0.0);
    } else if (reference_spheroid == "moon") {
      const double LUNAR_RADIUS = 1737400;
      std::cout << "Re-referencing altitude values using standard lunar spherical radius: " << LUNAR_RADIUS << "\n";
      datum = cartography::Datum("Lunar Datum",
                                 "Lunar Spheroid",
                                 "Prime Meridian",
                                 LUNAR_RADIUS,
                                 LUNAR_RADIUS,
                                 0.0);
    } else {
      std::cout << "Unknown reference spheroid: " << reference_spheroid << ".  Current options are [ moon , mars ]\nExiting.\n\n";
      exit(0);
    }
  } else if (semi_major != 0 && semi_minor != 0) {
    std::cout << "Re-referencing altitude values to user supplied datum.  Semi-major: " << semi_major << "  Semi-minor: " << semi_minor << "\n";
    datum = cartography::Datum("User Specified Datum",
                               "User Specified Spherem",
                               "Prime Meridian",
                               semi_major, semi_minor, 0.0);
  }

  // Set up the georeferencing information.  We specify everything
  // here except for the affine transform, which is defined later once
  // we know the bounds of the orthorasterizer view.  However, we can
  // still reproject the points in the point image without the affine
  // transform because this projection never requires us to convert to
  // or from pixel space.
  GeoReference georef(datum);

  // If the data was left in cartesian coordinates, we need to give
  // the DEM a projection that uses some physical units (meters),
  // rather than lon, lat.  This is actually mainly for compatibility
  // with Viz, and it's sort of a hack, but it's left in for the time
  // being.
  //
  // Otherwise, we honor the user's requested projection and convert
  // the points if necessary.
  if (!vm.count("xyz-to-lonlat"))
    georef.set_mercator(0,0,1);
  else if( vm.count("sinusoidal") ) georef.set_sinusoidal(proj_lon);
  else if( vm.count("mercator") ) georef.set_mercator(proj_lat,proj_lon,proj_scale);
  else if( vm.count("transverse-mercator") ) georef.set_transverse_mercator(proj_lat,proj_lon,proj_scale);
  else if( vm.count("orthographic") ) georef.set_orthographic(proj_lat,proj_lon);
  else if( vm.count("stereographic") ) georef.set_stereographic(proj_lat,proj_lon,proj_scale);
  else if( vm.count("lambert-azimuthal") ) georef.set_lambert_azimuthal(proj_lat,proj_lon);
  else if( vm.count("utm") ) georef.set_UTM( utm_zone );

  if (vm.count("xyz-to-lonlat"))
    point_image = cartography::project_point_image(point_image, georef);

  // Rasterize the results to a temporary file on disk so as to speed
  // up processing in the orthorasterizer, which accesses each pixel
  // multiple times.
  DiskCacheImageView<Vector3> point_image_cache(point_image, "tif");

  // write out the DEM, texture, and extrapolation mask as
  // georeferenced files.
  vw::cartography::OrthoRasterizerView<PixelGray<float> > rasterizer(point_image_cache, select_channel(point_image_cache,2), dem_spacing);
  if (!vm.count("default-value") ) {
    rasterizer.set_use_minz_as_default(true);
  } else {
    rasterizer.set_use_minz_as_default(false);
    rasterizer.set_default_value(default_value);
  }
  if (vm.count("use-alpha")) {
    rasterizer.set_use_alpha(true);
  }

  vw::BBox<float,3> dem_bbox = rasterizer.bounding_box();
  std::cout << "DEM Bounding box: " << dem_bbox << "\n";

  // Now we are ready to specify the affine transform.
  Matrix3x3 georef_affine_transform = rasterizer.geo_transform();
  std::cout << "Georeferencing Transform: " << georef_affine_transform << "\n";
  georef.set_transform(georef_affine_transform);

  // This is a workaround for now to make GDAL write files that don't
  // cause it to crash on read. - mbroxton
  georef.set_datum(Datum());

  // Write out a georeferenced orthoimage of the DTM with alpha.
  if (vm.count("orthoimage")) {
    rasterizer.set_use_minz_as_default(false);
    DiskImageView<PixelGray<float> > texture(texture_filename);
    rasterizer.set_texture(texture);
    BlockCacheView<PixelGray<float> > block_drg_raster(rasterizer, Vector2i(rasterizer.cols(), 2048));
    write_georeferenced_image(out_prefix + "-DRG.tif", channel_cast_rescale<uint8>(block_drg_raster), georef, TerminalProgressCallback() );

  } else {
    // Write out the DEM.
    std::cout << "\n\n Creating block cache view from rasterizer: " << rasterizer.cols() << "  " << rasterizer.rows() << "\n";
    BlockCacheView<PixelGray<float> > block_dem_raster(rasterizer, Vector2i(rasterizer.cols(), 2024));
    if (vm.count("z-offset")) {
      std::cout << "Adding the following z offset: " << z_offset << "\n";
      write_georeferenced_image(out_prefix + "-DEM." + output_file_type, block_dem_raster + z_offset, georef, TerminalProgressCallback());
    } else {
      write_georeferenced_image(out_prefix + "-DEM." + output_file_type, block_dem_raster, georef, TerminalProgressCallback());
    }

    // Write out a georeferenced DTM and (optionally) a normalized version of the DTM (for debugging)
    if (vm.count("normalized")) {
      DiskImageView<PixelGray<float> > dem_image(out_prefix + "-DEM." + output_file_type);
      write_georeferenced_image(out_prefix + "-DEM-normalized.tif", channel_cast_rescale<uint8>(normalize(dem_image)), georef, TerminalProgressCallback());
    }
  }

  if (vm.count("offset-files")) {
    // Write out the offset files
    std::cout << "Offset: " << dem_bbox.min().x()/rasterizer.spacing() << "   " << dem_bbox.max().y()/rasterizer.spacing() << "\n";
    std::string offset_filename = out_prefix + "-DRG.offset";
    FILE* offset_file = fopen(offset_filename.c_str(), "w");
    fprintf(offset_file, "%d\n%d\n", int(dem_bbox.min().x()/rasterizer.spacing()), -int(dem_bbox.max().y()/rasterizer.spacing()));
    fclose(offset_file);
    offset_filename = out_prefix + "-DEM-normalized.offset";
    offset_file = fopen(offset_filename.c_str(), "w");
    fprintf(offset_file, "%d\n%d\n", int(dem_bbox.min().x()/rasterizer.spacing()), -int(dem_bbox.max().y()/rasterizer.spacing()));
    fclose(offset_file);
  }
  return 0;
}
<commit_msg>Fixed a masking bug when using a z-offset<commit_after>#ifdef _MSC_VER
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4996)
#endif

#ifdef NDEBUG
#undef NDEBUG
#endif

#include <stdlib.h>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <vw/FileIO.h>
#include <vw/Image.h>
#include <vw/Math.h>
#include <vw/Stereo.h>
#include <vw/Cartography.h>
using namespace vw;
using namespace vw::stereo;
using namespace vw::cartography;

#include "stereo.h"
#include "DEM.h"
#include "nff_terrain.h"
#include "OrthoRasterizer.h"

// Allows FileIO to correctly read/write these pixel types
namespace vw {
  template<> struct PixelFormatID<Vector3>   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
}

class PointTransFunc : public ReturnFixedType<Vector3> {
  Matrix3x3 m_trans;
public:
  PointTransFunc(Matrix3x3 trans) : m_trans(trans) {}
  Vector3 operator() (Vector3 const& pt) const { return m_trans*pt; }
};

int main( int argc, char *argv[] ) {
  set_debug_level(VerboseDebugMessage+11);

  std::string input_file_name, out_prefix, output_file_type, texture_filename;
  unsigned cache_size, max_triangles;
  float dem_spacing, default_value=0;
  unsigned simplemesh_h_step, simplemesh_v_step;
  int debug_level;
  double semi_major, semi_minor;
  std::string reference_spheroid;
  double phi_rot, omega_rot, kappa_rot;
  std::string rot_order;
  double proj_lat=0, proj_lon=0, proj_scale=1;
  double z_offset;
  unsigned utm_zone;

  po::options_description desc("Options");
  desc.add_options()
    ("help", "Display this help message")
    ("default-value", po::value<float>(&default_value), "Explicitly set the default (missing pixel) value.  By default, the min z value is used.")
    ("use-alpha", "Create images that have an alpha channel")
    ("dem-spacing,s", po::value<float>(&dem_spacing)->default_value(0), "Set the DEM post size (if this value is 0, the post spacing size is computed for you)")
    ("normalized,n", "Also write a normalized version of the DEM (for debugging)")
    ("orthoimage", po::value<std::string>(&texture_filename), "Write an orthoimage based on the texture file given as an argument to this command line option")
    ("grayscale", "Use grayscale image processing for creating the orthoimage")
    ("offset-files", "Also write a pair of ascii offset files (for debugging)")
    ("cache", po::value<unsigned>(&cache_size)->default_value(1024), "Cache size, in megabytes")
    ("input-file", po::value<std::string>(&input_file_name), "Explicitly specify the input file")
    ("texture-file", po::value<std::string>(&texture_filename), "Specify texture filename")
    ("output-prefix,o", po::value<std::string>(&out_prefix)->default_value("terrain"), "Specify the output prefix")
    ("output-filetype,t", po::value<std::string>(&output_file_type)->default_value("tif"), "Specify the output file")
    ("debug-level,d", po::value<int>(&debug_level)->default_value(vw::DebugMessage-1), "Set the debugging output level. (0-50+)")
    ("xyz-to-lonlat", "Convert from xyz coordinates to longitude, latitude, altitude coordinates.")
    ("reference-spheroid,r", po::value<std::string>(&reference_spheroid)->default_value(""),"Set a reference surface to a hard coded value (one of [moon , mars].  This will override manually set datum information.")
    ("semi-major-axis", po::value<double>(&semi_major)->default_value(0),"Set the dimensions of the datum.")
    ("semi-minor-axis", po::value<double>(&semi_minor)->default_value(0),"Set the dimensions of the datum.")
    ("z-offset", po::value<double>(&z_offset)->default_value(0), "Add a vertical offset to the DEM")

    ("sinusoidal", "Save using a sinusoidal projection")
    ("mercator", "Save using a Mercator projection")
    ("transverse-mercator", "Save using a transverse Mercator projection")
    ("orthographic", "Save using an orthographic projection")
    ("stereographic", "Save using a stereographic projection")
    ("lambert-azimuthal", "Save using a Lambert azimuthal projection")
    ("utm", po::value<unsigned>(&utm_zone), "Save using a UTM projection with the given zone")
    ("proj-lat", po::value<double>(&proj_lat), "The center of projection latitude (if applicable)")
    ("proj-lon", po::value<double>(&proj_lon), "The center of projection longitude (if applicable)")
    ("proj-scale", po::value<double>(&proj_scale), "The projection scale (if applicable)")

    ("rotation-order", po::value<std::string>(&rot_order)->default_value("xyz"),"Set the order of an euler angle rotation applied to the 3D points prior to DEM rasterization")
    ("phi-rotation", po::value<double>(&phi_rot)->default_value(0),"Set a rotation angle phi")
    ("omega-rotation", po::value<double>(&omega_rot)->default_value(0),"Set a rotation angle omega")
    ("kappa-rotation", po::value<double>(&kappa_rot)->default_value(0),"Set a rotation angle kappa");

  po::positional_options_description p;
  p.add("input-file", 1);

  po::variables_map vm;
  po::store( po::command_line_parser( argc, argv ).options(desc).positional(p).run(), vm );
  po::notify( vm );

  // Set the Vision Workbench debug level
  set_debug_level(debug_level);
  Cache::system_cache().resize( cache_size*1024*1024 );

  if( vm.count("help") ) {
    std::cout << desc << std::endl;
    return 1;
  }

  if( vm.count("input-file") != 1 ) {
    std::cout << "Error: Must specify exactly one pointcloud file and one texture file!" << std::endl;
    std::cout << desc << std::endl;
    return 1;
  }

  DiskImageView<Vector3> point_disk_image(input_file_name);
  ImageViewRef<Vector3> point_image = point_disk_image;

  // Apply an (optional) rotation to the 3D points before building the mesh.
  if (phi_rot != 0 || omega_rot != 0 || kappa_rot != 0) {
    std::cout << "Applying rotation sequence: " << rot_order << "      Angles: " << phi_rot << "   " << omega_rot << "  " << kappa_rot << "\n";
    Matrix3x3 rotation_trans = math::euler_to_rotation_matrix(phi_rot,omega_rot,kappa_rot,rot_order);
    point_image = per_pixel_filter(point_image, PointTransFunc(rotation_trans));
  }

  if (vm.count("xyz-to-lonlat") ) {
    std::cout << "Reprojecting points into longitude, latitude, altitude.\n";
    point_image = cartography::xyz_to_lon_lat_radius(point_image);
  }

  // Select a cartographic DATUM.  There are several hard coded datums
  // that can be used here, or the user can specify their own.
  cartography::Datum datum;
  if ( reference_spheroid != "" ) {
    if (reference_spheroid == "mars") {
      const double MOLA_PEDR_EQUATORIAL_RADIUS = 3396000.0;
      std::cout << "Re-referencing altitude values using standard MOLA spherical radius: " << MOLA_PEDR_EQUATORIAL_RADIUS << "\n";
      datum = cartography::Datum("Mars Datum",
                                 "MOLA PEDR Spheroid",
                                 "Prime Meridian",
                                 MOLA_PEDR_EQUATORIAL_RADIUS,
                                 MOLA_PEDR_EQUATORIAL_RADIUS,
                                 0.0);
    } else if (reference_spheroid == "moon") {
      const double LUNAR_RADIUS = 1737400;
      std::cout << "Re-referencing altitude values using standard lunar spherical radius: " << LUNAR_RADIUS << "\n";
      datum = cartography::Datum("Lunar Datum",
                                 "Lunar Spheroid",
                                 "Prime Meridian",
                                 LUNAR_RADIUS,
                                 LUNAR_RADIUS,
                                 0.0);
    } else {
      std::cout << "Unknown reference spheroid: " << reference_spheroid << ".  Current options are [ moon , mars ]\nExiting.\n\n";
      exit(0);
    }
  } else if (semi_major != 0 && semi_minor != 0) {
    std::cout << "Re-referencing altitude values to user supplied datum.  Semi-major: " << semi_major << "  Semi-minor: " << semi_minor << "\n";
    datum = cartography::Datum("User Specified Datum",
                               "User Specified Spherem",
                               "Prime Meridian",
                               semi_major, semi_minor, 0.0);
  }

  // Set up the georeferencing information.  We specify everything
  // here except for the affine transform, which is defined later once
  // we know the bounds of the orthorasterizer view.  However, we can
  // still reproject the points in the point image without the affine
  // transform because this projection never requires us to convert to
  // or from pixel space.
  GeoReference georef(datum);

  // If the data was left in cartesian coordinates, we need to give
  // the DEM a projection that uses some physical units (meters),
  // rather than lon, lat.  This is actually mainly for compatibility
  // with Viz, and it's sort of a hack, but it's left in for the time
  // being.
  //
  // Otherwise, we honor the user's requested projection and convert
  // the points if necessary.
  if (!vm.count("xyz-to-lonlat"))
    georef.set_mercator(0,0,1);
  else if( vm.count("sinusoidal") ) georef.set_sinusoidal(proj_lon);
  else if( vm.count("mercator") ) georef.set_mercator(proj_lat,proj_lon,proj_scale);
  else if( vm.count("transverse-mercator") ) georef.set_transverse_mercator(proj_lat,proj_lon,proj_scale);
  else if( vm.count("orthographic") ) georef.set_orthographic(proj_lat,proj_lon);
  else if( vm.count("stereographic") ) georef.set_stereographic(proj_lat,proj_lon,proj_scale);
  else if( vm.count("lambert-azimuthal") ) georef.set_lambert_azimuthal(proj_lat,proj_lon);
  else if( vm.count("utm") ) georef.set_UTM( utm_zone );

  if (vm.count("xyz-to-lonlat"))
    point_image = cartography::project_point_image(point_image, georef);

  // Rasterize the results to a temporary file on disk so as to speed
  // up processing in the orthorasterizer, which accesses each pixel
  // multiple times.
  DiskCacheImageView<Vector3> point_image_cache(point_image, "tif");

  // write out the DEM, texture, and extrapolation mask as
  // georeferenced files.
  vw::cartography::OrthoRasterizerView<PixelGray<float> > rasterizer(point_image_cache, select_channel(point_image_cache,2), dem_spacing);
  if (!vm.count("default-value") ) {
    rasterizer.set_use_minz_as_default(true);
  } else {
    rasterizer.set_use_minz_as_default(false);
    rasterizer.set_default_value(default_value);
  }

  if (vw.count("z-offset")) {
    double val = rasterizer.default_value();
    rasterizer.set_use_minz_as_default(false);
    rasterizer.set_default_value(val-z_offset);
  }

  if (vm.count("use-alpha")) {
    rasterizer.set_use_alpha(true);
  }

  vw::BBox<float,3> dem_bbox = rasterizer.bounding_box();
  std::cout << "DEM Bounding box: " << dem_bbox << "\n";

  // Now we are ready to specify the affine transform.
  Matrix3x3 georef_affine_transform = rasterizer.geo_transform();
  std::cout << "Georeferencing Transform: " << georef_affine_transform << "\n";
  georef.set_transform(georef_affine_transform);

  // This is a workaround for now to make GDAL write files that don't
  // cause it to crash on read. - mbroxton
  georef.set_datum(Datum());

  // Write out a georeferenced orthoimage of the DTM with alpha.
  if (vm.count("orthoimage")) {
    rasterizer.set_use_minz_as_default(false);
    DiskImageView<PixelGray<float> > texture(texture_filename);
    rasterizer.set_texture(texture);
    BlockCacheView<PixelGray<float> > block_drg_raster(rasterizer, Vector2i(rasterizer.cols(), 2048));
    write_georeferenced_image(out_prefix + "-DRG.tif", channel_cast_rescale<uint8>(block_drg_raster), georef, TerminalProgressCallback() );

  } else {
    // Write out the DEM.
    std::cout << "\n\n Creating block cache view from rasterizer: " << rasterizer.cols() << "  " << rasterizer.rows() << "\n";
    BlockCacheView<PixelGray<float> > block_dem_raster(rasterizer, Vector2i(rasterizer.cols(), 2024));
    if (vm.count("z-offset")) {
      std::cout << "Adding the following z offset: " << z_offset << "\n";
      write_georeferenced_image(out_prefix + "-DEM." + output_file_type, block_dem_raster + z_offset, georef, TerminalProgressCallback());
    } else {
      write_georeferenced_image(out_prefix + "-DEM." + output_file_type, block_dem_raster, georef, TerminalProgressCallback());
    }

    // Write out a georeferenced DTM and (optionally) a normalized version of the DTM (for debugging)
    if (vm.count("normalized")) {
      DiskImageView<PixelGray<float> > dem_image(out_prefix + "-DEM." + output_file_type);
      write_georeferenced_image(out_prefix + "-DEM-normalized.tif", channel_cast_rescale<uint8>(normalize(dem_image)), georef, TerminalProgressCallback());
    }
  }

  if (vm.count("offset-files")) {
    // Write out the offset files
    std::cout << "Offset: " << dem_bbox.min().x()/rasterizer.spacing() << "   " << dem_bbox.max().y()/rasterizer.spacing() << "\n";
    std::string offset_filename = out_prefix + "-DRG.offset";
    FILE* offset_file = fopen(offset_filename.c_str(), "w");
    fprintf(offset_file, "%d\n%d\n", int(dem_bbox.min().x()/rasterizer.spacing()), -int(dem_bbox.max().y()/rasterizer.spacing()));
    fclose(offset_file);
    offset_filename = out_prefix + "-DEM-normalized.offset";
    offset_file = fopen(offset_filename.c_str(), "w");
    fprintf(offset_file, "%d\n%d\n", int(dem_bbox.min().x()/rasterizer.spacing()), -int(dem_bbox.max().y()/rasterizer.spacing()));
    fclose(offset_file);
  }
  return 0;
}
<|endoftext|>


<commit_before>/*
 * problem1.cpp
 * 作成者：Kenshiro.H
 * 第8回　問題1改
 */
#include <iostream>
#include <iomanip>      //std::setw用
#include <fstream>      //ファイル入出力用
#include <vector>       //動的配列用
#include <algorithm>    //std::max_element用

int main(){

    using std::cout;    // std::cout -> cout
    using std::endl;    // std::endl -> endl

    /// ファイル入力
    cout << "File open" << endl;
    std::fstream DATA("problem1data.txt");

    /// コスト，ペナルティ(ない場合はデータに0を記入)
    int COST,PENALTY;
    DATA >> COST >> PENALTY;
    cout << "COST:" << COST <<" PENALTY:" << PENALTY << endl;

    /// 各要素をファイルから読み取り後、表示
    int x_max = 0 , y_max = 0;
    int G_i = 0, G_j = 0;
    DATA >> x_max >> y_max;
    std::vector<std::vector<double> > V( y_max+2 , std::vector<double>(x_max+2 , COST*100) );  //周囲1個分確保する　全部コストよりもすごく小さい値で埋める

    for(int i=1; i < y_max+1; i++){
        for(int j=1; j < x_max+1; j++){
            DATA >> V[i][j];
            if( 1 != V[i][j]){
                V[i][j] = -10.0;    //ゴール以外の価値は-10.0
            }else{
                V[i][j] = 0.0;      //ゴールの価値は高い
                G_i = i;            //ゴールの場所を覚えておく
                G_j = j;
            }
            cout << std::setw(4) << V[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl << "--START--" << endl ;

    /// 各要素の価値を価値反復を用いて計算
    int count = 0;                          //ループ終了用カウント　前回と同じ値のセルが (x_max*y_max-1)と同じになったらループ終了
    std::vector<double> TEMP(4 , 0);
    while(count != (x_max*y_max)-1 ){
        count = 0;
        for(int i=1; i < y_max+1; i++){
            for(int j=1; j < x_max+1; j++){
                if( i != G_i || j != G_j ){
                    //cout << V[i-1][j] << "|" ;
                    TEMP[0] = V[i-1][j] + COST; //上
                    //cout << V[i][j-1] << "|" ;
                    TEMP[1] = V[i][j-1] + COST; //左
                    //cout << V[i+1][j] << "|" ;
                    TEMP[2] = V[i+1][j] + COST; //下
                    //cout << V[i][j+1] << "|" << endl;
                    TEMP[3] = V[i][j+1] + COST; //右
                    for(int t=0; t<3 ; t++){
                        if(TEMP[t]>TEMP[t+1]) TEMP[t+1]=TEMP[t];    //上下左右で値が大きいものを残していく
                    }
                    if(V[i][j] == TEMP[3]) count += 1;              //前回と同じ値の場合は count +1
                    V[i][j] = TEMP[3];                              //残された一番大きい値を代入
                    TEMP.clear();                                   //一時計算用配列　リセット
                }
                cout << std::setw(4) << V[i][j] << " " ;
            }
            cout << endl;
        }
    cout << endl;
    }
    cout << "--END--" << endl ;
    return 0;
}
<commit_msg>Update problem1.cpp<commit_after>/*
 * problem1.cpp
 * 作成者：Kenshiro.H
 * 第8回　問題1改
 */
#include <iostream>
#include <iomanip>      //std::setw用
#include <fstream>      //ファイル入出力用
#include <vector>       //動的配列用
#include <algorithm>    //std::max_element用

int main(){

    using std::cout;    // std::cout -> cout
    using std::endl;    // std::endl -> endl

    /// ファイル入力
    cout << "File open" << endl;
    std::fstream DATA("src/problem1data.txt");

    /// コスト，ペナルティ(ない場合はデータに0を記入)
    int COST,PENALTY;
    DATA >> COST >> PENALTY;
    cout << "COST:" << COST <<" PENALTY:" << PENALTY << endl;

    /// 各要素をファイルから読み取り後、表示
    int x_max = 0 , y_max = 0;
    int G_i = 0, G_j = 0;
    DATA >> x_max >> y_max;
    std::vector<std::vector<double> > V( y_max+2 , std::vector<double>(x_max+2 , COST*100) );  //周囲1個分確保する　全部コストよりもすごく小さい値で埋める

    for(int i=1; i < y_max+1; i++){
        for(int j=1; j < x_max+1; j++){
            DATA >> V[i][j];
            if( 1 != V[i][j]){
                V[i][j] = -10.0;    //ゴール以外の価値は-10.0
            }else{
                V[i][j] = 0.0;      //ゴールの価値は高い
                G_i = i;            //ゴールの場所を覚えておく
                G_j = j;
            }
            cout << std::setw(4) << V[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl << "--START--" << endl ;

    /// 各要素の価値を価値反復を用いて計算
    int count = 0;                          //ループ終了用カウント　前回と同じ値のセルが (x_max*y_max-1)と同じになったらループ終了
    std::vector<double> TEMP(4 , 0);
    while(count != (x_max*y_max)-1 ){
        count = 0;
        for(int i=1; i < y_max+1; i++){
            for(int j=1; j < x_max+1; j++){
                if( i != G_i || j != G_j ){
                    //cout << V[i-1][j] << "|" ;
                    TEMP[0] = V[i-1][j] + COST; //上
                    //cout << V[i][j-1] << "|" ;
                    TEMP[1] = V[i][j-1] + COST; //左
                    //cout << V[i+1][j] << "|" ;
                    TEMP[2] = V[i+1][j] + COST; //下
                    //cout << V[i][j+1] << "|" << endl;
                    TEMP[3] = V[i][j+1] + COST; //右
                    for(int t=0; t<3 ; t++){
                        if(TEMP[t]>TEMP[t+1]) TEMP[t+1]=TEMP[t];    //上下左右で値が大きいものを残していく
                    }
                    if(V[i][j] == TEMP[3]) count += 1;              //前回と同じ値の場合は count +1
                    V[i][j] = TEMP[3];                              //残された一番大きい値を代入
                    TEMP.clear();                                   //一時計算用配列　リセット
                }
                cout << std::setw(4) << V[i][j] << " " ;
            }
            cout << endl;
        }
    cout << endl;
    }
    cout << "--END--" << endl ;
    return 0;
}
<|endoftext|>


<commit_before>// Module:  Log4CPLUS
// File:    property.cxx
// Created: 2/2002
// Author:  Tad E. Smith
//
//
// Copyright 2002-2015 Tad E. Smith
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <log4cplus/config.hxx>

#include <cstring>
#if defined (UNICODE)
#  include <cwctype>
#else
#  include <cctype>
#endif
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) \
    || defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) \
    || defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET)
#  include <codecvt>
#endif
#include <locale>
#include <fstream>
#include <sstream>
#include <log4cplus/streams.h>
#include <log4cplus/fstreams.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/internal/internal.h>
#include <log4cplus/internal/env.h>
#include <log4cplus/helpers/loglog.h>

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
#include <catch.hpp>
#endif

namespace log4cplus { namespace helpers {

const tchar Properties::PROPERTIES_COMMENT_CHAR = LOG4CPLUS_TEXT('#');

namespace
{

static
int
is_space (tchar ch)
{
#if defined (UNICODE)
    return std::iswspace (ch);
#else
    return std::isspace (static_cast<unsigned char>(ch));
#endif
}

static
void
trim_leading_ws (tstring & str)
{
    tstring::iterator it = str.begin ();
    for (; it != str.end (); ++it)
    {
        if (! is_space (*it))
            break;
    }
    str.erase (str.begin (), it);
}

static
void
trim_trailing_ws (tstring & str)
{
    tstring::reverse_iterator rit = str.rbegin ();
    for (; rit != str.rend (); ++rit)
    {
        if (! is_space (*rit))
            break;
    }
    str.erase (rit.base (), str.end ());
}

static
void
trim_ws (tstring & str)
{
    trim_trailing_ws (str);
    trim_leading_ws (str);
}

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
CATCH_TEST_CASE( "String trimming", "[strings][properties]")
{
    CATCH_SECTION ("trim trailing whitespace")
    {
        tstring trailing_ws (LOG4CPLUS_TEXT ("abcd \t\n\v\f\r"));
        trim_trailing_ws (trailing_ws);
        CATCH_REQUIRE (trailing_ws == LOG4CPLUS_TEXT ("abcd"));
    }

    CATCH_SECTION ("trim leading whitespace")
    {
        tstring leading_ws (LOG4CPLUS_TEXT (" \t\n\v\f\rabcd"));
        trim_leading_ws (leading_ws);
        CATCH_REQUIRE (leading_ws == LOG4CPLUS_TEXT ("abcd"));
    }

    CATCH_SECTION ("trim all whitespace")
    {
        tstring ws (LOG4CPLUS_TEXT (" \t\n\v\f\rabcd \t\n\v\f\r"));
        trim_ws (ws);
        CATCH_REQUIRE (ws == LOG4CPLUS_TEXT ("abcd"));
    }
}
#endif

void
imbue_file_from_flags (tistream & file, unsigned flags)
{
    switch (flags & (Properties::fEncodingMask << Properties::fEncodingShift))
    {
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) && defined (UNICODE)
    case Properties::fUTF8:
        file.imbue (
            std::locale (file.getloc (),
                new std::codecvt_utf8<tchar, 0x10FFFF,
                    static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
        break;
#endif

#if defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) && defined (UNICODE)
    case Properties::fUTF16:
        file.imbue (
            std::locale (file.getloc (),
                new std::codecvt_utf16<tchar, 0x10FFFF,
                    static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
        break;

#elif defined (UNICODE) && defined (WIN32)
    case Properties::fUTF16:
        file.imbue (
            std::locale (file.getloc (),
                // TODO: This should actually be a custom "null" facet
                // that just copies the chars to wchar_t buffer.
                new std::codecvt<wchar_t, char, std::mbstate_t>));
    break;

#endif

#if defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET) && defined (UNICODE)
    case Properties::fUTF32:
        file.imbue (
            std::locale (file.getloc (),
                new std::codecvt_utf32<tchar, 0x10FFFF,
                    static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
        break;
#endif

    case Properties::fUnspecEncoding:;
    default:
        // Do nothing.
        ;
    }
}

} // namespace

///////////////////////////////////////////////////////////////////////////////
// Properties ctors and dtor
///////////////////////////////////////////////////////////////////////////////

Properties::Properties()
    : flags (0)
{
}

Properties::Properties(tistream& input)
    : flags (0)
{
    init(input);
}

Properties::Properties(const tstring& inputFile, unsigned f)
    : flags (f)
{
    if (inputFile.empty ())
        return;

    tifstream file;
    imbue_file_from_flags (file, flags);

    file.open(LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(inputFile).c_str(),
        std::ios::binary);
    if (! file.good ())
        helpers::getLogLog ().error (LOG4CPLUS_TEXT ("could not open file ")
            + inputFile);

    init(file);
}

void
Properties::init(tistream& input)
{
    if (! input)
        return;

    tstring buffer;
    while (std::getline (input, buffer))
    {
        trim_leading_ws (buffer);

        tstring::size_type const buffLen = buffer.size ();
        if (buffLen == 0 || buffer[0] == PROPERTIES_COMMENT_CHAR)
            continue;

        // Check if we have a trailing \r because we are
        // reading a properties file produced on Windows.
        if (buffer[buffLen-1] == LOG4CPLUS_TEXT('\r'))
            // Remove trailing 'Windows' \r.
            buffer.resize (buffLen - 1);

        tstring::size_type const idx = buffer.find(LOG4CPLUS_TEXT ('='));
        if (idx != tstring::npos)
        {
            tstring key = buffer.substr(0, idx);
            tstring value = buffer.substr(idx + 1);
            trim_trailing_ws (key);
            trim_ws (value);
            setProperty(key, value);
        }
        else if (buffer.compare (0, 7, LOG4CPLUS_TEXT ("include")) == 0
            && buffer.size () >= 7 + 1 + 1
            && is_space (buffer[7]))
        {
            tstring included (buffer, 8) ;
            trim_ws (included);

            tifstream file;
            imbue_file_from_flags (file, flags);

            file.open (LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(included).c_str(),
                std::ios::binary);
            if (! file.good ())
                helpers::getLogLog ().error (
                    LOG4CPLUS_TEXT ("could not open file ") + included);

            init (file);
        }
    }
}

Properties::~Properties()
{
}

///////////////////////////////////////////////////////////////////////////////
// helpers::Properties public methods
///////////////////////////////////////////////////////////////////////////////

bool
Properties::exists(const log4cplus::tstring& key) const
{
    return data.find(key) != data.end();
}

bool
Properties::exists(tchar const * key) const
{
    return data.find(key) != data.end();
}

tstring const &
Properties::getProperty(const tstring& key) const
{
    return get_property_worker (key);
}

log4cplus::tstring const &
Properties::getProperty(tchar const * key) const
{
    return get_property_worker (key);
}

tstring
Properties::getProperty(const tstring& key, const tstring& defaultVal) const
{
    StringMap::const_iterator it (data.find (key));
    if (it == data.end ())
        return defaultVal;
    else
        return it->second;
}

std::vector<tstring>
Properties::propertyNames() const
{
    std::vector<tstring> tmp;
    tmp.reserve (data.size ());
    for (auto const & kv : data)
        tmp.push_back(kv.first);

    return tmp;
}

void
Properties::setProperty(const log4cplus::tstring& key,
    const log4cplus::tstring& value)
{
    data[key] = value;
}

bool
Properties::removeProperty(const log4cplus::tstring& key)
{
    return data.erase(key) > 0;
}

Properties
Properties::getPropertySubset(const log4cplus::tstring& prefix) const
{
    Properties ret;
    auto const prefix_len = prefix.size ();
    std::vector<tstring> keys = propertyNames();
    for (tstring const & key : keys)
    {
        int result = key.compare (0, prefix_len, prefix);
        if (result == 0)
            ret.setProperty (key.substr (prefix_len), getProperty(key));
    }

    return ret;
}

bool
Properties::getInt (int & val, log4cplus::tstring const & key) const
{
    return get_type_val_worker (val, key);
}

bool
Properties::getUInt (unsigned & val, log4cplus::tstring const & key) const
{
    return get_type_val_worker (val, key);
}

bool
Properties::getLong (long & val, log4cplus::tstring const & key) const
{
    return get_type_val_worker (val, key);
}

bool
Properties::getULong (unsigned long & val, log4cplus::tstring const & key) const
{
    return get_type_val_worker (val, key);
}

bool
Properties::getBool (bool & val, log4cplus::tstring const & key) const
{
    if (! exists (key))
        return false;

    log4cplus::tstring const & prop_val = getProperty (key);
    return internal::parse_bool (val, prop_val);
}

bool
Properties::getString (log4cplus::tstring & val, log4cplus::tstring const & key)
    const
{
    StringMap::const_iterator it (data.find (key));
    if (it == data.end ())
        return false;

    val = it->second;
    return true;
}

template <typename StringType>
log4cplus::tstring const &
Properties::get_property_worker (StringType const & key) const
{
    StringMap::const_iterator it (data.find (key));
    if (it == data.end ())
        return log4cplus::internal::empty_str;
    else
        return it->second;
}

template <typename ValType>
bool
Properties::get_type_val_worker (ValType & val, log4cplus::tstring const & key)
    const
{
    if (! exists (key))
        return false;

    log4cplus::tstring const & prop_val = getProperty (key);
    log4cplus::tistringstream iss (prop_val);
    ValType tmp_val;
    tchar ch;

    iss >> tmp_val;
    if (! iss)
        return false;
    iss >> ch;
    if (iss)
        return false;

    val = tmp_val;
    return true;
}

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
CATCH_TEST_CASE ("Properties", "[properties]")
{
    Properties props;
    tistringstream iss (
        LOG4CPLUS_TEXT ("bool=true\r\n")
        LOG4CPLUS_TEXT ("bool1=1\n")
        LOG4CPLUS_TEXT ("int=-1\n")
        LOG4CPLUS_TEXT ("uint=42\n")
        LOG4CPLUS_TEXT ("long=-65537\n")
        LOG4CPLUS_TEXT ("ulong=65537")
    );
    Properties from_stream (iss);

    CATCH_SECTION ("new object is empty")
    {
        CATCH_REQUIRE (props.size () == 0);
    }

    CATCH_SECTION ("added property can be retrieved")
    {
        props.setProperty (LOG4CPLUS_TEXT ("a.b.c"), LOG4CPLUS_TEXT ("true"));
        CATCH_REQUIRE (props.getProperty (LOG4CPLUS_TEXT ("a.b.c"))
            == LOG4CPLUS_TEXT ("true"));
    }

    CATCH_SECTION ("type conversions work")
    {
        bool bool_;
        int int_;
        unsigned int uint;
        long long_;
        unsigned long ulong;

        CATCH_REQUIRE (from_stream.getBool (bool_, LOG4CPLUS_TEXT ("bool")));
        CATCH_REQUIRE (bool_);
        CATCH_REQUIRE (from_stream.getBool (bool_, LOG4CPLUS_TEXT ("bool1")));
        CATCH_REQUIRE (bool_);
        CATCH_REQUIRE (from_stream.getInt (int_, LOG4CPLUS_TEXT ("int")));
        CATCH_REQUIRE (int_ == -1);
        CATCH_REQUIRE (from_stream.getUInt (uint, LOG4CPLUS_TEXT ("uint")));
        CATCH_REQUIRE (uint == 42);
        CATCH_REQUIRE (from_stream.getLong (long_, LOG4CPLUS_TEXT ("long")));
        CATCH_REQUIRE (long_ == -65537);
        CATCH_REQUIRE (from_stream.getULong (ulong, LOG4CPLUS_TEXT ("ulong")));
        CATCH_REQUIRE (ulong == 65537);
    }
}
#endif

} } // namespace log4cplus { namespace helpers {
<commit_msg>Improve unit test coverage for Properties.<commit_after>// Module:  Log4CPLUS
// File:    property.cxx
// Created: 2/2002
// Author:  Tad E. Smith
//
//
// Copyright 2002-2015 Tad E. Smith
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <log4cplus/config.hxx>

#include <cstring>
#if defined (UNICODE)
#  include <cwctype>
#else
#  include <cctype>
#endif
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) \
    || defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) \
    || defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET)
#  include <codecvt>
#endif
#include <locale>
#include <fstream>
#include <sstream>
#include <log4cplus/streams.h>
#include <log4cplus/fstreams.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/internal/internal.h>
#include <log4cplus/internal/env.h>
#include <log4cplus/helpers/loglog.h>

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
#include <catch.hpp>
#endif

namespace log4cplus { namespace helpers {

const tchar Properties::PROPERTIES_COMMENT_CHAR = LOG4CPLUS_TEXT('#');

namespace
{

static
int
is_space (tchar ch)
{
#if defined (UNICODE)
    return std::iswspace (ch);
#else
    return std::isspace (static_cast<unsigned char>(ch));
#endif
}

static
void
trim_leading_ws (tstring & str)
{
    tstring::iterator it = str.begin ();
    for (; it != str.end (); ++it)
    {
        if (! is_space (*it))
            break;
    }
    str.erase (str.begin (), it);
}

static
void
trim_trailing_ws (tstring & str)
{
    tstring::reverse_iterator rit = str.rbegin ();
    for (; rit != str.rend (); ++rit)
    {
        if (! is_space (*rit))
            break;
    }
    str.erase (rit.base (), str.end ());
}

static
void
trim_ws (tstring & str)
{
    trim_trailing_ws (str);
    trim_leading_ws (str);
}

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
CATCH_TEST_CASE( "String trimming", "[strings][properties]")
{
    CATCH_SECTION ("trim trailing whitespace")
    {
        tstring trailing_ws (LOG4CPLUS_TEXT ("abcd \t\n\v\f\r"));
        trim_trailing_ws (trailing_ws);
        CATCH_REQUIRE (trailing_ws == LOG4CPLUS_TEXT ("abcd"));
    }

    CATCH_SECTION ("trim leading whitespace")
    {
        tstring leading_ws (LOG4CPLUS_TEXT (" \t\n\v\f\rabcd"));
        trim_leading_ws (leading_ws);
        CATCH_REQUIRE (leading_ws == LOG4CPLUS_TEXT ("abcd"));
    }

    CATCH_SECTION ("trim all whitespace")
    {
        tstring ws (LOG4CPLUS_TEXT (" \t\n\v\f\rabcd \t\n\v\f\r"));
        trim_ws (ws);
        CATCH_REQUIRE (ws == LOG4CPLUS_TEXT ("abcd"));
    }
}
#endif

void
imbue_file_from_flags (tistream & file, unsigned flags)
{
    switch (flags & (Properties::fEncodingMask << Properties::fEncodingShift))
    {
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) && defined (UNICODE)
    case Properties::fUTF8:
        file.imbue (
            std::locale (file.getloc (),
                new std::codecvt_utf8<tchar, 0x10FFFF,
                    static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
        break;
#endif

#if defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) && defined (UNICODE)
    case Properties::fUTF16:
        file.imbue (
            std::locale (file.getloc (),
                new std::codecvt_utf16<tchar, 0x10FFFF,
                    static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
        break;

#elif defined (UNICODE) && defined (WIN32)
    case Properties::fUTF16:
        file.imbue (
            std::locale (file.getloc (),
                // TODO: This should actually be a custom "null" facet
                // that just copies the chars to wchar_t buffer.
                new std::codecvt<wchar_t, char, std::mbstate_t>));
    break;

#endif

#if defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET) && defined (UNICODE)
    case Properties::fUTF32:
        file.imbue (
            std::locale (file.getloc (),
                new std::codecvt_utf32<tchar, 0x10FFFF,
                    static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
        break;
#endif

    case Properties::fUnspecEncoding:;
    default:
        // Do nothing.
        ;
    }
}

} // namespace

///////////////////////////////////////////////////////////////////////////////
// Properties ctors and dtor
///////////////////////////////////////////////////////////////////////////////

Properties::Properties()
    : flags (0)
{
}

Properties::Properties(tistream& input)
    : flags (0)
{
    init(input);
}

Properties::Properties(const tstring& inputFile, unsigned f)
    : flags (f)
{
    if (inputFile.empty ())
        return;

    tifstream file;
    imbue_file_from_flags (file, flags);

    file.open(LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(inputFile).c_str(),
        std::ios::binary);
    if (! file.good ())
        helpers::getLogLog ().error (LOG4CPLUS_TEXT ("could not open file ")
            + inputFile);

    init(file);
}

void
Properties::init(tistream& input)
{
    if (! input)
        return;

    tstring buffer;
    while (std::getline (input, buffer))
    {
        trim_leading_ws (buffer);

        tstring::size_type const buffLen = buffer.size ();
        if (buffLen == 0 || buffer[0] == PROPERTIES_COMMENT_CHAR)
            continue;

        // Check if we have a trailing \r because we are
        // reading a properties file produced on Windows.
        if (buffer[buffLen-1] == LOG4CPLUS_TEXT('\r'))
            // Remove trailing 'Windows' \r.
            buffer.resize (buffLen - 1);

        tstring::size_type const idx = buffer.find(LOG4CPLUS_TEXT ('='));
        if (idx != tstring::npos)
        {
            tstring key = buffer.substr(0, idx);
            tstring value = buffer.substr(idx + 1);
            trim_trailing_ws (key);
            trim_ws (value);
            setProperty(key, value);
        }
        else if (buffer.compare (0, 7, LOG4CPLUS_TEXT ("include")) == 0
            && buffer.size () >= 7 + 1 + 1
            && is_space (buffer[7]))
        {
            tstring included (buffer, 8) ;
            trim_ws (included);

            tifstream file;
            imbue_file_from_flags (file, flags);

            file.open (LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(included).c_str(),
                std::ios::binary);
            if (! file.good ())
                helpers::getLogLog ().error (
                    LOG4CPLUS_TEXT ("could not open file ") + included);

            init (file);
        }
    }
}

Properties::~Properties()
{
}

///////////////////////////////////////////////////////////////////////////////
// helpers::Properties public methods
///////////////////////////////////////////////////////////////////////////////

bool
Properties::exists(const log4cplus::tstring& key) const
{
    return data.find(key) != data.end();
}

bool
Properties::exists(tchar const * key) const
{
    return data.find(key) != data.end();
}

tstring const &
Properties::getProperty(const tstring& key) const
{
    return get_property_worker (key);
}

log4cplus::tstring const &
Properties::getProperty(tchar const * key) const
{
    return get_property_worker (key);
}

tstring
Properties::getProperty(const tstring& key, const tstring& defaultVal) const
{
    StringMap::const_iterator it (data.find (key));
    if (it == data.end ())
        return defaultVal;
    else
        return it->second;
}

std::vector<tstring>
Properties::propertyNames() const
{
    std::vector<tstring> tmp;
    tmp.reserve (data.size ());
    for (auto const & kv : data)
        tmp.push_back(kv.first);

    return tmp;
}

void
Properties::setProperty(const log4cplus::tstring& key,
    const log4cplus::tstring& value)
{
    data[key] = value;
}

bool
Properties::removeProperty(const log4cplus::tstring& key)
{
    return data.erase(key) > 0;
}

Properties
Properties::getPropertySubset(const log4cplus::tstring& prefix) const
{
    Properties ret;
    auto const prefix_len = prefix.size ();
    std::vector<tstring> keys = propertyNames();
    for (tstring const & key : keys)
    {
        int result = key.compare (0, prefix_len, prefix);
        if (result == 0)
            ret.setProperty (key.substr (prefix_len), getProperty(key));
    }

    return ret;
}

bool
Properties::getInt (int & val, log4cplus::tstring const & key) const
{
    return get_type_val_worker (val, key);
}

bool
Properties::getUInt (unsigned & val, log4cplus::tstring const & key) const
{
    return get_type_val_worker (val, key);
}

bool
Properties::getLong (long & val, log4cplus::tstring const & key) const
{
    return get_type_val_worker (val, key);
}

bool
Properties::getULong (unsigned long & val, log4cplus::tstring const & key) const
{
    return get_type_val_worker (val, key);
}

bool
Properties::getBool (bool & val, log4cplus::tstring const & key) const
{
    if (! exists (key))
        return false;

    log4cplus::tstring const & prop_val = getProperty (key);
    return internal::parse_bool (val, prop_val);
}

bool
Properties::getString (log4cplus::tstring & val, log4cplus::tstring const & key)
    const
{
    StringMap::const_iterator it (data.find (key));
    if (it == data.end ())
        return false;

    val = it->second;
    return true;
}

template <typename StringType>
log4cplus::tstring const &
Properties::get_property_worker (StringType const & key) const
{
    StringMap::const_iterator it (data.find (key));
    if (it == data.end ())
        return log4cplus::internal::empty_str;
    else
        return it->second;
}

template <typename ValType>
bool
Properties::get_type_val_worker (ValType & val, log4cplus::tstring const & key)
    const
{
    if (! exists (key))
        return false;

    log4cplus::tstring const & prop_val = getProperty (key);
    log4cplus::tistringstream iss (prop_val);
    ValType tmp_val;
    tchar ch;

    iss >> tmp_val;
    if (! iss)
        return false;
    iss >> ch;
    if (iss)
        return false;

    val = tmp_val;
    return true;
}

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
CATCH_TEST_CASE ("Properties", "[properties]")
{
    static tchar const PROP_ABC[] = LOG4CPLUS_TEXT ("a.b.c");
    Properties props;

    CATCH_SECTION ("new object is empty")
    {
        CATCH_REQUIRE (props.size () == 0);
    }

    CATCH_SECTION ("added property can be retrieved")
    {
        props.setProperty (PROP_ABC, LOG4CPLUS_TEXT ("true"));
        CATCH_REQUIRE (props.exists (PROP_ABC));
        CATCH_REQUIRE (props.exists (LOG4CPLUS_C_STR_TO_TSTRING (PROP_ABC)));
        CATCH_REQUIRE (props.getProperty (PROP_ABC)
            == LOG4CPLUS_TEXT ("true"));
    }

    CATCH_SECTION ("type conversions work")
    {
        bool bool_;
        int int_;
        unsigned int uint;
        long long_;
        unsigned long ulong;

        tistringstream iss (
            LOG4CPLUS_TEXT ("bool=true\r\n")
            LOG4CPLUS_TEXT ("bool1=1\n")
            LOG4CPLUS_TEXT ("int=-1\n")
            LOG4CPLUS_TEXT ("uint=42\n")
            LOG4CPLUS_TEXT ("long=-65537\n")
            LOG4CPLUS_TEXT ("ulong=65537")
        );
        Properties from_stream (iss);

        CATCH_REQUIRE (from_stream.getBool (bool_, LOG4CPLUS_TEXT ("bool")));
        CATCH_REQUIRE (bool_);
        CATCH_REQUIRE (from_stream.getBool (bool_, LOG4CPLUS_TEXT ("bool1")));
        CATCH_REQUIRE (bool_);
        CATCH_REQUIRE (from_stream.getInt (int_, LOG4CPLUS_TEXT ("int")));
        CATCH_REQUIRE (int_ == -1);
        CATCH_REQUIRE (from_stream.getUInt (uint, LOG4CPLUS_TEXT ("uint")));
        CATCH_REQUIRE (uint == 42);
        CATCH_REQUIRE (from_stream.getLong (long_, LOG4CPLUS_TEXT ("long")));
        CATCH_REQUIRE (long_ == -65537);
        CATCH_REQUIRE (from_stream.getULong (ulong, LOG4CPLUS_TEXT ("ulong")));
        CATCH_REQUIRE (ulong == 65537);
    }

    CATCH_SECTION ("remove property")
    {
        props.setProperty (PROP_ABC, LOG4CPLUS_TEXT ("true"));
        CATCH_REQUIRE (props.exists (PROP_ABC));
        props.removeProperty (PROP_ABC);
        CATCH_REQUIRE (! props.exists (PROP_ABC));
    }

    CATCH_SECTION ("retrieve property names")
    {
        props.setProperty (PROP_ABC, LOG4CPLUS_TEXT ("true"));
        static tchar const PROP_SECOND[] = LOG4CPLUS_TEXT ("second");
        props.setProperty (LOG4CPLUS_TEXT ("second"), LOG4CPLUS_TEXT ("false"));
        std::vector<log4cplus::tstring> names (props.propertyNames ());
        CATCH_REQUIRE (std::find (std::begin (names), std::end (names),
                PROP_ABC) != std::end (names));
        CATCH_REQUIRE (std::find (std::begin (names), std::end (names),
                PROP_SECOND) != std::end (names));
    }
}
#endif

} } // namespace log4cplus { namespace helpers {
<|endoftext|>


<commit_before>
#include "requests.h"
#include "macros.h"
#include <iostream>

#ifdef __linux__
Requests::Requests() {
    startWorkers();
};
#endif

//Requests::getPopRequest returns the first request of a queue
void Requests::getPopRequest(Requests::Request *req)
{
    req = requestsQueue.front();
    requestsQueue.pop();
};

//Request::workerThread is the main function for the worker thread(s)
void Requests::workerThread()
{
    std::unique_lock<std::mutex> lock(requestsQueueMtx);

    while (1)
    {
        threadCondVar.wait(lock, [this]{
            return (requestsQueue.size());
        });

        if (requestsQueue.size())
        {
            Requests::Request req;
            getPopRequest(&req);

            lock.unlock();

            fetchRequest(req);
            delete &req;
            std::cout << req.Url << std::endl;

            lock.lock();
        }
    }
};

//Requests::startWorkers initialize and setups the used worker threads once a time
void Requests::startWorkers()
{
    if (!workersStarted)
    {
        for (int i = 0; i < THREADS; i++)
        {
            std::thread t(&Requests::workerThread, this);
            t.detach();
        };
        workersStarted = true;
    }
};

//RequestsCurlCallbackWriter is a function used by cURL to receive the incoming byte packes of the URL content
static size_t RequestsCurlCallbackWriter(void *contents, size_t size, size_t nmemb, void *buf)
{
    ((std::string *)buf)->append((char *)contents, size * nmemb);
    return size * nmemb;
};

//Requests::isValidParameter checks if given parameter is existing or valid
bool Requests::isValidParameter(std::string param)
{
    if (
        param.compare("#url") == 0 ||
        param.compare("#method") == 0 ||
        param.compare("#clientid") == 0 ||
        param.compare("#jsonToArray") == 0
    ) return false;
    return true;
};

//Requests::addResult adds a struct of Requests::Result to the result map and returns its id
int Requests::addResult()
{
    int key = 1;

    resultsMtx.lock();
    while (true)
    {
        if (results.find(key) == results.end())
            break;
        key++;
    };
    resultsMtx.unlock();

    Requests::Result res;
    res.status = 1; // 0 = text pending, 1 = pending, 2 = error
    resultsMtx.lock();
    results.insert(std::pair<int, Requests::Result*>(key, &res));
    resultsMtx.unlock();

    #ifdef _MSC_VER
    startWorkers();
    #endif

    return key;
};

int Requests::addRequest(Arguments::Parameters params)
{
    int key = addResult();

    if (key < 1)
        return 0;

    Requests::Request req;
    req.RequestID = key;
    req.Url = params.Url;
    req.Method = params.Method;
    req.PostData = params.PostData;
    req.Headers = params.Headers;
    req.JsonToArray = params.JsonToArray;
    req.Redirect = params.Redirect;
    req.MaxRedirects = params.MaxRedirects;
    req.MaxTimeout = params.MaxTimeout;

    requestsQueueMtx.lock();
    requestsQueue.push(&req);
    requestsQueueMtx.unlock();

    return key;
};

//Requests::setResult sets a specific result by its id
void Requests::setResult(int id, Requests::Result res)
{
    if (id <= 0)
        return;

    resultsMtx.lock();

    if (results.find(id) != results.end())
    {
        results[id] = &res;
    }

    resultsMtx.unlock();
};

//Requests::removeResult removes an existing result from the map
bool Requests::removeResult(int id)
{
    std::map<int, Requests::Result*>::iterator f;
    f = results.find(id);
    if (f == results.end())
        return false;

    resultsMtx.lock();
    Requests::Result *r = f->second;
    delete r;
    results.erase(f);
    resultsMtx.unlock();

    return true;
};

//Requests::getResult sets the address of an given result pointer and return its status
int Requests::getResult(int id, Requests::Result *res)
{
    if (results.find(id) == results.end())
        return 2;

    resultsMtx.lock();
    res = results[id]; //error 3 on request...
    resultsMtx.unlock();

    if (res->status == 2) removeResult(id);

    return res->status;
};

//Requests::fetchRequest processes a given request by the parameters of Requests::Request
void Requests::fetchRequest(Requests::Request req)
{
    if (!results.size())
    {
        Requests::Result res;

        int status = getResult(req.RequestID, &res);
        res.status = 2;

        if (status == 1) {
            CURL *curl;
            CURLcode cS;

            curl = curl_easy_init();

            struct curl_slist *headers = NULL;
            for (unsigned int i = 0; i < req.Headers.size(); i++)
            {
                headers = curl_slist_append(headers, req.Headers[i].c_str());
            }

            std::string resStr;

            if (curl)
            {
                curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                curl_easy_setopt(curl, CURLOPT_URL, req.Url.c_str());
                curl_easy_setopt(curl, CURLOPT_USERAGENT, HTTP_VERSION);
                curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, req.Method.c_str());

                if (!req.Url.empty()) {
                    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req.PostData.c_str());
                }

                if (req.Redirect) {
                    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
                    if (req.MaxRedirects != 0) {
                        curl_easy_setopt(curl, CURLOPT_MAXREDIRS, (long int)req.MaxRedirects);
                    }
                }

                curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, req.MaxTimeout);
                curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resStr);
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, RequestsCurlCallbackWriter);

                cS = curl_easy_perform(curl);

                if (cS == CURLE_OK)
                {
                    if (req.JsonToArray)
                    {
                        resStr = A3URLCommon::ToArray(resStr);
                    }

                    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res.httpCode);

                    res.result = resStr;
                    res.status = 0;
                }
            }

            setResult(req.RequestID, res);
        }
    }
};

//Requests::AddRequest call Requests::addRequest and writes the output to an pointer class Output
int Requests::AddRequest(Output *op, Arguments::Parameters params)
{
    int id = addRequest(params);
    threadCondVar.notify_one();
    op->Write(id);

    if (id <= 0)
        return 0;

    return 0;
}

//Requests::getResultString copies the result of an Requests::Result class to an std::string pointer
int Requests::getResultString(int id, std::string *str)
{
    if (results.find(id) == results.end())
        return 2;

    Requests::Result res;
    res.status = getResult(id, &res);

    if (res.status == 0)
    {
        if (res.result.size() > 10200)
        {
            *str = res.result.substr(0, 10200);
            res.result.erase(res.result.begin(), (res.result.begin() + 10200));
            setResult(id, res);
        }
        else if (res.result.size() <= 10200)
        {
            *str = res.result;
            removeResult(id);
            res.status = res.httpCode;
        }
    }

    return res.status;
};

//Requests::GetResult copies the result of an result to an sstream Output
int Requests::GetResult(Output *op, int id)
{
    std::string str("");
    int status = getResultString(id, &str);

    op->Write(str.c_str()); // IF str IS EQUAL TO "", str IS FULLY EMPTIED

    return status;
};

int Requests::GetStatus(int id)
{
    if (results.find(id) == results.end())
        return 3;
    Requests::Result *res;

    resultsMtx.lock();
    res = results[id];
    resultsMtx.unlock();

    return res->status;
}
<commit_msg>update requests.cpp<commit_after>
#include "requests.h"
#include "macros.h"
#include <iostream>

#ifdef __linux__
Requests::Requests() {
    startWorkers();
};
#endif

//Requests::getPopRequest returns the first request of a queue
void Requests::getPopRequest(Requests::Request *req)
{
    req = requestsQueue.front();
    requestsQueue.pop();
};

//Request::workerThread is the main function for the worker thread(s)
void Requests::workerThread()
{
    std::unique_lock<std::mutex> lock(requestsQueueMtx);

    while (1)
    {
        threadCondVar.wait(lock, [this]{
            return (requestsQueue.size());
        });

        if (requestsQueue.size())
        {
            Requests::Request req;
            getPopRequest(&req);

            lock.unlock();

            fetchRequest(req);
            delete &req;
            std::cout << req.Url << std::endl;

            lock.lock();
        }
    }
};

//Requests::startWorkers initialize and setups the used worker threads once a time
void Requests::startWorkers()
{
    if (!workersStarted)
    {
        for (int i = 0; i < THREADS; i++)
        {
            std::thread t(&Requests::workerThread, this);
            t.detach();
        };
        workersStarted = true;
    }
};

//RequestsCurlCallbackWriter is a function used by cURL to receive the incoming byte packes of the URL content
static size_t RequestsCurlCallbackWriter(void *contents, size_t size, size_t nmemb, void *buf)
{
    ((std::string *)buf)->append((char *)contents, size * nmemb);
    return size * nmemb;
};

//Requests::isValidParameter checks if given parameter is existing or valid
bool Requests::isValidParameter(std::string param)
{
    if (
        param.compare("#url") == 0 ||
        param.compare("#method") == 0 ||
        param.compare("#clientid") == 0 ||
        param.compare("#jsonToArray") == 0
    ) return false;
    return true;
};

//Requests::addResult adds a struct of Requests::Result to the result map and returns its id
int Requests::addResult()
{
    int key = 1;

    resultsMtx.lock();
    while (true)
    {
        if (results.find(key) == results.end())
            break;
        key++;
    };
    resultsMtx.unlock();

    Requests::Result res;
    res.status = 1; // 0 = text pending, 1 = pending, 2 = error
    resultsMtx.lock();
    results.insert(std::pair<int, Requests::Result*>(key, &res));
    resultsMtx.unlock();

    #ifdef _MSC_VER
    startWorkers();
    #endif

    return key;
};

int Requests::addRequest(Arguments::Parameters params)
{
    int key = addResult();

    if (key < 1)
        return 0;

    Requests::Request req;
    req.RequestID = key;
    req.Url = params.Url;
    req.Method = params.Method;
    req.PostData = params.PostData;
    req.Headers = params.Headers;
    req.JsonToArray = params.JsonToArray;
    req.Redirect = params.Redirect;
    req.MaxRedirects = params.MaxRedirects;
    req.MaxTimeout = params.MaxTimeout;

    requestsQueueMtx.lock();
    requestsQueue.push(&req);
    requestsQueueMtx.unlock();

    return key;
};

//Requests::setResult sets a specific result by its id
void Requests::setResult(int id, Requests::Result res)
{
    if (id <= 0)
        return;

    resultsMtx.lock();

    if (results.find(id) != results.end())
    {
        results[id] = &res;
    }

    resultsMtx.unlock();
};

//Requests::removeResult removes an existing result from the map
bool Requests::removeResult(int id)
{
    std::map<int, Requests::Result*>::iterator f;
    f = results.find(id);
    if (f == results.end())
        return false;

    resultsMtx.lock();
    Requests::Result *r = f->second;
    delete r;
    results.erase(f);
    resultsMtx.unlock();

    return true;
};

//Requests::getResult sets the address of an given result pointer and return its status
int Requests::getResult(int id, Requests::Result *res)
{
    if (results.find(id) == results.end())
        return 2;

    resultsMtx.lock();
    res = results[id]; //error 3 on request...
    resultsMtx.unlock();

    if (res->status == 2) removeResult(id);

    return res->status;
};

//Requests::fetchRequest processes a given request by the parameters of Requests::Request
void Requests::fetchRequest(Requests::Request req)
{
    if (!results.empty())
    {
        Requests::Result res;

        int status = getResult(req.RequestID, &res);
        res.status = 2;

        if (status == 1) {
            CURL *curl;
            CURLcode cS;

            curl = curl_easy_init();

            struct curl_slist *headers = NULL;
            for (unsigned int i = 0; i < req.Headers.size(); i++)
            {
                headers = curl_slist_append(headers, req.Headers[i].c_str());
            }

            std::string resStr;

            if (curl)
            {
                curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                curl_easy_setopt(curl, CURLOPT_URL, req.Url.c_str());
                curl_easy_setopt(curl, CURLOPT_USERAGENT, HTTP_VERSION);
                curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, req.Method.c_str());

                if (!req.Url.empty()) {
                    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req.PostData.c_str());
                }

                if (req.Redirect) {
                    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
                    if (req.MaxRedirects != 0) {
                        curl_easy_setopt(curl, CURLOPT_MAXREDIRS, (long int)req.MaxRedirects);
                    }
                }

                curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, req.MaxTimeout);
                curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resStr);
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, RequestsCurlCallbackWriter);

                cS = curl_easy_perform(curl);

                if (cS == CURLE_OK)
                {
                    if (req.JsonToArray)
                    {
                        resStr = A3URLCommon::ToArray(resStr);
                    }

                    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res.httpCode);

                    res.result = resStr;
                    res.status = 0;
                }
            }

            setResult(req.RequestID, res);
        }
    }
};

//Requests::AddRequest call Requests::addRequest and writes the output to an pointer class Output
int Requests::AddRequest(Output *op, Arguments::Parameters params)
{
    int id = addRequest(params);
    threadCondVar.notify_one();
    op->Write(id);

    if (id <= 0)
        return 0;

    return 0;
}

//Requests::getResultString copies the result of an Requests::Result class to an std::string pointer
int Requests::getResultString(int id, std::string *str)
{
    if (results.find(id) == results.end())
        return 2;

    Requests::Result res;
    res.status = getResult(id, &res);

    if (res.status == 0)
    {
        if (res.result.size() > 10200)
        {
            *str = res.result.substr(0, 10200);
            res.result.erase(res.result.begin(), (res.result.begin() + 10200));
            setResult(id, res);
        }
        else if (res.result.size() <= 10200)
        {
            *str = res.result;
            removeResult(id);
            res.status = res.httpCode;
        }
    }

    return res.status;
};

//Requests::GetResult copies the result of an result to an sstream Output
int Requests::GetResult(Output *op, int id)
{
    std::string str("");
    int status = getResultString(id, &str);

    op->Write(str.c_str()); // IF str IS EQUAL TO "", str IS FULLY EMPTIED

    return status;
};

int Requests::GetStatus(int id)
{
    if (results.find(id) == results.end())
        return 3;
    Requests::Result *res;

    resultsMtx.lock();
    res = results[id];
    resultsMtx.unlock();

    return res->status;
}
<|endoftext|>


<commit_before>#include "debug_log.hpp"
#include "connection_pool.hpp"

#include <boost/asio/io_service.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/program_options.hpp>

namespace {
void wait_on_signal() {
  boost::asio::io_service signal_io_service;
  boost::asio::io_service::work work{signal_io_service};
  boost::asio::signal_set signals(signal_io_service, SIGINT, SIGTERM);
  signals.async_wait([&](...) { signal_io_service.stop(); });
  signal_io_service.run();
}

template<class T, class U>
inline const T max(T a, U b) { return a < b ? b : a; }
}  // namespace

int main(int argc, char *argv[]) {
  using namespace riak;
  using namespace std::chrono;
  namespace po = boost::program_options;

  // Parse arguments
  std::string hostname;
  uint16_t port, num_threads, num_sockets, highwatermark;
  uint32_t nmsgs;
  po::options_description description{
    "Sends a lot of get_object requests to a Riak node using a connection pool."
  };
  description.add_options()
      ("help,h", "prints this help message")
      ("hostname,n",
       po::value<std::string>(&hostname)->default_value("localhost"),
       "hostname of Riak node")
      ("port,p",
       po::value<uint16_t>(&port)->default_value(10017),
       "port to connect on Riak node")
      ("num-threads,t",
       po::value<uint16_t>(&num_threads)->default_value(2),
       "number of I/O threads")
      ("num-sockets,s",
       po::value<uint16_t>(&num_sockets)->default_value(256),
       "number of sockets in pool")
      ("highwatermark,k",
       po::value<uint16_t>(&highwatermark)->default_value(1024),
       "max buffered requests")
      ("nmsgs,m",
       po::value<uint32_t>(&nmsgs)->default_value(1000),
       "number of messages to send to the node");
  po::variables_map variables;
  try {
    po::store(po::parse_command_line(argc, argv, description), variables);
    po::notify(variables);
  } catch (const std::exception& e) {
    DLOG << e.what();
    return -1;
  }
  if (variables.count("help")) {
    std::cerr << description << std::endl;
    return -1;
  }

  // Simple connection_pool usage:
  //   riak::connection_pool conn(hostname, port, num_threads, num_sockets,
  //                              highwatermark);
  //   conn.send(string_message1, deadline_ms, handler);
  //   conn.send(string_message2, deadline_ms, handler);
  //   etc.
  //
  // What follows is a mess because this is throwaway code.

  std::mutex num_sent_mutex;
  uint32_t num_sent = 0;
  auto start_clock = high_resolution_clock::now();
  auto first_response_clock = start_clock;

  std::string message{"\x09\x0A\01\x62\x12\x01\x6B", 7};
  DLOG << "Creating connection pool...";
  riak::connection_pool conn(hostname, port, num_threads, num_sockets,
                             highwatermark);

  DLOG << "Buffering messages...";
  auto log_every = max(1, nmsgs / 20);
  for (int i = 0 ; i < nmsgs ; ++ i) {
    conn.send(
        message, 1000,
        [&](const std::string & response, std::error_code error) {
          std::lock_guard<std::mutex> lock{num_sent_mutex};
          ++num_sent;
          if (num_sent == 1) {
            first_response_clock = high_resolution_clock::now();
            double secs = duration_cast<milliseconds>(
                first_response_clock - start_clock).count() / 1000.0;
            DLOG << error.message() << " [first message " << secs << " secs].";
          } else if (num_sent % log_every == 0 || num_sent == nmsgs) {
            if (num_sent <= num_sockets) return;
            auto total = duration_cast<milliseconds>(
                high_resolution_clock::now() - first_response_clock);
            auto msgs_per_sec =
                (num_sent - num_sockets) / (double(total.count()) / 1000.0);
            DLOG << error.message() << " [sent " << num_sent << " at "
                 << msgs_per_sec << " messages/sec]";
          }
    });

    if (i % log_every == 0) DLOG << "Buffered " << i << " messages.";
  }
  DLOG << "Buffered all the messages. Waiting on signal...";

  wait_on_signal();
  DLOG << "Signal caught.";

  return 0;
}
<commit_msg>minor whitespace fix<commit_after>#include "debug_log.hpp"
#include "connection_pool.hpp"

#include <boost/asio/io_service.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/program_options.hpp>

namespace {
void wait_on_signal() {
  boost::asio::io_service signal_io_service;
  boost::asio::io_service::work work{signal_io_service};
  boost::asio::signal_set signals(signal_io_service, SIGINT, SIGTERM);
  signals.async_wait([&](...) { signal_io_service.stop(); });
  signal_io_service.run();
}

template<class T, class U>
inline const T max(T a, U b) { return a < b ? b : a; }
}  // namespace

int main(int argc, char *argv[]) {
  using namespace riak;
  using namespace std::chrono;
  namespace po = boost::program_options;

  // Parse arguments
  std::string hostname;
  uint16_t port, num_threads, num_sockets, highwatermark;
  uint32_t nmsgs;
  po::options_description description{
    "Sends a lot of get_object requests to a Riak node using a connection pool."
  };
  description.add_options()
      ("help,h", "prints this help message")
      ("hostname,n",
       po::value<std::string>(&hostname)->default_value("localhost"),
       "hostname of Riak node")
      ("port,p",
       po::value<uint16_t>(&port)->default_value(10017),
       "port to connect on Riak node")
      ("num-threads,t",
       po::value<uint16_t>(&num_threads)->default_value(2),
       "number of I/O threads")
      ("num-sockets,s",
       po::value<uint16_t>(&num_sockets)->default_value(256),
       "number of sockets in pool")
      ("highwatermark,k",
       po::value<uint16_t>(&highwatermark)->default_value(1024),
       "max buffered requests")
      ("nmsgs,m",
       po::value<uint32_t>(&nmsgs)->default_value(1000),
       "number of messages to send to the node");
  po::variables_map variables;
  try {
    po::store(po::parse_command_line(argc, argv, description), variables);
    po::notify(variables);
  } catch (const std::exception& e) {
    DLOG << e.what();
    return -1;
  }
  if (variables.count("help")) {
    std::cerr << description << std::endl;
    return -1;
  }

  // Simple connection_pool usage:
  //   riak::connection_pool conn(hostname, port, num_threads, num_sockets,
  //                              highwatermark);
  //   conn.send(string_message1, deadline_ms, handler);
  //   conn.send(string_message2, deadline_ms, handler);
  //   etc.
  //
  // What follows is a mess because this is throwaway code.

  std::mutex num_sent_mutex;
  uint32_t num_sent = 0;
  auto start_clock = high_resolution_clock::now();
  auto first_response_clock = start_clock;

  std::string message{"\x09\x0A\01\x62\x12\x01\x6B", 7};
  DLOG << "Creating connection pool...";
  riak::connection_pool conn(hostname, port, num_threads, num_sockets,
                             highwatermark);

  DLOG << "Buffering messages...";
  auto log_every = max(1, nmsgs / 20);
  for (int i = 0 ; i < nmsgs ; ++ i) {
    conn.send(
        message, 1000,
        [&](const std::string & response, std::error_code error) {
          std::lock_guard<std::mutex> lock{num_sent_mutex};
          ++num_sent;
          if (num_sent == 1) {
            first_response_clock = high_resolution_clock::now();
            double secs = duration_cast<milliseconds>(
                first_response_clock - start_clock).count() / 1000.0;
            DLOG << error.message() << " [first message " << secs << " secs].";
          } else if (num_sent % log_every == 0 || num_sent == nmsgs) {
            if (num_sent <= num_sockets) return;
            auto total = duration_cast<milliseconds>(
                high_resolution_clock::now() - first_response_clock);
            auto msgs_per_sec =
                (num_sent - num_sockets) / (double(total.count()) / 1000.0);
            DLOG << error.message() << " [sent " << num_sent << " at "
                 << msgs_per_sec << " messages/sec]";
          }
    });

    if (i % log_every == 0) DLOG << "Buffered " << i << " messages.";
  }
  DLOG << "Buffered all the messages. Waiting on signal...";

  wait_on_signal();
  DLOG << "Signal caught.";

  return 0;
}
<|endoftext|>