/*
 * bitset.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: May 04, 2017
 * Author: Jan Travnicek
 */

#pragma once

#include <bitset>
#include <ostream>
#include <sstream>
#include <string>
#include <compare>

namespace ext {

/**
 * \brief
 * Class extending the bitset class from the standard library. Original reason is to allow printing of the container with overloaded operator <<.
 *
 * The class mimics the behavior of the bitset from the standatd library.
 *
 * \tparam N the size of the bitset
 */
template < std::size_t N >
class bitset : public std::bitset < N > {
public:
	/**
	 * Inherit constructors of the standard bitset
	 */
	using std::bitset < N >::bitset; // NOLINT(modernize-use-equals-default)

	/**
	 * Inherit operator = of the standard bitset
	 */
	using std::bitset < N >::operator =;
#ifndef __clang__

	/**
	 * Default constructor needed by g++ since it is not inherited
	 */
	bitset ( ) = default;

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

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

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

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

	std::strong_ordering operator <=> ( const ext::bitset < N > & second ) const {
		const bitset < N > & first = * this;
		for ( size_t i = 0; i < N; ++i ) {
			std::strong_ordering res = first [ i ] <=> second [ i ];
			if ( res != 0 )
				return res;
		}
		return std::strong_ordering::equal;
	}

	bool operator == ( const ext::bitset < N > & second ) const {
		return ( * this <=> second ) == 0;
	}
};

/**
 * \brief
 * Operator to print the bitset to the output stream.
 *
 * \param out the output stream
 * \param bitset the bitset to print
 *
 * \tparam N the size of the bitset
 *
 * \return the output stream from the \p out
 */
template < size_t N >
std::ostream & operator << ( std::ostream & out, const ext::bitset < N > & bitset ) {
	out << "[";

	for ( size_t i = 0; i < N; ++i ) {
		if ( i != 0 ) out << ", ";
		out << bitset [ i ];
	}

	out << "]";
	return out;
}

/**
 * \brief
 * Overload of to_string function.
 *
 * \param value the bitset to be converted to string
 *
 * \tparam N the size of the bitset
 *
 * \return string representation
 */
template < size_t N >
std::string to_string ( const ext::bitset < N > & value ) {
	std::stringstream ss;
	ss << value;
	return ss.str ( );
}

} /* namespace ext */

