text:
//          Copyright(C) Rishabh Arora 2017.
// Distributed under 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)

/** \mainpage BOOST uBLAS Dataframe
 *
 *
 * \section main_classes Main classes
 *
 * - \link #boost::numeric::ublas::data_frame                    data_frame \endlink
 * - \link #boost::numeric::ublas::df_column            df_column \endlink
 * - \link #boost::numeric::ublas::data_frame_range                data_frame_range \endlink
 * - \link #boost::numeric::ublas::data_frame_slice               data_frame_slice \endlink
 * - \link #boost::numeric::ublas::data_frame_indirect            data_frame_indirect \endlink
 */

#ifndef _BOOST_UBLAS_DATA_FRAME_
#define _BOOST_UBLAS_DATA_FRAME_

#include <string>
#include <map>
#include <boost/variant.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/for_each_product.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <algorithm>
#include "./data_frame_exceptions.hpp"
#include "./vector_proxy.cpp"

// Basic allowed types for vectors
#define INNER_TYPE \
(bool) \
(char) (unsigned char) \
(short) (unsigned short) \
(int) (unsigned int) \
(long) (unsigned long) \
(long long) (unsigned long long) \
(float) (double) (long double) \
(std::string) (std::string*) \

// Vector allowed types for columns
/* WARNING: we can't use all the vector types for the time being because boost::variant has a limit
 * of 20 different types because of another limitation in boost MPL
#define VECTOR_TYPE (scalar_vector)(unit_vector)(vector)(zero_vector)
*/

#define VECTOR_TYPE (vector)

// The following types will be integrated later
/*bounded_vector
compressed_vector
coordinate_vector
c_vector
mapped_vector
mapped_vector_of_mapped_vector
matrix_column_vector
matrix_row_vector
matrix_vector_indirect
matrix_vector_range
matrix_vector_slice
vector_indirect
vector_of_vector
vector_range
vector_slice
*/
/// \PreProcessing for the inner and outer types
// Expand macro
#define VMACRO(r, product) (ublas::BOOST_PP_SEQ_ELEM(0, product)<BOOST_PP_SEQ_ELEM(1, product)>)

// Make a sequence of all types
#define ALL_VARIANT_TYPES BOOST_PP_SEQ_FOR_EACH_PRODUCT(VMACRO, (VECTOR_TYPE) (INNER_TYPE))
// Variant of column types
#define COLUMN_TYPES BOOST_PP_SEQ_ENUM(ALL_VARIANT_TYPES)
// Variant of the inner types
#define COLUMN_DATA_TYPES BOOST_PP_SEQ_ENUM(INNER_TYPE)

namespace boost { namespace numeric { namespace ublas {

	// temporary vectors to be used by binary operators.
	vector < bool > A0; vector < char > A1; vector < unsigned char > A2;
	vector < short > A3; vector < unsigned short > A4; vector < int > A5; vector < unsigned int > A6;
	vector < long > A7; vector < unsigned long > A8; vector < long long > A9; vector < unsigned long long > A10;
	vector < float > A11; vector < double > A12; vector < long double > A13;
	vector < std::string > A14; vector < std::string* > A15;

	class print_data_frame_column: public boost::static_visitor<void> {
	public:
		template < class T >
		void operator () (const T& x_) const {
			for(size_t i = 0; i < x_.size(); ++i) {
				std::cout << x_ (i) << ' ';
			}
			std::cout << std::endl;
			return;
		}
	};

	//! Represents the column of a dataframe.
	/*! Internally represented by boost::variant < COLUMN_TYPES > .
	 *	Allowed types are: int, double, char, std::string...... (specified in INNER_TYPE).
	 */
	class df_column {
	public:
		//! \brief add 2 df_columns of same type.
		friend df_column operator + (df_column& a, df_column& b);

		//! \brief subtract 2 df_columns of same type.
		friend df_column operator - (df_column& a, df_column& b);

		//! \brief add a constant value val to a column of same type.
		template < class T > friend df_column operator + (df_column& a, const T& val);

		//! \brief subtract a constant value val from a column of same type.
		template < class T > friend df_column operator - (df_column& a, const T& val);

		//! \brief multiply a constant value val to a column of same type.
		template < class T > friend df_column operator * (df_column& a, const T& val);

		// ----------------------------
		// Construction and Destruction
		// ----------------------------

		/*! \brief Constructor of df_column.
		 *  By default \c size() == 0.
		 *  type of the column is unset.
		 */
		BOOST_UBLAS_INLINE
		df_column ():
			size_ (0) {}

		/*! \brief Copy Constructor of df_column.
		 *	Copies the vector into data_, T becomes the type of the column.
		 *  \param const lvalue reference to a vector of some type T.
		 */
		BOOST_UBLAS_INLINE
		template < class T >
		df_column (const vector<T>& data) :
			data_ (data),
			size_ (data.size()) {}

		/*! \brief Copy Constructor of df_column.
		 *	Copies the col into self.
		 *  \param const lvalue reference to a df_column.
		 */
		BOOST_UBLAS_INLINE
		df_column (const df_column& col) :
			data_ (col.data()),
			size_ (col.size()) {}

		/*! \brief Move Constructor of a df_column.
		 *	Moves the vector into data_, T becomes the type of the column.
		 *  \param rvalue reference to a vector <T>, T: type of vector.
		 */
		BOOST_UBLAS_INLINE
		template < class T >
		df_column (const vector <T>&& data) {
			data_ = std::move(data);
			size_ = std::move(size_);
		}

		/*! \brief Move Constructor of df_column.
		 *	Moves the col into self.
		 *  \param rvalue reference to a df_column.
		 */
		BOOST_UBLAS_INLINE
		df_column (const df_column&& col) {
			data_ = std::move(col.data());
			size_ = std::move(col.size());
		}

		//! \brief Destructor of df_column.
		BOOST_UBLAS_INLINE
		~df_column() {}

		// --------------------
		// Assignment Operators
		// --------------------

		/*! \brief Copy Assignment Operator of a df_column.
		 *	Copies the vector into data_, T becomes the type of the column.
		 *  \param const lvalue reference to a vector <T>, T: type of vector.
		 */
		template < class T >
		BOOST_UBLAS_INLINE
		df_column& operator = (const vector<T>& data) {
			data_ = data;
			size_ = data.size();
			return *this;
		}

		/*! \brief Copy Assignment operator of df_column.
		 *	Copies the col into self.
		 *  \param const lvalue reference to a df_column.
		 */
		BOOST_UBLAS_INLINE
		df_column& operator = (const df_column& col) {
			data_  = col.data();
			size_  = col.size();
			return *this;
		}

		/*! \brief Move Assignemnt Operator of a df_column.
		 *	Moves the vector into data_, T becomes the type of the column.
		 *  \param rvalue reference to a vector <T>, T: type of vector.
		 */
		template < class T >
		BOOST_UBLAS_INLINE
		df_column& operator = (const vector <T>&& data) {
			data_ = std::move(data);
			size_ = std::move(size_);
			return *this;
		}

		/*! \brief Move Assignment operator of df_column.
		 *	Copies the col into self.
		 *  \param rvalue reference to a df_column.
		 */
		BOOST_UBLAS_INLINE
		df_column& operator = (const df_column&& col) {
			data_ = std::move(col.data());
			size_ = std::move(col.size());
			return *this;
		}

		// ----------------------
		// Manipulation Operators
		// ----------------------

		/*! \brief Addition to df_column.
		 *	Adds x to self if the \c x.type() == \c self.type()  and \c x.size() == \c self.size().
		 *  \param lvalue reference to a df_column.
		 */
		BOOST_UBLAS_INLINE
		df_column operator += (df_column& x) {
			(*this) = (*this) + x;
			return *this;
		}

		/*! \brief Subtraction from df_column.
		 *	Subtracts x from self if the \c x.type() == \c self.type()  and \c x.size() == \c self.size().
		 *  \param lvalue reference to a df_column.
		 */
		BOOST_UBLAS_INLINE
		df_column operator -= (df_column& x) {
			return (*this) = (*this) - x;
		}

		/*! \brief Addition to df_column.
		 *	Adds val to self if the \c x.type() == T.
		 *  \param const lvalue reference to a value.
		 */
		BOOST_UBLAS_INLINE
		template < class T >
		df_column operator += (const T& val) {
			return (*this) = (*this) + val;
		}

		/*! \brief Subtraction from df_column.
		 *	Subtracts val from self if the \c x.type() == T.
		 *  \param const lvalue reference to a value.
		 */
		BOOST_UBLAS_INLINE
		template < class T >
		df_column operator -= (const T& val) {
			return (*this) = (*this) - val;
		}

		/*! \brief Multiplication to df_column.
		 *	Multiplies val to self if the \c x.type() == T.
		 *  \param const lvalue reference to a value.
		 */
		BOOST_UBLAS_INLINE
		template < class T >
		df_column operator *= (const T& val) {
			return (*this) = (*this) * val;
		}

		// ---------
		// Accessors
		// ---------

		//! \brief Returns the size of the column vector.
		BOOST_UBLAS_INLINE
		const size_t size() const {
			return size_;
		}

		//! \brief Returns the 0 - based index of the type of column vector in boost::variant < COLUMN_TYPES >.
		BOOST_UBLAS_INLINE
		const short type() const {
			return data_.which();
		}

		// -----------------
		// Storage Accessors
		// -----------------

		//! \brief Returns the data_ variable.
		BOOST_UBLAS_INLINE
		const boost::variant < COLUMN_TYPES > data() const {
			return data_;
		}

		/*! \brief Returns the df_column as vector<T>.
 		 *  T should be same as the type of the df_column.
 		 */
		template < class T >
		BOOST_UBLAS_INLINE
		vector<T>& get() {
			return boost::get<vector<T>>(data_);
		}

		/*! \brief Returns the i-th element of df_column.
 		 *  T should be same as the type of the df_column.
 		 */
		template < class T >
		BOOST_UBLAS_INLINE
		T& eval(const size_t& i) {
			return boost::get<vector<T>>(data_)(i);
		}

		//! \brief Print the contents of df_column in a single line.
		BOOST_UBLAS_INLINE
		void print() {
			boost::apply_visitor (print_data_frame_column{}, data_);
		}

		// ---------------------
		// Statistical Summaries
		// ---------------------

		//! \brief Returns the minimum element of the column vector.
		template < class T1, class T2 >
		BOOST_UBLAS_INLINE
		T2 Min () {
			T2 Minimum = get<T1> ()(0);
			for(size_t i = 1; i < size_; ++i) {
				if (get <T1> ()(i) < Minimum) {
					Minimum = (T2)get<T1>()(i);
				}
			}
			return Minimum;
		}

		//! \brief Returns the maximum element of the column vector.
		template < class T1, class T2>
		BOOST_UBLAS_INLINE
		T2 Max () {
			T2 Maximum = get<T1>()(0);
			for(size_t i = 1; i < size_; ++i) {
				if (get<T1>()(i) > Maximum) {
					Maximum = (T2) get<T1>()(i);
				}
			}
			return Maximum;
		}

		//! \brief Returns the mean of the column vector.
		template < class T1, class T2 >
		BOOST_UBLAS_INLINE
		T2 Mean() {
			T2 sum = 0;
			for(size_t i = 0; i < size_; ++i) {
				sum += (T2) get<T1>()(i);
			}
			return (T2) (sum / size_);
		}

		//! \brief Returns the median element of the column vector.
		template < class T1, class T2 >
		BOOST_UBLAS_INLINE
		T2 Median() {
			vector<T1> v = get<T1>();
			std::sort(v.begin(), v.end());
			if (v.size() & 1) {
				return (T2)v[v.size()/2];
			}
			else {
				return ((T2)(v[v.size()/2-1] + v[v.size()/2]) / 2);
			}
		}

		//! \brief Prints Minimum, Maximum, Mean, Median of a column vector.
		BOOST_UBLAS_INLINE
		template <class T1, class T2>
		void summary() {
			std::cout << "Min. : " << Min <T1, T2>()  << ", ";
			std::cout << "Max. : " << Max <T1, T2>()  << ", ";
			std::cout << "Mean : " << Mean <T1, T2>() << ", ";
			std::cout << "Median : " << Median <T1, T2>() << "  ";
			std::cout << std::endl;
		}

	private:
		//! \brief Stores the data in df_column.
		boost::variant < COLUMN_TYPES > data_;
		//! \brief Stores the size of the column vector.
		size_t size_;
	};

	//! \brief Returns the negation of the column if exists.
	BOOST_UBLAS_INLINE
	df_column operator - (df_column& a) {
		df_column X;
		switch (a.type()) {
			case 0:
				A0 = -a.get<bool>();
				return X = A0;
			case 3:
				A3 = -a.get<short>();
				X = A3;
				return X;
			case 4:
				A4 = -a.get<unsigned short>();
				X = A4;
				return X;
			case 5:
				A5 = -a.get<int>();
				X = A5;
				return X;
			case 6:
				A6 = -a.get<unsigned int>();
				X = A6;
				return X;
			case 7:
				A7 = -a.get<long>();
				X = A7;
				return X;
			case 8:
				A8 = -a.get<unsigned long>();
				X = A8;
				return X;
			case 9:
				A9 = -a.get<long long>();
				X = A9;
				return X;
			case 10:
				A10 = -a.get<unsigned long long>();
				X = A10;
				return X;
			case 11:
				A11 = -a.get<float>();
				X = A11;
				return X;
			case 12:
				A12 = -a.get<double>();
				X = A12;
				return X;
			case 13:
				A13 = -a.get<long double>();
				X = A13;
				return X;
		}
	}

	//! \brief Returns a df_column as sum of 2 df_columns.
	BOOST_UBLAS_INLINE
	df_column operator + (df_column& a, df_column& b) {
		df_column X;
		switch (a.type()) {
			case 0:
				A0 = a.get<bool>() + b.get<bool>();
				X = A0;
				return X;
			case 3:
				A3 = a.get<short>() + b.get<short>();
				X = A3;
				return X;
			case 4:
				A4 = a.get<unsigned short>() + b.get<unsigned short>();
				X = A4;
				return X;
			case 5:
				A5 = a.get<int>() + b.get<int>();
				X = A5;
				return X;
			case 6:
				A6 = a.get<unsigned int>() + b.get<unsigned int>();
				X = A6;
				return X;
			case 7:
				A7 = a.get<long>() + b.get<long>();
				X = A7;
				return X;
			case 8:
				A8 = a.get<unsigned long>() + b.get<unsigned long>();
				X = A8;
				return X;
			case 9:
				A9 = a.get<long long>() + b.get<long long>();
				X = A9;
				return X;
			case 10:
				A10 = a.get<unsigned long long>() + b.get<unsigned long long>();
				X = A10;
				return X;
			case 11:
				A11 = a.get<float>() + b.get<float>();
				X = A11;
				return X;
			case 12:
				A12 = a.get<double>() + b.get<double>();
				X = A12;
				return X;
			case 13:
				A13 = a.get<long double>() + b.get<long double>();
				X = A13;
				return X;
		}
	}

	//! \brief Returns a df_column as difference of 2 df_columns.
	BOOST_UBLAS_INLINE
	df_column operator - (df_column& a, df_column& b) {
		df_column X;
		switch (a.type()) {
			case 0:
				A0 = a.get<bool>() - b.get<bool>();
				X = A0;
				return X;
			case 3:
				A3 = a.get<short>() - b.get<short>();
				X = A3;
				return X;
			case 4:
				A4 = a.get<unsigned short>() - b.get<unsigned short>();
				X = A4;
				return X;
			case 5:
				A5 = a.get<int>() - b.get<int>();
				X = A5;
				return X;
			case 6:
				A6 = a.get<unsigned int>() - b.get<unsigned int>();
				X = A6;
				return X;
			case 7:
				A7 = a.get<long>() - b.get<long>();
				X = A7;
				return X;
			case 8:
				A8 = a.get<unsigned long>() - b.get<unsigned long>();
				X = A8;
				return X;
			case 9:
				A9 = a.get<long long>() - b.get<long long>();
				X = A9;
				return X;
			case 10:
				A10 = a.get<unsigned long long>() - b.get<unsigned long long>();
				X = A10;
				return X;
			case 11:
				A11 = a.get<float>() - b.get<float>();
				X = A11;
				return X;
			case 12:
				A12 = a.get<double>() - b.get<double>();
				X = A12;
				return X;
			case 13:
				A13 = a.get<long double>() - b.get<long double>();
				X = A13;
				return X;
		}
	}

	//! \brief Returns a df_column as sum of a df_column and a constant value.
	BOOST_UBLAS_INLINE
	template < class T >
	df_column operator + (df_column& a, const T& val) {
		df_column X;
		for(size_t i = 0; i < a.size(); ++i) {
			switch (a.type()) {
				case 0:
					if (i == 0) {
						A0.resize(a.size());
					}
					A0(i) = a.get<bool>()(i) + val;
					if (i == a.size()-1) {
						X = A0;
						A0.resize(0);
						return X;
					}
				break;
				case 3:
					if (i == 0) {
						A3.resize(a.size());
					}
					A3(i) = a.get<short>()(i) + val;
					if (i == a.size()-1) {
						X = A3;
						A3.resize(0);
						return X;
					}
				break;
				case 4:
					if (i == 0) {
						A4.resize(a.size());
					}
					A4(i) = a.get<unsigned short>()(i) + val;
					if (i == a.size()-1) {
						X = A4;
						A4.resize(0);
						return X;
					}
				break;
				case 5:
					if (i == 0) {
						A5.resize(a.size());
					}
					A5(i) = a.get<int>()(i) + val;
					if (i == a.size()-1) {
						X = A5;
						A5.resize(0);
						return X;
					}
				break;
				case 6:
					if (i == 0) {
						A6.resize(a.size());
					}
					A6(i) = a.get<unsigned int>()(i) + val;
					if (i == a.size()-1) {
						X = A6;
						A6.resize(0);
						return X;
					}
				break;
				case 7:
					if (i == 0) {
						A7.resize(a.size());
					}
					A7(i) = a.get<long>()(i) + val;
					if (i == a.size()-1) {
						X = A7;
						A7.resize(0);
						return X;
					}
				break;
				case 8:
					if (i == 0) {
						A8.resize(a.size());
					}
					A8(i) = a.get<unsigned long>()(i) + val;
					if (i == a.size()-1) {
						X = A8;
						A8.resize(0);
						return X;
					}
				break;
				case 9:
					if (i == 0) {
						A9.resize(a.size());
					}
					A9(i) = a.get<long long>()(i) + val;
					if (i == a.size()-1) {
						X = A9;
						A9.resize(0);
						return X;
					}
				break;
				case 10:
					if (i == 0) {
						A10.resize(a.size());
					}
					A10(i) = a.get<unsigned long long>()(i) + val;
					if (i == a.size()-1) {
						X = A10;
						A10.resize(0);
						return X;
					}
				break;
				case 11:
					if (i == 0) {
						A11.resize(a.size());
					}
					A11(i) = a.get<float>()(i) + val;
					if (i == a.size()-1) {
						X = A11;
						A11.resize(0);
						return X;
					}
				break;
				case 12:
					if (i == 0) {
						A12.resize(a.size());
					}
					A12(i) = a.get<double>()(i) + val;
					if (i == a.size()-1) {
						X = A12;
						A12.resize(0);
						return X;
					}
				break;
				case 13:
					if (i == 0) {
						A13.resize(a.size());
					}
					A13(i) = a.get<long double>()(i) + val;
					if (i == a.size()-1) {
						X = A13;
						A13.resize(0);
						return X;
					}
				break;
			}
		}
	}

	//! \brief Returns a df_column as sum of a df_column and a constant value.
	BOOST_UBLAS_INLINE
	template < class T >
	df_column operator + (const T& val, df_column& a) {
		return a + val;
	}

	//! \brief Returns a df_column as difference of a df_column and a constant value.
	BOOST_UBLAS_INLINE
	template < class T >
	df_column operator - (df_column& a, const T& val) {
		return a + (-val);
	}

	//! \brief Returns a df_column as product of a df_column and a constant value.
	BOOST_UBLAS_INLINE
	template < class T >
	df_column operator * (df_column& a, const T& val) {
		df_column X;
		switch (a.type()) {
			case 0:
				A0 = a.get<bool>() * val;
				X = A0;
				return X;
			case 3:
				A3 = a.get<short>() * val;
				X = A3;
				return X;
			case 4:
				A4 = a.get<unsigned short>() * val;
				X = A4;
				return X;
			case 5:
				A5 = a.get<int>() * val;
				X = A5;
				return X;
			case 6:
				A6 = a.get<unsigned int>() * val;
				X = A6;
				return X;
			case 7:
				A7 = a.get<long>() * val;
				X = A7;
				return X;
			case 8:
				A8 = a.get<unsigned long>() * val;
				X = A8;
				return X;
			case 9:
				A9 = a.get<long long>() * val;
				X = A9;
				return X;
			case 10:
				A10 = a.get<unsigned long long>() * val;
				X = A10;
				return X;
			case 11:
				A11 = a.get<float>() * val;
				X = A11;
				return X;
			case 12:
				A12 = a.get<double>() * val;
				X = A12;
				return X;
			case 13:
				A13 = a.get<long double>() * val;
				X = A13;
				return X;
		}
	}

	//! \brief Returns a df_column as product of a df_column and a constant value.
	BOOST_UBLAS_INLINE
	template < class T >
	df_column operator * (const T& val, df_column& a) {
		return a * val;
	}

	//! \brief Returns \c true if \c y.size() == \c x.size() and \c y.get<T> == \c x.get<T>() else \c false
	BOOST_UBLAS_INLINE
	bool operator == (df_column& y, df_column& x) {
		if (y.type() != x.type()) {
			return false;
		}
		else if(y.size() != x.size()) {
			return false;
		}
		for(size_t i = 0; i < x.size(); ++i) {
			switch (y.type()) {
				case 0: if((y.get<bool>()(i) != x.get<bool>()(i)) ) {
					return false;
				}
				break;
				case 1: if((y.get<char>()(i) != x.get<char>()(i)) ) {
					return false;
				}
				break;
				case 2: if((y.get<unsigned char>()(i) != x.get<unsigned char>()(i)) ) {
					return false;
				}
				break;
				case 3: if((y.get<short>()(i) != x.get<short>()(i)) ) {
					return false;
				}
				break;
				case 4: if((y.get<unsigned short>()(i) != x.get<unsigned short>()(i)) ) {
					return false;
				}
				break;
				case 5: if((y.get<int>()(i) != x.get<int>()(i)) ) {
					return false;
				}
				break;
				case 6: if((y.get<unsigned int>()(i) != x.get<unsigned int>()(i)) ) {
					return false;
				}
				break;
				case 7: if((y.get<long>()(i) != x.get<long>()(i)) ) {
					return false;
				}
				break;
				case 8: if((y.get<unsigned long>()(i) != x.get<unsigned long>()(i)) ) {
					return false;
				}
				break;
				case 9: if((y.get<long long>()(i) != x.get<long long>()(i)) ) {
					return false;
				}
				break;
				case 10: if((y.get<unsigned long long>()(i) != x.get<unsigned long long>()(i)) ) {
					return false;
				}
				break;
				case 11: if((y.get<float>()(i) != x.get<float>()(i)) ) {
					return false;
				}
				break;
				case 12: if((y.get<double>()(i) != x.get<double>()(i)) ) {
					return false;
				}
				break;
				case 13: if((y.get<long double>()(i) != x.get<long double>()(i)) ) {
					return false;
				}
				break;
				case 14: if((y.get<std::string>()(i) != x.get<std::string>()(i)) ) {
					return false;
				}
				break;
				case 15: if((y.get<std::string*>()(i) != x.get<std::string*>()(i)) ) {
					return false;
				}
				break;
			}
		}
		return true;
	}

	//! \brief Returns \c false if \c y.size() == \c x.size() and \c y.get<T> == \c x.get<T>() else \c true
	BOOST_UBLAS_INLINE
	bool operator != (df_column& y, df_column& x) {
		return !(x == y);
	}

	BOOST_UBLAS_INLINE
	void remove (vector<std::string>& v, size_t idx) {
	    for (size_t i = idx; i < v.size() - 1; i++) {
	        v(i) = v(i + 1);
	    }
	    v.resize(v.size() - 1);
	    return;
	}

	//! Represents a dataframe.
	/*! Internally represented as map < string, df_column > and a vector < string> to store the headers.
	 *	Allowed types are: int, double, char, std::string...... (specified in INNER_TYPE).
	 */
	class data_frame {
	public:

		friend data_frame operator + (data_frame& a, data_frame& b);
		friend data_frame operator - (data_frame& a, data_frame& b);
		template < class T > friend data_frame operator + (data_frame& a, const T& val);
		template < class T > friend data_frame operator - (data_frame& a, const T& val);
		template < class T > friend data_frame operator * (data_frame& a, const T& val);

		// construction and destruction

		/*! \brief Constructor of data_frame.
		 *  By default \c nrow() == 0 and ncol() == 0.
		 *  type of the columns is unset.
		 */
		BOOST_UBLAS_INLINE
		data_frame () :
			ncol_ (0),
			nrow_ (0) {}

		/*! \brief Constructor of data_frame.
		 *  \param: const lvalue reference to headers(vector<std::string>).
		 *  \param: const lvalue reference to data(vector<df_column>).
		 */
		BOOST_UBLAS_INLINE
		data_frame (const vector<std::string>& headers, const vector<df_column>& data) {
			try {
				// exception for unequal headers and columns
				if (headers.size() != data.size()) {
					throw inconsistent_arguments();
				}

				ncol_ = headers.size();
				nrow_ = (ncol_ > 0) ? data(0).size() : 0;

				// exception for unequal no. of rows in data_frame columns
				for(size_t i = 1; i < ncol_; ++i) {
					if (data (i).size() != nrow_) {
						throw differing_rows();
					}
				}

				// initialise the data_ members
				column_headers_ = headers;

				for(size_t i = 0; i < ncol_; ++i) {
					// if a column_name already exists throw an error
					if ( (i != 0) && (data_.find(headers(i))) != data_.end())  {
						throw same_header();
					}
					data_.insert({headers(i), data(i)});
				}

			}
			catch (std::exception &e) {
				std::terminate();
			}
		}

		//! Destructor of data_frame.
		BOOST_UBLAS_INLINE
		~data_frame() {}

		// ----------------
		// column accessors
		// ----------------

		/*! \brief Access operator of data_frame.
		 *  creates the column (with the given header) if doesn't exist.
		 *  \param column_header to be accessed.
		 *  \return Requested df_column.
		 */
		BOOST_UBLAS_INLINE
		df_column& operator[](const std::string& header) {
			// given column name already exists
			// return the particular column
			if(data_.find(header) != data_.end()) {
				return data_ [header];
			}
			// create the column (will be furthur used by = operator in df_column)
			column_headers_.resize(ncol_ + 1);
			column_headers_(ncol_) = header;
			++ncol_;
			return data_ [header];
		}

		/*! \brief Access operator of data_frame.
		 *  creates the column (if index is valid and non-existent) if doesn't exist.
		 *  valid-index == \c ncol()
		 *  \param column-index to be accessed.
		 *  \return Requested df_column.
		 */
		BOOST_UBLAS_INLINE
		df_column& operator[] (const size_t& i) {
			try {
				// given column name already exists
				// return the particular column
				if(i < ncol_) {
					return data_ [column_headers_ (i)];
				}
				else if(i > ncol_) {
					throw holes();
				}
				// custom name if no name is set by default
				column_headers_.resize(ncol_ + 1);
				column_headers_(ncol_) = default_name(ncol_);
				++ncol_;
				return data_ [column_headers_(i)];
			}
			catch(std::exception &e) {
				std::terminate();
			}
		}

		/*! \brief Access operator of data_frame.
		 *  \param column_header to be accessed.
		 *  \param T(template parameter): type of the column data.
		 *  \return vector<T> version of the column.
		 */
		template < class T >
		BOOST_UBLAS_INLINE
		vector<T>& column (const std::string& header) {
			try {
				if (data_.find(header) == data_.end()) {
					throw undefined_column_header();
				}
				return data_[header].get<T>();
			}
			catch(std::exception& e) {
				std::terminate();
			}
		}

		/*! \brief Access operator of data_frame.
		 *  \param column index to be accessed.
		 *  \param T(template parameter): type of the column data.
		 *  \return vector<T> version of the column.
		 */
		template < class T >
		BOOST_UBLAS_INLINE
		vector<T>& column(const size_t& i) {
			return data_[column_headers_ (i)].get<T>();
		}

		// -------------
		// row accessors
		// -------------

		/*! brief Row Access operator of data_frame.
		 *  \param row index to be accessed.
		 *  Returns the row as vector < int, double ...... >.
		 */
		vector < boost::variant < COLUMN_DATA_TYPES > > operator () (const size_t row) {
			vector < boost::variant < COLUMN_DATA_TYPES > > ret(ncol_);
			for(size_t i = 0; i < ncol_; ++i) {
				switch((*this)[i].type()) {
					case 0:
						ret(i) = (*this)[i].eval<bool>(row);
						break;
					case 1:
						ret(i) = (*this)[i].eval<char>(row);
						break;
					case 2:
						ret(i) = (*this)[i].eval<unsigned char>(row);
						break;
					case 3:
						ret(i) = (*this)[i].eval<short>(row);
						break;
					case 4:
						ret(i) = (*this)[i].eval<unsigned short>(row);
						break;
					case 5:
						ret(i) = (*this)[i].eval<int>(row);
						break;
					case 6:
						ret(i) = (*this)[i].eval<unsigned int>(row);
						break;
					case 7:
						ret(i) = (*this)[i].eval<long>(row);
						break;
					case 8:
						ret(i) = (*this)[i].eval<unsigned long>(row);
						break;
					case 9:
						ret(i) = (*this)[i].eval<long long>(row);
						break;
					case 10:
						ret(i) = (*this)[i].eval<unsigned long long>(row);
						break;
					case 11:
						ret(i) = (*this)[i].eval<float>(row);
						break;
					case 12:
						ret(i) = (*this)[i].eval<double>(row);
						break;
					case 13:
						ret(i) = (*this)[i].eval<long double>(row);
						break;
					case 14:
						ret(i) = (*this)[i].eval<std::string>(row);
						break;
					case 15:
						ret(i) = (*this)[i].eval<std::string*>(row);
						break;
				}
			}
			return ret;
		}

		// ------------
		// erase column
		// ------------

		/*! \brief erase_column operator of data_frame.
		 *  erase the column(\c i) and restructure the data_frame.
		 *  \param column index to be erased.
		 */
		BOOST_UBLAS_INLINE
		void erase_column(const size_t i) {
			try {
				if ( (i >= column_headers_.size()) || (i < 0)) {
					throw bad_index();
				}
				/// \i is valid so delete the column[$i]
				data_.erase(column_headers_[i]);
				remove(column_headers_, i);
				--ncol_;
			}
			catch(std::exception &e){
				std::terminate();
			}
		}

		/*! \brief erase_column operator of data_frame.
		 *  erase the column(\c header) and restructure the data_frame.
		 *  \param column header to be accessed.
		 */
		BOOST_UBLAS_INLINE
		void erase_column(const std::string& header) {
			try {
				if (data_.find(header) == data_.end()) {
					throw undefined_column_header();
				}
				// name is valid so delete the column[$name]
				data_.erase(header);
				for(size_t i = 0; i < column_headers_.size(); i++) {
					if (header == column_headers_(i)) {
						remove(column_headers_, i);
						break;
					}
				}
				--ncol_;
			}
			catch(std::exception &e) {
				std::terminate();
			}
		}

		// ----------
		// add column
		// ----------

		/*! \brief add_column operator of data_frame.
		 *  adds column at the end of the data_frame columns.
		 *  \param column header
		 *  \param const lvalue reference to the column data in the form of df_column.
		 */
		BOOST_UBLAS_INLINE
		data_frame& add_column(const std::string& header, const df_column& col) {
			try {
				for(size_t i = 0; i < ncol_; ++i) {
					if (column_headers_(i) == header) {
						same_header();
					}
				}
				column_headers_.resize(ncol_ + 1);
				column_headers_ (ncol_) = header;
				++ncol_;
				data_ [header] = col;
				return *this;
			}
			catch (std::exception& e) {
				std::terminate();
			}
		}

		/*! \brief prints the data in the data_frame.
		 *  Print Format: [column header]: data(0) data(1) .......
		 */
		BOOST_UBLAS_INLINE
		void print() {
			for(size_t i = 0; i < ncol_; ++i) {
				std::cout << "[" << column_headers_(i) << "]" << ": ";
				data_ [column_headers_(i)].print();
			}
		}

		// -----------------
		// Storage Accessors
		// -----------------

		//! \brief Returns the headers of data_frame as vector<std::string>.
		BOOST_UBLAS_INLINE
		vector<std::string>& headers() {
			return column_headers_;
		}

		// ------------------------
		// Random Access Containers
		// ------------------------

		//! \brief Returns the no. of columns in data_frame.
		BOOST_UBLAS_INLINE
		const size_t ncol() const {
			return ncol_;
		}

		//! \brief Returns the no. of rows in data_frame.
		BOOST_UBLAS_INLINE
		const size_t nrow() const {
			return nrow_;
		}

		//! \brief Returns the column header at i-th index.
		BOOST_UBLAS_INLINE
		const std::string colname(const size_t& i) {
			return column_headers_(i);
		}

		// ---------------------
		// Statistical Summaries
		// ---------------------

		/*! \brief prints the column statistics in the data_frame.
		 *  Print Format: [column header]: data(0) data(1) .......
		 *  Doesn't calculate statistics of non numerical types.
		 */
		BOOST_UBLAS_INLINE
		void summary() {
			for(size_t i = 0; i < ncol_; ++i) {
				std::cout << "[" << column_headers_(i) << "]" << ": ";
				 switch(data_[column_headers_(i)].type()) {
					case 0:
						data_[column_headers_(i)].summary <bool, long double >(); break;
					case 3:
						data_[column_headers_(i)].summary <short, long double >(); break;
					case 4:
						data_[column_headers_(i)].summary <unsigned short, long double >(); break;
					case 5:
						data_[column_headers_(i)].summary <int, long double >(); break;
					case 6:
						data_[column_headers_(i)].summary <unsigned int, long double >(); break;
					case 7:
						data_[column_headers_(i)].summary <long, long double >(); break;
					case 8:
						data_[column_headers_(i)].summary <unsigned long, long double >(); break;
					case 9:
						data_[column_headers_(i)].summary <long long, long double >(); break;
					case 10:
						data_[column_headers_(i)].summary <unsigned long long, long double >(); break;
					case 11:
						data_[column_headers_(i)].summary <float, long double >(); break;
					case 12:
						data_[column_headers_(i)].summary <double, long double >(); break;
					case 13:
						data_[column_headers_(i)].summary <long double, long double >(); break;
					default:
						std::cout << "Statistical Summaries not defined" << std::endl;
				}
			}
		}

		//! \brief Adds another data_frame to self.
		BOOST_UBLAS_INLINE
		data_frame operator += (data_frame& df_) {
			return (*this) = (*this) + df_;
		}

		//! \brief Subtracts another data_frame from self.
		BOOST_UBLAS_INLINE
		data_frame operator -= (data_frame& df_) {
			return (*this) = (*this) - df_;
		}

		//! \brief Adds a constant value to self.
		BOOST_UBLAS_INLINE
		template < class T >
		data_frame operator += (const T& val) {
			return (*this) = (*this) + val;
		}

		//! \brief Subtracts constant value from self.
		BOOST_UBLAS_INLINE
		template < class T >
		data_frame operator -= (const T& val) {
			return (*this) = (*this) - val;
		}

		//! \brief Multiplies constant value to self.
		BOOST_UBLAS_INLINE
		template < class T >
		data_frame operator *= (const T& val) {
			return (*this) = (*this) * val;
		}

		/*! \brief Update the column header of a column.
		 *	\param std::string to be updated, std::string updated to.
		 */
		BOOST_UBLAS_INLINE
		void set_col_header(const std::string& a, const std::string& b) {
			try {
				if (data_.find(a) == data_.end()) {
					throw column_header_mismatch();
				}
				for(size_t i = 0; i < column_headers_.size(); ++i) {
					if (column_headers_ (i) == a) {
						column_headers_(i) = b;
						break;
					}
				}
				data_[b] = data_[a];
				data_.erase(a);
			}
			catch (std::exception& e) {
				std::terminate();
			}
		}

		/*! \brief Update the column header of a column.
		 *	\param index of the column to be updated, std::string updated to.
		 */
		BOOST_UBLAS_INLINE
		void set_col_header(const size_t col, const std::string& b) {
			data_[b] = data_[column_headers_(col)];
			data_.erase(column_headers_(col));
			column_headers_(col) = b;
		}

	private:
		//! \brief Stores data.
		std::map < std::string, df_column > data_;
		//! \brief Stores sizes.
		size_t ncol_, nrow_;
		//! \brief Stores column headers.
		vector < std::string> column_headers_;

		//! \brief Returns the default column name.
		//! used when the column name is not set by the user.s
		BOOST_UBLAS_INLINE
		std::string default_name(size_t i) {
			return ("Col-" + boost::lexical_cast<std::string>(i));
		}
	};

	//! \brief Returns the negation of the data_frame if exists.
	data_frame operator - (data_frame& a) {
		vector<std::string> header(a.ncol());
		vector<df_column> col(a.ncol());
		for(size_t i = 0; i < a.ncol(); ++i) {
			header(i) = a.colname(i);
			col(i) = - a[i];
		}
		return data_frame(header, col);
	}

	//! \brief Returns a data_frame as sum of 2 data_frames.
	data_frame operator + (data_frame& a, data_frame& b) {
		try {
			if (a.ncol() != b.ncol()) {
				throw unequal_columns();
			}
			else if (a.nrow() != b.nrow()) {
				throw unequal_rows();
			}
			vector<std::string> header(a.ncol());
			vector<df_column> col(a.ncol());
			for(size_t i = 0; i < a.ncol(); ++i) {
				if (a.colname(i) != b.colname(i)) {
					throw column_header_mismatch();
				}
				header(i) = a.colname(i);
				col(i) = a[i] + b[i];
			}
			return data_frame(header, col);
		}
		catch (std::exception& e) {
			std::terminate();
		}
	}

	//! \brief Returns a data_frame as difference of 2 data_frames.
	data_frame operator - (data_frame& a, data_frame& b) {
		try {
			if (a.ncol() != b.ncol()) {
				throw unequal_columns();
			}
			else if (a.nrow() != b.nrow()) {
				throw unequal_rows();
			}
			vector<std::string> header(a.ncol());
			vector<df_column> col(a.ncol());
			for(size_t i = 0; i < a.ncol(); ++i) {
				if (a.colname(i) != b.colname(i)) {
					throw column_header_mismatch();
				}
				header(i) = a.colname(i);
				col(i) = a[i] - b[i];
			}
			return data_frame(header, col);
		}
		catch (std::exception& e) {
			std::terminate();
		}
	}

	//! \brief Returns a data_frame as sum of a data_frame and a constant value.
	template < class T >
	data_frame operator + (data_frame& a, const T& val) {
		vector<std::string> header(a.ncol());
		vector<df_column> col(a.ncol());
		for(size_t i = 0; i < a.ncol(); ++i) {
			header(i) = a.colname(i);
			col(i) = a[i] + val;
		}
		return data_frame(header, col);
	}

	//! \brief Returns a data_frame as sum of a data_frame and a constant value.
	template < class T >
	data_frame operator + (const T& val, data_frame& a) {
		return a + val;
	}

	//! \brief Returns a data_frame as difference of a data_frame and a constant value.
	template < class T >
	data_frame operator - (data_frame& a, const T& val) {
		return a + (-val);
	}

	//! \brief Returns a data_frame as product of a data_frame and a constant value.
	template < class T >
	data_frame operator * (data_frame& a, const T& val) {
		vector<std::string> header(a.ncol());
		vector<df_column> col(a.ncol());
		for(size_t i = 0; i < a.ncol(); ++i) {
			header(i) = a.colname(i);
			col(i) = a[i] * val;
		}
		return data_frame(header, col);
	}

	//! \brief Returns a data_frame as product of a data_frame and a constant value.
	template < class T >
	data_frame operator * (const T& val, data_frame& a) {
		return a * val;
	}

	//! \brief Returns \c true if (for all columns of a and b) \c y.size() == \c x.size() and \c y.get<T> == \c x.get<T>() else \c false
	bool operator == (data_frame& a, data_frame& b) {
		if (a.ncol() != b.ncol()) {
			return false;
		}
		else if(a.nrow() != b.nrow()) {
			return false;
		}
		for(size_t i = 0; i < a.ncol(); ++i) {
			if (a.headers()(i) != b.headers()(i)) {
				return false;
			}
			else if(a[i] != b[i]) {
				return false;
			}
		}
		return true;
	}

	//! \brief Returns \c false if (for all columns of a and b) \c y.size() == \c x.size() and \c y.get<T> == \c x.get<T>() else \c true
	bool operator != (data_frame& a, data_frame& b) {
		return !(a == b);
	}

	// -----------------
	// dataframe proxies
	// -----------------

	/*! \brief Represents data_frame column range class
	 *	Builds a range on columns of another data_frame.
	 *	allows access and modifications operations
	 */
	class data_frame_range {
	public:
		typedef vector<std::string>::size_type size_type;
		typedef vector<std::string>::difference_type difference_type;
		typedef basic_range<size_type, difference_type> range_type;

		//! \brief: default constructor of data_frame_range.
		BOOST_UBLAS_INLINE
		data_frame_range();

		/*! \brief constructor of data_frame_range.
		 *	\param pointer to base data_frame (over which the proxy needs to be built).
		 *	\param Boost.range over vector<std::string>(column headers).
		 */
		BOOST_UBLAS_INLINE
		data_frame_range (data_frame* df, const range_type& range):
			column_headers_(df->headers(), range) {
				df_ = df;
		}

		//! \brief: destructor of data_frame_range.
		~data_frame_range() {}

		//! \brief Returns a new data_frame containing copy of columns referenced by the given vector_range.
		BOOST_UBLAS_INLINE
		data_frame DataFrame () {
			vector<std::string> v1(column_headers_.size());
			vector<ublas::df_column> v2(column_headers_.size());
			for(size_t i = 0; i < column_headers_.size(); ++i) {
				v1(i) = column_headers_(i);
				v2(i) = (*df_)[v1(i)];
			}
			return data_frame(v1, v2);
		}

		/*! \brief Access operator of data_frame_range.
		 * 	\param column index to be accessed.
		 *  Returns reference to the column in the base data_frame.
		 */
		BOOST_UBLAS_INLINE
		df_column& operator [] (const size_t& i) {
			return (*df_)[column_headers_[i]];
		}

		//! \brief Returns the size of the range (number of elements in the range).
		BOOST_UBLAS_INLINE
		const size_t size() const {
			return column_headers_.size();
		}

		//! \brief Prints the range similar to a data_frame.
		BOOST_UBLAS_INLINE
		void print() {
			for(auto header: column_headers_) {
				std::cout << "[" << header << "]: ";
				(*df_)[header].print();
			}
			return;
		}

		//! \brief Adds all the values in range by \c val.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_range operator += (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] += val;
			}
			return (*this);
		}

		//! \brief Subtracts \c val from all the values in range.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_range operator -= (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] -= val;
			}
			return (*this);
		}

		//! \brief Multiplies all the values in range by \c val.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_range operator *= (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] *= val;
			}
			return (*this);
		}

	private:
		//! \brief Represents the base data_frame.
		data_frame *df_;
		//! \brief Range over the column of data_frame.
		vector_range < vector <std::string> > column_headers_;
	};

	/*! \brief Represents data_frame column slice class
	 *	Builds a slice on columns of another data_frame.
	 *	Allows access and modifications operations
	 */
	class data_frame_slice {
	public:
		typedef vector<std::string>::size_type size_type;
		typedef vector<std::string>::difference_type difference_type;
		typedef basic_slice<size_type, difference_type> slice_type;

		//! \brief: default constructor of data_frame_slice.
		BOOST_UBLAS_INLINE
		data_frame_slice ();

		/*! \brief constructor of data_frame_slice.
		 *	\param pointer to base data_frame (over which the proxy needs to be built).
		 *	\param Boost.slice over vector<std::string>(column headers).
		 */
		BOOST_UBLAS_INLINE
		data_frame_slice (data_frame* df, const slice_type& slice):
			column_headers_(df->headers(), slice) {
				df_ = df;
		}

		//! \brief: destructor of data_frame_slice.
		~data_frame_slice() {}

		//! \brief Returns a new data_frame containing copy of columns referenced by the given vector_slcie.
		BOOST_UBLAS_INLINE
		data_frame DataFrame () {
			vector<std::string> v1(column_headers_.size());
			vector<ublas::df_column> v2(column_headers_.size());
			for(size_t i = 0; i < column_headers_.size(); ++i) {
				v1(i) = column_headers_(i);
				v2(i) = (*df_)[v1(i)];
			}
			return data_frame(v1, v2);
		}

		/*! \brief Access operator of data_frame_slice.
		 * 	\param column index to be accessed.
		 *  Returns reference to the column in the base data_frame.
		 */
		BOOST_UBLAS_INLINE
		df_column& operator [] (const size_t& i) {
			return (*df_)[column_headers_[i]];
		}

		//! \brief Returns the size of the slice (number of elements in the slice).
		BOOST_UBLAS_INLINE
		const size_t size() const {
			return column_headers_.size();
		}

		//! \brief Prints the slice similar to a data_frame.
		BOOST_UBLAS_INLINE
		void print() {
			for(auto header: column_headers_) {
				std::cout << "[" << header << "]: ";
				(*df_)[header].print();
			}
			return;
		}

		//! \brief Adds all the values in slice by \c val.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_slice operator += (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] += val;
			}
			return (*this);
		}

		//! \brief Subtracts \c val from all the values in slice.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_slice operator -= (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] -= val;
			}
			return (*this);
		}

		//! \brief Multiplies all the values in slice by \c val.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_slice operator *= (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] *= val;
			}
			return (*this);
		}
	private:
		//! \brief Represents the base data_frame.
		data_frame *df_;
		//! \brief Slice over the column of data_frame.
		vector_slice < vector <std::string> > column_headers_;
	};

	/*! \brief Represents data_frame column indirect class
	 *	Builds an indirect vector on columns of another data_frame.
	 *	allows access and modifications operations
	 */
	class data_frame_indirect {
	public:

		//! \brief: default constructor of data_frame_indirect.
		BOOST_UBLAS_INLINE
		data_frame_indirect();

		/*! \brief constructor of data_frame_indirect.
		 *	\param pointer to base data_frame (over which the proxy needs to be built).
		 *	\param indirect_array over vector<std::string>(column headers).
		 */
		BOOST_UBLAS_INLINE
		data_frame_indirect(data_frame* df, const indirect_array<> ia):
		 	column_headers_(df->headers(), ia){
		 	df_ = df;
		}

		//! \brief Returns a new data_frame containing copy of columns referenced by the given vector_slcie.
		BOOST_UBLAS_INLINE
		data_frame DataFrame () {
			vector<std::string> v1(column_headers_.size());
			vector<df_column> v2(column_headers_.size());
			for(size_t i = 0; i < column_headers_.size(); ++i) {
				v1(i) = column_headers_(i);
				v2(i) = (*df_)[v1(i)];
			}
			return data_frame(v1, v2);
		}

		//! \brief: destructor of data_frame_indirect.
		~data_frame_indirect() {}

		/*! \brief Access operator of data_frame_indirect.
		 * 	\param column index to be accessed.
		 *  Returns reference to the column in the base data_frame.
		 */
		BOOST_UBLAS_INLINE
		df_column& operator [] (const size_t& i) {
			return (*df_)[column_headers_[i]];
		}

		//! \brief Returns the size of the indirect_data_frame (number of elements in the indirect data_frame).
		BOOST_UBLAS_INLINE
		const size_t size() const {
			return column_headers_.size();
		}

		//! \brief Prints the data_frame_indirect similar to a data_frame.
		BOOST_UBLAS_INLINE
		void print() {
			for(auto header: column_headers_) {
				std::cout << "[" << header << "]: ";
				(*df_)[header].print();
			}
			return;
		}

		//! \brief Adds all the values in data_frame_indirect by \c val.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_indirect operator += (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] += val;
			}
			return (*this);
		}

		//! \brief Subtracts \c val from all the values in data_frame_indirect.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_indirect operator -= (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] -= val;
			}
			return (*this);
		}

		//! \brief Multiplies all the values in data_frame_indirect by \c val.
		template < class T >
		BOOST_UBLAS_INLINE
		data_frame_indirect operator *= (const T& val) {
			for(auto header: column_headers_) {
				(*df_)[header] *= val;
			}
			return (*this);
		}

	private:
		//! \brief Represents the base data_frame.
		data_frame *df_;
		//! \brief vector_indirect over the column of data_frame.
		vector_indirect < vector < std::string> > column_headers_;
	};
}}}

#endif


text:
/*

Copyright (c) 2005-2019, University of Oxford.
All rights reserved.

University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.

This file is part of Chaste.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 * Neither the name of the University of Oxford nor the names of its
   contributors may be used to endorse or promote products derived from this
   software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.

*/

#ifndef ABSTRACTGROWINGDOMAINPDEMODIFIER_HPP_
#define ABSTRACTGROWINGDOMAINPDEMODIFIER_HPP_

#include "ChasteSerialization.hpp"
#include <boost/serialization/base_object.hpp>

#include "AbstractPdeModifier.hpp"

/**
 * An abstract modifier class containing functionality common to EllipticGrowingDomainPdeModifier
 * and ParabolicGrowingDomainPdeModifier, which both solve a linear elliptic or parabolic PDE
 * coupled to a cell-based simulation on an evolving domain defined by the cell population.
 */
template<unsigned DIM>
class AbstractGrowingDomainPdeModifier : public AbstractPdeModifier<DIM>
{
    friend class TestEllipticGrowingDomainPdeModifier;
    friend class TestParabolicGrowingDomainPdeModifier;

private:

    /** Needed for serialization. */
    friend class boost::serialization::access;
    /**
     * Boost Serialization method for archiving/checkpointing.
     * Archives the object and its member variables.
     *
     * @param archive  The boost archive.
     * @param version  The current version of this class.
     */
    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & boost::serialization::base_object<AbstractPdeModifier<DIM> >(*this);
    }

public:

    /**
     * Constructor.
     *
     * @param pPde A shared pointer to a linear PDE object (defaults to NULL)
     * @param pBoundaryCondition A shared pointer to an abstract boundary condition
     *     (defaults to NULL, corresponding to a constant boundary condition with value zero)
     * @param isNeumannBoundaryCondition Whether the boundary condition is Neumann (defaults to true)
     * @param solution solution vector (defaults to NULL)
     */
    AbstractGrowingDomainPdeModifier(boost::shared_ptr<AbstractLinearPde<DIM,DIM> > pPde=boost::shared_ptr<AbstractLinearPde<DIM,DIM> >(),
                                     boost::shared_ptr<AbstractBoundaryCondition<DIM> > pBoundaryCondition=boost::shared_ptr<AbstractBoundaryCondition<DIM> >(),
                                     bool isNeumannBoundaryCondition=true,
                                     Vec solution=nullptr);

    /**
     * Destructor.
     */
    virtual ~AbstractGrowingDomainPdeModifier();

    /**
     * Helper method to generate the mesh from the Cell population.
     *
     * @param rCellPopulation reference to the cell population
     */
    void GenerateFeMesh(AbstractCellPopulation<DIM,DIM>& rCellPopulation);

    /**
     * Helper method to copy the PDE solution to CellData
     *
     * Here there is a 1-1 correspondence between cells and nodes in the FE mesh
     *
     * @param rCellPopulation reference to the cell population
     */
    void UpdateCellData(AbstractCellPopulation<DIM,DIM>& rCellPopulation);

    /**
     * Overridden OutputSimulationModifierParameters() method.
     * Output any simulation modifier parameters to file.
     *
     * @param rParamsFile the file stream to which the parameters are output
     */
    void OutputSimulationModifierParameters(out_stream& rParamsFile);
};

#include "SerializationExportWrapper.hpp"
TEMPLATED_CLASS_IS_ABSTRACT_1_UNSIGNED(AbstractGrowingDomainPdeModifier)

#endif /*ABSTRACTGROWINGDOMAINPDEMODIFIER_HPP_*/

ext: hpp


text:
#ifndef LIB_MODBUS_MODBUS_REQUEST_HANDLER_HPP_
#define LIB_MODBUS_MODBUS_REQUEST_HANDLER_HPP_

#include <string_view>

#include <boost/core/noncopyable.hpp>

#include "types.hpp"

namespace modbus {
// forward declaration
class table;

class request_handler : private boost::noncopyable {
public:
  /**
   * Handle request
   *
   * @param data_table data table
   * @param packet     request packet
   *
   * @return packet to send
   */
  static packet_t handle(table* data_table, const std::string_view& packet);
  /**
   * Handle request
   *
   * @param data_table data table
   * @param packet     request packet
   *
   * @return packet to send
   */
  static packet_t handle(table* data_table, const packet_t& packet);
};
}  // namespace modbus

#endif  // LIB_MODBUS_MODBUS_REQUEST_HANDLER_HPP_

max_stars_repo_name: rayandrews/modbus-cpp

max_issues_repo_name: rayandrews/modbus-cpp

max_forks_repo_name: rayandrews/modbus-cpp


text:
#include <cdrm/cdrm.h>

#include <cdrm/cdrm_serialisation.h>
#include <cdrm/utils.h>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/filesystem.hpp>

#include <ros/console.h>

#include <fstream>

namespace cdrm
{
Cdrm::Cdrm(double resolution) : resolution_(resolution)
{
}

Key Cdrm::pointToKey(const Eigen::Vector3d &p) const
{
  Key k;
  k[0] = static_cast<std::int16_t>(std::round(p(0) / resolution_));
  k[1] = static_cast<std::int16_t>(std::round(p(1) / resolution_));
  k[2] = static_cast<std::int16_t>(std::round(p(2) / resolution_));
  return k;
}

Eigen::Vector3d Cdrm::keyToPoint(const Key &k) const
{
  Eigen::Vector3d p;
  p(0) = resolution_ * k[0];
  p(1) = resolution_ * k[1];
  p(2) = resolution_ * k[2];
  return p;
}

const Eigen::VectorXd &Cdrm::getVertexConfig(const VertexDescriptor &v) const
{
  return roadmap_[v].q_;
}

bool Cdrm::save(const std::string &filename) const
{
  try
  {
    std::ofstream ofs(filename);
    boost::archive::binary_oarchive oa(ofs);
    oa << *this;
  }
  catch (const boost::archive::archive_exception &ex)
  {
    ROS_ERROR("%s", ex.what());
    return false;
  }

  return true;
}

bool Cdrm::load(const std::string &filename)
{
  // If it's relative, then default to reading from ROS home.
  boost::filesystem::path path(filename);

  if (path.is_relative())
    path = boost::filesystem::path(getRosHome() + filename);

  try
  {
    std::ifstream ifs(path.c_str());
    boost::archive::binary_iarchive ia(ifs);
    ia >> *this;
  }
  catch (const boost::archive::archive_exception &ex)
  {
    ROS_ERROR("%s", ex.what());
    return false;
  }

  return true;
}
}

ext: cpp

max_stars_repo_name: ajshort/cdrm

max_issues_repo_name: ajshort/cdrm

max_forks_repo_name: ajshort/cdrm


text:
/*
 * Distributed under 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)
 *
 * Copyright (c) 2009 Helge Bahmann
 * Copyright (c) 2012 Tim Blechmann
 * Copyright (c) 2013 - 2014 Andrey Semashev
 */
/*!
 * \file   atomic/detail/caps_gcc_x86.hpp
 *
 * This header defines feature capabilities macros
 */

#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_
#define BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_

#include <boost/atomic/detail/config.hpp>
#include <boost/atomic/detail/hwcaps_gcc_x86.hpp>

#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif

#define BOOST_ATOMIC_INT8_LOCK_FREE 2
#define BOOST_ATOMIC_INT16_LOCK_FREE 2
#define BOOST_ATOMIC_INT32_LOCK_FREE 2
#if defined(__x86_64__) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B)
#define BOOST_ATOMIC_INT64_LOCK_FREE 2
#endif
#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) && (defined(BOOST_HAS_INT128) || !defined(BOOST_NO_ALIGNMENT))
#define BOOST_ATOMIC_INT128_LOCK_FREE 2
#endif
#define BOOST_ATOMIC_POINTER_LOCK_FREE 2

#define BOOST_ATOMIC_THREAD_FENCE 2
#define BOOST_ATOMIC_SIGNAL_FENCE 2

#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_

max_stars_repo_name: cfsengineering/tigl

max_issues_repo_name: cfsengineering/tigl

max_forks_repo_name: cfsengineering/tigl


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

#include "coordinates.hpp"
#include "fixture.hpp"

#include "osrm/trip_parameters.hpp"
#include <engine/api/flatbuffers/fbresult_generated.h>

#include "osrm/coordinate.hpp"
#include "osrm/engine_config.hpp"
#include "osrm/json_container.hpp"
#include "osrm/osrm.hpp"
#include "osrm/status.hpp"

BOOST_AUTO_TEST_SUITE(trip)

BOOST_AUTO_TEST_CASE(test_roundtrip_response_for_locations_in_small_component)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_small_component();

    TripParameters params;
    params.coordinates.push_back(locations.at(0));
    params.coordinates.push_back(locations.at(1));
    params.coordinates.push_back(locations.at(2));

    engine::api::ResultT result = json::Object();
    const auto rc = osrm.Trip(params, result);
    BOOST_CHECK(rc == Status::Ok);

    auto &json_result = result.get<json::Object>();
    const auto code = json_result.values.at("code").get<json::String>().value;
    BOOST_CHECK_EQUAL(code, "Ok");

    const auto &waypoints = json_result.values.at("waypoints").get<json::Array>().values;
    BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size());

    const auto &trips = json_result.values.at("trips").get<json::Array>().values;
    BOOST_CHECK_EQUAL(trips.size(), 1);

    for (const auto &waypoint : waypoints)
    {
        const auto &waypoint_object = waypoint.get<json::Object>();

        const auto location = waypoint_object.values.at("location").get<json::Array>().values;
        const auto longitude = location[0].get<json::Number>().value;
        const auto latitude = location[1].get<json::Number>().value;
        BOOST_CHECK(longitude >= -180. && longitude <= 180.);
        BOOST_CHECK(latitude >= -90. && latitude <= 90.);

        const auto trip = waypoint_object.values.at("trips_index").get<json::Number>().value;
        const auto pos = waypoint_object.values.at("waypoint_index").get<json::Number>().value;
        BOOST_CHECK(trip >= 0 && trip < trips.size());
        BOOST_CHECK(pos >= 0 && pos < waypoints.size());
    }
}

BOOST_AUTO_TEST_CASE(test_roundtrip_response_for_locations_in_small_component_skip_waypoints)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_small_component();

    TripParameters params;
    params.skip_waypoints = true;
    params.coordinates.push_back(locations.at(0));
    params.coordinates.push_back(locations.at(1));
    params.coordinates.push_back(locations.at(2));

    engine::api::ResultT result = json::Object();
    const auto rc = osrm.Trip(params, result);
    BOOST_CHECK(rc == Status::Ok);

    auto &json_result = result.get<json::Object>();
    const auto code = json_result.values.at("code").get<json::String>().value;
    BOOST_CHECK_EQUAL(code, "Ok");

    BOOST_CHECK(json_result.values.find("waypoints") == json_result.values.end());
}

BOOST_AUTO_TEST_CASE(test_roundtrip_response_for_locations_in_big_component)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_big_component();

    TripParameters params;
    params.coordinates.push_back(locations.at(0));
    params.coordinates.push_back(locations.at(1));
    params.coordinates.push_back(locations.at(2));

    engine::api::ResultT result = json::Object();
    const auto rc = osrm.Trip(params, result);
    BOOST_CHECK(rc == Status::Ok);

    auto &json_result = result.get<json::Object>();
    const auto code = json_result.values.at("code").get<json::String>().value;
    BOOST_CHECK_EQUAL(code, "Ok");

    const auto &waypoints = json_result.values.at("waypoints").get<json::Array>().values;
    BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size());

    const auto &trips = json_result.values.at("trips").get<json::Array>().values;
    BOOST_CHECK_EQUAL(trips.size(), 1);

    for (const auto &waypoint : waypoints)
    {
        const auto &waypoint_object = waypoint.get<json::Object>();

        const auto location = waypoint_object.values.at("location").get<json::Array>().values;
        const auto longitude = location[0].get<json::Number>().value;
        const auto latitude = location[1].get<json::Number>().value;
        BOOST_CHECK(longitude >= -180. && longitude <= 180.);
        BOOST_CHECK(latitude >= -90. && latitude <= 90.);

        const auto trip = waypoint_object.values.at("trips_index").get<json::Number>().value;
        const auto pos = waypoint_object.values.at("waypoint_index").get<json::Number>().value;
        BOOST_CHECK(trip >= 0 && trip < trips.size());
        BOOST_CHECK(pos >= 0 && pos < waypoints.size());
    }
}

BOOST_AUTO_TEST_CASE(test_roundtrip_response_for_locations_across_components)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto small = get_locations_in_small_component();
    const auto big = get_locations_in_big_component();

    TripParameters params;
    params.coordinates.push_back(small.at(0));
    params.coordinates.push_back(big.at(0));
    params.coordinates.push_back(small.at(1));
    params.coordinates.push_back(big.at(1));

    engine::api::ResultT result = json::Object();
    const auto rc = osrm.Trip(params, result);
    BOOST_CHECK(rc == Status::Ok);

    auto &json_result = result.get<json::Object>();
    const auto code = json_result.values.at("code").get<json::String>().value;
    BOOST_CHECK_EQUAL(code, "Ok");

    const auto &waypoints = json_result.values.at("waypoints").get<json::Array>().values;
    BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size());

    const auto &trips = json_result.values.at("trips").get<json::Array>().values;
    BOOST_CHECK_EQUAL(trips.size(), 1);
    // ^ First snapping, then SCC decomposition (see plugins/trip.cpp). Therefore only a single
    // trip.

    for (const auto &waypoint : waypoints)
    {
        const auto &waypoint_object = waypoint.get<json::Object>();

        const auto location = waypoint_object.values.at("location").get<json::Array>().values;
        const auto longitude = location[0].get<json::Number>().value;
        const auto latitude = location[1].get<json::Number>().value;
        BOOST_CHECK(longitude >= -180. && longitude <= 180.);
        BOOST_CHECK(latitude >= -90. && latitude <= 90.);

        const auto trip = waypoint_object.values.at("trips_index").get<json::Number>().value;
        const auto pos = waypoint_object.values.at("waypoint_index").get<json::Number>().value;
        BOOST_CHECK(trip >= 0 && trip < trips.size());
        BOOST_CHECK(pos >= 0 && pos < waypoints.size());
    }
}

BOOST_AUTO_TEST_CASE(test_tfse_1)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_small_component();

    TripParameters params;
    params.coordinates.push_back(locations.at(0));
    params.coordinates.push_back(locations.at(1));
    params.coordinates.push_back(locations.at(2));

    params.source = TripParameters::SourceType::First;
    params.destination = TripParameters::DestinationType::Last;
    params.roundtrip = false;

    engine::api::ResultT result = json::Object();
    const auto rc = osrm.Trip(params, result);
    BOOST_CHECK(rc == Status::Ok);

    auto &json_result = result.get<json::Object>();
    const auto code = json_result.values.at("code").get<json::String>().value;
    BOOST_CHECK_EQUAL(code, "Ok");

    const auto &waypoints = json_result.values.at("waypoints").get<json::Array>().values;
    BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size());

    const auto &trips = json_result.values.at("trips").get<json::Array>().values;
    BOOST_CHECK_EQUAL(trips.size(), 1);

    for (const auto &waypoint : waypoints)
    {
        const auto &waypoint_object = waypoint.get<json::Object>();

        const auto location = waypoint_object.values.at("location").get<json::Array>().values;
        const auto longitude = location[0].get<json::Number>().value;
        const auto latitude = location[1].get<json::Number>().value;
        BOOST_CHECK(longitude >= -180. && longitude <= 180.);
        BOOST_CHECK(latitude >= -90. && latitude <= 90.);

        const auto trip = waypoint_object.values.at("trips_index").get<json::Number>().value;
        const auto pos = waypoint_object.values.at("waypoint_index").get<json::Number>().value;
        BOOST_CHECK(trip >= 0 && trip < trips.size());
        BOOST_CHECK(pos >= 0 && pos < waypoints.size());
    }
}

BOOST_AUTO_TEST_CASE(test_tfse_2)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_big_component();

    TripParameters params;
    params.coordinates.push_back(locations.at(0));
    params.coordinates.push_back(locations.at(2));
    params.coordinates.push_back(locations.at(1));

    params.source = TripParameters::SourceType::First;
    params.destination = TripParameters::DestinationType::Last;
    params.roundtrip = false;

    engine::api::ResultT result = json::Object();
    const auto rc = osrm.Trip(params, result);
    BOOST_CHECK(rc == Status::Ok);

    auto &json_result = result.get<json::Object>();
    const auto code = json_result.values.at("code").get<json::String>().value;
    BOOST_CHECK_EQUAL(code, "Ok");

    const auto &waypoints = json_result.values.at("waypoints").get<json::Array>().values;
    BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size());

    const auto &trips = json_result.values.at("trips").get<json::Array>().values;
    BOOST_CHECK_EQUAL(trips.size(), 1);

    for (const auto &waypoint : waypoints)
    {
        const auto &waypoint_object = waypoint.get<json::Object>();

        const auto location = waypoint_object.values.at("location").get<json::Array>().values;
        const auto longitude = location[0].get<json::Number>().value;
        const auto latitude = location[1].get<json::Number>().value;
        BOOST_CHECK(longitude >= -180. && longitude <= 180.);
        BOOST_CHECK(latitude >= -90. && latitude <= 90.);

        const auto trip = waypoint_object.values.at("trips_index").get<json::Number>().value;
        const auto pos = waypoint_object.values.at("waypoint_index").get<json::Number>().value;
        BOOST_CHECK(trip >= 0 && trip < trips.size());
        BOOST_CHECK(pos >= 0 && pos < waypoints.size());
    }
}

void ResetParams(const Locations &locations, osrm::TripParameters &params)
{
    params = osrm::TripParameters();
    params.coordinates.push_back(locations.at(0));
    params.coordinates.push_back(locations.at(1));
    params.coordinates.push_back(locations.at(2));
}
void CheckNotImplemented(const osrm::OSRM &osrm, osrm::TripParameters &params)
{
    using namespace osrm;
    engine::api::ResultT result = json::Object();
    auto rc = osrm.Trip(params, result);
    BOOST_REQUIRE(rc == osrm::Status::Error);
    auto &json_result = result.get<json::Object>();
    auto code = json_result.values.at("code").get<osrm::json::String>().value;
    BOOST_CHECK_EQUAL(code, "NotImplemented");
}

void CheckOk(const osrm::OSRM &osrm, osrm::TripParameters &params)
{
    using namespace osrm;
    engine::api::ResultT result = json::Object();
    auto rc = osrm.Trip(params, result);
    BOOST_REQUIRE(rc == osrm::Status::Ok);
    auto &json_result = result.get<json::Object>();
    auto code = json_result.values.at("code").get<osrm::json::String>().value;
    BOOST_CHECK_EQUAL(code, "Ok");
}

BOOST_AUTO_TEST_CASE(test_tfse_illegal_parameters)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_big_component();
    auto params = osrm::TripParameters();

    // one parameter set
    ResetParams(locations, params);
    params.roundtrip = false;
    CheckNotImplemented(osrm, params);

    // two parameter set
    ResetParams(locations, params);
    params.source = TripParameters::SourceType::Any;
    params.roundtrip = false;
    CheckNotImplemented(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::First;
    params.roundtrip = false;
    CheckNotImplemented(osrm, params);

    ResetParams(locations, params);
    params.destination = TripParameters::DestinationType::Any;
    params.roundtrip = false;
    CheckNotImplemented(osrm, params);

    ResetParams(locations, params);
    params.destination = TripParameters::DestinationType::Last;
    params.roundtrip = false;
    CheckNotImplemented(osrm, params);

    // three parameters set
    params.source = TripParameters::SourceType::Any;
    params.destination = TripParameters::DestinationType::Any;
    params.roundtrip = false;
    CheckNotImplemented(osrm, params);

    params.source = TripParameters::SourceType::Any;
    params.destination = TripParameters::DestinationType::Last;
    params.roundtrip = false;
    CheckNotImplemented(osrm, params);

    params.source = TripParameters::SourceType::First;
    params.destination = TripParameters::DestinationType::Any;
    params.roundtrip = false;
    CheckNotImplemented(osrm, params);
}

BOOST_AUTO_TEST_CASE(test_tfse_legal_parameters)
{
    using namespace osrm;
    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_big_component();
    json::Object result;
    TripParameters params;

    // no parameter set
    ResetParams(locations, params);
    CheckOk(osrm, params);

    // one parameter set
    ResetParams(locations, params);
    params.roundtrip = true;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::First;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::Any;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.destination = TripParameters::DestinationType::Any;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.destination = TripParameters::DestinationType::Last;
    CheckOk(osrm, params);

    // two parameter set
    ResetParams(locations, params);
    params.destination = TripParameters::DestinationType::Last;
    params.roundtrip = true;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::First;
    params.roundtrip = true;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::First;
    params.destination = TripParameters::DestinationType::Any;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::Any;
    params.destination = TripParameters::DestinationType::Last;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::First;
    params.destination = TripParameters::DestinationType::Last;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::Any;
    params.roundtrip = true;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.destination = TripParameters::DestinationType::Any;
    params.roundtrip = true;
    CheckOk(osrm, params);

    ResetParams(locations, params);
    params.source = TripParameters::SourceType::Any;
    params.destination = TripParameters::DestinationType::Any;
    CheckOk(osrm, params);

    // three parameter set
    params.source = TripParameters::SourceType::Any;
    params.destination = TripParameters::DestinationType::Any;
    params.roundtrip = true;
    CheckOk(osrm, params);

    params.source = TripParameters::SourceType::First;
    params.destination = TripParameters::DestinationType::Last;
    params.roundtrip = false;
    CheckOk(osrm, params);

    params.source = TripParameters::SourceType::Any;
    params.destination = TripParameters::DestinationType::Last;
    params.roundtrip = true;
    CheckOk(osrm, params);

    params.source = TripParameters::SourceType::First;
    params.destination = TripParameters::DestinationType::Any;
    params.roundtrip = true;
    CheckOk(osrm, params);

    params.source = TripParameters::SourceType::First;
    params.destination = TripParameters::DestinationType::Last;
    params.roundtrip = true;
    CheckOk(osrm, params);
}

BOOST_AUTO_TEST_CASE(test_roundtrip_response_fb_serialization)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_small_component();

    TripParameters params;
    params.coordinates.push_back(locations.at(0));
    params.coordinates.push_back(locations.at(1));
    params.coordinates.push_back(locations.at(2));

    engine::api::ResultT result = flatbuffers::FlatBufferBuilder();
    const auto rc = osrm.Trip(params, result);
    BOOST_CHECK(rc == Status::Ok);

    auto &fb_result = result.get<flatbuffers::FlatBufferBuilder>();
    auto fb = engine::api::fbresult::GetFBResult(fb_result.GetBufferPointer());

    BOOST_CHECK(!fb->error());

    BOOST_CHECK(fb->waypoints() != nullptr);
    const auto waypoints = fb->waypoints();
    BOOST_CHECK(waypoints->size() == params.coordinates.size());

    BOOST_CHECK(fb->routes() != nullptr);
    const auto trips = fb->routes();
    BOOST_CHECK_EQUAL(trips->size(), 1);

    for (const auto &waypoint : *waypoints)
    {
        const auto longitude = waypoint->location()->longitude();
        const auto latitude = waypoint->location()->latitude();
        BOOST_CHECK(longitude >= -180. && longitude <= 180.);
        BOOST_CHECK(latitude >= -90. && latitude <= 90.);

        const auto trip = waypoint->trips_index();
        const auto pos = waypoint->waypoint_index();
        BOOST_CHECK(trip < trips->size());
        BOOST_CHECK(pos < waypoints->size());
    }
}

BOOST_AUTO_TEST_CASE(test_roundtrip_response_fb_serialization_skip_waypoints)
{
    using namespace osrm;

    auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
    const auto locations = get_locations_in_small_component();

    TripParameters params;
    params.skip_waypoints = true;
    params.coordinates.push_back(locations.at(0));
    params.coordinates.push_back(locations.at(1));
    params.coordinates.push_back(locations.at(2));

    engine::api::ResultT result = flatbuffers::FlatBufferBuilder();
    const auto rc = osrm.Trip(params, result);
    BOOST_CHECK(rc == Status::Ok);

    auto &fb_result = result.get<flatbuffers::FlatBufferBuilder>();
    auto fb = engine::api::fbresult::GetFBResult(fb_result.GetBufferPointer());

    BOOST_CHECK(!fb->error());

    BOOST_CHECK(fb->waypoints() == nullptr);
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: OgreTransporter/osrm-backend

max_issues_repo_name: zhangdida/osrm-backend

max_forks_repo_name: zhangdida/osrm-backend


text:
#ifdef STAND_ALONE
#   define BOOST_TEST_MODULE DemoTests
#endif

#include <boost/test/unit_test.hpp>
#include "../src/shared/Foo.hpp"

BOOST_AUTO_TEST_SUITE(foo_suite)

    BOOST_AUTO_TEST_CASE(constructor_test)
    {
        Foo foo(3);

        BOOST_CHECK_EQUAL(foo.doubleValue(), 6);
    }

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: albertchan/cmake-boost-demo

max_issues_repo_name: albertchan/cmake-boost-demo

max_forks_repo_name: albertchan/cmake-boost-demo


text:
/*
 * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
 */

#include "base/os.h"
#if 0
#include <sys/socket.h>

#include <net/if.h>

#ifdef __linux__
#include <linux/netlink.h>
#include <linux/if_tun.h>
#include <linux/if_packet.h>
#endif

#ifdef __FreeBSD__
#include <sys/sockio.h>
#include <ifaddrs.h>
#endif
#endif
#include "testing/gunit.h"

#include <base/logging.h>
#include <io/event_manager.h>
#include <tbb/task.h>
#include <base/task.h>

#include <cmn/agent_cmn.h>

#include "cfg/cfg_init.h"
#include "cfg/cfg_interface.h"
#include "oper/operdb_init.h"
#include "controller/controller_init.h"
#include "pkt/pkt_init.h"
#include "services/services_init.h"
#include "vrouter/ksync/ksync_init.h"
#include "oper/interface_common.h"
#include "oper/nexthop.h"
#include "route/route.h"
#include "oper/vrf.h"
#include "oper/mpls.h"
#include "oper/vm.h"
#include "oper/vn.h"
#include "filter/acl.h"
#include "test_cmn_util.h"
#include "vr_types.h"
#include <controller/controller_export.h>
#include <ksync/ksync_sock_user.h>
#include <boost/assign/list_of.hpp>
#include "pkt/test/test_flow_util.h"
#include "uve/test/test_uve_util.h"

#define vm1_ip "11.1.1.1"
#define vm2_ip "11.1.1.2"

void RouterIdDepInit(Agent *agent) {
}

typedef enum {
    INGRESS = 0,
    EGRESS = 1,
    BIDIRECTION = 2
} AclDirection;

static string AddAclXmlString(const char *node_name, const char *name, int id,
                              int proto, const char *action) {
    char buff[10240];
    sprintf(buff,
    "<?xml version=\"1.0\"?>\n"
    "<config>\n"
    "   <update>\n"
    "       <node type=\"%s\">\n"
    "           <name>%s</name>\n"
    "           <id-perms>\n"
    "               <permissions>\n"
    "                   <owner></owner>\n"
    "                   <owner_access>0</owner_access>\n"
    "                   <group></group>\n"
    "                   <group_access>0</group_access>\n"
    "                   <other_access>0</other_access>\n"
    "               </permissions>\n"
    "               <uuid>\n"
    "                   <uuid-mslong>0</uuid-mslong>\n"
    "                   <uuid-lslong>%d</uuid-lslong>\n"
    "               </uuid>\n"
    "           </id-perms>\n"
    "           <access-control-list-entries>\n"
    "                <acl-rule>\n"
    "                    <match-condition>\n"
    "                        <src-address>\n"
    "                            <virtual-network> any </virtual-network>\n"
    "                        </src-address>\n"
    "                        <protocol>%d</protocol>\n"
    "                        <src-port>\n"
    "                            <start-port> 0 </start-port>\n"
    "                            <end-port> 10000 </end-port>\n"
    "                        </src-port>\n"
    "                        <dst-address>\n"
    "                            <virtual-network> any </virtual-network>\n"
    "                        </dst-address>\n"
    "                        <dst-port>\n"
    "                            <start-port> 0 </start-port>\n"
    "                            <end-port> 10000 </end-port>\n"
    "                        </dst-port>\n"
    "                    </match-condition>\n"
    "                    <action-list>\n"
    "                        <simple-action>\n"
    "                            %s\n"
    "                        </simple-action>\n"
    "                    </action-list>\n"
    "                </acl-rule>\n"
    "                <acl-rule>\n"
    "                    <match-condition>\n"
    "                        <src-address>\n"
    "                            <virtual-network> any </virtual-network>\n"
    "                        </src-address>\n"
    "                        <protocol>any</protocol>\n"
    "                        <src-port>\n"
    "                            <start-port> 0 </start-port>\n"
    "                            <end-port> 60000 </end-port>\n"
    "                        </src-port>\n"
    "                        <dst-address>\n"
    "                            <virtual-network> any </virtual-network>\n"
    "                        </dst-address>\n"
    "                        <dst-port>\n"
    "                            <start-port> 0 </start-port>\n"
    "                            <end-port> 60000 </end-port>\n"
    "                        </dst-port>\n"
    "                    </match-condition>\n"
    "                    <action-list>\n"
    "                        <simple-action>\n"
    "                            deny\n"
    "                        </simple-action>\n"
    "                    </action-list>\n"
    "                </acl-rule>\n"
    "           </access-control-list-entries>\n"
    "       </node>\n"
    "   </update>\n"
    "</config>\n", node_name, name, id, proto, action);
    string s(buff);
    return s;
}

static void AddAclEntry(const char *name, int id, int proto,
                        const char *action, AclDirection direction) {
    char acl_name[1024];
    uint16_t max_len = sizeof(acl_name) - 1;
    strncpy(acl_name, name, max_len);
    if (direction == EGRESS) {
        strncat(acl_name, "egress-access-control-list", max_len);
    } else {
        strncat(acl_name, "ingress-access-control-list", max_len);
    }
    std::string s = AddAclXmlString("access-control-list", acl_name, id, proto,
                                    action);
    pugi::xml_document xdoc_;
    pugi::xml_parse_result result = xdoc_.load(s.c_str());
    EXPECT_TRUE(result);
    Agent::GetInstance()->ifmap_parser()->ConfigParse(xdoc_.first_child(), 0);
    client->WaitForIdle();
}

static void AddSgEntry(const char *sg_name, const char *name, int id,
                       int proto, const char *action, AclDirection direction) {

    AddSg(sg_name, 1);
    char acl_name[1024];
    uint16_t max_len = sizeof(acl_name) - 1;
    strncpy(acl_name, name, max_len);
    switch (direction) {
        case INGRESS:
            AddAclEntry(name, id, proto, action, direction);
            strncat(acl_name, "ingress-access-control-list", max_len);
            AddLink("security-group", sg_name, "access-control-list", acl_name);
            break;
        case EGRESS:
            AddAclEntry(name, id, proto, action, direction);
            strncat(acl_name, "egress-access-control-list", max_len);
            AddLink("security-group", sg_name, "access-control-list", acl_name);
            break;
        case BIDIRECTION:
            AddAclEntry(name, id, proto, action, EGRESS);
            strncat(acl_name, "egress-access-control-list", max_len);
            AddLink("security-group", sg_name, "access-control-list", acl_name);

            strncpy(acl_name, name, max_len);
            strncat(acl_name, "ingress-access-control-list", max_len);
            AddAclEntry(name, id+1, proto, action, INGRESS);
            AddLink("security-group", sg_name, "access-control-list", acl_name);
            break;
    }
}

class PolicyTest : public ::testing::Test {
public:
    PolicyTest() : util_() {
        agent_ = Agent::GetInstance();
        flow_proto_ = agent_->pkt()->get_flow_proto();
    }

    void SetPolicyDisabledStatus(struct PortInfo *input, bool status) {
        ostringstream str;

        str << "<virtual-machine-interface-disable-policy>";
        if (status) {
            str << "true";
        } else {
            str << "false";
        }
        str << "</virtual-machine-interface-disable-policy>";

        AddNode("virtual-machine-interface", input[0].name, input[0].intf_id,
                str.str().c_str());
    }

    TestUveUtil util_;
    Agent *agent_;
    FlowProto *flow_proto_;
};

TEST_F(PolicyTest, IntfPolicyDisable_Vn) {
    struct PortInfo input[] = {
        {"vnet1", 1, "1.1.1.1", "00:00:00:00:00:01", 1, 1},
    };

    CreateVmportEnv(input, 1, 1);
    client->WaitForIdle();
    EXPECT_TRUE(VmPortFind(1));

    //Verify that interface has policy enabled
    VmInterface *intf = static_cast<VmInterface *>(VmPortGet(1));
    EXPECT_TRUE(intf->policy_enabled());

    uint32_t prev_label = intf->label();
    //Verify that interface's MPLS label points to policy-enabled NH
    const NextHop *nh = MplsToNextHop(prev_label);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's L2 MPLS label points to policy-enabled NH
    nh = MplsToNextHop(intf->l2_label());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's route points to policy-enabled NH
    nh = RouteToNextHop("vrf1", intf->primary_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's L2 route points to policy-enabled NH
    MacAddress mac(intf->vm_mac());
    nh = L2RouteToNextHop("vrf1", mac);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's flow_key_nh points to policy-enabled NH
    nh = intf->flow_key_nh();
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's mdata route points to policy-enabled NH
    nh = RouteToNextHop(agent_->fabric_vrf_name(), intf->mdata_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Configure disable-policy as true on interface
    //---------------------------------------------
    SetPolicyDisabledStatus(input, true);
    client->WaitForIdle();

    //Verify that policy is disabled on interface
    EXPECT_FALSE(intf->policy_enabled());

    //Verify that interface's MPLS label has changed
    EXPECT_TRUE (prev_label != intf->label());
    prev_label = intf->label();

    //Verify that interface's MPLS label points to policy-disabled NH
    nh = MplsToNextHop(prev_label);
    EXPECT_TRUE(nh != NULL);
    EXPECT_FALSE(nh->PolicyEnabled());

    //Verify that interface's L2 MPLS label points to policy-disabled NH
    nh = MplsToNextHop(intf->l2_label());
    EXPECT_TRUE(nh != NULL);
    EXPECT_FALSE(nh->PolicyEnabled());

    //Verify that interface's route points to policy-disabled NH
    nh = RouteToNextHop("vrf1", intf->primary_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_FALSE(nh->PolicyEnabled());

    //Verify that interface's L2 route points to policy-disabled NH
    nh = L2RouteToNextHop("vrf1", mac);
    EXPECT_TRUE(nh != NULL);
    EXPECT_FALSE(nh->PolicyEnabled());

    //Verify that interface's flow_key_nh still points to policy-enabled NH
    nh = intf->flow_key_nh();
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's mdata route still points to policy-enabled NH
    nh = RouteToNextHop(agent_->fabric_vrf_name(), intf->mdata_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Configure disable-policy as false on interface
    //---------------------------------------------
    SetPolicyDisabledStatus(input, false);
    client->WaitForIdle();

    //Verify that policy is enabled
    EXPECT_TRUE(intf->policy_enabled());

    //Verify that interface's MPLS label has changed
    EXPECT_TRUE (prev_label != intf->label());

    //Verify that interface's MPLS label points to policy-enabled NH
    nh = MplsToNextHop(intf->label());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's L2 MPLS label points to policy-enabled NH
    nh = MplsToNextHop(intf->l2_label());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's route points to policy-enabled NH
    nh = RouteToNextHop("vrf1", intf->primary_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's L2 route points to policy-enabled NH
    nh = L2RouteToNextHop("vrf1", mac);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's flow_key_nh points to policy-enabled NH
    nh = intf->flow_key_nh();
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's mdata route points to policy-enabled NH
    nh = RouteToNextHop(agent_->fabric_vrf_name(), intf->mdata_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    DeleteVmportEnv(input, 1, true, 1);
    client->WaitForIdle();
    EXPECT_FALSE(VmPortFind(1));
    client->Reset();
}

TEST_F(PolicyTest, IntfPolicyDisable_Fip) {
    struct PortInfo input[] = {
        {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}
    };

    //Add VN
    util_.VnAdd(input[0].vn_id);
    // Nova Port add message
    util_.NovaPortAdd(&input[0]);
    // Config Port add
    util_.ConfigPortAdd(&input[0]);
    //Verify that the port is inactive
    EXPECT_TRUE(VmPortInactive(input, 0));

    //Add necessary objects and links to make vm-intf active
    util_.VmAdd(input[0].vm_id);
    util_.VrfAdd(input[0].vn_id);
    AddLink("virtual-network", "vn1", "routing-instance", "vrf1");
    client->WaitForIdle();
    AddLink("virtual-network", "vn1", "virtual-machine-interface", "vnet1");
    client->WaitForIdle();
    AddLink("virtual-machine", "vm1", "virtual-machine-interface", "vnet1");
    client->WaitForIdle();
    AddVmPortVrf("vnet1", "", 0);
    client->WaitForIdle();
    AddInstanceIp("instance0", input[0].vm_id, input[0].addr);
    AddLink("virtual-machine-interface", input[0].name,
            "instance-ip", "instance0");
    client->WaitForIdle(3);
    AddLink("virtual-machine-interface-routing-instance", "vnet1",
            "routing-instance", "vrf1");
    client->WaitForIdle(3);
    AddLink("virtual-machine-interface-routing-instance", "vnet1",
            "virtual-machine-interface", "vnet1");
    client->WaitForIdle(3);
    EXPECT_TRUE(VmPortActive(input, 0));
    const VmInterface *intf = VmInterfaceGet(input[0].intf_id);
    EXPECT_TRUE(intf != NULL);
    EXPECT_FALSE(intf->policy_enabled());

    //Create a VN for floating-ip
    client->Reset();
    AddVn("default-project:vn2", 2);
    client->WaitForIdle();
    WAIT_FOR(1000, 100, (client->vn_notify_ >= 1));
    AddVrf("default-project:vn2:vn2");
    client->WaitForIdle();
    EXPECT_TRUE(client->VrfNotifyWait(1));
    EXPECT_TRUE(VrfFind("default-project:vn2:vn2"));
    AddLink("virtual-network", "default-project:vn2", "routing-instance",
            "default-project:vn2:vn2");
    client->WaitForIdle();

    // Configure Floating-IP
    AddFloatingIpPool("fip-pool1", 1);
    AddFloatingIp("fip1", 1, "71.1.1.100");
    AddLink("floating-ip", "fip1", "floating-ip-pool", "fip-pool1");
    AddLink("floating-ip-pool", "fip-pool1", "virtual-network",
            "default-project:vn2");
    client->WaitForIdle();
    AddLink("virtual-machine-interface", "vnet1", "floating-ip", "fip1");
    client->WaitForIdle();
    WAIT_FOR(1000, 500, ((VmPortFloatingIpCount(1, 1) == true)));
    EXPECT_TRUE(intf->policy_enabled());

    uint32_t prev_label = intf->label();
    //Verify that interface's MPLS label points to policy-enabled NH
    const NextHop *nh = MplsToNextHop(prev_label);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's L2 MPLS label points to policy-enabled NH
    nh = MplsToNextHop(intf->l2_label());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's route points to policy-enabled NH
    nh = RouteToNextHop("vrf1", intf->primary_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's L2 route points to policy-enabled NH
    MacAddress mac(intf->vm_mac());
    nh = L2RouteToNextHop("vrf1", mac);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's flow_key_nh points to policy-enabled NH
    nh = intf->flow_key_nh();
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's mdata route points to policy-enabled NH
    nh = RouteToNextHop(agent_->fabric_vrf_name(), intf->mdata_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Configure disable-policy as true on interface
    //---------------------------------------------
    SetPolicyDisabledStatus(input, true);
    client->WaitForIdle();

    //Verify that policy is disabled on interface
    EXPECT_FALSE(intf->policy_enabled());

    //Verify that interface's MPLS label has changed
    EXPECT_TRUE (prev_label != intf->label());
    prev_label = intf->label();

    //Verify that interface's MPLS label points to policy-disabled NH
    nh = MplsToNextHop(prev_label);
    EXPECT_TRUE(nh != NULL);
    EXPECT_FALSE(nh->PolicyEnabled());

    //Verify that interface's L2 MPLS label points to policy-disabled NH
    nh = MplsToNextHop(intf->l2_label());
    EXPECT_TRUE(nh != NULL);
    EXPECT_FALSE(nh->PolicyEnabled());

    //Verify that interface's route points to policy-disabled NH
    nh = RouteToNextHop("vrf1", intf->primary_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_FALSE(nh->PolicyEnabled());

    //Verify that interface's L2 route points to policy-disabled NH
    nh = L2RouteToNextHop("vrf1", mac);
    EXPECT_TRUE(nh != NULL);
    EXPECT_FALSE(nh->PolicyEnabled());

    //Verify that interface's flow_key_nh still points to policy-enabled NH
    nh = intf->flow_key_nh();
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's mdata route still points to policy-enabled NH
    nh = RouteToNextHop(agent_->fabric_vrf_name(), intf->mdata_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Configure disable-policy as false on interface
    //---------------------------------------------
    SetPolicyDisabledStatus(input, false);
    client->WaitForIdle();

    //Verify that policy is enabled
    EXPECT_TRUE(intf->policy_enabled());

    //Verify that interface's MPLS label has changed
    EXPECT_TRUE (prev_label != intf->label());

    //Verify that interface's MPLS label points to policy-enabled NH
    nh = MplsToNextHop(intf->label());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's L2 MPLS label points to policy-enabled NH
    nh = MplsToNextHop(intf->l2_label());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's route points to policy-enabled NH
    nh = RouteToNextHop("vrf1", intf->primary_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's L2 route points to policy-enabled NH
    nh = L2RouteToNextHop("vrf1", mac);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's flow_key_nh points to policy-enabled NH
    nh = intf->flow_key_nh();
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Verify that interface's mdata route points to policy-enabled NH
    nh = RouteToNextHop(agent_->fabric_vrf_name(), intf->mdata_ip_addr(), 32);
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(nh->PolicyEnabled());

    //Delete the floating-IP
    DelLink("floating-ip", "fip1", "floating-ip-pool", "fip-pool1");
    DelLink("virtual-machine-interface", "vnet1", "floating-ip", "fip1");
    DelFloatingIp("fip1");
    client->WaitForIdle();

    //cleanup
    DelLink("floating-ip-pool", "fip-pool1", "virtual-network",
            "default-project:vn2");
    DelLink("floating-ip-pool", "fip-pool1", "virtual-network", "vn1");
    DelFloatingIpPool("fip-pool1");
    DelLink("virtual-machine-interface-routing-instance", "vnet1",
            "routing-instance", "vrf1");
    DelLink("virtual-machine-interface-routing-instance", "vnet1",
            "virtual-machine-interface", "vnet1");
    DelLink("virtual-machine", "vm1", "virtual-machine-interface", "vnet1");
    DelLink("virtual-network", "vn1", "virtual-machine-interface", "vnet1");
    client->WaitForIdle();
    DelLink("virtual-network", "default-project:vn2", "routing-instance",
            "default-project:vn2:vn2");
    client->WaitForIdle(3);
    DelLink("virtual-machine-interface", input[0].name,
            "instance-ip", "instance0");
    DelLink("virtual-network", "vn1", "routing-instance", "vrf1");
    client->WaitForIdle(3);

    DelNode("virtual-network", "default-project:vn2");
    DelVrf("default-project:vn2:vn2");
    client->WaitForIdle(3);
    DelNode("virtual-machine-interface-routing-instance", "vnet1");
    client->WaitForIdle(3);
    DelNode("virtual-machine", "vm1");
    DelNode("routing-instance", "vrf1");
    client->WaitForIdle(3);
    DelNode("virtual-machine-interface", "vnet1");
    DelInstanceIp("instance0");
    client->WaitForIdle(3);
    IntfCfgDel(input, 0);
    util_.VnDelete(input[0].vn_id);
    client->WaitForIdle(3);
    WAIT_FOR(1000, 500, (VnGet(input[0].vn_id) == NULL));

    //clear counters at the end of test case
    client->Reset();
}

TEST_F(PolicyTest, IntfPolicyDisable_Flow) {
    struct PortInfo input[] = {
        {"flow0", 6, vm1_ip, "00:00:00:01:01:01", 5, 1},
        {"flow1", 7, vm2_ip, "00:00:00:01:01:02", 5, 2},
    };

    VmInterface *flow0, *flow1;

    CreateVmportEnv(input, 2, 1);
    client->WaitForIdle(5);

    EXPECT_TRUE(VmPortActive(input, 0));
    EXPECT_TRUE(VmPortActive(input, 1));
    WAIT_FOR(100, 1000, (VmPortPolicyEnable(input, 0)));
    WAIT_FOR(100, 1000, (VmPortPolicyEnable(input, 1)));

    flow0 = VmInterfaceGet(input[0].intf_id);
    assert(flow0);
    flow1 = VmInterfaceGet(input[1].intf_id);
    assert(flow1);

    AddSgEntry("sg1", "sg_acl1", 10, 1, "pass", BIDIRECTION);
    AddLink("virtual-machine-interface", "flow1", "security-group", "sg1");
    client->WaitForIdle();
    EXPECT_EQ(flow1->sg_list().list_.size(), 1U);

    TestFlow flow[] = {
        //Add a ICMP forward and reverse flow
        {  TestFlowPkt(Address::INET, vm1_ip, vm2_ip, 1, 0, 0, "vrf5",
                       flow0->id()),
        {
            new VerifyVn("vn5", "vn5"),
            new VerifyVrf("vrf5", "vrf5")
        }
        }
    };

    CreateFlow(flow, 1);
    EXPECT_EQ(2U, flow_proto_->FlowCount());

    //Since policy is enabled on reverse flow's VMI, verify that out SG rules
    //are present
    const FlowEntry *fe = flow[0].pkt_.FlowFetch();
    EXPECT_TRUE(fe->data().match_p.out_sg_rule_present);

    //Delete all the flows
    client->EnqueueFlowFlush();
    client->WaitForIdle(10);
    EXPECT_EQ(0U, flow_proto_->FlowCount());

    //Disable policy on flow1 VMI
    SetPolicyDisabledStatus(&input[1], true);
    client->WaitForIdle();

    //Verify that policy status of interfaces
    WAIT_FOR(100, 1000, ((VmPortPolicyEnabled(input, 0)) == true));
    WAIT_FOR(100, 1000, ((VmPortPolicyEnabled(input, 1)) == false));

    //Setup flows again
    CreateFlow(flow, 1);
    EXPECT_EQ(2U, flow_proto_->FlowCount());

    //Since policy is disabled on reverse flow's VMI, verify that out SG rules
    //are not present
    fe = flow[0].pkt_.FlowFetch();
    EXPECT_FALSE(fe->data().match_p.out_sg_rule_present);

    //Cleanup
    client->EnqueueFlowFlush();
    client->WaitForIdle(10);
    client->Reset();
    EXPECT_EQ(0U, flow_proto_->FlowCount());
    char acl_name[1024];
    uint16_t max_len = sizeof(acl_name) - 1;

    DelLink("virtual-machine-interface", "flow1", "security-group", "sg1");
    strncpy(acl_name, "sg_acl1", max_len);
    strncat(acl_name, "egress-access-control-list", max_len);
    DelLink("security-group", "sg1", "access-control-list", acl_name);
    DelNode("access-control-list", acl_name);

    strncpy(acl_name, "sg_acl1", max_len);
    strncat(acl_name, "ingress-access-control-list", max_len);
    DelLink("security-group", "sg1", "access-control-list", acl_name);
    DelNode("access-control-list", acl_name);
    DelNode("security-group", "sg1");
    client->WaitForIdle();
    EXPECT_EQ(flow1->sg_list().list_.size(), 0U);

    DeleteVmportEnv(input, 2, true, 1);
    client->WaitForIdle(3);
    WAIT_FOR(1000, 1000, (VmPortFind(input, 0) == false));
    WAIT_FOR(1000, 1000, (VmPortFind(input, 1) == false));
    EXPECT_EQ(0U, flow_proto_->FlowCount());
}

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

    client = TestInit(init_file, ksync_init, false, false, false);

    int ret = RUN_ALL_TESTS();

    usleep(10000);
    client->WaitForIdle();
    usleep(10000);
    TestShutdown();
    delete client;

    return ret;
}

ext: cc

max_stars_repo_name: UbuntuEvangelist/contrail-controller

max_issues_repo_name: UbuntuEvangelist/contrail-controller

max_forks_repo_name: UbuntuEvangelist/contrail-controller