From 1fb18c8cf6f1a52fd8096517c6bf9156d55492da Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Tue, 4 Sep 2018 07:50:01 +0200 Subject: [PATCH] add wip managed containers --- alib2std/src/alib/managed_linear_set | 1 + alib2std/src/alib/managed_value | 1 + .../container/managed/managed_linear_set.hpp | 989 ++++++++++++++++++ .../container/managed/managed_value.hpp | 322 ++++++ .../managed/ManagedLinearSetTest.cpp | 51 + .../container/managed/ManagedLinearSetTest.h | 18 + .../container/managed/ManagedValueTest.cpp | 22 + .../container/managed/ManagedValueTest.h | 18 + 8 files changed, 1422 insertions(+) create mode 100644 alib2std/src/alib/managed_linear_set create mode 100644 alib2std/src/alib/managed_value create mode 100644 alib2std/src/extensions/container/managed/managed_linear_set.hpp create mode 100644 alib2std/src/extensions/container/managed/managed_value.hpp create mode 100644 alib2std/test-src/extensions/container/managed/ManagedLinearSetTest.cpp create mode 100644 alib2std/test-src/extensions/container/managed/ManagedLinearSetTest.h create mode 100644 alib2std/test-src/extensions/container/managed/ManagedValueTest.cpp create mode 100644 alib2std/test-src/extensions/container/managed/ManagedValueTest.h diff --git a/alib2std/src/alib/managed_linear_set b/alib2std/src/alib/managed_linear_set new file mode 100644 index 0000000000..5aa1229dc8 --- /dev/null +++ b/alib2std/src/alib/managed_linear_set @@ -0,0 +1 @@ +#include <extensions/container/managed/managed_linear_set.hpp> diff --git a/alib2std/src/alib/managed_value b/alib2std/src/alib/managed_value new file mode 100644 index 0000000000..af452afc85 --- /dev/null +++ b/alib2std/src/alib/managed_value @@ -0,0 +1 @@ +#include <extensions/container/managed/managed_value.hpp> diff --git a/alib2std/src/extensions/container/managed/managed_linear_set.hpp b/alib2std/src/extensions/container/managed/managed_linear_set.hpp new file mode 100644 index 0000000000..e3c4e7e831 --- /dev/null +++ b/alib2std/src/extensions/container/managed/managed_linear_set.hpp @@ -0,0 +1,989 @@ +/* + * managed_linear_set.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: Sep 13, 2016 + * Author: Jan Travnicek + */ + +#ifndef __MANAGED_LINEAR_SET_HPP_ +#define __MANAGED_LINEAR_SET_HPP_ + +#include <extensions/container/linear_set.hpp> +#include <extensions/algorithm.hpp> + +namespace ext { + +/** + * \brief + * Implementation of set mimicking the iterface of the standard library set. The inner representation is using sorted vector of unique value. + * + * \tparam T the type of stored values + * \tparam Compare the less comparator used to determinine order between elements - defaults to std::less < T > + * \tparam Alloc the allocator of elements - defaults to std::allocator < T > + */ +template < class T, class Compare = std::less<T>, class Alloc = std::allocator<T> > +class managed_linear_set { + /** + * \brief + * The inner values holder. + */ + ext::linear_set < T, Compare, Alloc > m_data; + + std::vector < std::function < void ( const T & ) > > insertCallbacks; + + std::vector < std::function < void ( const T & ) > > removeCallbacks; + + void fireInsert ( const T & element ) const { + for ( const std::function < void ( const T & ) > & callback : insertCallbacks ) { + callback ( element ); + } + } + + void fireRemove ( const T & element ) const { + for ( const std::function < void ( const T & ) > & callback : removeCallbacks ) { + callback ( element ); + } + } + + /** + * \brief + * Equality test helper function + * + * \param first the first value + * \param second the second value + */ + bool eq ( const T & first, const T & second ) { + return ! m_data.value_comp ( ) ( first, second ) && ! m_data.value_comp ( ) ( second, first ); + } + +public: + void addInsertCallback ( const std::function < void ( const T & ) > & callback ) { + insertCallbacks.push_back ( callback ); + } + + void addRemoveCallback ( const std::function < void ( const T & ) > & callback ) { + removeCallbacks.push_back ( callback ); + } + + /** + * \brief + * The type of values in the set. + */ + typedef T value_type; + + /** + * \brief + * The type of iterator over values in the set. It is the same as the underling vector's const iterator. + */ + typedef typename ext::vector < T, Alloc >::const_iterator iterator; + + /** + * \brief + * The type of const iterator over values in the set. It is the same as the underling vector's const iterator. + */ + typedef typename ext::vector < T, Alloc >::const_iterator const_iterator; + + /** + * \brief + * The type of reverse iterator over values in the set. It is the same as the underling vector's const reverse iterator. + */ + typedef typename ext::vector < T, Alloc >::const_reverse_iterator reverse_iterator; + + /** + * \brief + * The type of const reverse iterator over values in the set. It is the same as the underling vector's const reverse iterator. + */ + typedef typename ext::vector < T, Alloc >::const_reverse_iterator const_reverse_iterator; + + /** + * \brief + * Default constructor of the empty set. + * + * \param comp the instance of custom comparator or defaultly constructed comparator based on the comparator type + * \param alloc the instance of custom allocator or defaultly constructed allocator based on the comparator type + */ + explicit managed_linear_set (const Compare& comp = Compare(), const Alloc& alloc = Alloc()) : m_data ( comp, alloc ) { + } + + /** + * \brief + * Constructor of the empty set with specified allocator. + * + * \param alloc the instance of custom allocator + */ + explicit managed_linear_set (const Alloc& alloc) : m_data ( alloc, Compare ( ) ) { + } + + /** + * \brief + * Set constructor from a range of values. + * + * \param first the begining of the range of values + * \param last the end of the range of values + * \param comp the instance of custom comparator or defaultly constructed comparator based on the comparator type + * \param alloc the instance of custom allocator or defaultly constructed allocator based on the comparator type + */ + template <class InputIterator> + managed_linear_set (InputIterator first, InputIterator last, const Compare& comp = Compare(), const Alloc& alloc = Alloc()) : m_data ( first, last, comp, alloc ) { + } + + /** + * Constructor from range of values. + * + * \tparam Iterator the type of range iterator + * + * \param range the source range + */ + template < class Iterator > + managed_linear_set ( const ext::iterator_range < Iterator > & range ) : managed_linear_set ( range.begin ( ), range.end ( ) ) { + } + + /** + * \brief + * Copy constructor. + * + * \param x the other linear set instance + */ + managed_linear_set (const managed_linear_set& x) : m_data ( x.m_data ) { + } + + /** + * \brief + * Copy constructor including allocator specification. + * + * \param x the other linear set instance + * \param alloc the new allocator instance + */ + managed_linear_set ( const managed_linear_set & x, const Alloc & alloc ) : m_data ( x.m_data, x.value_comp ( ), alloc ) { + } + + /** + * \brief + * Move constructor. + * + * \param x the other linear set instance + */ + managed_linear_set ( managed_linear_set && x ) { + for ( const T & elem : x ) { + x.fireRemove ( elem ); + } + + m_data = std::move ( x.m_data ); + } + + /** + * \brief + * Move constructor including allocator specification. + * + * \param x the other linear set instance + * \param alloc the new allocator instance + */ + managed_linear_set (managed_linear_set&& x, const Alloc& alloc) : m_data ( x.value_comp ( ), alloc ) { + for ( const T & elem : x ) { + x.fireRemove ( elem ); + } + + m_data = std::move ( x.m_data ); + } + + /** + * \brief + * Set constructor from initializer list. + * + * \param il the source of values represented by initializer list + * \param comp the instance of custom comparator or defaultly constructed comparator based on the comparator type + * \param alloc the instance of custom allocator or defaultly constructed allocator based on the comparator type + */ + managed_linear_set (std::initializer_list<T> il, const Compare& comp = Compare(), const Alloc& alloc = Alloc()) : m_data ( std::move ( il ), comp, alloc ) { + } + + /** + * \brief + * The destructor of the linear set. + */ + ~managed_linear_set ( ) { + } + + /** + * \brief + * Getter of an iterator to the begining of range of values in the container. + * + * \return begin iterator + */ + iterator begin() & noexcept { + return m_data.begin ( ); + } + + /** + * \brief + * Getter of a const iterator to the begining of range of values in the container. + * + * \return begin const iterator + */ + const_iterator begin() const & noexcept { + return m_data.begin ( ); + } + + /** + * \brief + * Getter of a move iterator to the begining of range of values in the container. + * + * \return begin move iterator + */ + auto begin ( ) && noexcept { + return std::move ( * this ).begin ( ); + } + + /** + * \brief + * Getter of a const iterator to the begining of range of values in the container. + * + * \return begin const iterator + */ + const_iterator cbegin() const noexcept { + return m_data.cbegin ( ); + } + + /** + * \brief + * Getter of an iterator to the end of range of values in the container. + * + * \return end iterator + */ + iterator end() & noexcept { + return m_data.end ( ); + } + + /** + * \brief + * Getter of a const iterator to the end of range of values in the container. + * + * \return end const iterator + */ + const_iterator end() const & noexcept { + return m_data.end ( ); + } + + /** + * \brief + * Getter of a move iterator to the end of range of values in the container. + * + * \return end move iterator + */ + auto end ( ) && noexcept { + return std::move ( * this ).end ( ); + } + + /** + * \brief + * Getter of a const iterator to the end of range of values in the container. + * + * \return end const iterator + */ + const_iterator cend() const noexcept { + return m_data.cend ( ); + } + + /** + * \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 + * Removes all values from the conainer,. + * + */ + void clear() noexcept { + for ( const T & elem : m_data ) { + fireRemove ( elem ); + } + + m_data.clear ( ); + } + + /** + * \brief + * Computes the number of values in the container. + * + * \return the number of values in the container. + */ + size_t count ( const T& value ) const { + return m_data.count ( value ); + } + + /** + * \brief + * Getter of a const revese iterator to the begining of reverse range of values in the container. + * + * \return begin const reverse iterator + */ + const_reverse_iterator crbegin() const noexcept { + return m_data.crbegin ( ); + } + + /** + * \brief + * Getter of a const revese iterator to the end of reverse range of values in the container. + * + * \return end const reverse iterator + */ + const_reverse_iterator crend() const noexcept { + return m_data.crend ( ); + } + + /** + * \brief + * Emplace a value to the container. Internaly the method uses insert since the place to put the value requires call to comparator and that needs the value. + * + * \tparam Args ... types of arguments of constructor of T + * + * \param args ... actual parameters pased to constructor of T + * + * \return pair of iterator and bool, where the iterator points to newly inserted value (or already existing one) and the bool is true of the value was inserted, or false if the value was alread inside the container + */ + template <class... Args> + std::pair < iterator, bool > emplace ( Args && ... args ) { + return insert ( T ( std::forward ( args ) ... ) ); + } + + /** + * \brief + * Emplace a value to the container with provided position as a hint. Internaly the method uses insert since the place to put the value requires call to comparator and that needs the value. + * + * \tparam Args ... types of arguments of constructor of T + * + * \param position the position hint where to place the new value + * \param args ... actual parameters pased to constructor of T + * + * \return pair of iterator and bool, where the iterator points to newly inserted value (or already existing one) and the bool is true of the value was inserted, or false if the value was alread inside the container + */ + template <class... Args> + iterator emplace_hint ( const_iterator position, Args && ... args ) { + return insert ( position, T ( std::forward ( args ) ... ) ); + } + + /** + * \brief + * Tests whether the container is empty. + * + * \return true if the container is empty, false othervise + */ + bool empty ( ) const noexcept { + return m_data.empty ( ); + } + + /** + * \brief + * Returns a range of values equal to the \p val. The range is specified by const iterators. + * + * \param val the queried value + * + * \returns pair of iterators representing the range + */ + std::pair < const_iterator, const_iterator > equal_range ( const T & val ) const { + return std::make_pair ( lower_bound ( val ), upper_bound ( val ) ); + } + + /** + * \brief + * Returns a range of values equal to the \p val. The range is specified by iterators. + * + * \param val the queried value + * + * \returns pair of iterators representing the range + */ + std::pair < iterator, iterator > equal_range ( const T & val ) { + return std::make_pair ( lower_bound ( val ), upper_bound ( val ) ); + } + + /** + * \brief + * Removes value from the container based on the position given by iterator. + * + * \param position the iterator pointing to the value to remove. + * + * \return updated iterator pointing to the next value + */ + iterator erase ( const_iterator position ) { + fireRemove ( * position ); + return m_data.erase ( position ); + } + + /** + * \brief + * Removes value from the container. + * + * \param val the value to remove. + * + * \return the number of removed values + */ + size_t erase ( const T & val ) { + const_iterator position = lower_bound ( val ); + if ( position != end ( ) && eq ( * position, val ) ) { + fireRemove ( * position ); + m_data.erase ( position ); + return 1; + } else { + return 0; + } + } + + /** + * \brief + * Removes values in the specified range. The range is specified by pair of iterators. + * + * \param first the begining of removed range of values + * \param last the end of removed range of values + * + * \return iterator to value after last removed value + */ + iterator erase (const_iterator first, const_iterator last) { + for ( const T & elem : ext::make_iterator_range ( first, last ) ) + fireRemove ( elem ); + + return m_data.erase ( first, last ); + } + + /** + * \brief + * Function to binary search for given value. + * + * \param val the value to search for + * + * \return iterator pointing to searched value or iterator to end + */ + const_iterator find ( const T & val ) const { + m_data.find ( val ); + } + + /** + * \brief + * Function to binary search for given value. + * + * \param val the value to search for + * + * \return iterator pointing to searched value or iterator to end + */ + iterator find ( const T & val ) { + m_data.find ( val ); + } + + /** + * \brief + * Getter of the allocator. + * + * \return the allocator + */ + Alloc get_allocator() const noexcept { + return m_data.get_allocator ( ); + } + + /** + * \brief + * Inserts a new value to the container. + * + * \param val the value to insert + * + * \return pair of iterator and bool, where the iterator points to newly inserted value (or already existing one) and the bool is true of the value was inserted, or false if the value was alread inside the container + */ + std::pair < iterator, bool > insert ( const T & val ) { + return insert ( T ( val ) ); + } + + /** + * \brief + * Inserts a new value to the container. + * + * \param val the value to insert + * + * \return pair of iterator and bool, where the iterator points to newly inserted value (or already existing one) and the bool is true of the value was inserted, or false if the value was alread inside the container + */ + std::pair < iterator, bool > insert ( T && val ) { + const_iterator position = lower_bound ( val ); + if ( position != end ( ) && eq ( * position, val ) ) + return std::make_pair ( position, false ); + else { + fireInsert ( val ); + return std::make_pair ( m_data.insert ( position, std::move ( val ) ), true ); + } + } + + /** + * \brief + * Inserts a new value to the container. The method accepts a position hint where to place the new value. + * + * \param position the hint where to insert + * \param val the value to insert + * + * \return iterator pointing to newly inserted value (or already existing one). + */ + iterator insert ( const_iterator position, const T & val ) { + return insert ( position, T ( val ) ); + } + + /** + * \brief + * Inserts a new value to the container. The method accepts a position hint where to place the new value. + * + * \param position the hint where to insert + * \param val the value to insert + * + * \return iterator pointing to newly inserted value (or already existing one). + */ + iterator insert (const_iterator position, T&& val) { + if ( position != end ( ) && eq ( * position, val ) ) + return position; + + if ( position != end ( ) && m_comp ( val, * position ) && ( position == begin ( ) || m_comp ( * std::prev ( position ), val ) ) ) { + fireInsert ( val ); + return m_data.emplace ( position, std::move ( val ) ); + } + + return insert ( std::move ( val ) ).first; + } + + /** + * \brief + * Insert values from a range speified by pair of iterators. + * + * \param first the begining of removed range of values + * \param last the end of removed range of values + */ + template <class InputIterator> + void insert (InputIterator first, InputIterator last) { + for ( const T & elem : ext::make_iterator_range ( first, last ) ) + fireInsert ( elem ); + + m_data.insert ( first, last ); + } + + /** + * \brief + * Insert values from a range speified by initializer list. + * + * \param il the source of values represented by initializer list + */ + void insert (std::initializer_list<T> il) { + insert ( il.begin ( ), il.end ( ) ); + } + + /** + * \brief + * Getter of the key comparator instance. + * + * \return the key comparator instance + */ + Compare key_comp() const { + return m_data.key_comp(); + } + + /** + * \brief + * Returns an iterator pointing to the first element in the range [first,last) which does not compare less than val. + * + * \param val the border value + * + * \return the iterator meeting lower_bound criteria + */ + iterator lower_bound ( const T & val ) { + return m_data.lower_bound ( val ); + } + + /** + * \brief + * Returns an iterator pointing to the first element in the range [first,last) which does not compare less than val. + * + * \param val the border value + * + * \return the iterator meeting lower_bound criteria + */ + const_iterator lower_bound (const T& val) const { + return m_data.lower_bound ( val ); + } + + /** + * \brief + * Returns the maximal number of values possible to store inside the container. + * + * \return the maximal number of values + */ + size_t max_size() const noexcept { + return m_data.max_size ( ); + } + + /** + * \brief + * Copy operator of assignmet. + * + * \param x the other instance + * + * \return the modified instance + */ + managed_linear_set & operator= ( const managed_linear_set & data ) { + ext::set_symmetric_difference ( m_data.begin ( ), m_data.end ( ), data.begin ( ), data.end ( ), ext::make_callback_iterator < const T & > ( std::bind ( & managed_linear_set::fireRemove, this, std::placeholders::_1 ) ), ext::make_callback_iterator < const T & > ( std::bind ( & managed_linear_set::fireInsert, this, std::placeholders::_1 ) ) ); + + m_data = data.m_data; + return *this; + } + + /** + * \brief + * Move operator of assignmet. + * + * \param x the other instance + * + * \return the modified instance + */ + managed_linear_set & operator= ( managed_linear_set && data ) { + ext::set_symmetric_difference ( m_data.begin ( ), m_data.end ( ), data.begin ( ), data.end ( ), ext::make_callback_iterator < const T & > ( std::bind ( & managed_linear_set::fireRemove, this, std::placeholders::_1 ) ), ext::make_callback_iterator < const T & > ( std::bind ( & managed_linear_set::fireInsert, this, std::placeholders::_1 ) ) ); + + for ( const T & elem : data ) { + data.fireRemove ( elem ); + } + + m_data = std::move ( data.m_data ); + return *this; + } + + /** + * \brief + * Asignment from the initializer list. + * + * \param il the source initializer list + * + * \return the modified instance + */ + managed_linear_set & operator= ( std::initializer_list < T > il ) { + linear_set < T > data ( il ); + ext::set_symmetric_difference ( m_data.begin ( ), m_data.end ( ), data.begin ( ), data.end ( ), ext::make_callback_iterator < const T & > ( std::bind ( & managed_linear_set::fireRemove, this, std::placeholders::_1 ) ), ext::make_callback_iterator < const T & > ( std::bind ( & managed_linear_set::fireInsert, this, std::placeholders::_1 ) ) ); + + m_data = std::move ( data ); + return *this; + } + + /** + * \brief + * Getter of a reverse iterator to the begining of range of values in the container. + * + * \return begin reverse iterator + */ + reverse_iterator rbegin() noexcept { + return m_data.rbegin ( ); + } + + /** + * \brief + * Getter of a const reverse iterator to the begining of range of values in the container. + * + * \return begin const reverse iterator + */ + const_reverse_iterator rbegin() const noexcept { + return m_data.rbegin ( ); + } + + /** + * \brief + * Getter of a reverse iterator to the end of range of values in the container. + * + * \return end reverse iterator + */ + reverse_iterator rend() noexcept { + return m_data.rend ( ); + } + + /** + * \brief + * Getter of a const reverse iterator to the end of range of values in the container. + * + * \return end const reverse iterator + */ + const_reverse_iterator rend() const noexcept { + return m_data.rend ( ); + } + + /** + * \brief + * Getter of the number of values inside the container. + * + * \return the number of values + */ + size_t size() const noexcept { + return m_data.size ( ); + } + + /** + * \brief + * Swaps two instances of linear set + * + * \param x the other instance to swap with + */ + void swap ( managed_linear_set & data ) { + ext::callback_iterator < const T & > thisToOther ( [ this, & data ] ( const T & element ) { this->fireRemove ( element ); data.fireInsert ( element ); } ); + ext::callback_iterator < const T & > otherToThis ( [ this, & data ] ( const T & element ) { data.fireRemove ( element ); this->fireInsert ( element ); } ); + ext::set_symmetric_difference ( m_data.begin ( ), m_data.end ( ), data.begin ( ), data.end ( ), thisToOther, otherToThis ); + + m_data.swap ( data.m_data ); + } + + /** + * \brief + * Returns an iterator pointing to the first element in the range [first,last) which compares greater than val. + * + * \param val the border value + * + * \return the iterator meeting upper_bound criteria + */ + iterator upper_bound ( const T & val) { + return m_data.upper_bound ( val ); + } + + /** + * \brief + * Returns an iterator pointing to the first element in the range [first,last) which compares greater than val. + * + * \param val the border value + * + * \return the iterator meeting upper_bound criteria + */ + const_iterator upper_bound (const T& val) const { + return m_data.upper_bound ( val ); + } + + /** + * \brief + * Getter of the value comparator instance. Actually the value_type is the same as key_type so this is an alias to key_comp method + * + * \return the key comparator instance + */ + Compare value_comp() const { + return m_data.value_comp ( ); + } + + /** + * \brief + * Compares two set instances for equvalence. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the two compared instance are equal, false othervise + */ + friend bool operator== ( const managed_linear_set<T,Compare,Alloc>& lhs, const managed_linear_set<T,Compare,Alloc>& rhs ) { + return lhs.m_data == rhs.m_data; + } + + /** + * \brief + * Compares two set instances for non equvalence. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the two compared instance are not equal, false othervise + */ + friend bool operator!= ( const managed_linear_set<T,Compare,Alloc>& lhs, const managed_linear_set<T,Compare,Alloc>& rhs ) { + return lhs.m_data != rhs.m_data; + } + + /** + * \brief + * Compares two set instances by less relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is less than the other instance, false othervise + */ + friend bool operator< ( const managed_linear_set<T,Compare,Alloc>& lhs, const managed_linear_set<T,Compare,Alloc>& rhs ) { + return lhs.m_data < rhs.m_data; + } + + /** + * \brief + * Compares two set instances by less or equal relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is less than or equal than the other instance, false othervise + */ + friend bool operator<= ( const managed_linear_set<T,Compare,Alloc>& lhs, const managed_linear_set<T,Compare,Alloc>& rhs ) { + return lhs.m_data <= rhs.m_data; + } + + /** + * \brief + * Compares two set instances by greater relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is greater than the other instance, false othervise + */ + friend bool operator> ( const managed_linear_set<T,Compare,Alloc>& lhs, const managed_linear_set<T,Compare,Alloc>& rhs ) { + return lhs.m_data > rhs.m_data; + } + + /** + * \brief + * Compares two set instances by greater or equal relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is greater than or equal than the other instance, false othervise + */ + friend bool operator>= ( const managed_linear_set<T,Compare,Alloc>& lhs, const managed_linear_set<T,Compare,Alloc>& rhs ) { + return lhs.m_data >= rhs.m_data; + } + +}; + +/** + * \brief + * Operator to print the set to the output stream. + * + * \param out the output stream + * \param value the array to print + * + * \tparam T the type of values inside the array + * \tparam Ts ... remaining unimportant template parameters of the set + * + * \return the output stream from the \p out + */ +template< class T, class ... Ts > +std::ostream& operator<<(std::ostream& out, const ext::managed_linear_set<T, Ts ...>& value) { + out << "{"; + + bool first = true; + for(const T& item : value) { + 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 values inside the set + * \tparam Ts ... remaining unimportant template parameters of the set + */ +template<class T, class ... Ts> +struct compare<ext::managed_linear_set<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::managed_linear_set<T, Ts ...>& first, const ext::managed_linear_set<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 set to be converted to string + * + * \tparam T the type of values inside the set + * \tparam Ts ... remaining unimportant template parameters of the set + * + * \return string representation + */ +template < class T, class ... Ts > +std::string to_string ( const ext::managed_linear_set < T, Ts ... > & value ) { + std::stringstream ss; + ss << value; + return ss.str(); +} + +} /* namespace ext */ + +namespace std { + +/** + * \brief + * Specialisation of swap for linear set + * + * \tparam T the value of the set + * \tpatam Compare the comparator + * \tparam Alloc the values Allocator + * + * \param x the first instance + * \param y the second instance + */ +template <class T, class Compare, class Alloc> +void swap ( ext::managed_linear_set < T, Compare, Alloc > & x, ext::managed_linear_set < T, Compare, Alloc > & y ) { + x.swap ( y ); +} + +} + +#endif /* __MANAGED_LINEAR_SET_HPP_ */ diff --git a/alib2std/src/extensions/container/managed/managed_value.hpp b/alib2std/src/extensions/container/managed/managed_value.hpp new file mode 100644 index 0000000000..ca3abfc970 --- /dev/null +++ b/alib2std/src/extensions/container/managed/managed_value.hpp @@ -0,0 +1,322 @@ +/* + * managed_value.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: Sep 13, 2016 + * Author: Jan Travnicek + */ + +#ifndef __MANAGED_VALUE_HPP_ +#define __MANAGED_VALUE_HPP_ + +#include <extensions/container/linear_set.hpp> + +namespace ext { + +/** + * \brief + * Implementation of managed value mimicking the behavior of the underlying value. The class is designed to fire change events when the value is modified. + * + * \tparam T the type of stored values + */ +template < class T > +class managed_value { + /** + * \brief + * The inner values holder. + */ + T m_data; + + std::vector < std::function < void ( const T & ) > > changeCallbacks; + + void fireChange ( const T & element ) { + for ( const std::function < void ( const T & ) > & callback : changeCallbacks ) { + callback ( element ); + } + } + +public: + void addChangeCallback ( const std::function < void ( const T & ) > & callback ) { + changeCallbacks.push_back ( callback ); + } + + /** + * \brief + * The type of values in the set. + */ + typedef T value_type; + + /** + * Constructor from range of values. + * + * \tparam Iterator the type of range iterator + * + * \param range the source range + */ + managed_value ( const T & value ) : m_data ( value ) { + } + + /** + * Constructor from range of values. + * + * \tparam Iterator the type of range iterator + * + * \param range the source range + */ + managed_value ( T && value ) : m_data ( std::move ( value ) ) { + } + + /** + * \brief + * Copy constructor. + * + * \param x the other linear set instance + */ + managed_value ( const managed_value & x ) : m_data ( x.m_data ) { + } + + /** + * \brief + * Move constructor. + * + * \param x the other linear set instance + */ + managed_value ( managed_value && x ) : m_data ( std::move ( x.m_data ) ) { + } + + /** + * \brief + * The destructor of the linear set. + */ + ~managed_value ( ) { + } + + /** + * \brief + * Copy operator of assignmet. + * + * \param x the other instance + * + * \return the modified instance + */ + managed_value & operator= ( const managed_value & x ) { + m_data = x.m_data; + fireChange ( m_data ); + return *this; + } + + /** + * \brief + * Move operator of assignmet. + * + * \param x the other instance + * + * \return the modified instance + */ + managed_value& operator= ( managed_value && x ) { + m_data = std::move ( x.m_data ); + fireChange ( m_data ); + return *this; + } + + /** + * \brief + * Swaps two instances of linear set + * + * \param x the other instance to swap with + */ + void swap ( managed_value & x ) { + // intentionally swaped values the change fired is before its execution + this->fireChange ( x.getValue ( ) ); + x.fireChange ( this->getValue ( ) ); + + using std::swap; + swap ( m_data, x.m_data ); + } + + /** + * \brief + * Compares two set instances for equvalence. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the two compared instance are equal, false othervise + */ + friend bool operator== ( const managed_value < T > & lhs, const managed_value < T > & rhs ) { + return lhs.m_data == rhs.m_data; + } + + /** + * \brief + * Compares two set instances for non equvalence. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the two compared instance are not equal, false othervise + */ + friend bool operator!= ( const managed_value < T > & lhs, const managed_value < T > & rhs ) { + return lhs.m_data != rhs.m_data; + } + + /** + * \brief + * Compares two set instances by less relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is less than the other instance, false othervise + */ + friend bool operator< ( const managed_value < T > & lhs, const managed_value < T > & rhs ) { + return lhs.m_data < rhs.m_data; + } + + /** + * \brief + * Compares two set instances by less or equal relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is less than or equal than the other instance, false othervise + */ + friend bool operator<= ( const managed_value < T > & lhs, const managed_value < T > & rhs ) { + return lhs.m_data <= rhs.m_data; + } + + /** + * \brief + * Compares two set instances by greater relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is greater than the other instance, false othervise + */ + friend bool operator> ( const managed_value < T > & lhs, const managed_value < T > & rhs ) { + return lhs.m_data > rhs.m_data; + } + + /** + * \brief + * Compares two set instances by greater or equal relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is greater than or equal than the other instance, false othervise + */ + friend bool operator>= ( const managed_value < T > & lhs, const managed_value < T > & rhs ) { + return lhs.m_data >= rhs.m_data; + } + + /** + * Operator to give the managed value as raw constant reference. + * + * \return the managed value + */ + operator const T & ( ) const { + return m_data; + } + + /** + * Managed value getter providing the managed value as raw constant reference. + * + * \return the managed value + */ + const T & getValue ( ) const { + return m_data; + } + +}; + +/** + * \brief + * Specialisation of swap for linear set + * + * \tparam T the value of the set + * + * \param x the first instance + * \param y the second instance + */ +template < class T > +void swap ( ext::managed_value < T > & x, ext::managed_value < T > & y) { + x.swap ( y ); +} + +/** + * \brief + * Operator to print the set to the output stream. + * + * \param out the output stream + * \param value the array to print + * + * \tparam T the type of values inside the array + * + * \return the output stream from the \p out + */ +template< class T > +std::ostream & operator << ( std::ostream & out, const ext::managed_value < T > & value ) { + out << value.getValue ( ); + return out; +} + +/** + * \brief + * Specialisation of the compare structure implementing the three-way comparison. + * + * \tparam T the type of values inside the set + */ +template < class T > +struct compare < ext::managed_value < T > > { + + /** + * \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::managed_value < T > & first, const ext::managed_value < T > & second ) const { + static compare < typename std::decay < T >::type > comp; + return comp ( first.getValue ( ), second.getValue ( ) ); + } +}; + +/** + * \brief + * Overload of to_string function. + * + * \param value the set to be converted to string + * + * \tparam T the type of values inside the set + * + * \return string representation + */ +template < class T > +std::string to_string ( const ext::managed_value < T > & value ) { + return to_string < T > ( value.getValue ( ) ); +} + +} /* namespace ext */ + +#endif /* __MANAGED_VALUE_HPP_ */ diff --git a/alib2std/test-src/extensions/container/managed/ManagedLinearSetTest.cpp b/alib2std/test-src/extensions/container/managed/ManagedLinearSetTest.cpp new file mode 100644 index 0000000000..5e52e3502b --- /dev/null +++ b/alib2std/test-src/extensions/container/managed/ManagedLinearSetTest.cpp @@ -0,0 +1,51 @@ +#include "ManagedLinearSetTest.h" +#include <exception> + +#include <alib/managed_linear_set> + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION ( ManagedLinearSetTest, "bits" ); +CPPUNIT_TEST_SUITE_REGISTRATION ( ManagedLinearSetTest ); + +void ManagedLinearSetTest::setUp ( ) { +} + +void ManagedLinearSetTest::tearDown ( ) { +} + +void ManagedLinearSetTest::testBasics ( ) { + ext::managed_linear_set < int > mod2; + mod2.addInsertCallback ( [](const int & value) { if ( value % 2 != 0 ) throw value; } ); + CPPUNIT_ASSERT_NO_THROW ( mod2.insert ( 12 ) ); + CPPUNIT_ASSERT_THROW ( mod2.insert ( 13 ), int ); + + ext::managed_linear_set < int > mod6; + mod6.addInsertCallback ( [](const int & value) { if ( value % 6 != 0 ) throw value; } ); + CPPUNIT_ASSERT_NO_THROW ( mod6.insert ( 6 ) ); + CPPUNIT_ASSERT_THROW ( mod6.insert ( 4 ), int ); + + CPPUNIT_ASSERT_NO_THROW ( std::swap ( mod2, mod6 ) ); + + mod2.insert ( 4 ); + + mod2.addInsertCallback ( [](const int & value) { std::cout << "mod2 added: " << value << std::endl; } ); + mod2.addRemoveCallback ( [](const int & value) { std::cout << "mod2 removed: " << value << std::endl; } ); + mod6.addInsertCallback ( [](const int & value) { std::cout << "mod6 added: " << value << std::endl; } ); + mod6.addRemoveCallback ( [](const int & value) { std::cout << "mod6 removed: " << value << std::endl; } ); + + std::cout << "mod2: " << mod2 << std::endl; + std::cout << "mod6: " << mod6 << std::endl; + CPPUNIT_ASSERT_THROW ( std::swap ( mod2, mod6 ), int ); + std::cout << "mod2: " << mod2 << std::endl; + std::cout << "mod6: " << mod6 << std::endl; + CPPUNIT_ASSERT_THROW ( swap ( mod2, mod6 ), int ); + std::cout << "mod2: " << mod2 << std::endl; + std::cout << "mod6: " << mod6 << std::endl; + + CPPUNIT_ASSERT_NO_THROW ( mod2.insert ( mod6.begin ( ), mod6.end ( ) ) ); + CPPUNIT_ASSERT_THROW ( mod2.insert ( { 8, 9 } ), int ); + + std::cout << "mod2: " << mod2 << std::endl; + std::cout << "mod6: " << mod6 << std::endl; + + mod2 = { 4, 6, 8 }; +} diff --git a/alib2std/test-src/extensions/container/managed/ManagedLinearSetTest.h b/alib2std/test-src/extensions/container/managed/ManagedLinearSetTest.h new file mode 100644 index 0000000000..03dba93740 --- /dev/null +++ b/alib2std/test-src/extensions/container/managed/ManagedLinearSetTest.h @@ -0,0 +1,18 @@ +#ifndef MANAGED_LINEAR_SET_TEST_H_ +#define MANAGED_LINEAR_SET_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class ManagedLinearSetTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE ( ManagedLinearSetTest ); + CPPUNIT_TEST ( testBasics ); + CPPUNIT_TEST_SUITE_END ( ); + +public: + void setUp ( ); + void tearDown ( ); + + void testBasics ( ); +}; + +#endif // MANAGED_LINEAR_SET_TEST_H_ diff --git a/alib2std/test-src/extensions/container/managed/ManagedValueTest.cpp b/alib2std/test-src/extensions/container/managed/ManagedValueTest.cpp new file mode 100644 index 0000000000..33e899938f --- /dev/null +++ b/alib2std/test-src/extensions/container/managed/ManagedValueTest.cpp @@ -0,0 +1,22 @@ +#include "ManagedValueTest.h" +#include <exception> + +#include <alib/managed_value> + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION ( ManagedValueTest, "bits" ); +CPPUNIT_TEST_SUITE_REGISTRATION ( ManagedValueTest ); + +void ManagedValueTest::setUp ( ) { +} + +void ManagedValueTest::tearDown ( ) { +} + +void ManagedValueTest::testBasics ( ) { + ext::managed_value < int > number ( 1 ); + number.addChangeCallback ( [ ] ( const int & value ) { if ( value >= 10 ) throw value; } ); + CPPUNIT_ASSERT_NO_THROW ( number = 2 ); + CPPUNIT_ASSERT_THROW ( number = 10, int ); + + +} diff --git a/alib2std/test-src/extensions/container/managed/ManagedValueTest.h b/alib2std/test-src/extensions/container/managed/ManagedValueTest.h new file mode 100644 index 0000000000..a94f5a1759 --- /dev/null +++ b/alib2std/test-src/extensions/container/managed/ManagedValueTest.h @@ -0,0 +1,18 @@ +#ifndef MANAGED_VALUE_TEST_H_ +#define MANAGED_VALUE_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class ManagedValueTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE ( ManagedValueTest ); + CPPUNIT_TEST ( testBasics ); + CPPUNIT_TEST_SUITE_END ( ); + +public: + void setUp ( ); + void tearDown ( ); + + void testBasics ( ); +}; + +#endif // MANAGED_VALUE_TEST_H_ -- GitLab