text:
/*!
 * Copyright (C) tkornuta, IBM Corporation 2015-2019
 *
 * 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.
 */
/*!
 * \file Layer.hpp
 * \brief Contains a template class representing a layer.
 * \author tkornut
 * \date Mar 31, 2016
 */

#ifndef SRC_MLNN_LAYER_HPP_
#define SRC_MLNN_LAYER_HPP_

#include <iostream>
#include <string>

#include<types/MatrixTypes.hpp>
#include<types/MatrixArray.hpp>
#include <optimization/OptimizationFunctionTypes.hpp>
#include <optimization/OptimizationArray.hpp>

#include <boost/serialization/serialization.hpp>
// include this header to serialize vectors
#include <boost/serialization/vector.hpp>
// include this header to serialize arrays
#include <boost/serialization/array.hpp>
#include <boost/serialization/version.hpp>

#include <logger/Log.hpp>

// Forward declaration of class boost::serialization::access
namespace boost {
namespace serialization {
class access;
}//: serialization
}//: access

namespace mic {
namespace mlnn {

/*!
 * \brief Enumeration of possible layer types.
 * \author tkornuta
 */
enum class LayerTypes : short
{
	// activation
	ELU = 0,
	ReLU,
	Sigmoid,
	// convolution
	Convolution,
	Cropping,
	Padding,
	MaxPooling,
	// cost_function
	Softmax,
	// fully_connected
	Linear,
	SparseLinear,
	HebbianLinear,
    BinaryCorrelator,
	// regularization
    Dropout,
    // Experimental
    ConvHebbian
};

// Forward declaration of MultiLayerNeuralNetwork - required for "lazy connection".
template <typename eT>
class MultiLayerNeuralNetwork;

/*!
 * Template base (abstract) class representing a layer.
 * \author tkornuta/krocki
 * \tparam eT Template parameter denoting precision of variables (float for calculations/double for testing).
 */
template <typename eT=float>
class Layer {
public:
	/*!
	 * Default constructor of the layer parent class. Sets the input-output dimensions, layer type and name.
	 * @param input_height_ Height of the input sample.
	 * @param input_width_ Width of the input sample.
	 * @param input_depth_ Depth of the input sample.
	 * @param output_height_ Width of the output sample.
	 * @param output_width_ Height of the output sample.
	 * @param output_depth_ Depth of the output sample.
	 * @param layer_type_ Type of the layer.
	 * @param name_ Name of the layer.
	 */
	Layer(size_t input_height_, size_t input_width_, size_t input_depth_,
			size_t output_height_, size_t output_width_, size_t output_depth_,
			LayerTypes layer_type_, std::string name_ = "layer") :
		// Set "reduced" input dimensions.
		input_height(input_height_),
		input_width(input_width_),
		input_depth(input_depth_),
		// Set "reduced" output dimensions.
		output_height(output_height_),
		output_width(output_width_),
		output_depth(output_depth_),
		// Set batch size.
		batch_size(1),
		// Set layer type and name.
		layer_type(layer_type_),
		layer_name(name_),
		// Initialize matrice arrays.
		s("state"),
		g("gradients"),
		p("parameters"),
		m("memory")
	{
		// State.
		s.add ( "x", input_depth*input_height*input_width, batch_size ); 	// inputs
		s.add ( "y", output_depth*output_height*output_width, batch_size); 	// outputs

		// Gradients.
		g.add ( "x", input_depth*input_height*input_width, batch_size ); 	// inputs
		g.add ( "y", output_depth*output_height*output_width, batch_size); 	// outputs

		// Allocate (temporary) memory for "input sample" - column vector.
		m.add ("xs", input_depth*input_height*input_width, 1);
		// Allocate (temporary) memory for "input channel" - column vector.
		m.add ("xc", input_height*input_width, 1);

		// Allocate (temporary) memory for "output sample" - a column vector of all channels of a given sample.
		m.add ("ys", output_depth*output_height*output_width, 1);

		// Allocate (temporary) memory for "output sample" - a column vector.
		m.add ("yc", output_height * output_width, 1);

	};

	/*!
	 * Virtual destructor - required for the correct destruction of objects of derived classes.
	 */
	virtual ~Layer() {};

	/*!
	 * Abstract method responsible for processing the data from the inputs to outputs. To be overridden in the derived classes.
	 * @param test Test mode - used for dropout-alike regularization techniques.
	 */
	virtual void forward(bool test = false) = 0;

	/*!
	 * Forwards the activations of the neural network.
	 */
	mic::types::MatrixPtr<eT> forward(mic::types::MatrixPtr<eT> x_, bool test = false) {
		// Copy "input" sample/batch.
		(*s["x"]) = (*x_);

		// Call the (abstract, implemented by a given layer) forward pass.
		forward(test);

		// Return "output".
		return s["y"];
	}

	/*!
	 * Abstract method responsible for processing the gradients from outputs to inputs (i.e. in the opposite direction). To be overridden in the derived classes.
	 */
	virtual void backward() = 0;

	/*!
	 * Backward pass - backpropagation.
	 */
	mic::types::MatrixPtr<eT> backward(mic::types::MatrixPtr<eT> dy_) {
		// Copy "output" sample/batch gradient.
		(*g["y"]) = (*dy_);

		// Call the (abstract, implemented by a given layer) backward pass.
		backward();

		// Return "input" gradient.
		return g["x"];
	}

	/*!
	 * Changes the size of the batch. By default it resizes state (x,y) and gradients (x,y).
	 * @param New size of the batch.
	 */
	virtual void resizeBatch(size_t batch_size_) {
		// Change the "value". (depricated)
		batch_size = batch_size_;
		// Reshape the inputs...
		s["x"]->resize(s["x"]->rows(), batch_size_);
		g["x"]->resize(g["x"]->rows(), batch_size_);
		// ... and outputs.
		s["y"]->resize(s["y"]->rows(), batch_size_);
		g["y"]->resize(g["y"]->rows(), batch_size_);
	}

	/*!
	 * Calculates the numerical gradient.
	 * @param x_ Input vector.
	 * @param target_y_ Target (desired) output.
	 * @param loss_ Loss function.
	 * @param delta_ Delta.
	 * @tparam loss Loss function type.
	 */
	template<typename loss>
	mic::types::MatrixPtr<eT> calculateNumericalGradient(mic::types::MatrixPtr<eT> x_, mic::types::MatrixPtr<eT> target_y_, mic::types::MatrixPtr<eT> param_, loss loss_, eT delta_) {
		// Allocate memory.
		mic::types::MatrixPtr<eT> nGrad = MAKE_MATRIX_PTR(eT, param_->rows(), param_->cols());
		for (size_t i=0; i<(size_t)param_->size(); i++) {
			// Add delta.
			(*param_)[i] += delta_;
			// Calculate loss.
			eT p = loss_.calculateLoss(target_y_, forward(x_));
			// Substract delta.
			(*param_)[i] -= 2*delta_;
			// Calculate loss.
			eT m = loss_.calculateLoss(target_y_, forward(x_));

			// Store numerical gradient.
			(*nGrad)[i] = (p-m)/(2*delta_);
			// Set original value.
			(*param_)[i] += delta_;

		}//: for
		return nGrad;
	}

	/*!
	 * Reset gradients. Virtual empty method - to be implemented by the inherited classes.
	 */
	virtual void resetGrads() {};

	/*!
	 * Performs the update according to the calculated gradients and injected optimization method. Abstract.
	 * @param alpha_ Learning rate - passed to the optimization functions of all layers.
	 * @param decay_ Weight decay rate (determining that the "unused/unupdated" weights will decay to 0) (DEFAULT=0.0 - no decay).
	 */
	virtual void update(eT alpha_, eT decay_  = 0.0f) = 0;

	/// Returns size (length) of inputs.
	inline size_t inputSize() {
		return input_height*input_width*input_depth;
	}

	/// Returns size (length) of outputs.
	inline size_t outputSize() {
		return output_height*output_width*output_depth;
	}

	/// Returns size (length) of (mini)batch.
	inline size_t batchSize() {
		return batch_size;
	}

	/// Returns name of the layer.
	inline const std::string name() const {
		return layer_name;
	}

	/*!
	 * Returns the pointer to a parameter (matrix) (or throws an exception!)
	 */
	mic::types::MatrixPtr<eT> getParam(std::string name_) {
		return p[name_];
	}

	/*!
	 * Returns the pointer to state (matrix) (or throws an exception!)
	 */
	mic::types::MatrixPtr<eT> getState(std::string name_) {
		return s[name_];
	}

	/*!
	 * Returns the pointer to gradient (matrix) (or throws an exception!)
	 */
	mic::types::MatrixPtr<eT> getGradient(std::string name_) {
		return g[name_];
	}

	/*!
	 * Sets state (matrix) (or throws an exception!)
	 */
	void setState(std::string name_, mic::types::MatrixPtr<eT> mat_ptr_) {
		(*s[name_]) = (*mat_ptr_);
	}

	/*!
	 * Sets the optimization method.
	 * @tparam omT Optimization method type
	 */
	template<typename omT>
	void setOptimization () {
		// Remove all previous optimization functions.
		opt.clear();

		// Iterate through parameters and add a separate optimization function for each parameter.
		for (auto& i: p.keys()) {
			opt.add(
					i.first,
					std::make_shared< omT > (omT ( (p[i.second])->rows(), (p[i.second])->cols() ))
					);
		}//: for keys
	}

	/*!
	 * Returns the type of layer.
	 */
	const std::string type() const {
		switch(layer_type) {
		// activation
		case(LayerTypes::ELU):
			return "ELU";
		case(LayerTypes::ReLU):
			return "ReLU";
		case(LayerTypes::Sigmoid):
			return "Sigmoid";
		// convolution
		case(LayerTypes::Convolution):
			return "Convolution";
		case(LayerTypes::Padding):
			return "Padding";
		case(LayerTypes::MaxPooling):
			return "MaxPooling";
		// cost_function
		case(LayerTypes::Softmax):
			return "Softmax";
		// fully_connected
		case(LayerTypes::Linear):
			return "Linear";
		case(LayerTypes::SparseLinear):
			return "SparseLinear";
		case(LayerTypes::HebbianLinear):
			return "HebbianLinear";
		case(LayerTypes::BinaryCorrelator):
			return "BinaryCorrelator";
		// regularization
		case(LayerTypes::Dropout):
			return "Dropout";
		default:
			return "Undefined";
		}//: switch
	}

	/*!
	 * Stream layer parameters.
	 * @return Ostream object.
	 */
	virtual std::string streamLayerParameters() {
		std::ostringstream os_;
		// Display id/type.
		os_ << "  [" << type() << "]: " << layer_name << ": " << inputSize() << "x" << batch_size << " -> " << outputSize() << "x" << batch_size << "\n";

		// Display dimensions.
		os_<<"    * input_height = " << input_height <<std::endl;
		os_<<"    * input_width = " << input_width <<std::endl;
		os_<<"    * input_channels = " << input_depth <<std::endl;
		os_<<"    * output_height = " << output_height <<std::endl;
		os_<<"    * output_width = " << output_width <<std::endl;
		os_<<"    * output_channels = " << output_depth;

		return os_.str();
	}

	/*!
	 * Stream operator enabling to print neural network.
	 * @param os_ Ostream object.
	 * @param obj_ Tensor object.
	 */
	friend std::ostream& operator<<(std::ostream& os_, Layer& obj_) {
		// Display dimensions.
		os_ << obj_.streamLayerParameters();

		// Display inputs.
		os_ << "    [" << obj_.s.name() << "]:\n";
		for (auto& i: obj_.s.keys()) {
			// Display elements.
			os_ << "      [" << i.first << "]: ";
			os_ << (obj_.s[i.second])->cols() << "x" << (obj_.s[i.second])->rows() << std::endl;
		}//: for keys

		// Display gradients.
		os_ << "    [" << obj_.g.name() << "]:\n";
		for (auto& i: obj_.g.keys()) {
			// Display elements.
			os_ << "      [" << i.first << "]: ";
			os_ << (obj_.g[i.second])->cols() << "x" << (obj_.g[i.second])->rows() << std::endl;
		}//: for keys

		// Display parameters.
		os_ << "    [" << obj_.p.name() << "]:\n";
		for (auto& i: obj_.p.keys()) {
			// Display elements.
			os_ << "      [" << i.first << "]: ";
			os_ << (obj_.p[i.second])->cols() << "x" << (obj_.p[i.second])->rows() << std::endl;
		}//: for keys

		// Display gradients.
		os_ << "    [" << obj_.m.name() << "]:\n";
		for (auto& i: obj_.m.keys()) {
			// Display elements.
			os_ << "      [" << i.first << "]: ";
			os_ << (obj_.m[i.second])->cols() << "x" << (obj_.m[i.second])->rows() << std::endl;
		}//: for keys

		return os_;
	}

	/*!
	 * Returns sample from batch. If a given memory array does not contain such a memory pointer - it (lazy) allocates it.
	 * OMP secured - critical section inside.
	 * @param batch_ptr_ Pointer to a batch.
	 * @param array_ Array of matrices where a given matrix (sample) is/will be stored.
	 * @param id_ Sample id (variable prefix).
	 * @param sample_number_ Number of the sample in batch.
	 * @param sample_size_ Size of the sample.
	 */
	mic::types::MatrixPtr<eT> lazyReturnSampleFromBatch (mic::types::MatrixPtr<eT> batch_ptr_, mic::types::MatrixArray<eT> & array_, std::string id_, size_t sample_number_, size_t sample_size_){
		// Generate "unique id" for a given sample.
		std::string sample_id = id_ + std::to_string(sample_number_);
		mic::types::MatrixPtr<eT> sample;

		#pragma omp critical
		{
			if (!array_.keyExists(sample_id)) {
				// Allocate memory.
				array_.add(sample_id, sample_size_, 1);
			}//: if

			// Get array.
			sample = m[sample_id];
			// Copy data.
			(*sample) = batch_ptr_->col(sample_number_);
		}//: end OMP critical section

		// Return it.
		return sample;
	}

	/*!
	 * Returns input sample, with lazy matrix ptr allocation.
	 * @param batch_ptr_ Pointer to a batch.
	 * @param sample_number_ Number of the sample in batch.
	 */
	inline mic::types::MatrixPtr<eT> lazyReturnInputSample (mic::types::MatrixPtr<eT> batch_ptr_, size_t sample_number_){
		return lazyReturnSampleFromBatch(batch_ptr_, m, "xs", sample_number_, Layer<eT>::inputSize());
	}

	/*!
	 * Returns output sample, with lazy matrix ptr allocation.
	 * @param batch_ptr_ Pointer to a batch.
	 * @param sample_number_ Number of the sample in batch.
	 */
	inline mic::types::MatrixPtr<eT> lazyReturnOutputSample (mic::types::MatrixPtr<eT> batch_ptr_, size_t sample_number_){
		return lazyReturnSampleFromBatch(batch_ptr_, m, "ys", sample_number_, Layer<eT>::outputSize());
	}

	/*!
	 * Returns channel from a sample. If a given memory array does not contain such a memory pointer - it (lazy) allocates it.
	 * Assumes that: a) a sample is a column vector and b) there is one "channel memory ptr" for each sample (so the whole batch can be processed in parallel).
	 * OMP secured - critical section inside.
	 * @param sample_ptr Pointer to a sample.
	 * @param array_ Array of matrices where a given matrix (channel) is/will be stored.
	 * @param id_ Channel id (variable prefix).
	 * @param sample_number_ Number of the sample in batch.
	 * @param channel_number_ Number of the channel.
	 * @param height_ Height of the channel.
	 * @param width_ Width of the channel.
	 */
	mic::types::MatrixPtr<eT> lazyReturnChannelFromSample (mic::types::MatrixPtr<eT> sample_ptr_, mic::types::MatrixArray<eT> & array_, std::string id_, size_t sample_number_, size_t channel_number_, size_t height_, size_t width_){
		// Generate "unique id" for a given sample.
		std::string channel_id = id_ + std::to_string(channel_number_);
		mic::types::MatrixPtr<eT> channel;

		#pragma omp critical
		{
			if (!array_.keyExists(channel_id)) {
				// Allocate memory.
				array_.add(channel_id, height_*width_, 1);
			}//: if

			// Get array.
			channel = m[channel_id];
			// Just in case - resize.
			sample_ptr_->resize(sample_ptr_->size(), 1);
			// Copy data.
			(*channel) = sample_ptr_->block(channel_number_*height_*width_, 0, height_*width_, 1);
			// Resize channel.
			channel-> resize(height_, width_);
		}//: end OMP critical section

		// Return it.
		return channel;
	}

	/*!
	 * Returns input channel, with lazy matrix ptr allocation.
	 * @param batch_ptr_ Pointer to a batch.
	 * @param sample_number_ Number of the sample in batch.
	 * @param channel_number_ Number of the channel in sample.
	 */
	inline mic::types::MatrixPtr<eT> lazyReturnInputChannel (mic::types::MatrixPtr<eT> sample_ptr_, size_t sample_number_, size_t channel_number_){
		return lazyReturnChannelFromSample(sample_ptr_, m, "xc", sample_number_, channel_number_, input_height, input_width);
	}

	/*!
	 * Returns output sample, with lazy matrix ptr allocation.
	 * @param batch_ptr_ Pointer to a batch.
	 * @param sample_number_ Number of the sample in batch.
	 * @param channel_number_ Number of the channel in sample.
	 */
	inline mic::types::MatrixPtr<eT> lazyReturnOutputChannel (mic::types::MatrixPtr<eT> sample_ptr_, size_t sample_number_, size_t channel_number_){
		return lazyReturnChannelFromSample(sample_ptr_, m, "yc", sample_number_, channel_number_, output_height, output_width);
	}

	/*!
	 * Allocates memory to a matrix vector (lazy).
	 * @param vector_ Vector that will store the matrices.
	 * @param vector_size Number of matrices to be added.
	 * @param matrix_height_ Height of matrices.
	 * @param matrix_width_ Width of matrices.
	 */
	void lazyAllocateMatrixVector(std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & vector_, size_t vector_size_, size_t matrix_height_, size_t matrix_width_) {
		// Check if memory for the activations was allocated.
		if (vector_.size() != vector_size_) {
			// Free memory.
			vector_.clear();
			// Allocate.
			for (size_t i=0; i < vector_size_; i++) {
				// Allocate memory for activation of every neuron.
				mic::types::MatrixPtr<eT> m = MAKE_MATRIX_PTR(eT, matrix_height_, matrix_width_);
				vector_.push_back(m);
			}//: for
		}//: if
	}

	/*!
	 * Normalizes the matrix. to the range <-1.0, 1.0>, e.g. for the visualization purposes.
	 * DEPRICATED - functionality moved to mi-visualization!
	 * @param matrix_ Matrix to be normalized.
	 */
	/*void normalizeMatrixForVisualization(mic::types::MatrixPtr<eT> matrix_) {
		// Epsilon added for numerical stability.
		//eT eps = 1e-5;
		//eT l2 = matrix_->norm() + eps;

		// Calculate the norm.
		eT max = matrix_->maxCoeff();
		eT min = matrix_->minCoeff();
		eT ultimate_max=  (max > -min) ? max : -min;

		//std::cout << "before: min:" << (*matrix_).minCoeff() <<" max: " << (*matrix_).maxCoeff() << std::endl;
		// Normalize the inputs to range <0.0, 1.0>.
		// Check if we can normalize.
		if (ultimate_max != 0.0) {
            (*matrix_) = matrix_->unaryExpr ( [&] ( eT x ) { return ( (x)/ultimate_max ); } ).template cast<eT>();
			//std::cout << "after: min:" << (*matrix_).minCoeff() <<" max: " << (*matrix_).maxCoeff() << std::endl;
		}//: else: do nothing, all values are ~0 already.
	}*/

	/*!
	 * Returns activations of input neurons.
	 */
	virtual std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getInputActivations() {

 		// Allocate memory.
		lazyAllocateMatrixVector(x_activations, input_depth * batch_size, input_height*input_width, 1);

		// Get y batch.
		mic::types::MatrixPtr<eT> batch_x = s['x'];

		// Iterate through filters and generate "activation image" for each one.
		for (size_t ib=0; ib< batch_size; ib++) {

			// Get input sample from batch!
			mic::types::MatrixPtr<eT> sample_x = m["xs"];
			(*sample_x) = batch_x->col(ib);

			// Iterate through input channels.
			for (size_t ic=0; ic< input_depth; ic++) {
				// Get activation "row".
				mic::types::MatrixPtr<eT> row = x_activations[ib*input_depth + ic];

				// Copy "channel block" from given dx sample.
				(*row) = sample_x->block(ic*input_height*input_width, 0, input_height*input_width, 1);
				row->resize(input_height, input_width);

			}//: for channel
		}//: for batch

		// Return output activations.
		return x_activations;
	}

	/*!
	 * Returns activations of input gradients (dx).
	 */
	virtual std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getInputGradientActivations() {

		// Allocate memory.
		lazyAllocateMatrixVector(dx_activations, batch_size * input_depth, input_height*input_width, 1);

		// Get dx batch.
		mic::types::MatrixPtr<eT> batch_dx = g['x'];

		// Iterate through filters and generate "activation image" for each one.
		for (size_t ib=0; ib< batch_size; ib++) {

			// Get input sample from batch!
			mic::types::MatrixPtr<eT> sample_dx = m["xs"];
			(*sample_dx) = batch_dx->col(ib);

			// Iterate through input channels.
			for (size_t ic=0; ic< input_depth; ic++) {
				// Get dx "row".
				mic::types::MatrixPtr<eT> row = dx_activations[ib*input_depth + ic];

				// Copy "channel block" from given dx sample.
				(*row) = sample_dx->block(ic*input_height*input_width, 0, input_height*input_width, 1);
				row->resize(input_height, input_width);

			}//: for channel
		}//: for batch

		// Return dx activations.
		return dx_activations;
	}

	/*!
	 * Returns activations of output neurons.
	 */
	virtual std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getOutputActivations() {

		// Allocate memory.
		lazyAllocateMatrixVector(y_activations, batch_size*output_depth, output_height*output_width, 1);

		// Get y batch.
		mic::types::MatrixPtr<eT> batch_y = s['y'];

		// Iterate through filters and generate "activation image" for each one.
		for (size_t ib=0; ib< batch_size; ib++) {

			// Get input sample from batch!
			mic::types::MatrixPtr<eT> sample_y = m["ys"];
			(*sample_y) = batch_y->col(ib);

			// Iterate through output channels.
			for (size_t oc=0; oc< output_depth; oc++) {
				// Get y "row".
				mic::types::MatrixPtr<eT> row = y_activations[ib*output_depth + oc];

				// Copy "channel block" from given dx sample.
				(*row) = sample_y->block(oc*output_height*output_width, 0, output_height*output_width, 1);
				row->resize(output_height, output_width);

			}//: for channel
		}//: for batch

		// Return output activations.
		return y_activations;
	}

	/*!
	 * Returns activations of gradients of output neurons.
	 */
	virtual std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getOutputGradientActivations() {

		// Allocate memory.
		lazyAllocateMatrixVector(dy_activations, output_depth*batch_size, output_height*output_width, 1);

		// Get dy batch.
		mic::types::MatrixPtr<eT> batch_dy = g['y'];

		// Iterate through filters and generate "activation image" for each one.
		for (size_t ib=0; ib< batch_size; ib++) {

			// Get input sample from batch!
			mic::types::MatrixPtr<eT> sample_dy = m["ys"];
			(*sample_dy) = batch_dy->col(ib);

			// Iterate through output channels.
			for (size_t oc=0; oc< output_depth; oc++) {
				// Get y "row".
				mic::types::MatrixPtr<eT> row = dy_activations[ib*output_depth + oc];

				// Copy "channel block" from given dx sample.
				(*row) = sample_dy->block(oc*output_height*output_width, 0, output_height*output_width, 1);
				row->resize(output_height, output_width);

			}//: for channel
		}//: for batch

		// Return output activations.
		return dy_activations;
	}

protected:

    /// Height of the input (e.g. 28 for MNIST).
    size_t input_height;

    /// Width of the input (e.g. 28 for MNIST).
    size_t input_width;

    /// Number of channels of the input (e.g. 3 for RGB images).
    size_t input_depth;

	/// Number of receptive fields in a single channel - vertical direction.
	size_t output_height;

	/// Number of receptive fields in a single channel - horizontal direction.
	size_t output_width;

	/// Number of filters = number of output channels.
	size_t output_depth;

	/// Size (length) of (mini)batch.
	size_t batch_size;

	/// Type of the layer.
	LayerTypes layer_type;

	/// Name (identifier of the type) of the layer.
	std::string layer_name;

	/// States - contains input [x] and output [y] matrices.
	mic::types::MatrixArray<eT> s;

	/// Gradients - contains input [x] and output [y] matrices.
	mic::types::MatrixArray<eT> g;

	/// Parameters - parameters of the layer, to be used by the derived classes.
	mic::types::MatrixArray<eT> p;

	/// Memory - a list of temporal parameters, to be used by the derived classes.
	mic::types::MatrixArray<eT> m;

	/// Array of optimization functions.
	mic::neural_nets::optimization::OptimizationArray<eT> opt;

	/// Vector containing activations of input neurons - used in visualization.
	std::vector< std::shared_ptr <mic::types::Matrix<eT> > > x_activations;

	/// Vector containing activations of gradients of inputs (dx) - used in visualization.
	std::vector< std::shared_ptr <mic::types::Matrix<eT> > > dx_activations;

	/// Vector containing activations of output neurons - used in visualization.
	std::vector< std::shared_ptr <mic::types::Matrix<eT> > > y_activations;

	/// Vector containing activations of gradients of outputs (dy) - used in visualization.
	std::vector< std::shared_ptr <mic::types::Matrix<eT> > > dy_activations;

	/*!
	 * Protected constructor, used only by the derived classes during the serialization. Empty!!
	 */
	Layer () { }

private:
	// Friend class - required for using boost serialization.
	template<typename tmp> friend class MultiLayerNeuralNetwork;
	template<typename tmp> friend class BackpropagationNeuralNetwork;
	template<typename tmp> friend class HebbianNeuralNetwork;

	// Friend class - required for using boost serialization.
    friend class boost::serialization::access;

    /*!
     * Serializes the layer to and from archive.
     * @param ar Used archive.
     * @param version Version of the layer class (not used currently).
     */
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version) {
        // Archive parameters.
        ar & input_height;
        ar & input_width;
        ar & input_depth;
        ar & output_height;
        ar & output_width;
        ar & output_depth;
        ar & batch_size;
        ar & layer_type;
        ar & layer_name;
        // Archive four matrix arrays.
        ar & s;
        ar & g;
        ar & p;
        ar & m;
        // TODO: serialize optimization function!
    }

};

} /* namespace mlnn */
} /* namespace mic */

// Just in the case that something important will change in the Layer class - set version.
BOOST_CLASS_VERSION(mic::mlnn::Layer<float>, 2)
BOOST_CLASS_VERSION(mic::mlnn::Layer<double>, 2)

#endif /* SRC_MLNN_LAYER_HPP_ */

max_stars_repo_name: kant/mi-neural-nets

max_issues_repo_name: kant/mi-neural-nets

max_forks_repo_name: kant/mi-neural-nets


text:
// Copyright(c) 2015-2016 Vittorio Romeo
// License: Academic Free License ("AFL") v. 3.0
// AFL License page: http://opensource.org/licenses/AFL-3.0
// http://vittorioromeo.info | vittorio.romeo@outlook.com

// #define VR_USE_BOOST_VARIANT

#include "any_type.hpp"
#include "variant_aliases.hpp"
#include <boost/hana.hpp>
#include <experimental/type_traits>
#include <iostream>
#include <map>
#include <memory>
#include <tuple>
#include <type_traits>
#include <vector>

// Compatibility with MinGW:
namespace std
{
    template <class... B>
    constexpr bool disjunction_v = disjunction<B...>::value;
}

namespace deduced_arity
{
    template <std::size_t TS>
    struct deducible_t : std::integral_constant<std::size_t, TS>
    {
    };

    struct undeducible_t
    {
    };

    constexpr undeducible_t undeducible{};
    constexpr deducible_t<1> unary{};
    constexpr deducible_t<2> binary{};
}

template <typename TF, typename... Ts>
using is_unary_callable_with_any =
    std::disjunction<std::is_callable<TF(Ts)>...>;

template <typename TF, typename T>
struct is_binary_callable_with_any_lbound
{
    template <typename... Ts>
    using apply = std::disjunction<std::is_callable<TF(T, Ts)>...>;
};

template <typename TF, typename T>
struct is_binary_callable_with_any_rbound
{
    template <typename... Ts>
    using apply = std::disjunction<std::is_callable<TF(Ts, T)>...>;
};

template <typename TF, typename... Ts>
using is_binary_callable_with_any =
    std::disjunction<typename is_binary_callable_with_any_lbound<TF,
                         Ts>::template apply<Ts...>...,
        typename is_binary_callable_with_any_rbound<TF,
            Ts>::template apply<Ts...>...>;

/*
template <typename... TFs>
auto make_visitor_great_again(TFs... fs)
{
    auto unary = filter([](auto f)( return deduce_arity(f) ==
deduced_arity::unary; }, fs...);
    auto binary = filter([](auto f)( return deduce_arity(f) ==
deduced_arity::binary; }, fs...);

    auto undeducible_fns = filter([](auto f)( return deduce_arity(f) ==
deduced_arity::undeducible; }, fs...);
    static_assert
}
*/

// TODO: assume undeducible are unary? Force disambiguation?
// TODO: abstract wrapper?

namespace impl
{
    template <typename T, typename TDerived>
    struct wrapper_impl
    {
        T _data;

        template <typename... Ts,
            typename = std::enable_if_t<!std::disjunction_v<
                std::is_same<std::decay_t<Ts>, TDerived>...>>>
        wrapper_impl(Ts&&... xs) : _data{FWD(xs)...}
        {
        }
    };
}

// TODO:
struct placeholder
{
};
using _me = placeholder;

template <typename TReplacement, typename T>
struct replace_all
{
    using type =
        std::conditional_t<std::is_same_v<T, placeholder>, TReplacement, T>;
};

template <typename TReplacement, template <typename...> class TTemplate,
    typename... Ts>
struct replace_all<TReplacement, TTemplate<Ts...>>
{
    using type = TTemplate<typename replace_all<TReplacement, Ts>::type...>;
};

template <typename... Ts>
struct recursive_variant_helper
{
    struct me_wrapper;

    template <typename T>
    using sub = typename replace_all<me_wrapper, T>::type;

    using variant_type = typename replace_all<me_wrapper, vr::variant<Ts...>>::type;

    struct me_wrapper : impl::wrapper_impl<variant_type, me_wrapper>
    {
        // seems to work on libc++
        using impl::wrapper_impl<variant_type, me_wrapper>::wrapper_impl;
    };

    using type = variant_type;
};

template <typename TRV, typename T>
using resolve = typename TRV::template sub<T>;

/* template <typename... Ts>
using recursive_variant_builder =
    typename recursive_variant_helper<Ts...>::type;*/

namespace impl
{
    using varr_x = std::vector<_me>;
    using vmap_x = std::map<int, _me>;
    using rv_h =
        recursive_variant_helper<int, float, double, varr_x, long, vmap_x>;

    using vnum = rv_h::type;
    using varr = resolve<rv_h, varr_x>;
    using vmap = resolve<rv_h, vmap_x>;
}

using vnum = impl::vnum;
using impl::varr;
using impl::vmap;

using number = int;

struct plus
{
};
struct minus
{
};
using op = vr::variant<plus, minus>;

namespace impl
{
    using r_expr_x = std::tuple<number, op, _me>;
    using rv_expr_h =
        recursive_variant_helper<number, std::unique_ptr<r_expr_x>>;
}

using r_expr = resolve<impl::rv_expr_h, impl::r_expr_x>;
using expr = impl::rv_expr_h::type;

template <typename TTpl>
auto overload_tuple(TTpl&& x)
{
    return boost::hana::unpack(FWD(x), boost::hana::overload);
}

template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{
};

template <typename T, typename TReturn, typename... TArgs>
struct function_traits<TReturn (T::*)(TArgs...) const>
{
    static constexpr std::size_t arity = sizeof...(TArgs);

    using result_type = TReturn;

    template <std::size_t TI>
    using arg = std::tuple_element_t<TI, std::tuple<TArgs...>>;
};

template <typename T>
using is_not_overloaded_impl = decltype(&std::decay_t<T>::operator());

template <typename T>
using is_not_overloaded =
    std::experimental::is_detected<is_not_overloaded_impl, T>;

template <typename T, typename... Ts>
using can_invoke_with_impl = decltype(std::declval<T>()(std::declval<Ts>()...));

template <typename T>
using is_binary_callable_impl = can_invoke_with_impl<T, any_type, any_type>;

template <typename T>
using is_unary_callable_impl = can_invoke_with_impl<T, any_type>;

template <typename T>
using is_binary_callable = std::is_callable<T(any_type, any_type)>;
// using is_binary_callable =
// std::experimental::is_detected<is_binary_callable_impl, T>;

template <typename T>
using is_unary_callable = std::is_callable<T(any_type)>;
// using is_unary_callable =
// std::experimental::is_detected<is_unary_callable_impl, T>;

struct arity_detector_t
{
    template <typename TF>
    constexpr auto operator()(TF&&) const
    {
        return is_binary_callable<TF>{};
    }
};

constexpr arity_detector_t arity_detector;

template <bool TOverloaded>
struct adapt_helper;

template <>
struct adapt_helper<true>
{
    template <typename TF>
    auto operator()(TF&& f)
    {
        return [f = FWD(f)](auto, auto&& x)->decltype(f(FWD(x)))
        {
            return f(FWD(x));
        };
    }
};

template <>
struct adapt_helper<false>
{
    template <typename TF>
    auto operator()(TF&& f)
    {
        using argt = typename function_traits<
            std::decay_t<decltype(f)>>::template arg<0>;

        return [f = FWD(f)](auto, argt x)->decltype(f(x))
        {
            return f(x);
        };
    }
};

namespace vr
{
    struct recursive_tag_t
    {
    };
    constexpr recursive_tag_t recursive;

    struct non_recursive_tag_t
    {
    };
    constexpr non_recursive_tag_t non_recursive;

    template <typename TTag, typename TF>
    struct tagged_branch : TF
    {
        using tag = TTag;

        template <typename TFFwd>
        tagged_branch(TFFwd&& f) : TF(FWD(f))
        {
        }
    };

    template <typename TF>
    using recursive_visitor_branch = tagged_branch<recursive_tag_t, TF>;

    template <typename TF>
    using non_recursive_visitor_branch = tagged_branch<non_recursive_tag_t, TF>;

    template <typename T>
    auto operator|(recursive_tag_t, T&& x)
    {
        return recursive_visitor_branch<std::decay_t<T>>{x};
    }

    template <typename T>
    auto operator|(non_recursive_tag_t, T&& x)
    {
        return non_recursive_visitor_branch<std::decay_t<T>>{x};
    }
}

template <typename, template <typename...> class>
struct is_specialization_of : boost::hana::false_
{
};

template <template <typename...> class TTemplate, typename... Ts>
struct is_specialization_of<TTemplate<Ts...>, TTemplate> : boost::hana::true_
{
};

template <class T>
using has_tag = typename T::tag;

template <typename T>
using is_tagged_as_recursive =
    std::experimental::is_detected_exact<vr::recursive_tag_t, has_tag, T>;

template <typename T>
using is_tagged_as_non_recursive =
    std::experimental::is_detected_exact<vr::non_recursive_tag_t, has_tag, T>;

template <typename>
struct dependent_false : std::false_type
{
};

namespace impl
{
    template <typename... THelpers>
    struct arity_deducer_t
    {
        template <typename TF>
        constexpr auto operator()(TF&&) const
        {
            using f_type = std::decay_t<TF>;
            using is_unary_c =
                is_unary_callable_with_any<f_type, any_type, THelpers...>;
            using is_binary_c =
                is_binary_callable_with_any<f_type, any_type, THelpers...>;

            // clang-format off
            if constexpr(is_tagged_as_recursive<f_type>{})
            {
                if constexpr(is_unary_c{})
                {
                    static_assert(dependent_false<f_type>{},
                        "Marked recursive but unary callable.");
                }
                else
                {
                    return deduced_arity::binary;
                }
            }
            else if constexpr(is_tagged_as_non_recursive<f_type>{})
            {
                if constexpr(is_binary_c{})
                {
                    static_assert(dependent_false<f_type>{},
                        "Marked non-recursive but binary callable.");
                }
                else
                {
                    return deduced_arity::unary;
                }
            }
            else if constexpr(is_binary_c{})
            {
                return deduced_arity::binary;
            }
            else if constexpr(is_unary_c{})
            {
                return deduced_arity::unary;
            }
            else if constexpr(is_not_overloaded<f_type>{})
            {
                constexpr auto arity = function_traits<f_type>::arity;

                if constexpr(arity == 1)
                {
                    return deduced_arity::unary;
                }
                else if constexpr(arity == 2)
                {
                    return deduced_arity::binary;
                }
                else
                {
                    static_assert(dependent_false<f_type>{},
                        "Unsuppored arity.");
                }
            }
            else
            {
                return deduced_arity::undeducible;
            }
            // clang-format on
        }
    };
}

template <typename... THelpers>
constexpr impl::arity_deducer_t<THelpers...> arity_deducer{};

// Added single 'f' due to gcc61 segfault
template <typename TRet, typename... THelpers, typename TF, typename... TFs>
auto make_recursive_visitor(TF&& f, TFs&&... fs)
{
    namespace bh = boost::hana;

    auto fns_tuple = bh::make_tuple(FWD(f), FWD(fs)...);

    auto fns_arities = bh::transform(fns_tuple, arity_deducer<THelpers...>);

    // clang-format off
    bh::for_each(fns_arities, [](auto x)
    {
        if constexpr(std::is_same<decltype(x), deduced_arity::undeducible_t>{})
        {
            std::cout << "undeducible\n";
        }
        else
        {
            std::cout << x << "\n";
        }
    });
    // clang-format on

    auto non_recs = bh::remove_if(fns_tuple, arity_detector);

    auto recs = bh::filter(fns_tuple, arity_detector);

    auto rnrecs = bh::transform(non_recs, [](auto&& f) {
        return adapt_helper<!is_not_overloaded<decltype(f)>{}>{}(FWD(f));
    });

    auto alltpl = bh::concat(rnrecs, recs);

    auto final_overload = overload_tuple(alltpl);

    // Probably need to assert tthat every lambda returns same type
    // TODO:
    // using return_type = decltype(f(any_type{}));

    return bh::fix([fo = std::move(final_overload)](auto self, auto&& x)->TRet {
        return fo([&self](auto&& v) { return vr::visit_recursively(self, v); },
            FWD(x));
    });
}

template <typename T, typename... TFs>
decltype(auto) match(T&& v, TFs&&... fs)
{
    return vr::visit(boost::hana::overload(FWD(fs)...), FWD(v));
}

int main()
{
    auto k = vr::recursive | [] {};
    static_assert(
        is_tagged_as_recursive<vr::recursive_visitor_branch<decltype(k)>>{});

    // clang-format off
    auto vnp = make_recursive_visitor<void, long> // returns void, `long` helps deduction
    (
        [](auto x) -> std::enable_if_t<std::is_arithmetic<std::decay_t<decltype(x)>>{}> { std::cout << x << "N\n"; },
        [](int x)    { std::cout << x << "i\n"; },
        [](float x)  { std::cout << x << "f\n"; },
        [](double x) { std::cout << x << "d\n"; },
        [](auto recurse, const varr& x) { for(const auto& y : x) recurse(y); },
        [](auto recurse, const vmap& x) { for(const auto& y : x) recurse(y.second); }
    );
    // clang-format on

    /*
    #define MAKE_RECURSIVE_VISITOR(return_type, ...) \
        make_recursive_visitor<return_type>([](auto overload, auto recurse) \
        { \
            return overload \
            ( \
                __VA_ARGS__ \
            ); \
        }
    */

    /*
    // Alternative:
    auto vnp = make_recursive_visitor<void>([](auto overload, auto recurse)
    {
        return overload
        (
            [](auto x) ->
    std::enable_if_t<std::is_arithmetic<std::decay_t<decltype(x)>>{}> {
    std::cout << x << "N\n"; },
            [](int x)          { std::cout << x << "i\n"; },
            [](float x)        { std::cout << x << "f\n"; },
            [](double x)       { std::cout << x << "d\n"; },
            [&](const varr& x) { for(const auto& y : x) recurse(y); },
            [&](const vmap& x) { for(const auto& y : x) recurse(y.second); }
        );
    });
    */

    vnum v0{0};
    vr::visit(vnp, v0);

    v0 = 5.f;
    vr::visit(vnp, v0);

    v0 = 33.51;
    vr::visit(vnp, v0);

    v0 = 500l;
    vr::visit(vnp, v0);

    v0 = varr{vnum{1}, vnum{2.0}, vnum{3.f}};
    vr::visit(vnp, v0);

    v0 = varr{vnum{5}, varr{vnum{7}, vnum{8.0}, vnum{9.}}, vnum{4.f}};
    vr::visit(vnp, v0);

    v0 = varr{vnum{1}, vmap{{1, vnum{2.0}}}, vnum{3.f}};
    vr::visit(vnp, v0);

    std::cout << "\n\n\n\n";

    auto evaluate = make_recursive_visitor<int>( // .
        [](int x) { return x; },                 // .
        [](auto recurse, const std::unique_ptr<r_expr>& x) {
            const auto& lhs = std::get<0>(*x);
            const auto& op = std::get<1>(*x);
            const auto& rhs = std::get<2>(*x);
            return match(op, [&](plus) { return lhs + recurse(rhs); },
                [&](minus) { return lhs - recurse(rhs); });
        } // .
        );

    using std::make_unique;
    expr e0{5};
    expr e1{make_unique<r_expr>(9, plus{}, 3)};
    expr e2{make_unique<r_expr>(1, minus{}, make_unique<r_expr>(3, plus{}, 7))};

    std::cout << vr::visit(evaluate, e0) << "\n";
    std::cout << vr::visit(evaluate, e1) << "\n";
    std::cout << vr::visit(evaluate, e2) << "\n";
}

ext: cpp


text:
#ifndef SESSION_LISTENER_BASE_HPP__
#define SESSION_LISTENER_BASE_HPP__

#include <boost/asio.hpp>
#include <boost/beast.hpp>

#if USE_SSL == 1
#include <boost/asio/ssl.hpp>
#include <boost/beast/ssl.hpp>
#endif /* USE_SSL == 1 */
#include <type_traits>
#include <iostream>

#include "my_async/util/traits.hpp"
#include "my_async/traits.hpp"

#include "my_async/util/shareable.hpp"

namespace My_Async{
namespace Listener{

// Accepts incoming connections and launches the sessions
template<typename Session, bool MakeStrand = true>
class Listener_Base :
		public std::enable_shared_from_this<Listener_Base<Session, MakeStrand>>
{
		static constexpr const bool is_shareable = My_Async::Util::is_shareable<Session>::value;

		boost::asio::io_context& ioc_;
		boost::asio::ip::tcp::acceptor acceptor_;

#if USE_SSL == 1
		//Check if the session is SSL. If not, exclude ctx_ attribute
		using ssl_context = My_Async::Util::exclude_attr_if<
				Session::use_ssl, boost::asio::ssl::context&>;
		ssl_context ctx_;
#else
		using ssl_context = struct{};
#endif
		using shareable = My_Async::Util::exclude_attr_if<is_shareable,
				std::shared_ptr<My_Async::Util::Shareable<Session, typename Session::shareable_data_type>>>;
		shareable share_;
	public:
		static constexpr const bool use_ssl = Session::use_ssl;
		using Session_Type = Session;
		static constexpr const bool has_strand = MakeStrand;

		Listener_Base(
			boost::asio::io_context& ioc)
			: ioc_(ioc)
			, acceptor_(boost::asio::make_strand(ioc))
		{
			if constexpr(is_shareable)
				share_ = std::make_shared<My_Async::Util::Shareable<Session, typename Session::shareable_data_type>>();
		}
#if USE_SSL == 1
		Listener_Base(
				boost::asio::io_context& ioc,
				ssl_context ctx)
				: ioc_(ioc), acceptor_(boost::asio::make_strand(ioc))
				, ctx_(ctx)
		{
			if constexpr(is_shareable)
				share_ = std::make_shared<My_Async::Util::Shareable<Session, typename Session::shareable_data_type>>();
		}
#endif
		virtual ~Listener_Base(){}

		shareable
		get_share(){ return share_; }

		template<typename U = Session>
		typename std::enable_if<U::is_shareable,
					std::vector<boost::asio::ip::tcp::endpoint>>::type
		clients() const noexcept{
			std::vector<boost::asio::ip::tcp::endpoint> v;

			share_->exec_to_all([&v](Session* session){
				v.push_back(session->endpoint());
			});

			return v;
		}

		void
		close(boost::system::error_code&) noexcept
		{
			boost::asio::post(
				acceptor_.get_executor(),
					std::bind(&Listener_Base::closing,
							this->shared_from_this()));
		}

		template<typename U = Session,
				typename = typename std::enable_if<U::is_shareable>::type>
		void
		close(boost::system::error_code& ec, bool close_clients) noexcept
		{
			if(close_clients){
				share_->exec_to_all([this](Session* session){
					session->close();
				});
			}
			close(ec);
		}

		template<typename U = Session,
			typename = typename std::enable_if<U::is_shareable>::type>
		void
		close_clients(std::vector<boost::asio::ip::tcp::endpoint> eps)
		{
			share_->exec_to_all([&](Session* session){
				for(auto const& ep : eps){
					if(ep == session->endpoint()){
						session->close();
						break;
					}
				}
			});
		}

		template<typename OutContainer, typename U = Session,
			typename = typename std::enable_if<U::is_shareable>::type>
		void
		write(boost::asio::ip::tcp::endpoint client, std::shared_ptr<OutContainer const> const& data)
		{
			share_->exec_to_all([&](Session* session){
				if(client == session->endpoint())
					session->write(data);
			});
		}

		void
		init(boost::asio::ip::tcp::endpoint endpoint,
				boost::system::error_code& ec) noexcept
		{
			// Open the acceptor
			acceptor_.open(endpoint.protocol(), ec);
			if(ec)
				return fail(ec, "open");

			// Allow address reuse
			acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec);
			if(ec) return fail(ec, "set_option");

			// Bind to the server address
			acceptor_.bind(endpoint, ec);
			if(ec) return fail(ec, "bind");

			// Start listening for connections
			acceptor_.listen(
				boost::asio::socket_base::max_listen_connections, ec);
			if(ec) return fail(ec, "listen");

			do_accept();
		}

	protected:
		virtual void
		fail(boost::system::error_code ec, char const* what) noexcept
		{
			std::cerr << what << ": " << ec.message() << "\n";
		}

		void closing()
		{
			boost::system::error_code ec;
			acceptor_.cancel(ec);
			if(ec) return fail(ec, "cancel");
			acceptor_.close(ec);
			if(ec) return fail(ec, "close");
		}

		void
		do_accept() noexcept
		{
			// The new connection gets its own strand
			if constexpr (MakeStrand){
				// The new connection gets its own strand
				acceptor_.async_accept(
					boost::asio::make_strand(ioc_),
					boost::beast::bind_front_handler(
						&Listener_Base<Session, MakeStrand>::on_accept,
						this->shared_from_this()));
			} else {
				//No strand
				acceptor_.async_accept(
					ioc_,
					boost::beast::bind_front_handler(
						&Listener_Base<Session, MakeStrand>::on_accept,
						this->shared_from_this()));
			}
		}

		virtual void on_accept(boost::system::error_code ec,
							boost::asio::ip::tcp::socket socket) noexcept
		{
			if(ec)
				return fail(ec, "accept");

			if constexpr (Session::use_ssl == false){
				//Plain
				if constexpr(!is_shareable)
					std::make_shared<Session>(std::move(socket))->run();
				else
					std::make_shared<Session>(std::move(socket), share_)->run();
			} else {
#if USE_SSL == 1
				//SSL
				if constexpr(!is_shareable)
					std::make_shared<Session>(std::move(socket), ctx_)->run();
				else
					std::make_shared<Session>(std::move(socket), ctx_, share_)->run();
#endif
			}

			// Accept another connection
			do_accept();
		}
};

}//Listener
}//My_Async

#endif /* SESSION_LISTENER_BASE_HPP__ */

ext: hpp


text:
////////////////////////////////////////////////////////////////////////////////
///
/// \file thread.cpp
/// ----------------
///
/// (c) Copyright Domagoj Saric 2016 - 2021.
///
///  Use, modification and distribution are subject to the
///  Boost Software License, Version 1.0. (See accompanying file
///  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
///
///  See http://www.boost.org for most recent version.
///
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
#include "thread.hpp"

#include <boost/assert.hpp>

#include <cerrno>
#include <cstdint>

#ifdef __ANDROID__
#include <sys/time.h>
#include <sys/resource.h>
#endif // __ANDROID__
//------------------------------------------------------------------------------
namespace boost
{
//------------------------------------------------------------------------------
namespace thrd_lite
{
//------------------------------------------------------------------------------

namespace
{
#if !defined( __ANDROID__ )
#ifdef __EMSCRIPTEN__
    auto const default_policy_priority_min        { 0 };
    auto const default_policy_priority_max        { 0 };
#else
    auto const default_policy_priority_min        { ::sched_get_priority_min( SCHED_OTHER ) };
    auto const default_policy_priority_max        { ::sched_get_priority_max( SCHED_OTHER ) };
#endif
    auto const default_policy_priority_range      { static_cast<std::uint8_t>( default_policy_priority_max - default_policy_priority_min ) };
    [[ maybe_unused ]]
    auto const default_policy_priority_unchangable{ default_policy_priority_range == 0 };

    std::uint8_t round_divide( std::uint16_t const numerator, std::uint8_t const denominator ) noexcept
    {
        auto const integral_division      {   numerator / denominator                          };
        auto const at_least_half_remainder{ ( numerator % denominator ) >= ( denominator / 2 ) };
        return integral_division + at_least_half_remainder;
    }
#endif // !__ANDROID__
} // anonymous namespace

void                            BOOST_NOTHROW_LITE thread_impl::join  ()       noexcept { BOOST_VERIFY( pthread_join  ( handle_, nullptr ) == 0 ); handle_ = {}; }
void                            BOOST_NOTHROW_LITE thread_impl::detach()       noexcept { BOOST_VERIFY( pthread_detach( handle_          ) == 0 ); handle_ = {}; }
thread_impl::native_handle_type BOOST_NOTHROW_LITE thread_impl::get_id() const noexcept { return handle_; }

BOOST_ATTRIBUTES( BOOST_MINSIZE )
bool thread_impl::set_priority( priority const new_priority ) noexcept
{
#ifdef __EMSCRIPTEN__
    if constexpr ( true )
        return ( new_priority == priority::normal );
#endif
    auto const nice_value{ static_cast<int>( new_priority ) };
#if defined( __ANDROID__ )
    /// \note Android's pthread_setschedparam() does not actually work so we
    /// have to abuse the general Linux' setpriority() non-POSIX compliance
    /// (i.e. that it sets the calling thread's priority).
    /// http://stackoverflow.com/questions/17398075/change-native-thread-priority-on-android-in-c-c
    /// https://android.googlesource.com/platform/dalvik/+/gingerbread/vm/alloc/Heap.c
    /// https://developer.android.com/topic/performance/threads.html
    /// _or_
    /// try the undocumented things the Java Process.setThreadPriority()
    /// function seems to be doing:
    /// https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/Process.java#L634
    /// https://github.com/android/platform_frameworks_base/blob/master/core/jni/android_util_Process.cpp#L475
    /// https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/utils/Threads.cpp#329
    ///                                   (03.05.2017.) (Domagoj Saric)
    return ::setpriority( PRIO_PROCESS, get_id(), nice_value ) == 0;
#else
    std::uint8_t const api_range            { static_cast<std::int8_t>( priority::idle ) - static_cast<std::int8_t>( priority::time_critical ) };
    auto         const platform_range       { default_policy_priority_range };
    auto         const uninverted_nice_value{ static_cast<std::uint8_t>( - ( nice_value - static_cast<std::int8_t>( priority::idle ) ) ) };
    int          const priority_value       { default_policy_priority_min + round_divide( uninverted_nice_value * platform_range, api_range ) }; // surely it will be hoisted
#   if defined( __APPLE__ )
    BOOST_ASSERT( !default_policy_priority_unchangable );
    ::sched_param scheduling_parameters;
    int           policy;
    auto const handle{ get_id() };
    BOOST_VERIFY( pthread_getschedparam( handle, &policy, &scheduling_parameters ) == 0 );
    scheduling_parameters.sched_priority = priority_value;
    return pthread_setschedparam( handle, policy, &scheduling_parameters ) == 0;
#   else
    return !default_policy_priority_unchangable && ( pthread_setschedprio( get_id(), priority_value ) == 0 );
#   endif // Apple or
#endif // Android or
}

bool thread_impl::bind_to_cpu( [[ maybe_unused ]] affinity_mask const mask ) noexcept
{
    // Android does not have pthread_setaffinity_np or pthread_attr_setaffinity_np
    // and there seems to be no way of detecting its presence.
#if 0
    return pthread_setaffinity_np( get_id(), sizeof( mask.value_ ), &mask.value_ ) == 0;
#elif 0
    return bind_to_cpu( pthread_getthreadid_np( get_id() ), mask ) == 0;
#else
    return false;
#endif
}

BOOST_ATTRIBUTES( BOOST_COLD )
bool thread_impl::bind_to_cpu( native_handle_type const handle, affinity_mask const mask ) noexcept
{
#ifdef __linux__
    return sched_setaffinity( handle, sizeof( mask.value_ ), &mask.value_ ) == 0;
#else // TODO Mach
    (void)handle; (void)mask;
    return 0;
#endif
}

int BOOST_NOTHROW_LITE thread_impl::create( thread_procedure const start_routine, void * const arg ) noexcept
{
    auto const error{ pthread_create( &handle_, nullptr, start_routine, arg ) };
    if ( BOOST_UNLIKELY( error ) )
    {
        BOOST_ASSUME( error == EAGAIN ); // any other error indicates a programmer error
        handle_ = {};
    }
    return error;
}

//------------------------------------------------------------------------------
} // namespace thrd_lite
//------------------------------------------------------------------------------
} // namespace boost
//------------------------------------------------------------------------------

max_stars_repo_name: microblink/sweater

max_issues_repo_name: microblink/sweater

max_forks_repo_name: microblink/sweater


text:
// Copyright (c) 2015, Daniel Pfeifer <daniel@pfeifer-mail.de>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#ifndef BYOM_EXT_FALLBACK_HPP
#define BYOM_EXT_FALLBACK_HPP

#include <boost/type_index.hpp>
#include <stdexcept>
#include <ostream>

namespace byom {
namespace detail {

struct fallback
{
  template <typename T>
  static bool empty_impl(T const&)
  {
    using boost::typeindex::type_id_with_cvr;
    throw std::invalid_argument{ "'empty(" +
                                 type_id_with_cvr<T const&>().pretty_name() +
                                 ")' is not implemented" };
  }

  template <typename T, typename K>
  static std::nullptr_t const& at_impl(T const&, K const&)
  {
    using boost::typeindex::type_id_with_cvr;
    throw std::invalid_argument{
      "'at(" + type_id_with_cvr<T const&>().pretty_name() + ", " +
      type_id_with_cvr<K const&>().pretty_name() + ")' is not implemented"
    };
  }

  template <typename T>
  static void for_each_impl(T const&, visit_function const&)
  {
    using boost::typeindex::type_id_with_cvr;
    throw std::invalid_argument{
      "'for_each(" + type_id_with_cvr<T const&>().pretty_name() +
      ", byom::visit_function const&)' is not implemented"
    };
  }

  template <typename T>
  static unsigned long long int to_integral(T const&)
  {
    using boost::typeindex::type_id_with_cvr;
    throw std::invalid_argument{ "'to_integral(" +
                                 type_id_with_cvr<T const&>().pretty_name() +
                                 ")' is not implemented" };
  }

  template <typename T>
  static long double to_floating_point(T const&)
  {
    using boost::typeindex::type_id_with_cvr;
    throw std::invalid_argument{ "'to_floating_point(" +
                                 type_id_with_cvr<T const&>().pretty_name() +
                                 ")' is not implemented" };
  }

  template <typename T>
  static std::string to_string(T const&)
  {
    using boost::typeindex::type_id_with_cvr;
    throw std::invalid_argument{ "'to_string(" +
                                 type_id_with_cvr<T const&>().pretty_name() +
                                 ")' is not implemented" };
  }

  template <typename T>
  static void print_impl(std::ostream& os, T const&)
  {
    using boost::typeindex::type_id_with_cvr;
    throw std::invalid_argument{ "'print(std::ostream&, " +
                                 type_id_with_cvr<T const&>().pretty_name() +
                                 ")' is not implemented" };
  }
};

} // namespace detail

template <>
struct ext<std::nullptr_t> : detail::fallback
{
  static bool empty_impl(std::nullptr_t)
  {
    return true;
  }

  static void print_impl(std::ostream& os, std::nullptr_t)
  {
    os << "null";
  }
};

} // namespace byom

#endif /* BYOM_EXT_FALLBACK_HPP */

max_stars_repo_name: purpleKarrot/BYOM

max_issues_repo_name: purpleKarrot/BYOM

max_forks_repo_name: purpleKarrot/BYOM


text:
//
// Created by Ragesh on 5/5/18.
//

////////////////////////////////////////////////////////////////////////////////
// My naming conventions for the project
// Put header files in separate categories and in alphabetical order
// unless there some compatibility issue between the header files
// macros and const : ALL_IN_CAPS
// namespace : NS_prefix_small_letter_with_underscore
// class and structs : First_letter_caps_with_underscore
// functions and variables: all_small_letters
/////////////////////////////////////////////////////////////////////////////////

/***
 * This cpp file is used to generate executable to that can make the robot move according to a path planned which
 * maximizes the Mutual Information between the map uncertainty and forward ranger sensor model
 */

// ros libraries
#include <geometry_msgs/Twist.h>
#include <ros/ros.h>
#include <ros/console.h>

// C++ library header files
#include <iostream>
#include <string>

// C library header files
#include <stdio.h>

// third party libraries
#include <boost/math/constants/constants.hpp>
#include <opencv2/opencv.hpp>

// local header files
#include "my_robot.h"
#include "planners.h"
#include "command_line_parser.h"
#include "occupancyGrid.hpp"

// Short name for the namespaces
namespace clp=NS_rag_command_line_parser;
namespace rob=NS_my_robot;
namespace map=NS_occupancy_grid;

int main(int argc, char** argv)
{
  // robot speed parameters
  static const double cruisesSpeed = 0.4;
  static const double turnSpeed = 0.2;

  // parse the inputs
  clp::CommandLineParser cml_parser(argc, argv);

  // Parse input arguments for robot id.
  std::string robot_number;
  if (cml_parser["-id"])
  {
    robot_number = cml_parser("-id");
  }else{
    ROS_ERROR("Need to provide robot id");
  }

  std::string no_of_robots;
  if (cml_parser["-n"])
  {
    no_of_robots = cml_parser("-n");
  }else{
    ROS_ERROR("Need to provide number of robots n");
  }

  // Initializing the ROS node
  std::string node_name{"MI_wanderer_node_" + robot_number};
  ros::init(argc, argv, node_name);
  // display the name of the node
  ROS_INFO_STREAM("Initiated node : "<<ros::this_node::getName());
  // The parameters for map object
  const double min_x = -8; // in meters
  const double min_y = -8; // in meters
  const double cell_size_x = 0.02; // in meters
  const double cell_size_y = 0.02; // in meters
  const int n_cell_x = 800; // no of cells along x
  const int n_cell_y = 800; // no of cells along y

  // Create a map object

  map::occupancyGrid2D<double, int> occ_grid{min_x, min_y, cell_size_x, cell_size_y, n_cell_x, n_cell_y};

  // Velocity object
  Velocity velocity;
  velocity.linear.x=cruisesSpeed;
  velocity.linear.y=0;
  velocity.linear.z=0;
  velocity.angular.x=0;
  velocity.angular.y=0;
  velocity.angular.z=turnSpeed;

  Pose startP{0.0, 0.0, 0.0};

  // radial range sensor noise
  double radial_noise = 0.01;

  // forward sensor model parameter
  NS_my_planner::F_S_M_parameters fsm;
  fsm.sigma = radial_noise;

  // Create a planner object
  NS_my_planner::base_planner planner{50, 0, startP, velocity};
  NS_my_planner::MI_levyWalk_planner MI_planner{0, startP, velocity, fsm, NS_my_planner::CSQMI, 5};

  // Create a robot object
  rob::Robot robot{static_cast<uint>(std::stoi(robot_number)), std::string{"robot_"}, &MI_planner,
                   static_cast<uint>(std::stoi(no_of_robots)), radial_noise};

  // Assigning the map object to the robot
  robot.occ_grid_map = &occ_grid;

  // ROS loop rate
  ros::Rate loop_rate(10);

  long unsigned int pre_time=0;

  while (ros::ok()){
    // Publish, Spin and Sleep
    //ROS_INFO("\n Ros time now is %f ", ros::Time::now().toSec());
    robot.move();
    robot.build_map();
    //robot.merge_map();
    // to do some action every 20 seconds
    long unsigned int time_now = static_cast<long unsigned int>(ros::Time::now().toSec());
    if (time_now%30 == 0 &&
        (pre_time != time_now)){
      //ROS_INFO("\n In condition ");
      //robot.write_map_image();
      pre_time = time_now;
    }
    robot.update_neighbors();
    robot.publish_map();
    ros::spinOnce();
    loop_rate.sleep();
  }
}


text:
#include <boost/test/auto_unit_test.hpp>

#include <memory>

#include "coconut/milk/graphics/TestSuite.hpp"

#include "coconut/milk/fs.hpp"

#include "coconut/pulp/renderer/shader/InputFactory.hpp"
#include "coconut/pulp/renderer/shader/ShaderFactory.hpp"
#include "coconut/pulp/renderer/OrientedCamera.hpp"
#include "coconut/pulp/renderer/CommandBuffer.hpp"
#include "coconut/pulp/renderer/Scene.hpp"

#include "coconut/milk/graphics/DirectXError.hpp"

using namespace coconut;
using namespace coconut::pulp;
using namespace coconut::pulp::renderer;
using namespace coconut::pulp::renderer::shader;

BOOST_FIXTURE_TEST_SUITE(PulpRendererShaderShaderFactoryTestSuite, milk::graphics::TestSuite);

BOOST_AUTO_TEST_CASE(SetsConstantBuffers) {
	// init shaders
	auto fs = std::make_shared<milk::Filesystem>();

	auto mount = std::make_unique<milk::DirectoryMount>("Debug/", true); // TODO!
	fs->mount("/", std::move(mount), milk::Filesystem::PredecessorHidingPolicy::HIDE);

	auto fsContext = milk::FilesystemContext(fs);

	auto passFactory = shader::PassFactory();
	passFactory.scanCompiledShaderDirectory(fs, "");

	// init data
	auto scene = Scene(renderer());

	{
		// TODO: put this in a file
		auto submeshes = pulp::Mesh::Submeshes();
		auto materials = pulp::Mesh::MaterialConfigurations();

		{
			auto material = pulp::MaterialConfiguration();

			material.renderStateConfiguration().cullMode = milk::graphics::RenderState::CullMode::BACK;
			material.renderStateConfiguration().fillMode = milk::graphics::RenderState::FillMode::SOLID;
			material.renderStateConfiguration().frontCounterClockwise = false;

			material.properties().emplace(mesh::MaterialConfiguration::AMBIENT_COLOUR_PROPERTY,
				pulp::Colour(0.01f, 0.02f, 0.03f, 0.04f));
			material.properties().emplace(mesh::MaterialConfiguration::DIFFUSE_COLOUR_PROPERTY,
				pulp::Colour(0.05f, 0.06f, 0.07f, 0.08f));
			material.properties().emplace(mesh::MaterialConfiguration::SPECULAR_COLOUR_PROPERTY,
				pulp::Colour(0.09f, 0.1f, 0.11f, 0.12f));

			material.shaderName() = "ConstantBuffers";

			materials.emplace("phong", std::move(material));

			auto submesh = pulp::Submesh();

			submesh.primitiveTopology() = milk::graphics::PrimitiveTopology::TRIANGLE_STRIP;

			auto vertex = pulp::Submesh::Vertex();
			vertex.normal = pulp::Vector(0.0f, 0.0f, -1.0f);

			vertex.position = pulp::Position(-1.0f, 1.0f, 0.0f);
			submesh.indices().emplace_back(submesh.vertices().size());
			submesh.vertices().emplace_back(vertex);

			vertex.position = pulp::Position(-1.0f, -1.0f, 0.0f);
			submesh.indices().emplace_back(submesh.vertices().size());
			submesh.vertices().emplace_back(vertex);

			vertex.position = pulp::Position(1.0f, -1.0f, 0.0f);
			submesh.indices().emplace_back(submesh.vertices().size());
			submesh.vertices().emplace_back(vertex);

			vertex.position = pulp::Position(1.0f, 1.0f, 0.0f);
			submesh.indices().emplace_back(submesh.vertices().size());
			submesh.vertices().emplace_back(vertex);

			submesh.materialId() = "phong";

			submeshes.emplace_back(std::move(submesh));
		}

		auto rectangleData = pulp::mesh::Mesh(submeshes, materials);
		auto model = std::make_shared<Model>(rectangleData, renderer(), passFactory, fs);
		auto rectangle = std::make_shared<Actor>(model);

		scene.add(rectangle);

		auto camera = std::make_unique<OrientedCamera>(); // TODO: shit api
		camera->translate(coconut::pulp::math::Vec3(0.13f, 0.14f, 0.15f));
		scene.setCamera(std::move(camera));

		{
			scene.add(lighting::DirectionalLight(
				pulp::math::Vec3(0.28f, 0.29f, 0.30f),
				pulp::math::Vec4(0.16f, 0.17f, 0.18f, 0.19f),
				pulp::math::Vec4(0.20f, 0.21f, 0.22f, 0.23f),
				pulp::math::Vec4(0.24f, 0.25f, 0.26f, 0.27f)
				));

			scene.add(lighting::DirectionalLight(
				pulp::math::Vec3(0.43f, 0.44f, 0.45f),
				pulp::math::Vec4(0.31f, 0.32f, 0.33f, 0.34f),
				pulp::math::Vec4(0.35f, 0.36f, 0.37f, 0.38f),
				pulp::math::Vec4(0.39f, 0.40f, 0.41f, 0.42f)
				));

			scene.add(lighting::PointLight(
				pulp::math::Vec3(0.46f, 0.47f, 0.48f),
				pulp::math::Vec3(0.49f, 0.50f, 0.51f),
				pulp::math::Vec4(0.52f, 0.53f, 0.54f, 0.55f),
				pulp::math::Vec4(0.56f, 0.57f, 0.58f, 0.59f),
				pulp::math::Vec4(0.60f, 0.61f, 0.62f, 0.63f)
				));
		}
	}

	// render
	for (;;)
	{
		app().update();

		renderer().beginScene();

		CommandBuffer commandBuffer;
		scene.render(commandBuffer);
		commandBuffer.submit(renderer().getImmediateCommandList());

		renderer().endScene();
	}

	BOOST_FAIL("No checks done");
}

BOOST_AUTO_TEST_SUITE_END(/* PulpRendererShaderShaderFactoryTestSuite */);

max_stars_repo_name: mikosz/coconut

max_issues_repo_name: mikosz/coconut

max_forks_repo_name: mikosz/coconut


text:
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#include <qi/assert.hpp>
#include <qi/buffer.hpp>
#include <qi/log.hpp>

#include <cstdio>
#include <cstring>
#include <stdexcept>
#include <iomanip>
#include <ctype.h>
#include <algorithm>

#include <boost/make_shared.hpp>
#include <boost/utility/compare_pointees.hpp>

#include "buffer_p.hpp"

qiLogCategory("qi.Buffer");

namespace qi
{
  BufferPrivate::BufferPrivate() = default;

  BufferPrivate::~BufferPrivate()
  {
    if (_bigdata)
    {
      free(_bigdata);
      _bigdata = NULL;
    }
  }

  BufferPrivate::BufferPrivate(const BufferPrivate& b)
    : _bigdata(nullptr)
    , _cachedSubBufferTotalSize(b._cachedSubBufferTotalSize)
    , used(b.used)
    , available(b.available)
    , _subBuffers(b._subBuffers)
  {
    if (b._bigdata)
    {
      _bigdata = static_cast<unsigned char*>(malloc(b.used));
      ::memcpy(_bigdata, b._bigdata, b.used);
    }
    else
    {
      ::memcpy(_data, b._data, b.used);
    }
  }

  BufferPrivate& BufferPrivate::operator=(const BufferPrivate& b)
  {
    if (&b == this) return *this;
    _cachedSubBufferTotalSize = b._cachedSubBufferTotalSize;
    used = b.used;
    available = b.available;
    _subBuffers = b._subBuffers;
    if (_bigdata)
    {
      free(_bigdata);
      _bigdata = NULL;
    }
    if (b._bigdata)
    {
      _bigdata = static_cast<unsigned char*>(malloc(b.used));
      ::memcpy(_bigdata, b._bigdata, b.used);
    }
    else
    {
      ::memcpy(_data, b._data, b.used);
    }
    return *this;
  }

  boost::optional<size_t> BufferPrivate::indexOfSubBuffer(size_t offset) const
  {
    for(unsigned i = 0; i < _subBuffers.size(); ++i) {
      if (_subBuffers[i].first == offset) {
        return i;
      }
    }

    return {};
  }

  namespace
  {
    bool dataEqual(const unsigned char* aData, std::size_t aSize,
                   const unsigned char* bData, std::size_t bSize)
    {
      if (aSize != bSize) return false;
      const bool aIsNull = (aData == nullptr);
      const bool bIsNull = (bData == nullptr);
      if (aIsNull != bIsNull) return false;
      if (aIsNull) return true;  // Both are null.
      // Neither a nor b are null. We also know that their size are equal.
      return std::equal(aData, aData + aSize, bData);
    }
  }

  bool BufferPrivate::operator==(const BufferPrivate& o) const
  {
    // The "available" member is ignored as it does not affect the behavior of the object.
    // Idem for _cachedSubBufferTotalSize which is a cached data.
    return dataEqual(data(), used, o.data(), o.used) && _subBuffers == o._subBuffers;
  }

  unsigned char* BufferPrivate::data()
  {
    return _bigdata ? _bigdata : _data;
  }

  const unsigned char* BufferPrivate::data() const
  {
    return const_cast<BufferPrivate*>(this)->data();
  }

  bool BufferPrivate::resize(size_t neededSize)
  {
    neededSize += BLOCK; // Should be enough in most cases;

    qiLogDebug() << "Resizing buffer from " << available << " to " << neededSize;
    unsigned char *newBigdata;

    newBigdata = static_cast<unsigned char *>(realloc(_bigdata, neededSize));
    if (newBigdata == NULL)
      return false;
    if (!_bigdata && used > 0)
      ::memcpy(newBigdata, _data, used);
    available = neededSize;
    _bigdata = newBigdata; // Don't worry, realloc free previous buffer if needed
    return true;
  }

  Buffer::Buffer()
    : _p(boost::make_shared<BufferPrivate>())
  {
  }

  Buffer::Buffer(const Buffer& b)
    : _p(boost::make_shared<BufferPrivate>(*b._p))
  {
  }

  Buffer& Buffer::operator=(const Buffer& b)
  {
    _p = boost::make_shared<BufferPrivate>(*b._p);
    return *this;
  }

  Buffer::Buffer(Buffer&& b)
    : _p(std::move(b._p))
  {
    // The default state of a qi::Buffer contains a valid BufferPrivate pointer.
    b._p = boost::make_shared<BufferPrivate>();
  }

  Buffer& Buffer::operator=(Buffer&& b)
  {
    _p = std::move(b._p);
    b._p = boost::make_shared<BufferPrivate>();
    return *this;
  }

  bool Buffer::write(const void *data, size_t size)
  {
    if (_p->used + size > _p->available)
    {
      bool ret = _p->resize(_p->used + size);
      if (!ret) {
        qiLogVerbose() << "write(" << size << ") failed, buffer size is " << _p->available;
        return false;
      }
    }

    memcpy(_p->data() + _p->used, data, size);
    _p->used += size;

    return true;
  }

  size_t Buffer::addSubBuffer(const Buffer& buffer)
  {
    size_t subBufferSize = buffer.size();
    size_t actualUsed = _p->used;

    write((size_type*)&subBufferSize, sizeof(size_type));

    _p->_subBuffers.push_back(std::make_pair(actualUsed, buffer));
    _p->_cachedSubBufferTotalSize += buffer.totalSize();
    return actualUsed;
  }

  bool Buffer::hasSubBuffer(size_t offset) const
  {
    return _p->indexOfSubBuffer(offset) ? true : false;
  }

  const Buffer& Buffer::subBuffer(size_t offset) const
  {
    if (const auto index = _p->indexOfSubBuffer(offset))
    {
      return _p->_subBuffers[*index].second;
    }
    else
    {
      throw std::runtime_error("No sub-buffer at the specified offset.");
    }
  }

  size_t Buffer::size() const
  {
    return _p->used;
  }

  size_t Buffer::totalSize() const
  {
    return size() + _p->_cachedSubBufferTotalSize;
  }

  const std::vector<std::pair<size_t, Buffer> > & Buffer::subBuffers() const
  {
    return _p->_subBuffers;
  }

  /*
  ** We need to allocate memory as soon as this function is called
  ** Returned memory MUST be coherent with the buffer used (either on stack/heap)
  ** As we can't know if the buffer will be used on heap later, we've to resize on heap
  **
  ** Returns a pointer to the first available byte in the (potentially
  ** reallocated) buffer memory, or nullptr in case of error.
  */
  void *Buffer::reserve(size_t size)
  {
    if (_p->used + size > _p->available)
    {
      bool success = _p->resize(_p->used + size);
      if (!success) {
        qiLogVerbose() << "reserve(" << size << ") failed, buffer size is " << _p->available;
        return nullptr;
      }
    }

    void *p = _p->data() + _p->used;
    _p->used += size;

    return p;
  }

  void Buffer::clear()
  {
    _p->used = 0;
    _p->_subBuffers.clear();
    _p->_cachedSubBufferTotalSize = 0;
  }

  void* Buffer::data()
  {
    return _p ? _p->data() : 0;
  }

  const void* Buffer::data() const
  {
    return _p ? _p->data() : 0;
  }

  const void *Buffer::read(size_t offset, size_t length) const
  {
    if (offset + length > _p->used)
    {
      qiLogDebug() << "Attempt to read " << offset+length
       <<" on buffer of size " << _p->used;
      return  nullptr;
    }
    return (char*)_p->data() + offset;
  }

  size_t Buffer::read(void* buffer, size_t offset, size_t length) const
  {
    if (offset > _p->used)
    {
      qiLogDebug() << "Attempt to read " << offset+length
      <<" on buffer of size " << _p->used;
      return -1;
    }
    size_t copy = std::min(length, _p->used - offset);
    memcpy(buffer, (char*)_p->data()+offset, copy);
    return copy;
  }

  bool Buffer::operator==(const Buffer& b) const
  {
    return boost::equal_pointees(_p, b._p);
  }

  namespace detail {
    void printBuffer(std::ostream& stream, const Buffer& buffer)
    {
      if (buffer.size() == 0) {
        qiLogDebug() << "dump on empty buffer";
        return;
      }

      std::ios_base::fmtflags flags = stream.flags();
      unsigned int i = 0;
      const unsigned char* data = (const unsigned char*)buffer.data();

      while (i < buffer.size()) {
        if (i % 16 == 0) stream << std::hex << std::setfill('0') << std::setw(8) << i << ": ";
        stream << std::setw(2) << static_cast<unsigned int>(data[i]);
        i++;
        if (i % 2 == 0) stream << ' ';
        if (i % 16 == 0)
        {
          for (unsigned int j = i - 16; j < i ; j++)
          {
            const auto c = data[j];
            stream << (isgraph(c) ? c : '.');
          }
          stream << '\n';
        }
      }

      while (i % 16 != 0) {
        stream << "  ";
        if (i % 2 == 0) stream << ' ';
        i++;
      }
      stream << ' ';

      for (unsigned int j = i - 16; j < buffer.size(); j++) {
        const auto c = data[j];
        stream << (isgraph(c) ? c : '.');
      }

      stream.flags(flags);
    }
  }
} // !qi

max_stars_repo_name: arntanguy/libqi

max_issues_repo_name: arntanguy/libqi

max_forks_repo_name: arntanguy/libqi


text:
#pragma once

#include <merely3d/material.hpp>
#include <merely3d/primitives.hpp>
#include <merely3d/renderable.hpp>
#include <merely3d/mesh.hpp>

#include <Eigen/Dense>

#include <type_traits>
#include <vector>

namespace merely3d
{
    class CommandBuffer
    {
    public:
        void clear();

        template <typename Shape>
        void push_renderable(const Renderable<Shape> & renderable);

        void push_line(const Line & line);

        void push_particle(const Particle & particle);

        const std::vector<Renderable<Rectangle>> &  rectangles() const;
        const std::vector<Renderable<Box>> &        boxes() const;
        const std::vector<Renderable<Sphere>> &     spheres() const;
        const std::vector<Renderable<StaticMesh>> & meshes() const;
        const std::vector<Line> &                   lines() const;
        const std::vector<float> &                  particle_data() const;

        std::vector<Renderable<Rectangle>> &  rectangles();
        std::vector<Renderable<Box>> &        boxes();
        std::vector<Renderable<Sphere>> &     spheres();
        std::vector<Renderable<StaticMesh>> & meshes();
        std::vector<Line> &                   lines();
        std::vector<float> &                  particle_data();

    private:
        std::vector<Renderable<Rectangle>>  _rectangles;
        std::vector<Renderable<Box>>        _boxes;
        std::vector<Renderable<Sphere>>     _spheres;
        std::vector<Renderable<StaticMesh>> _meshes;
        std::vector<Line>                   _lines;
        std::vector<float>                  _particle_data;
    };

    inline void CommandBuffer::clear()
    {
        _rectangles.clear();
        _boxes.clear();
        _spheres.clear();
        _meshes.clear();
        _lines.clear();
        _particle_data.clear();
    }

    inline const std::vector<Renderable<Rectangle>> & CommandBuffer::rectangles() const
    {
        return _rectangles;
    }

    inline const std::vector<Renderable<Box>> & CommandBuffer::boxes() const
    {
        return _boxes;
    }

    inline const std::vector<Renderable<Sphere>> & CommandBuffer::spheres() const
    {
        return _spheres;
    }

    inline const std::vector<Renderable<StaticMesh>> & CommandBuffer::meshes() const
    {
        return _meshes;
    }

    inline const std::vector<Line> & CommandBuffer::lines() const {
        return _lines;
    }

    inline const std::vector<float> & CommandBuffer::particle_data() const
    {
        return _particle_data;
    }

    inline std::vector<Renderable<Rectangle>> & CommandBuffer::rectangles()
    {
        return _rectangles;
    }

    inline std::vector<Renderable<Box>> & CommandBuffer::boxes()
    {
        return _boxes;
    }

    inline std::vector<Renderable<Sphere>> & CommandBuffer::spheres()
    {
        return _spheres;
    }

    inline std::vector<Renderable<StaticMesh>> & CommandBuffer::meshes()
    {
        return _meshes;
    }

    inline std::vector<Line> & CommandBuffer::lines()
    {
        return _lines;
    }

    inline std::vector<float> & CommandBuffer::particle_data()
    {
        return _particle_data;
    }

    template<typename Shape>
    inline void CommandBuffer::push_renderable(const Renderable <Shape> & renderable)
    {
        static_assert(!std::is_same<Shape, Shape>::value, "Shape not supported");
    }

    template <>
    inline void CommandBuffer::push_renderable(const Renderable<Box> & renderable)
    {
        _boxes.push_back(renderable);
    }

    template <>
    inline void CommandBuffer::push_renderable(const Renderable<Rectangle> & renderable)
    {
        _rectangles.push_back(renderable);
    }

    template <>
    inline void CommandBuffer::push_renderable(const Renderable<Sphere> &renderable)
    {
        _spheres.push_back(renderable);
    }

    template <>
    inline void CommandBuffer::push_renderable(const merely3d::Renderable<StaticMesh> &renderable)
    {
        _meshes.push_back(renderable);
    }

    inline void CommandBuffer::push_line(const Line &line)
    {
        _lines.push_back(line);
    }

    inline void CommandBuffer::push_particle(const Particle & particle)
    {
        const auto & p = particle;
        const auto offset = _particle_data.size();
        _particle_data.resize(offset + 7);
        _particle_data[offset + 0] = p.position.x();
        _particle_data[offset + 1] = p.position.y();
        _particle_data[offset + 2] = p.position.z();
        _particle_data[offset + 3] = p.color.r();
        _particle_data[offset + 4] = p.color.g();
        _particle_data[offset + 5] = p.color.b();
        _particle_data[offset + 6] = p.radius;
    }
}


text:
// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

#include <boost/hana/assert.hpp>
#include <boost/hana/integral_constant.hpp>
#include <boost/hana/less.hpp>
#include <boost/hana/lexicographical_compare.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/type.hpp>
namespace hana = boost::hana;

int main() {
    // works with elements whose `less` does not return a Constant
    {
        constexpr auto xs = hana::make_tuple(1, 2, 3, 4);
        constexpr auto ys = hana::make_tuple(1, 6, 3, 4);
        static_assert(hana::lexicographical_compare(xs, ys), "");
    }

    // and with those that do
    {
        auto xs = hana::make_tuple(hana::int_c<1>, hana::int_c<2>, hana::int_c<3>);
        auto ys = hana::make_tuple(hana::int_c<1>, hana::int_c<5>, hana::int_c<3>);
        BOOST_HANA_CONSTANT_CHECK(hana::lexicographical_compare(xs, ys));
    }

    // it also accepts a custom predicate
    {
        auto xs = hana::make_tuple(hana::type_c<int>, hana::type_c<char>, hana::type_c<void*>);
        auto ys = hana::make_tuple(hana::type_c<int>, hana::type_c<long>, hana::type_c<void*>);
        BOOST_HANA_CONSTANT_CHECK(
            hana::lexicographical_compare(xs, ys, [](auto t, auto u) {
                return hana::sizeof_(t) < hana::sizeof_(u);
            })
        );
    }
}

max_stars_repo_name: nxplatform/nx-mobile

max_issues_repo_name: nxplatform/nx-mobile

max_forks_repo_name: nxplatform/nx-mobile


text:
/*
   Copyright 2012 Technical University of Denmark, DTU Compute.
   All rights reserved.

   This file is part of the Patmos simulator.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

      1. Redistributions of source code must retain the above copyright notice,
         this list of conditions and the following disclaimer.

      2. 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.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 HOLDER 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.

   The views and conclusions contained in the software and documentation are
   those of the authors and should not be interpreted as representing official
   policies, either expressed or implied, of the copyright holder.
 */

//
// Main file of a simple Patmos disassembler.
//

#include "basic-types.h"
#include "decoder.h"
#include "instruction.h"
#include "streams.h"
#include "symbol.h"
#include "loader.h"
#include "decoder.h"

#include <boost/format.hpp>

#include <fstream>
#include <iostream>

class instruction_printer_t : public patmos::decoder_callback_t
{
private:
  patmos::uword_t num_errors;
  std::ostream &out;

public:
  instruction_printer_t(std::ostream &out) : num_errors(0), out(out) {}

  patmos::uword_t get_errors() { return num_errors; }

  virtual int process_bundle(patmos::uword_t addr,
                             patmos::instruction_data_t *bundle,
                             unsigned slots, patmos::symbol_map_t &symbols)
  {
    if (slots == 0) {
      num_errors ++;
      return 1;
    }
    // decode bundle
    out << boost::format("  0x%1$08x:  ") % addr;

    for (unsigned int i = 0; i < slots; i++) {
      if (i > 0) out << " || ";
      bundle[i].print(out, symbols);
    }
    out << ";\n";

    return 0;
  }
};

int main(int argc, char **argv)
{
  patmos::decoder_t padasm;
  patmos::symbol_map_t symbols;
  patmos::section_list_t text;

  patmos::uword_t words = 0;
  int retcode = 0;

  // check arguments
  if (argc != 3)
  {
    std::cerr << "Usage: padasm <input> <output>\n";
    return 1;
  }

  // open streams
  try
  {
    std::istream &in = *patmos::get_stream<std::ifstream>(argv[1], std::cin);
    std::ostream &out = *patmos::get_stream<std::ofstream>(argv[2], std::cout);

    patmos::loader_t *loader = patmos::create_loader(in);
    loader->load_symbols(symbols, text);

    patmos::decoder_t decoder;
    instruction_printer_t printer(out);

    for (patmos::section_list_t::iterator t = text.begin(), te = text.end();
         t != te; t++)
    {
      int rc = decoder.decode(*loader, *t, symbols, printer);
      if (rc != 0) retcode = rc;
      words += t->size;
    }

    // some status messages
    std::cerr << boost::format("Disassembled: %1% words\nErrors : %2%\n")
              % words % printer.get_errors();

    delete loader;

    // free streams
    patmos::free_stream(&in);
    patmos::free_stream(&out);
  }
  catch(std::ios_base::failure f)
  {
    std::cerr << f.what() << "\n";
    return -1;
  }

  return retcode;
}

ext: cc

max_stars_repo_name: laurenkosub/wormhole-noc

max_issues_repo_name: laurenkosub/wormhole-noc

max_forks_repo_name: laurenkosub/wormhole-noc


text:
/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE symmetric_matrix_test
#include <boost/test/unit_test.hpp>
#include <votca/xtp/symmetric_matrix.h>
#include <iostream>

using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(symmetric_matrix_test)

BOOST_AUTO_TEST_CASE(Constructor_test) {
  int dim=3;
Eigen::MatrixXd test=Eigen::MatrixXd::Random(dim,dim);
 Eigen::MatrixXd trans=test.transpose();
test+=trans;
Symmetric_Matrix sym=Symmetric_Matrix(test);

Eigen::MatrixXd back=Eigen::MatrixXd::Zero(dim,dim);

sym.AddtoEigenMatrix(back);

bool check_matrices=back.isApprox(test,0.000001);
if(!check_matrices){
   std::cout<<sym<<std::endl;
  std::cout<<test<<std::endl;
  std::cout<<back<<std::endl;
}
BOOST_CHECK_EQUAL(check_matrices, 1);
}

BOOST_AUTO_TEST_CASE(Add_test) {

   int dim=3;
Eigen::MatrixXd test=Eigen::MatrixXd::Random(dim,dim);
 Eigen::MatrixXd trans=test.transpose();
test+=trans;
Symmetric_Matrix sym=Symmetric_Matrix(test);

Eigen::MatrixXd rand=Eigen::MatrixXd::Random(dim,dim);

Eigen::MatrixXd result=rand+2*test;

sym.AddtoEigenMatrix(rand,2.0);

bool check_matrices2=rand.isApprox(result,0.000001);
if(!check_matrices2){
  std::cout<<test<<std::endl;
  std::cout<<sym<<std::endl;
  std::cout<<rand<<std::endl;
  std::cout<<result<<std::endl;
}
BOOST_CHECK_EQUAL(check_matrices2, 1);

}

BOOST_AUTO_TEST_CASE(FullMatrix_test) {

int dim=3;
Eigen::MatrixXd test=Eigen::MatrixXd::Random(dim,dim);
 Eigen::MatrixXd trans=test.transpose();
test+=trans;
Symmetric_Matrix sym=Symmetric_Matrix(test);
Eigen::MatrixXd result=sym.FullMatrix();
bool check_matrices=test.isApprox(result,0.000001);

BOOST_CHECK_EQUAL(check_matrices, 1);
}

BOOST_AUTO_TEST_CASE(TraceofProd_test) {

   int dim=3;
Eigen::MatrixXd test=Eigen::MatrixXd::Random(dim,dim);
 Eigen::MatrixXd trans=test.transpose();
test+=trans;
Symmetric_Matrix sym1=Symmetric_Matrix(test);

Eigen::MatrixXd test2=Eigen::MatrixXd::Random(dim,dim);
 Eigen::MatrixXd trans2=test2.transpose();
test2+=trans2;
Symmetric_Matrix sym2=Symmetric_Matrix(test2);

double ref=test2.cwiseProduct(test).sum();
double result=sym1.TraceofProd(sym2);

bool check=std::abs(ref-result)<1e-7;
if(!check){
  std::cout<<"Ref: "<<ref<<" Sym: "<<result<<std::endl;
}

BOOST_CHECK_EQUAL(check, 1);

}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: mbarbry/xtp

max_issues_repo_name: mbarbry/xtp

max_forks_repo_name: mbarbry/xtp


text:
/*
 *  compile:

 g++-5 -std=c++11 -O2 -o multi-thread-pcre.bin multi-thread-pcre.cpp -lpthread \
 -lre2 -lboost_date_time -lpcre

 */

/*
 * ref: https://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm
 */

/*
 * 1. For std::regex, using -O2 can achive 10X faster performance than using -O0
 * 2. Both std::regex and re2:regex can scall well in multi-thread, but re2::regex is much faster than std::regex
 * 3. If we using 96 cores, the re2 throughput can reach around 20GB/s.
 * 4. Performance numbers:
 *	Uing 1 core
 *		-- re2: 0.59 GB/s
 *		-- std::regex: 0.003 GB/s (using -O0)
 *		-- std::regex: 0.03 GB/s (using -O2)
 *	Using 5 cores
 *		-- re2: 2.2 GB/s
 *		-- std::regex: 0.014 GB/s (using -O0)
 *		-- std::regex: 0.14 GB/s (using -O2)
 *	Using 10 cores
 *		-- re2: 3.5 GB/s
 *		-- std::regex: 0.028 GB/s (using -O0)
 *		-- std::regex: 0.28 GB/s (using -O2)
 */

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
#include <fstream>
//#include <boost/regex.hpp>
#include <re2/re2.h>
#include "boost/date_time/posix_time/posix_time.hpp"
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <string>
#include <regex>
//#include <boost/regex.hpp>
#include <pcre.h>

using namespace std;
using namespace boost::posix_time;

#define NUM_THREADS     24

void *wait(void *t)
{
   int i;
   long tid;

   tid = (long)t;

   sleep(1);
   cout << "Sleeping in thread " << endl;
   cout << "Thread with id : " << tid << "  ...exiting " << endl;
   pthread_exit(NULL);
}

void * pcre_regex(void * t){

	pcre *reCompiled;
	pcre_extra *pcreExtra;
	int pcreExecRet;
	int subStrVec[30];
	const char *pcreErrorStr;
	int pcreErrorOffset;
	char *aStrRegex;
	const char *psubStrMatchStr;
	int j;
	int count = 0;
	char * testStrings = (char *)t;

	//aStrRegex = "\\d\\d\\d\\d";
	aStrRegex = (char *)"\\d\\d\\d\\d";
	//std::cout << "Regex to use: " << aStrRegex << std::endl;

	// First, the regex string must be compiled.
	reCompiled = pcre_compile(aStrRegex, 0, &pcreErrorStr, &pcreErrorOffset, NULL);

	// pcre_compile returns NULL on error, and sets pcreErrorOffset & pcreErrorStr
	if(reCompiled == NULL) {
		std::cout << "ERROR: Could not compile " << aStrRegex << " " << pcreErrorStr << std::endl;
		exit(1);
	}

	// Optimize the regex
	pcreExtra = pcre_study(reCompiled, 0, &pcreErrorStr);

	/* pcre_study() returns NULL for both errors and when it can not optimize the regex.  The last argument is how one checks for
	   errors (it is NULL if everything works, and points to an error string otherwise. */
	if(pcreErrorStr != NULL) {
		std::cout << "ERROR: Could not study " << aStrRegex << " " << pcreErrorStr << std::endl;
		exit(1);
	}

	int subject_length = strlen(testStrings);
	int start_offset = 0;

	/* find all matched substring*/
	while (1) {
		//std::cout << "string " << testStrings << std::endl;

		pcreExecRet = pcre_exec(reCompiled,
				pcreExtra,
				testStrings,
				subject_length,
				start_offset,                      // Start looking at this point
				0,                      // OPTIONS
				subStrVec,              //subStrVec[0] is the position of the first matched substring
				30);                    // Length of subStrVec
		//std::cout << "pcreExecRet is:" << pcreExecRet << std::endl;

		/* no matched string*/
		if(pcreExecRet < 0) {
			//std::cout << "NO match" << std::endl;
			//return 0;
			goto out;
		} else {
			//printf("Result: We have a match!\n");
			//std::cout << "Result: We have a match!" << std::endl;
			count += pcreExecRet;
//			printf("submatches %d. len %d \n", pcreExecRet, subStrVec[1] -subStrVec[0]);

#if 1
			// PCRE contains a handy function to do the above for you:
			for(int i=0; i<pcreExecRet; i++) {
/*
				char *substring_start = testStrings + subStrVec[2*i];
				int substring_length = subStrVec[2*i+1] - subStrVec[2*i];
*/

//				printf("%2d: %.*s\n", i, substring_length, substring_start);

				pcre_get_substring(testStrings, subStrVec, pcreExecRet, i, &(psubStrMatchStr));
				std::cout << "matched string: " << psubStrMatchStr << std::endl;
			}
#endif

			//subStrVec[0] is the position of matched substring
//			std::cout << "subStrVec: " << (testStrings + subStrVec[0]) << std::endl;

//			testStrings += subStrVec[0];
			start_offset = subStrVec[1];
//			testStrings += strlen(psubStrMatchStr);

			// Free up the substring
//			pcre_free_substring(psubStrMatchStr);
		}
		//std::cout << std::endl;
	}
out:
	//printf("done. count =%d\n", count);

	// Free up the regular expression.
	pcre_free(reCompiled);

	// Free up the EXTRA PCRE value (may be NULL at this point)
	if(pcreExtra != NULL) {
#ifdef PCRE_CONFIG_JIT
		pcre_free_study(pcreExtra);
#else
		pcre_free(pcreExtra);
#endif
	}
        std::cout << "cout is " << count << std::endl;
	pthread_exit(NULL);
}

void * re2_regex(void * t){
	char *buff = (char *)t;
	std::string matched;
	RE2 re("(\\d\\d\\d\\d)");
	//RE2 re("(((http[s]{0,1}|ftp)://)[a-zA-Z0-9\\.\\-]+\\.([a-z]|[A-Z]|[0-9]|[/.]|[~]|[-])*)");
	int count = 0;
	re2::StringPiece input(buff);
	while(RE2::FindAndConsume(&input, re, &matched)) {
		count ++;
	}
	//std::cout << "one re2_regex thread finished, count is" << count << std::endl;
	pthread_exit(NULL);
}

void * std_regex(void * t){
	char * buff = (char *)t;
	std::string str(buff);
	std::regex ex("(\\d\\d\\d\\d)");
	std::smatch res;
	int count = 0;
	std::string::const_iterator searchStart(str.cbegin());
	while( std::regex_search(searchStart, str.cend(), res, ex)){
		count ++;
		searchStart += res.position() + res.length();
	}
	//std::cout << "one std_regex thread finished, count is" << count << std::endl;
	pthread_exit(NULL);
}

void * std_regex_2(void * t){
	char * buff = (char *)t;
	std::string str(buff);
	std::regex ex("(\\d\\d\\d\\d)");

	std::sregex_iterator it(str.begin(), str.end(), ex);
	std::sregex_iterator reg_end;
	int count = 0;
	for (; it != reg_end; ++it) {
		count ++;
	}
	std::cout << "one std_regex thread finished, count is" << count << std::endl;
	pthread_exit(NULL);
}

void * str_str(void * t){
	char * buff = (char *)t;
	char * p = strstr(buff, "very");
	int count = 0;

	while(p != NULL){
		p = p + 4;
		count ++;
		p = strstr(p, "very");
	}

	//std::cout << "one str_str thread finished, count is" << count << std::endl;
	pthread_exit(NULL);
}

int main ()
{
	int rc;
	int i;
	pthread_t threads[NUM_THREADS];
	pthread_attr_t attr;
	void *status;

//	int fd = open("/tmp/large1.txt", O_RDONLY); //100MB
//	int fd = open("/shared/stream_data_set/movies.txt", O_RDONLY);
//	int fd = open("/tmp/1g.txt.part00", O_RDONLY);
//	int fd = open("/tmp/movies.txt.part00.part00.part00.part00.part00.part00", O_RDONLY);

	//int fd = open("/tmp/1gb.txt", O_RDONLY);
	int fd = open("/tmp/10mb.txt", O_RDONLY);
//	int fd = open("/ssd/word_10MB.txt", O_RDONLY);
//	int fd = open("/home/xzl/tmp/word_10MB.txt", O_RDONLY);

	struct stat finfo;
	if(fd < 0)
		std::cout << "open fail!" << std::endl;
	fstat(fd, &finfo);
	char *buff = (char *) malloc(finfo.st_size);
	int size = pread(fd, buff, finfo.st_size, 0);
	std::cout << "Input size: "<< size/1024/1024 << "MB" << std::endl;

	// Initialize and set thread joinable
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	while(1){
		//start time
		ptime begin = boost::posix_time::microsec_clock::local_time();

		for( i=0; i < NUM_THREADS; i++ ){
			//cout << "main() : creating thread, " << i << endl;
			//rc = pthread_create(&threads[i], &attr, wait, (void *)buff );
			//rc = pthread_create(&threads[i], &attr, re2_regex, (void *)buff );
			//rc = pthread_create(&threads[i], &attr, std_regex, (void *)buff );
			//rc = pthread_create(&threads[i], &attr, str_str, (void *)buff );
			//rc = pthread_create(&threads[i], &attr, std_regex_2, (void *)buff );
			rc = pthread_create(&threads[i], &attr, pcre_regex, (void *)buff );
			if (rc){
				cout << "Error:unable to create thread," << rc << endl;
				exit(-1);
			}
		}

		// free attribute and wait for the other threads
		pthread_attr_destroy(&attr);
		for( i=0; i < NUM_THREADS; i++ ){
			rc = pthread_join(threads[i], &status);
			if (rc){
				cout << "Error:unable to join," << rc << endl;
				exit(-1);
			}
			//cout << "Main: completed thread id :" << i ;
			//cout << "  exiting with status :" << status << endl;
		}

		//end time
		ptime end  = boost::posix_time::microsec_clock::local_time();
		boost::posix_time::time_duration diff = end - begin;
		double interval_sec = (double) diff.total_milliseconds() / 1000;
		//std::cout << "interval_sec is " << interval_sec << std::endl;
		//std::cout << "size * NUM_THREAD is " << (unsigned long long ) (size *  NUM_THREADS) << std::endl;
		//std::cout << "Bandwidth is: " << (size * NUM_THREADS) / interval_sec / (1024*1024*1024)<< "GB/s" << std::endl;
		std::cout << "Bandwidth is: " << NUM_THREADS * (size / interval_sec / (1024*1024*1024))<< "GB/s" << std::endl;
		//std::cout << "Bandiwdth is " << (((double)((size * NUM_THREADS)/(1024 * 1024 * 1024)) * 1000) / (double) diff.total_milliseconds()) << " GB/s" << std::endl;

	} //end while(1)

	cout << "Main: program exiting." << endl;
	pthread_exit(NULL);
}

max_stars_repo_name: chenzongxiong/streambox

max_issues_repo_name: chenzongxiong/streambox

max_forks_repo_name: chenzongxiong/streambox