From 9a8c6b5f4410854b30950130c16a9b3261a70fc8 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Tue, 3 Dec 2019 19:17:04 +0100 Subject: [PATCH] multiset extensions --- alib2std/src/alib/multiset | 1 + .../src/extensions/container/multiset.hpp | 368 ++++++++++++++++++ 2 files changed, 369 insertions(+) create mode 100644 alib2std/src/alib/multiset create mode 100644 alib2std/src/extensions/container/multiset.hpp diff --git a/alib2std/src/alib/multiset b/alib2std/src/alib/multiset new file mode 100644 index 0000000000..832b97e839 --- /dev/null +++ b/alib2std/src/alib/multiset @@ -0,0 +1 @@ +#include <extensions/container/multiset.hpp> diff --git a/alib2std/src/extensions/container/multiset.hpp b/alib2std/src/extensions/container/multiset.hpp new file mode 100644 index 0000000000..1dcba0b4f9 --- /dev/null +++ b/alib2std/src/extensions/container/multiset.hpp @@ -0,0 +1,368 @@ +/* + * multiset.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 + */ + +#ifndef __MULTI_SET_H_ +#define __MULTI_SET_H_ + +#include <set> +#include <ostream> +#include <sstream> +#include <string> + +#include <extensions/compare.hpp> +#include <extensions/range.hpp> + +namespace ext { + +/** + * Class extending the multiset class from the standard library. Original reason is to allow printing of the container with overloaded operator <<. + * + * The class mimics the behavior of the multiset from the standatd library. + * + * \tparam T the type of keys inside the multiset + * \tparam Cmp the comparator type used to order keys + * \tparam Alloc the allocator of values of type T + */ +template < typename T, typename Cmp = std::less < >, typename Alloc = std::allocator < T > > +class multiset : public std::multiset < T, Cmp, Alloc > { +public: + /** + * Inherit constructors of the standard multiset + */ + using std::multiset < T, Cmp, Alloc >::multiset; // NOLINT(modernize-use-equals-default) + + /** + * Inherit operator = of the standard multiset + */ + using std::multiset < T, Cmp, Alloc >::operator =; +#ifndef __clang__ + + /** + * Default constructor needed by g++ since it is not inherited + */ + multiset ( ) = default; + + /** + * Copy constructor needed by g++ since it is not inherited + */ + multiset ( const multiset & other ) = default; + + /** + * Move constructor needed by g++ since it is not inherited + */ + multiset ( multiset && other ) = default; + + /** + * Copy operator = needed by g++ since it is not inherited + */ + multiset & operator = ( multiset && other ) = default; + + /** + * Move operator = needed by g++ since it is not inherited + */ + multiset & operator = ( const multiset & other ) = default; +#endif + /** + * Constructor from range of values. + * + * \tparam Iterator the type of range iterator + * + * \param range the source range + */ + template < class Iterator > + explicit multiset ( const ext::iterator_range < Iterator > & range ) : multiset ( range.begin ( ), range.end ( ) ) { + } + + /** + * \brief + * Inherited behavior of begin for non-const instance. + * + * \return iterator the first element of multiset + */ + auto begin ( ) & { + return std::multiset < T, Cmp, Alloc >::begin ( ); + } + + /** + * \brief + * Inherited behavior of begin for const instance. + * + * \return const_iterator the first element of multiset + */ + auto begin ( ) const & { + return std::multiset < T, Cmp, Alloc >::begin ( ); + } + + /** + * \brief + * New variant of begin for rvalues. + * + * \return move_iterator the first element of multiset + */ + auto begin ( ) && { + return make_set_move_iterator ( this->begin ( ) ); + } + + /** + * \brief + * Inherited behavior of end for non-const instance. + * + * \return iterator to one after the last element of multiset + */ + auto end ( ) & { + return std::multiset < T, Cmp, Alloc >::end ( ); + } + + /** + * \brief + * Inherited behavior of end for const instance. + * + * \return const_iterator to one after the last element of multiset + */ + auto end ( ) const & { + return std::multiset < T, Cmp, Alloc >::end ( ); + } + + /** + * \brief + * New variant of end for rvalues. + * + * \return move_iterator to one after the last element of multiset + */ + auto end ( ) && { + return make_set_move_iterator ( this->end ( ) ); + } + + /** + * \brief + * Make range of non-const begin to end iterators. + * + * \return full range over container values + */ + auto range ( ) & { + auto endIter = end ( ); + auto beginIter = begin ( ); + return ext::iterator_range < decltype ( endIter ) > ( beginIter, endIter ); + } + + /** + * \brief + * Make range of non-const begin to end iterators. + * + * \return full range over container values + */ + auto range ( ) const & { + auto endIter = end ( ); + auto beginIter = begin ( ); + return ext::iterator_range < decltype ( endIter ) > ( beginIter, endIter ); + } + + /** + * \brief + * Make range of move begin to end iterators. + * + * \return full range over container values + */ + auto range ( ) && { + auto endIter = std::move ( * this ).end ( ); + auto beginIter = std::move ( * this ).begin ( ); + return ext::iterator_range < decltype ( endIter ) > ( beginIter, endIter ); + } + + /** + * \brief + * Make range of elements with key equal to the @p key. + * + * \tparam K the key used in the query + * + * \param key the value used in the query + * + * \return selected range of elements + */ + template < class K > + auto equal_range ( K && key ) const & { + auto res = std::multiset < T, Cmp, Alloc >::equal_range ( std::forward < K > ( key ) ); + return ext::iterator_range < decltype ( res.first ) > ( res.first, res.second ); + } + + /** + * \brief + * Make range of elements with key equal to the @p key. + * + * \tparam K the key used in the query + * + * \param key the value used in the query + * + * \return selected range of elements + */ + template < class K > + auto equal_range ( K && key ) & { + auto res = std::multiset < T, Cmp, Alloc >::equal_range ( std::forward < K > ( key ) ); + return ext::iterator_range < decltype ( res.first ) > ( res.first, res.second ); + } + + /** + * \brief + * Make range of elements with key equal to the @p key. + * + * \tparam K the key used in the query + * + * \param key the value used in the query + * + * \return selected range of elements + */ + template < class K > + auto equal_range ( K && key ) && { + auto res = std::multiset < T, Cmp, Alloc >::equal_range ( std::forward < K > ( key ) ); + return ext::make_iterator_range ( make_set_move_iterator < T > ( res.first ), make_set_move_iterator < T > ( res.second ) ); + } + + /** + * \brief + * Test whether the multiset contains a given key + * + * \param key the tested key + * + * \return true if the multiset contains the key, false otherwise + */ + bool contains ( const T & key ) const { // TODO remove after switching C++20 + return this->count ( key ) != 0U; + } + + /** + * \brief + * Test whether the multiset contains a given key + * + * \tparam K the type of the key + * + * \param key the tested key + * + * \return true if the multiset contains the key, false otherwise + */ + template < class K > + bool contains ( const K & key ) const { // TODO remove after switching C++20 + return this->count ( key ) != 0U; + } +}; + +/** + * \brief + * Operator to print the multiset to the output stream. + * + * \param out the output stream + * \param multiset the multiset to print + * + * \tparam T the type of keys inside the multiset + * \tparam R the type of values inside the multiset + * \tparam Ts ... remaining unimportant template parameters of the multiset + * + * \return the output stream from the \p out + */ +template< class T, class ... Ts > +std::ostream& operator<<(std::ostream& out, const ext::multiset<T, Ts ...>& list) { + out << "{"; + + bool first = true; + for(const T& item : list) { + if(!first) out << ", "; + first = false; + out << item; + } + + out << "}"; + return out; +} + +/** + * \brief + * Specialisation of the compare structure implementing the three-way comparison. + * + * \tparam T the type of keys inside the multiset + * \tparam R the type of values inside the multiset + * \tparam Ts ... remaining unimportant template parameters of the multiset + */ +template<class T, class ... Ts> +struct compare < ext::multiset < T, Ts ... > > { + + /** + * \brief + * Implementation of the three-way comparison. + * + * \param first the left operand of the comparison + * \param second the right operand of the comparison + * + * \return negative value of left < right, positive value if left > right, zero if left == right + */ + int operator()(const ext::multiset<T, Ts ...>& first, const ext::multiset<T, Ts ...>& second) const { + if(first.size() < second.size()) return -1; + if(first.size() > second.size()) return 1; + + static compare<typename std::decay < T >::type > comp; + for(auto iterF = first.begin(), iterS = second.begin(); iterF != first.end(); ++iterF, ++iterS) { + int res = comp(*iterF, *iterS); + if(res != 0) return res; + } + return 0; + } +}; + +/** + * \brief + * Overload of to_string function. + * + * \param value the multiset to be converted to string + * + * \tparam T the type of values inside the multiset + * \tparam Ts ... remaining unimportant template parameters of the multiset + * + * \return string representation + */ +template < class T, class ... Ts > +std::string to_string ( const ext::multiset < T, Ts ... > & value ) { + std::stringstream ss; + ss << value; + return ss.str(); +} + +/** + * \brief + * Implementation of union of two multisets. + * + * \tparam T the type of values stored in unioned multisets + * + * \param first the first multiset to union + * \param second the second multiset to union + * + * \return multiset representing union + */ +template < class T > +ext::multiset < T > operator +( const ext::multiset < T > & first, const ext::multiset < T > & second ) { + ext::multiset < T > res ( first ); + + res.insert ( second.begin ( ), second.end ( ) ); + return res; +} + +} /* namespace ext */ + +#endif /* __MULTI_SET_H_ */ -- GitLab