/*
 * pair.hpp
 *
 * This file is part of Algorithms library toolkit.
 * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)

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

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

 * You should have received a copy of the GNU General Public License
 * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Created on: Apr 1, 2013
 * Author: Jan Travnicek
 */

#pragma once

#include <sstream>
#include <string>

#include <extensions/type_traits.hpp>
#include <extensions/utility.hpp>

namespace ext {

/**
 * \brief
 * Class extending the pair class from the standard library. Original reason is to allow printing of the pair with overloaded operator <<.
 *
 * The class mimics the behavior of the pair from the standatd library.
 *
 * \tparam T the type of the first value inside the pair
 * \tparam R the type of the second value inside the pair
 */
template < class T, class R >
class pair : public std::pair < T, R > {
public:
	/**
	 * Inherit constructors of the standard pair
	 */
	using std::pair < T, R >::pair; // NOLINT(modernize-use-equals-default)

	/**
	 * Inherit operator = of the standard pair
	 */
	using std::pair < T, R >::operator =;
#ifndef __clang__

	/**
	 * Default constructor needed by g++ since it is not inherited
	 */
	pair ( const pair & other ) = default;

	/**
	 * Copy constructor needed by g++ since it is not inherited
	 */
	pair ( pair && other ) = default;

	/**
	 * Copy operator = needed by g++ since it is not inherited
	 */
	pair & operator = ( pair && other ) = default;

	/**
	 * Move operator = needed by g++ since it is not inherited
	 */
	pair & operator = ( const pair & other ) = default;
#endif
};

template<typename T1, typename T2>
constexpr auto make_pair ( T1 && x, T2 && y ) {
	typedef typename ext::strip_reference_wrapper < std::decay_t < T1 > >::type ds_type1;
	typedef typename ext::strip_reference_wrapper < std::decay_t < T2 > >::type ds_type2;
	return pair < ds_type1, ds_type2 > ( std::forward < T1 > ( x ), std::forward < T2 > ( y ) );
}

/**
 * \brief
 * Operator to print the pair to the output stream.
 *
 * \param out the output stream
 * \param pair the pair to print
 *
 * \tparam T the type of the first value inside the pair
 * \tparam R the type of the second value inside the pair
 *
 * \return the output stream from the \p out
 */
template< class T, class R >
std::ostream& operator<<(std::ostream& out, const ext::pair<T, R>& pair) {
	out << "(" << pair.first << ", " << pair.second << ")";
	return out;
}

/**
 * \brief
 * Overload of to_string function.
 *
 * \param value the pair to be converted to string
 *
 * \tparam T the type of the first value inside the pair
 * \tparam R the type of the second value inside the pair
 *
 * \return string representation
 */
template < class T, class R >
std::string to_string ( const ext::pair < T, R > & value ) {
	std::stringstream ss;
	ss << value;
	return ss.str();
}

} /* namespace ext */

