From cb28239f236b44760fcfb5305996762bdd5f7d83 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 16 Apr 2017 18:52:47 +0100 Subject: [PATCH] Added intrusive flat map/multimap/set/multiset --- src/intrusive_flat_map.h | 951 ++++++++++++++++++++++++++ src/intrusive_flat_multimap.h | 864 +++++++++++++++++++++++ src/intrusive_flat_multiset.h | 850 +++++++++++++++++++++++ src/intrusive_flat_set.h | 860 +++++++++++++++++++++++ test/test_flat_set.cpp | 69 +- test/test_intrusive_flat_map.cpp | 802 ++++++++++++++++++++++ test/test_intrusive_flat_multimap.cpp | 685 +++++++++++++++++++ test/test_intrusive_flat_multiset.cpp | 649 ++++++++++++++++++ test/test_intrusive_flat_set.cpp | 592 ++++++++++++++++ 9 files changed, 6289 insertions(+), 33 deletions(-) create mode 100644 src/intrusive_flat_map.h create mode 100644 src/intrusive_flat_multimap.h create mode 100644 src/intrusive_flat_multiset.h create mode 100644 src/intrusive_flat_set.h create mode 100644 test/test_intrusive_flat_map.cpp create mode 100644 test/test_intrusive_flat_multimap.cpp create mode 100644 test/test_intrusive_flat_multiset.cpp create mode 100644 test/test_intrusive_flat_set.cpp diff --git a/src/intrusive_flat_map.h b/src/intrusive_flat_map.h new file mode 100644 index 00000000..2de66ac3 --- /dev/null +++ b/src/intrusive_flat_map.h @@ -0,0 +1,951 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_INTRUSIVE_FLAT_MAP__ +#define __ETL_INTRUSIVE_FLAT_MAP__ + +#include + +#include "exception.h" +#include "vector.h" +#include "ivector.h" +#include "error_handler.h" + +#undef ETL_FILE +#define ETL_FILE "30" + +//***************************************************************************** +///\defgroup intrusive_flat_map intrusive_flat_map +/// An intrusive_flat_map with the capacity defined at compile time. +/// Has insertion of O(N) and search of O(logN) +/// Duplicate entries are not allowed. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + ///\ingroup intrusive_flat_map + /// Exception base for intrusive_flat_maps + //*************************************************************************** + class intrusive_flat_map_exception : public exception + { + public: + + intrusive_flat_map_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup intrusive_flat_map + /// Vector full exception. + //*************************************************************************** + class intrusive_flat_map_full : public intrusive_flat_map_exception + { + public: + + intrusive_flat_map_full(string_type file_name, numeric_type line_number) + : intrusive_flat_map_exception(ETL_ERROR_TEXT("intrusive_flat_map: full", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup intrusive_flat_map + /// Vector out of bounds exception. + //*************************************************************************** + class intrusive_flat_map_out_of_bounds : public intrusive_flat_map_exception + { + public: + + intrusive_flat_map_out_of_bounds(string_type file_name, numeric_type line_number) + : intrusive_flat_map_exception(ETL_ERROR_TEXT("intrusive_flat_map:bounds", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized intrusive_flat_maps. + /// Can be used as a reference type for all intrusive_flat_maps containing a specific type. + ///\ingroup intrusive_flat_map + //*************************************************************************** + template > + class iintrusive_flat_map + { + public: + + typedef size_t size_type; + typedef std::pair value_type; + + private: + + typedef etl::ivector lookup_t; + + public: + + typedef TKey key_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class iintrusive_flat_map; + + iterator() + { + } + + iterator(typename lookup_t::iterator ilookup) + : ilookup(ilookup) + { + } + + iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + iterator& operator ++() + { + ++ilookup; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + ++ilookup; + return temp; + } + + iterator& operator --() + { + --ilookup; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return &(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::iterator ilookup; + }; + + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class iintrusive_flat_map; + + const_iterator() + { + } + + const_iterator(typename lookup_t::const_iterator ilookup) + : ilookup(ilookup) + { + } + + const_iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator(const const_iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator =(const const_iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator ++() + { + ++ilookup; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + ++ilookup; + return temp; + } + + const_iterator& operator --() + { + --ilookup; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + --ilookup; + return temp; + } + + const_reference operator *() const + { + return *(*ilookup); + } + + const_pointer operator &() const + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::const_iterator ilookup; + }; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef typename std::iterator_traits::difference_type difference_type; + + protected: + + typedef typename parameter_type::type key_value_parameter_t; + + private: + + //********************************************************************* + /// How to compare elements and keys. + //********************************************************************* + class compare + { + public: + + bool operator ()(const value_type& element, key_type key) const + { + return key_compare()(element.first, key); + } + + bool operator ()(key_type key, const value_type& element) const + { + return key_compare()(key, element.first); + } + }; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the intrusive_flat_map. + ///\return An iterator to the beginning of the intrusive_flat_map. + //********************************************************************* + iterator begin() + { + return iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the intrusive_flat_map. + ///\return A const iterator to the beginning of the intrusive_flat_map. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the intrusive_flat_map. + ///\return An iterator to the end of the intrusive_flat_map. + //********************************************************************* + iterator end() + { + return iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the intrusive_flat_map. + ///\return A const iterator to the end of the intrusive_flat_map. + //********************************************************************* + const_iterator end() const + { + return const_iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the intrusive_flat_map. + ///\return A const iterator to the beginning of the intrusive_flat_map. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(lookup.cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the intrusive_flat_map. + ///\return A const iterator to the end of the intrusive_flat_map. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(lookup.cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the intrusive_flat_map. + ///\return Iterator to the reverse beginning of the intrusive_flat_map. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the intrusive_flat_map. + ///\return Const iterator to the reverse beginning of the intrusive_flat_map. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the intrusive_flat_map. + ///\return Reverse iterator to the end + 1 of the intrusive_flat_map. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the intrusive_flat_map. + ///\return Const reverse iterator to the end + 1 of the intrusive_flat_map. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the intrusive_flat_map. + ///\return Const reverse iterator to the reverse beginning of the intrusive_flat_map. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(lookup.crbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the intrusive_flat_map. + ///\return Const reverse iterator to the end + 1 of the intrusive_flat_map. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(lookup.crend()); + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& operator [](key_value_parameter_t key) + { + iterator i_element = lower_bound(key); + + ETL_ASSERT(i_element != end(), ETL_ERROR(intrusive_flat_map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'key' + ///\param i The index. + ///\return A const reference to the value at index 'key' + //********************************************************************* + const mapped_type& operator [](key_value_parameter_t key) const + { + iterator i_element = lower_bound(key); + + ETL_ASSERT(i_element != end(), ETL_ERROR(intrusive_flat_map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& at(key_value_parameter_t key) + { + iterator i_element = lower_bound(key); + + ETL_ASSERT(i_element != end(), ETL_ERROR(intrusive_flat_map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A const reference to the value at index 'key' + //********************************************************************* + const mapped_type& at(key_value_parameter_t key) const + { + const_iterator i_element = lower_bound(key); + + ETL_ASSERT(i_element != end(), ETL_ERROR(intrusive_flat_map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Assigns values to the intrusive_flat_map. + /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined, emits flat_map_full if the intrusive_flat_map does not have enough free space. + /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined, emits flat_map_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type count = std::distance(first, last); + ETL_ASSERT(count <= difference_type(capacity()), ETL_ERROR(intrusive_flat_map_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the intrusive_flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the intrusive_flat_map is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair insert(value_type& value) + { + iterator i_element = lower_bound(value.first); + + return insert_at(i_element, value); + } + + //********************************************************************* + /// Inserts a value to the intrusive_flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the intrusive_flat_map is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, value_type& value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the intrusive_flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the intrusive_flat_map does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(key_value_parameter_t key) + { + iterator i_element = find(key); + + if (i_element == end()) + { + return 0; + } + else + { + lookup.erase(i_element.ilookup); + return 1; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + lookup.erase(i_element.ilookup); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + lookup.erase(first.ilookup, last.ilookup); + } + + //************************************************************************* + /// Clears the intrusive_flat_map. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_value_parameter_t key) + { + iterator itr = lower_bound(key); + + if (itr != end()) + { + if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_value_parameter_t key) const + { + const_iterator itr = lower_bound(key); + + if (itr != end()) + { + if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_value_parameter_t key) const + { + return (find(key) == end()) ? 0 : 1; + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(key_value_parameter_t key) + { + return std::lower_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(key_value_parameter_t key) const + { + return std::lower_bound(cbegin(), cend(), key, compare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(key_value_parameter_t key) + { + return std::upper_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(key_value_parameter_t key) const + { + return std::upper_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair equal_range(key_value_parameter_t key) + { + iterator i_lower = std::lower_bound(begin(), end(), key, compare()); + + return std::make_pair(i_lower, std::upper_bound(i_lower, end(), key, compare())); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair equal_range(key_value_parameter_t key) const + { + const_iterator i_lower = std::lower_bound(cbegin(), cend(), key, compare()); + + return std::make_pair(i_lower, std::upper_bound(i_lower, cend(), key, compare())); + } + + //************************************************************************* + /// Gets the current size of the intrusive_flat_map. + ///\return The current size of the intrusive_flat_map. + //************************************************************************* + size_type size() const + { + return lookup.size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the intrusive_flat_map. + ///\return true if empty. + //************************************************************************* + bool empty() const + { + return lookup.empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the intrusive_flat_map. + ///\return true if full. + //************************************************************************* + bool full() const + { + return lookup.full(); + } + + //************************************************************************* + /// Returns the capacity of the intrusive_flat_map. + ///\return The capacity of the intrusive_flat_map. + //************************************************************************* + size_type capacity() const + { + return lookup.capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the intrusive_flat_map. + ///\return The maximum size of the intrusive_flat_map. + //************************************************************************* + size_type max_size() const + { + return lookup.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return lookup.available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iintrusive_flat_map(lookup_t& lookup_) + : lookup(lookup_) + { + } + + private: + + //********************************************************************* + /// Inserts a value to the intrusive_flat_map. + ///\param i_element The place to insert. + ///\param value The value to insert. + //********************************************************************* + std::pair insert_at(iterator i_element, value_type& value) + { + std::pair result(end(), false); + + if (i_element == end()) + { + // At the end. + ETL_ASSERT(!lookup.full(), ETL_ERROR(intrusive_flat_map_full)); + + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + result.first = i_element; + + // Existing element? + if (value.first != i_element->first) + { + // A new one. + ETL_ASSERT(!lookup.full(), ETL_ERROR(intrusive_flat_map_full)); + lookup.insert(i_element.ilookup, &value); + result.second = true; + } + } + + return result; + } + + // Disable copy construction and assignment. + iintrusive_flat_map(const iintrusive_flat_map&); + iintrusive_flat_map& operator = (const iintrusive_flat_map&); + + lookup_t& lookup; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first intrusive_flat_map. + ///\param rhs Reference to the second intrusive_flat_map. + ///\return true if the arrays are equal, otherwise false + ///\ingroup intrusive_flat_map + //*************************************************************************** + template + bool operator ==(const etl::iintrusive_flat_map& lhs, const etl::iintrusive_flat_map& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first intrusive_flat_map. + ///\param rhs Reference to the second intrusive_flat_map. + ///\return true if the arrays are not equal, otherwise false + ///\ingroup intrusive_flat_map + //*************************************************************************** + template + bool operator !=(const etl::iintrusive_flat_map& lhs, const etl::iintrusive_flat_map& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// A intrusive_flat_map implementation that uses a fixed size buffer. + ///\tparam TKey The key type. + ///\tparam TValue The value type. + ///\tparam TCompare The type to compare keys. Default = std::less + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup intrusive_flat_map + //*************************************************************************** + template > + class intrusive_flat_map : public iintrusive_flat_map + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + intrusive_flat_map() + : iintrusive_flat_map(lookup) + { + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template + intrusive_flat_map(TIterator first, TIterator last) + : iintrusive_flat_map(lookup) + { + iintrusive_flat_map::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~intrusive_flat_map() + { + iintrusive_flat_map::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + intrusive_flat_map& operator = (const intrusive_flat_map& rhs) + { + if (&rhs != this) + { + iintrusive_flat_map::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + intrusive_flat_map(const intrusive_flat_map&); + + typedef typename iintrusive_flat_map::value_type node_t; + + // The vector that stores pointers to the nodes. + etl::vector lookup; + }; + +} + +#undef ETL_FILE + +#endif diff --git a/src/intrusive_flat_multimap.h b/src/intrusive_flat_multimap.h new file mode 100644 index 00000000..1b6be516 --- /dev/null +++ b/src/intrusive_flat_multimap.h @@ -0,0 +1,864 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_INTRUSIVE_FLAT_MULTIMAP_BASE__ +#define __ETL_INTRUSIVE_FLAT_MULTIMAP_BASE__ + +#include + +#include "exception.h" +#include "ivector.h" +#include "error_handler.h" +#include "debug_count.h" +#include "vector.h" +#include "ivector.h" + +#undef ETL_FILE +#define ETL_FILE "31" + +namespace etl +{ + //*************************************************************************** + ///\ingroup intrusive_flat_multimap + /// Exception base for intrusive_flat_multimaps + //*************************************************************************** + class intrusive_flat_multimap_exception : public exception + { + public: + + intrusive_flat_multimap_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup intrusive_flat_multimap + /// Vector full exception. + //*************************************************************************** + class intrusive_flat_multimap_full : public intrusive_flat_multimap_exception + { + public: + + intrusive_flat_multimap_full(string_type file_name, numeric_type line_number) + : intrusive_flat_multimap_exception(ETL_ERROR_TEXT("intrusive_flat_multimap:full", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized intrusive_flat_multimaps. + /// Can be used as a reference type for all intrusive_flat_multimaps containing a specific type. + ///\ingroup intrusive_flat_multimap + //*************************************************************************** + template > + class iintrusive_flat_multimap + { + public: + + typedef std::pair value_type; + typedef size_t size_type; + + private: + + typedef etl::ivector lookup_t; + + public: + + typedef TKey key_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class iintrusive_flat_multimap; + + iterator() + { + } + + iterator(typename lookup_t::iterator ilookup) + : ilookup(ilookup) + { + } + + iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + iterator& operator ++() + { + ++ilookup; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + ++ilookup; + return temp; + } + + iterator& operator --() + { + --ilookup; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return &(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::iterator ilookup; + }; + + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class iintrusive_flat_multimap; + + const_iterator() + { + } + + const_iterator(typename lookup_t::const_iterator ilookup) + : ilookup(ilookup) + { + } + + const_iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator(const const_iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator =(const const_iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator ++() + { + ++ilookup; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + ++ilookup; + return temp; + } + + const_iterator& operator --() + { + --ilookup; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + --ilookup; + return temp; + } + + const_reference operator *() const + { + return *(*ilookup); + } + + const_pointer operator &() const + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::const_iterator ilookup; + }; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef typename std::iterator_traits::difference_type difference_type; + + protected: + + typedef typename parameter_type::type key_value_parameter_t; + + private: + + //********************************************************************* + /// How to compare elements and keys. + //********************************************************************* + class compare + { + public: + + bool operator ()(const value_type& element, key_type key) const + { + return key_compare()(element.first, key); + } + + bool operator ()(key_type key, const value_type& element) const + { + return key_compare()(key, element.first); + } + }; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the intrusive_flat_multimap. + ///\return An iterator to the beginning of the intrusive_flat_multimap. + //********************************************************************* + iterator begin() + { + return iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the intrusive_flat_multimap. + ///\return A const iterator to the beginning of the intrusive_flat_multimap. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the intrusive_flat_multimap. + ///\return An iterator to the end of the intrusive_flat_multimap. + //********************************************************************* + iterator end() + { + return iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the intrusive_flat_multimap. + ///\return A const iterator to the end of the intrusive_flat_multimap. + //********************************************************************* + const_iterator end() const + { + return const_iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the intrusive_flat_multimap. + ///\return A const iterator to the beginning of the intrusive_flat_multimap. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(lookup.cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the intrusive_flat_multimap. + ///\return A const iterator to the end of the intrusive_flat_multimap. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(lookup.cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the intrusive_flat_multimap. + ///\return Iterator to the reverse beginning of the intrusive_flat_multimap. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the intrusive_flat_multimap. + ///\return Const iterator to the reverse beginning of the intrusive_flat_multimap. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the intrusive_flat_multimap. + ///\return Reverse iterator to the end + 1 of the intrusive_flat_multimap. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the intrusive_flat_multimap. + ///\return Const reverse iterator to the end + 1 of the intrusive_flat_multimap. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the intrusive_flat_multimap. + ///\return Const reverse iterator to the reverse beginning of the intrusive_flat_multimap. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(lookup.crbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the intrusive_flat_multimap. + ///\return Const reverse iterator to the end + 1 of the intrusive_flat_multimap. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(lookup.crend()); + } + + //********************************************************************* + /// Assigns values to the intrusive_flat_multimap. + /// If asserts or exceptions are enabled, emits intrusive_flat_multimap_full if the intrusive_flat_multimap does not have enough free space. + /// If asserts or exceptions are enabled, emits intrusive_flat_multimap_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type count = std::distance(first, last); + ETL_ASSERT(count <= difference_type(capacity()), ETL_ERROR(intrusive_flat_multimap_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the intrusive_flat_multimap. + /// If asserts or exceptions are enabled, emits intrusive_flat_multimap_full if the intrusive_flat_multimap is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair insert(value_type& value) + { + ETL_ASSERT(!lookup.full(), ETL_ERROR(intrusive_flat_multimap_full)); + + std::pair result(end(), false); + + iterator i_element = lower_bound(value.first); + + return insert_at(i_element, value); + } + + //********************************************************************* + /// Inserts a value to the flast_multi. + /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, const value_type& value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the intrusive_flat_multimap. + /// If asserts or exceptions are enabled, emits intrusive_flat_multimap_full if the intrusive_flat_multimap does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(key_value_parameter_t key) + { + std::pair range = equal_range(key); + + if (range.first == end()) + { + return 0; + } + else + { + size_t count = std::distance(range.first, range.second); + erase(range.first, range.second); + return count; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + lookup.erase(i_element.ilookup); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + lookup.erase(first.ilookup, last.ilookup); + } + + //************************************************************************* + /// Clears the intrusive_flat_multimap. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_value_parameter_t key) + { + iterator itr = lower_bound(key); + + if (itr != end()) + { + if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_value_parameter_t key) const + { + const_iterator itr = lower_bound(key); + + if (itr != end()) + { + if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_value_parameter_t key) const + { + std::pair range = equal_range(key); + + return std::distance(range.first, range.second); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(key_value_parameter_t key) + { + return std::lower_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(key_value_parameter_t key) const + { + return std::lower_bound(cbegin(), cend(), key, compare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(key_value_parameter_t key) + { + return std::upper_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(key_value_parameter_t key) const + { + return std::upper_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair equal_range(key_value_parameter_t key) + { + iterator i_lower = std::lower_bound(begin(), end(), key, compare()); + + return std::make_pair(i_lower, std::upper_bound(i_lower, end(), key, compare())); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair equal_range(key_value_parameter_t key) const + { + const_iterator i_lower = std::lower_bound(cbegin(), cend(), key, compare()); + + return std::make_pair(i_lower, std::upper_bound(i_lower, cend(), key, compare())); + } + + //************************************************************************* + /// Gets the current size of the flat_multiset. + ///\return The current size of the flat_multiset. + //************************************************************************* + size_type size() const + { + return lookup.size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the flat_multiset. + ///\return true if empty. + //************************************************************************* + bool empty() const + { + return lookup.empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the flat_multiset. + ///\return true if full. + //************************************************************************* + bool full() const + { + return lookup.full(); + } + + //************************************************************************* + /// Returns the capacity of the flat_multiset. + ///\return The capacity of the flat_multiset. + //************************************************************************* + size_type capacity() const + { + return lookup.capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the flat_multiset. + ///\return The maximum size of the flat_multiset. + //************************************************************************* + size_type max_size() const + { + return lookup.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return lookup.available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iintrusive_flat_multimap(lookup_t& lookup_) + : lookup(lookup_) + { + } + + private: + + //********************************************************************* + /// Inserts a value to the intrusive_flat_multimap. + ///\param i_element The place to insert. + ///\param value The value to insert. + //********************************************************************* + std::pair insert_at(iterator i_element, value_type& value) + { + std::pair result(end(), false); + + if (i_element == end()) + { + // At the end. + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + lookup.insert(i_element.ilookup, &value); + result.first = i_element; + result.second = true; + } + + return result; + } + + // Disable copy construction and assignment. + iintrusive_flat_multimap(const iintrusive_flat_multimap&); + iintrusive_flat_multimap& operator = (const iintrusive_flat_multimap&); + + lookup_t& lookup; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first intrusive_flat_multimap. + ///\param rhs Reference to the second intrusive_flat_multimap. + ///\return true if the arrays are equal, otherwise false + ///\ingroup intrusive_flat_multimap + //*************************************************************************** + template + bool operator ==(const etl::iintrusive_flat_multimap& lhs, const etl::iintrusive_flat_multimap& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first intrusive_flat_multimap. + ///\param rhs Reference to the second intrusive_flat_multimap. + ///\return true if the arrays are not equal, otherwise false + ///\ingroup intrusive_flat_multimap + //*************************************************************************** + template + bool operator !=(const etl::iintrusive_flat_multimap& lhs, const etl::iintrusive_flat_multimap& rhs) + { + return !(lhs == rhs); + } + + template > + //*************************************************************************** + /// A intrusive_flat_multimap implementation that uses a fixed size buffer. + ///\tparam TKey The key type. + ///\tparam TValue The value type. + ///\tparam TCompare The type to compare keys. Default = std::less + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup intrusive_flat_multimap + //*************************************************************************** + class intrusive_flat_multimap : public iintrusive_flat_multimap + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + intrusive_flat_multimap() + : iintrusive_flat_multimap(lookup) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + intrusive_flat_multimap(const intrusive_flat_multimap& other) + : iintrusive_flat_multimap(lookup) + { + iintrusive_flat_multimap::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template + intrusive_flat_multimap(TIterator first, TIterator last) + : iintrusive_flat_multimap(lookup) + { + iintrusive_flat_multimap::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~intrusive_flat_multimap() + { + iintrusive_flat_multimap::clear(); + } + + private: + + typedef typename iintrusive_flat_multimap::value_type node_t; + + // The vector that stores pointers to the nodes. + etl::vector lookup; + }; +} + +#undef ETL_FILE + +#endif \ No newline at end of file diff --git a/src/intrusive_flat_multiset.h b/src/intrusive_flat_multiset.h new file mode 100644 index 00000000..af50ad61 --- /dev/null +++ b/src/intrusive_flat_multiset.h @@ -0,0 +1,850 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_INTRUSIVE_FLAT_MULTISET__ +#define __ETL_INTRUSIVE_FLAT_MULTISET__ + +#include +#include +#include +#include +#include + +#include "platform.h" +#include "type_traits.h" +#include "ivector.h" +#include "vector.h" +#include "ipool.h" +#include "error_handler.h" +#include "exception.h" + +#undef ETL_FILE +#define ETL_FILE "33" + +namespace etl +{ + //*************************************************************************** + ///\ingroup intrusive_flat_multiset + /// Exception base for intrusive_flat_multisets + //*************************************************************************** + class intrusive_flat_multiset_exception : public exception + { + public: + + intrusive_flat_multiset_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup intrusive_flat_multiset + /// Vector full exception. + //*************************************************************************** + class intrusive_flat_multiset_full : public intrusive_flat_multiset_exception + { + public: + + intrusive_flat_multiset_full(string_type file_name, numeric_type line_number) + : intrusive_flat_multiset_exception(ETL_ERROR_TEXT("intrusive_flat_multiset:full", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup intrusive_flat_multiset + /// Vector iterator exception. + //*************************************************************************** + class intrusive_flat_multiset_iterator : public intrusive_flat_multiset_exception + { + public: + + intrusive_flat_multiset_iterator(string_type file_name, numeric_type line_number) + : intrusive_flat_multiset_exception(ETL_ERROR_TEXT("intrusive_flat_multiset:iterator", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized intrusive_flat_multisets. + /// Can be used as a reference type for all intrusive_flat_multisets containing a specific type. + ///\ingroup intrusive_flat_multiset + //*************************************************************************** + template > + class iintrusive_flat_multiset + { + public: + + typedef T key_type; + typedef T value_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + private: + + typedef etl::ivector lookup_t; + + public: + + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class iintrusive_flat_multiset; + + iterator() + { + } + + iterator(typename lookup_t::iterator ilookup) + : ilookup(ilookup) + { + } + + iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + iterator& operator ++() + { + ++ilookup; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + ++ilookup; + return temp; + } + + iterator& operator --() + { + --ilookup; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return &(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::iterator ilookup; + }; + + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class iintrusive_flat_multiset; + + const_iterator() + { + } + + const_iterator(typename lookup_t::const_iterator ilookup) + : ilookup(ilookup) + { + } + + const_iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator(const const_iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator =(const const_iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator ++() + { + ++ilookup; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + ++ilookup; + return temp; + } + + const_iterator& operator --() + { + --ilookup; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return etl::addressof(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::const_iterator ilookup; + }; + + public: + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef typename std::iterator_traits::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the intrusive_flat_multiset. + ///\return An iterator to the beginning of the intrusive_flat_multiset. + //********************************************************************* + iterator begin() + { + return iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the intrusive_flat_multiset. + ///\return A const iterator to the beginning of the intrusive_flat_multiset. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the intrusive_flat_multiset. + ///\return An iterator to the end of the intrusive_flat_multiset. + //********************************************************************* + iterator end() + { + return iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the intrusive_flat_multiset. + ///\return A const iterator to the end of the intrusive_flat_multiset. + //********************************************************************* + const_iterator end() const + { + return const_iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the intrusive_flat_multiset. + ///\return A const iterator to the beginning of the intrusive_flat_multiset. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(lookup.cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the intrusive_flat_multiset. + ///\return A const iterator to the end of the intrusive_flat_multiset. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(lookup.cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the intrusive_flat_multiset. + ///\return Iterator to the reverse beginning of the intrusive_flat_multiset. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the intrusive_flat_multiset. + ///\return Const iterator to the reverse beginning of the intrusive_flat_multiset. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the intrusive_flat_multiset. + ///\return Reverse iterator to the end + 1 of the intrusive_flat_multiset. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the intrusive_flat_multiset. + ///\return Const reverse iterator to the end + 1 of the intrusive_flat_multiset. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the intrusive_flat_multiset. + ///\return Const reverse iterator to the reverse beginning of the intrusive_flat_multiset. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(lookup.crbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the intrusive_flat_multiset. + ///\return Const reverse iterator to the end + 1 of the intrusive_flat_multiset. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(lookup.crend()); + } + + //********************************************************************* + /// Assigns values to the intrusive_flat_multiset. + /// If asserts or exceptions are enabled, emits intrusive_flat_multiset_full if the intrusive_flat_multiset does not have enough free space. + /// If asserts or exceptions are enabled, emits intrusive_flat_multiset_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type count = std::distance(first, last); + ETL_ASSERT(count <= difference_type(capacity()), ETL_ERROR(intrusive_flat_multiset_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the intrusive_flat_multiset. + /// If asserts or exceptions are enabled, emits intrusive_flat_multiset_full if the intrusive_flat_multiset is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair insert(value_type& value) + { + std::pair result(end(), false); + + ETL_ASSERT(!lookup.full(), ETL_ERROR(intrusive_flat_multiset_full)); + + iterator i_element = std::lower_bound(begin(), end(), value, TKeyCompare()); + + if (i_element == end()) + { + // At the end. Doesn't exist. + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + lookup.insert(i_element.ilookup, &value); + result.first = i_element; + result.second = true; + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the intrusive_flat_multiset. + /// If asserts or exceptions are enabled, emits intrusive_flat_multiset_full if the intrusive_flat_multiset is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, value_type& value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the intrusive_flat_multiset. + /// If asserts or exceptions are enabled, emits intrusive_flat_multiset_full if the intrusive_flat_multiset does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(value_type& key) + { + std::pair range = equal_range(key); + + if (range.first == end()) + { + return 0; + } + else + { + size_t count = std::distance(range.first, range.second); + erase(range.first, range.second); + return count; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + lookup.erase(i_element.ilookup); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + lookup.erase(first.ilookup, last.ilookup);; + } + + //************************************************************************* + /// Clears the intrusive_flat_multiset. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(value_type& key) + { + iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare()); + + if (itr != end()) + { + if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(value_type& key) const + { + const_iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare()); + + if (itr != end()) + { + if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(value_type& key) const + { + std::pair range = equal_range(key); + + return std::distance(range.first, range.second); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(value_type& key) + { + return std::lower_bound(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(value_type& key) const + { + return std::lower_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(value_type& key) + { + return std::upper_bound(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(value_type& key) const + { + return std::upper_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair equal_range(value_type& key) + { + return std::equal_range(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair equal_range(value_type& key) const + { + return std::equal_range(begin(), end(), key, TKeyCompare()); + } + + //************************************************************************* + /// Gets the current size of the intrusive_flat_multiset. + ///\return The current size of the intrusive_flat_multiset. + //************************************************************************* + size_type size() const + { + return lookup.size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the intrusive_flat_multiset. + ///\return true if empty. + //************************************************************************* + bool empty() const + { + return lookup.empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the intrusive_flat_multiset. + ///\return true if full. + //************************************************************************* + bool full() const + { + return lookup.full(); + } + + //************************************************************************* + /// Returns the capacity of the intrusive_flat_multiset. + ///\return The capacity of the intrusive_flat_multiset. + //************************************************************************* + size_type capacity() const + { + return lookup.capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the intrusive_flat_multiset. + ///\return The maximum size of the intrusive_flat_multiset. + //************************************************************************* + size_type max_size() const + { + return lookup.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return lookup.available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iintrusive_flat_multiset(lookup_t& lookup_) + : lookup(lookup_) + { + } + + private: + + // Disable copy construction. + iintrusive_flat_multiset(const iintrusive_flat_multiset&); + iintrusive_flat_multiset& operator =(const iintrusive_flat_multiset&); + + lookup_t& lookup; + }; + + //*************************************************************************** + /// An intrusive flat set + ///\ingroup intrusive_flat_multiset + //*************************************************************************** + template > + class intrusive_flat_multiset : public iintrusive_flat_multiset + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + intrusive_flat_multiset() + : iintrusive_flat_multiset(lookup) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + intrusive_flat_multiset(const intrusive_flat_multiset& other) + : iintrusive_flat_multiset(lookup) + { + iintrusive_flat_multiset::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template + intrusive_flat_multiset(TIterator first, TIterator last) + : iintrusive_flat_multiset(lookup) + { + iintrusive_flat_multiset::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~intrusive_flat_multiset() + { + iintrusive_flat_multiset::clear(); + } + + private: + + typedef TKey value_type; + + // The vector that stores pointers to the nodes. + etl::vector lookup; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first intrusive_flat_multiset. + ///\param rhs Reference to the second intrusive_flat_multiset. + ///\return true if the arrays are equal, otherwise false + ///\ingroup intrusive_flat_multiset + //*************************************************************************** + template + bool operator ==(const etl::iintrusive_flat_multiset& lhs, const etl::iintrusive_flat_multiset& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first intrusive_flat_multiset. + ///\param rhs Reference to the second intrusive_flat_multiset. + ///\return true if the arrays are not equal, otherwise false + ///\ingroup intrusive_flat_multiset + //*************************************************************************** + template + bool operator !=(const etl::iintrusive_flat_multiset& lhs, const etl::iintrusive_flat_multiset& rhs) + { + return !(lhs == rhs); + } +} + +#undef ETL_FILE +#endif diff --git a/src/intrusive_flat_set.h b/src/intrusive_flat_set.h new file mode 100644 index 00000000..28c46962 --- /dev/null +++ b/src/intrusive_flat_set.h @@ -0,0 +1,860 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_INTRUSIVE_FLAT_SET__ +#define __ETL_INTRUSIVE_FLAT_SET__ + +#include +#include +#include +#include +#include + +#include "platform.h" +#include "type_traits.h" +#include "ipool.h" +#include "error_handler.h" +#include "exception.h" +#include "vector.h" +#include "ivector.h" + +#undef ETL_FILE +#define ETL_FILE "32" + +namespace etl +{ + //*************************************************************************** + ///\ingroup intrusive_flat_set + /// Exception base for intrusive_flat_sets + //*************************************************************************** + class intrusive_flat_set_exception : public exception + { + public: + + intrusive_flat_set_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup intrusive_flat_set + /// Vector full exception. + //*************************************************************************** + class intrusive_flat_set_full : public intrusive_flat_set_exception + { + public: + + intrusive_flat_set_full(string_type file_name, numeric_type line_number) + : intrusive_flat_set_exception(ETL_ERROR_TEXT("intrusive_flat_set:full", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup intrusive_flat_set + /// Vector iterator exception. + //*************************************************************************** + class intrusive_flat_set_iterator : public intrusive_flat_set_exception + { + public: + + intrusive_flat_set_iterator(string_type file_name, numeric_type line_number) + : intrusive_flat_set_exception(ETL_ERROR_TEXT("intrusive_flat_set:iterator", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized intrusive_flat_sets. + /// Can be used as a reference type for all intrusive_flat_sets containing a specific type. + ///\ingroup intrusive_flat_set + //*************************************************************************** + template > + class iintrusive_flat_set + { + public: + + typedef T key_type; + typedef T value_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + private: + + typedef etl::ivector lookup_t; + + public: + + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class iintrusive_flat_set; + + iterator() + { + } + + iterator(typename lookup_t::iterator ilookup) + : ilookup(ilookup) + { + } + + iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + iterator& operator ++() + { + ++ilookup; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + ++ilookup; + return temp; + } + + iterator& operator --() + { + --ilookup; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return &(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::iterator ilookup; + }; + + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class iintrusive_flat_set; + + const_iterator() + { + } + + const_iterator(typename lookup_t::const_iterator ilookup) + : ilookup(ilookup) + { + } + + const_iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator(const const_iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator =(const const_iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator ++() + { + ++ilookup; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + ++ilookup; + return temp; + } + + const_iterator& operator --() + { + --ilookup; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return etl::addressof(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::const_iterator ilookup; + }; + + protected: + + typedef typename parameter_type::type parameter_t; + + public: + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef typename std::iterator_traits::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the intrusive_flat_set. + ///\return An iterator to the beginning of the intrusive_flat_set. + //********************************************************************* + iterator begin() + { + return iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the intrusive_flat_set. + ///\return A const iterator to the beginning of the intrusive_flat_set. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the intrusive_flat_set. + ///\return An iterator to the end of the intrusive_flat_set. + //********************************************************************* + iterator end() + { + return iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the intrusive_flat_set. + ///\return A const iterator to the end of the intrusive_flat_set. + //********************************************************************* + const_iterator end() const + { + return const_iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the intrusive_flat_set. + ///\return A const iterator to the beginning of the intrusive_flat_set. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(lookup.cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the intrusive_flat_set. + ///\return A const iterator to the end of the intrusive_flat_set. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(lookup.cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the intrusive_flat_set. + ///\return Iterator to the reverse beginning of the intrusive_flat_set. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the intrusive_flat_set. + ///\return Const iterator to the reverse beginning of the intrusive_flat_set. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the intrusive_flat_set. + ///\return Reverse iterator to the end + 1 of the intrusive_flat_set. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the intrusive_flat_set. + ///\return Const reverse iterator to the end + 1 of the intrusive_flat_set. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the intrusive_flat_set. + ///\return Const reverse iterator to the reverse beginning of the intrusive_flat_set. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(lookup.crbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the intrusive_flat_set. + ///\return Const reverse iterator to the end + 1 of the intrusive_flat_set. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(lookup.crend()); + } + + //********************************************************************* + /// Assigns values to the intrusive_flat_set. + /// If asserts or exceptions are enabled, emits intrusive_flat_set_full if the intrusive_flat_set does not have enough free space. + /// If asserts or exceptions are enabled, emits intrusive_flat_set_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type count = std::distance(first, last); + ETL_ASSERT(count <= difference_type(capacity()), ETL_ERROR(intrusive_flat_set_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the intrusive_flat_set. + /// If asserts or exceptions are enabled, emits intrusive_flat_set_full if the intrusive_flat_set is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair insert(value_type& value) + { + std::pair result(end(), false); + + ETL_ASSERT(!lookup.full(), ETL_ERROR(intrusive_flat_set_full)); + + iterator i_element = std::lower_bound(begin(), end(), value, TKeyCompare()); + + if (i_element == end()) + { + // At the end. Doesn't exist. + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + // Does not exist already? + if (*i_element != value) + { + lookup.insert(i_element.ilookup, &value); + result.first = i_element; + result.second = true; + } + else + { + result.first = i_element; + result.second = false; + } + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the intrusive_flat_set. + /// If asserts or exceptions are enabled, emits intrusive_flat_set_full if the intrusive_flat_set is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, value_type& value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the intrusive_flat_set. + /// If asserts or exceptions are enabled, emits intrusive_flat_set_full if the intrusive_flat_set does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(value_type& key) + { + iterator i_element = find(key); + + if (i_element == end()) + { + return 0; + } + else + { + lookup.erase(i_element.ilookup); + return 1; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + lookup.erase(i_element.ilookup); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + lookup.erase(first.ilookup, last.ilookup);; + } + + //************************************************************************* + /// Clears the intrusive_flat_set. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(value_type& key) + { + iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare()); + + if (itr != end()) + { + if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(value_type& key) const + { + const_iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare()); + + if (itr != end()) + { + if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(value_type& key) const + { + return (find(key) == end()) ? 0 : 1; + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(value_type& key) + { + return std::lower_bound(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(value_type& key) const + { + return std::lower_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(value_type& key) + { + return std::upper_bound(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(value_type& key) const + { + return std::upper_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair equal_range(value_type& key) + { + return std::equal_range(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair equal_range(value_type& key) const + { + return std::upper_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //************************************************************************* + /// Gets the current size of the intrusive_flat_set. + ///\return The current size of the intrusive_flat_set. + //************************************************************************* + size_type size() const + { + return lookup.size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the intrusive_flat_set. + ///\return true if empty. + //************************************************************************* + bool empty() const + { + return lookup.empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the intrusive_flat_set. + ///\return true if full. + //************************************************************************* + bool full() const + { + return lookup.full(); + } + + //************************************************************************* + /// Returns the capacity of the intrusive_flat_set. + ///\return The capacity of the intrusive_flat_set. + //************************************************************************* + size_type capacity() const + { + return lookup.capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the intrusive_flat_set. + ///\return The maximum size of the intrusive_flat_set. + //************************************************************************* + size_type max_size() const + { + return lookup.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return lookup.available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iintrusive_flat_set(lookup_t& lookup_) + : lookup(lookup_) + { + } + + private: + + // Disable copy construction. + iintrusive_flat_set(const iintrusive_flat_set&); + iintrusive_flat_set& operator =(const iintrusive_flat_set&); + + lookup_t& lookup; + }; + + //*************************************************************************** + /// An intrusive flat set + ///\ingroup intrusive_flat_set + //*************************************************************************** + template > + class intrusive_flat_set : public iintrusive_flat_set + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + intrusive_flat_set() + : iintrusive_flat_set(lookup) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + intrusive_flat_set(const intrusive_flat_set& other) + : iintrusive_flat_set(lookup) + { + iintrusive_flat_set::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template + intrusive_flat_set(TIterator first, TIterator last) + : iintrusive_flat_set(lookup) + { + iintrusive_flat_set::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~intrusive_flat_set() + { + iintrusive_flat_set::clear(); + } + + private: + + typedef TKey value_type; + + // The vector that stores pointers to the nodes. + etl::vector lookup; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first intrusive_flat_set. + ///\param rhs Reference to the second intrusive_flat_set. + ///\return true if the arrays are equal, otherwise false + ///\ingroup intrusive_flat_set + //*************************************************************************** + template + bool operator ==(const etl::iintrusive_flat_set& lhs, const etl::iintrusive_flat_set& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first intrusive_flat_set. + ///\param rhs Reference to the second intrusive_flat_set. + ///\return true if the arrays are not equal, otherwise false + ///\ingroup intrusive_flat_set + //*************************************************************************** + template + bool operator !=(const etl::iintrusive_flat_set& lhs, const etl::iintrusive_flat_set& rhs) + { + return !(lhs == rhs); + } +} + +#undef ETL_FILE +#endif diff --git a/test/test_flat_set.cpp b/test/test_flat_set.cpp index c770a1fa..59b8b809 100644 --- a/test/test_flat_set.cpp +++ b/test/test_flat_set.cpp @@ -40,45 +40,48 @@ SOFTWARE. #include "../src/flat_set.h" -static const size_t SIZE = 10; +namespace +{ + static const size_t SIZE = 10; -typedef TestDataDC DC; -typedef TestDataNDC NDC; + typedef TestDataDC DC; + typedef TestDataNDC NDC; -typedef etl::flat_set DataDC; -typedef etl::flat_set DataNDC; -typedef etl::iflat_set IDataNDC; + typedef etl::flat_set DataDC; + typedef etl::flat_set DataNDC; + typedef etl::iflat_set IDataNDC; -typedef std::set Compare_DataDC; -typedef std::set Compare_DataNDC; + typedef std::set Compare_DataDC; + typedef std::set Compare_DataNDC; -NDC NX = NDC("@"); -NDC NY = NDC("["); + NDC NX = NDC("@"); + NDC NY = NDC("["); -NDC N0 = NDC("A"); -NDC N1 = NDC("B"); -NDC N2 = NDC("C"); -NDC N3 = NDC("D"); -NDC N4 = NDC("E"); -NDC N5 = NDC("F"); -NDC N6 = NDC("G"); -NDC N7 = NDC("H"); -NDC N8 = NDC("I"); -NDC N9 = NDC("J"); -NDC N10 = NDC("K"); -NDC N11 = NDC("L"); -NDC N12 = NDC("M"); -NDC N13 = NDC("N"); -NDC N14 = NDC("O"); -NDC N15 = NDC("P"); -NDC N16 = NDC("Q"); -NDC N17 = NDC("R"); -NDC N18 = NDC("S"); -NDC N19 = NDC("T"); + NDC N0 = NDC("A"); + NDC N1 = NDC("B"); + NDC N2 = NDC("C"); + NDC N3 = NDC("D"); + NDC N4 = NDC("E"); + NDC N5 = NDC("F"); + NDC N6 = NDC("G"); + NDC N7 = NDC("H"); + NDC N8 = NDC("I"); + NDC N9 = NDC("J"); + NDC N10 = NDC("K"); + NDC N11 = NDC("L"); + NDC N12 = NDC("M"); + NDC N13 = NDC("N"); + NDC N14 = NDC("O"); + NDC N15 = NDC("P"); + NDC N16 = NDC("Q"); + NDC N17 = NDC("R"); + NDC N18 = NDC("S"); + NDC N19 = NDC("T"); -std::vector initial_data; -std::vector excess_data; -std::vector different_data; + std::vector initial_data; + std::vector excess_data; + std::vector different_data; +} //************************************************************************* std::ostream& operator <<(std::ostream& os, const DataDC::iterator& itr) diff --git a/test/test_intrusive_flat_map.cpp b/test/test_intrusive_flat_map.cpp new file mode 100644 index 00000000..6157bc34 --- /dev/null +++ b/test/test_intrusive_flat_map.cpp @@ -0,0 +1,802 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "data.h" + +#include "../src/intrusive_flat_map.h" + +namespace +{ + static const size_t SIZE = 10; + + typedef TestDataDC DC; + typedef TestDataNDC NDC; + + typedef std::pair ElementDC; + typedef std::pair ElementNDC; + + typedef etl::intrusive_flat_map DataDC; + typedef etl::intrusive_flat_map DataNDC; + typedef etl::iintrusive_flat_map IDataDC; + typedef etl::iintrusive_flat_map IDataNDC; + + typedef std::map Compare_DataDC; + typedef std::map Compare_DataNDC; + + //************************************************************************* + template + bool Check_Equal(T1 begin1, T1 end1, T2 begin2) + { + while (begin1 != end1) + { + if ((begin1->first != begin2->first) || (begin1->second != begin2->second)) + { + return false; + } + + ++begin1; + ++begin2; + } + + return true; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataDC::iterator& itr) + { + os << itr->first; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataDC::const_iterator& itr) + { + os << itr->first; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataNDC::iterator& itr) + { + os << itr->first; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataNDC::const_iterator& itr) + { + os << itr->first; + + return os; + } + + SUITE(test_flat_map) + { + NDC N0 = NDC("A"); + NDC N1 = NDC("B"); + NDC N2 = NDC("C"); + NDC N3 = NDC("D"); + NDC N4 = NDC("E"); + NDC N5 = NDC("F"); + NDC N6 = NDC("G"); + NDC N7 = NDC("H"); + NDC N8 = NDC("I"); + NDC N9 = NDC("J"); + NDC N10 = NDC("K"); + NDC N11 = NDC("L"); + NDC N12 = NDC("M"); + NDC N13 = NDC("N"); + NDC N14 = NDC("O"); + NDC N15 = NDC("P"); + NDC N16 = NDC("Q"); + NDC N17 = NDC("R"); + NDC N18 = NDC("S"); + NDC N19 = NDC("T"); + + DC M0 = DC("A"); + DC M1 = DC("B"); + DC M2 = DC("C"); + DC M3 = DC("D"); + DC M4 = DC("E"); + DC M5 = DC("F"); + DC M6 = DC("G"); + DC M7 = DC("H"); + DC M8 = DC("I"); + DC M9 = DC("J"); + DC M10 = DC("K"); + DC M11 = DC("L"); + DC M12 = DC("M"); + DC M13 = DC("N"); + DC M14 = DC("O"); + DC M15 = DC("P"); + DC M16 = DC("Q"); + DC M17 = DC("R"); + DC M18 = DC("S"); + DC M19 = DC("T"); + + std::vector initial_data_dc; + std::vector initial_data; + std::vector excess_data; + std::vector different_data; + + //************************************************************************* + template + bool Check_Equal(T1 begin1, T1 end1, T2 begin2) + { + while (begin1 != end1) + { + if ((begin1->first != begin2->first) || (begin1->second != begin2->second)) + { + return false; + } + + ++begin1; + ++begin2; + } + + return true; + } + + //************************************************************************* + struct SetupFixture + { + SetupFixture() + { + ElementNDC n[] = + { + ElementNDC(0, N0), ElementNDC(1, N1), ElementNDC(2, N2), ElementNDC(3, N3), ElementNDC(4, N4), + ElementNDC(5, N5), ElementNDC(6, N6), ElementNDC(7, N7), ElementNDC(8, N8), ElementNDC(9, N9) + }; + + ElementNDC n2[] = + { + ElementNDC(0, N0), ElementNDC(1, N1), ElementNDC(2, N2), ElementNDC(3, N3), ElementNDC(4, N4), + ElementNDC(5, N5), ElementNDC(6, N6), ElementNDC(7, N7), ElementNDC(8, N8), ElementNDC(9, N9), + ElementNDC(10, N10) + }; + + ElementNDC n3[] = + { + ElementNDC(10, N10), ElementNDC(11, N11), ElementNDC(12, N12), ElementNDC(13, N13), ElementNDC(14, N14), + ElementNDC(15, N15), ElementNDC(16, N16), ElementNDC(17, N17), ElementNDC(18, N18), ElementNDC(19, N19) + }; + + ElementDC n4[] = + { + ElementDC(0, M0), ElementDC(1, M1), ElementDC(2, M2), ElementDC(3, M3), ElementDC(4, M4), + ElementDC(5, M5), ElementDC(6, M6), ElementDC(7, M7), ElementDC(8, M8), ElementDC(9, M9) + }; + + initial_data.assign(std::begin(n), std::end(n)); + excess_data.assign(std::begin(n2), std::end(n2)); + different_data.assign(std::begin(n3), std::end(n3)); + initial_data_dc.assign(std::begin(n4), std::end(n4)); + } + }; + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_default_constructor) + { + DataDC data; + + CHECK_EQUAL(data.size(), size_t(0)); + CHECK(data.empty()); + CHECK_EQUAL(data.capacity(), SIZE); + CHECK_EQUAL(data.max_size(), SIZE); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK(data.size() == SIZE); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_begin) + { + DataNDC data(initial_data.begin(), initial_data.end()); + const DataNDC constData(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.begin(), std::begin(data)); + CHECK_EQUAL(constData.begin(), std::begin(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_end) + { + DataNDC data(initial_data.begin(), initial_data.end()); + const DataNDC constData(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.end(), std::end(data)); + CHECK_EQUAL(constData.end(), std::end(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_empty) + { + DataNDC data; + data.insert(initial_data.begin(), initial_data.end()); + + CHECK(data.full()); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_full) + { + DataDC data; + + CHECK(!data.full()); + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_index) + { + Compare_DataDC compare_data(initial_data_dc.begin(), initial_data_dc.end()); + + DataDC data(initial_data_dc.begin(), initial_data_dc.end()); + + CHECK_EQUAL(compare_data[0], data[0]); + CHECK_EQUAL(compare_data[1], data[1]); + CHECK_EQUAL(compare_data[2], data[2]); + CHECK_EQUAL(compare_data[3], data[3]); + CHECK_EQUAL(compare_data[4], data[4]); + CHECK_EQUAL(compare_data[5], data[5]); + CHECK_EQUAL(compare_data[6], data[6]); + CHECK_EQUAL(compare_data[7], data[7]); + CHECK_EQUAL(compare_data[8], data[8]); + CHECK_EQUAL(compare_data[9], data[9]); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_index_value_changed) + { + Compare_DataDC compare_data; + DataDC data; + + DataDC::value_type item(0, M0); + + data.insert(item); + compare_data[0] = M0; + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + data[0] = M2; + compare_data[0] = M2; + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_at) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.at(0), compare_data.at(0)); + CHECK_EQUAL(data.at(1), compare_data.at(1)); + CHECK_EQUAL(data.at(2), compare_data.at(2)); + CHECK_EQUAL(data.at(3), compare_data.at(3)); + CHECK_EQUAL(data.at(4), compare_data.at(4)); + CHECK_EQUAL(data.at(5), compare_data.at(5)); + CHECK_EQUAL(data.at(6), compare_data.at(6)); + CHECK_EQUAL(data.at(7), compare_data.at(7)); + CHECK_EQUAL(data.at(8), compare_data.at(8)); + CHECK_EQUAL(data.at(9), compare_data.at(9)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_at_out_of_bounds) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.at(10), etl::intrusive_flat_map_out_of_bounds); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_at_const) + { + const Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + const DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.at(0), compare_data.at(0)); + CHECK_EQUAL(data.at(1), compare_data.at(1)); + CHECK_EQUAL(data.at(2), compare_data.at(2)); + CHECK_EQUAL(data.at(3), compare_data.at(3)); + CHECK_EQUAL(data.at(4), compare_data.at(4)); + CHECK_EQUAL(data.at(5), compare_data.at(5)); + CHECK_EQUAL(data.at(6), compare_data.at(6)); + CHECK_EQUAL(data.at(7), compare_data.at(7)); + CHECK_EQUAL(data.at(8), compare_data.at(8)); + CHECK_EQUAL(data.at(9), compare_data.at(9)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_at_const_out_of_bounds) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.at(10), etl::intrusive_flat_map_out_of_bounds); + } + + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data; + + data.assign(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value) + { + Compare_DataNDC compare_data; + DataNDC data; + + std::pair result; + + DataNDC::value_type item(0, N0); + result = data.insert(item); + compare_data.insert(item); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + CHECK(result.second); + CHECK(*result.first == std::make_pair(0, N0)); + + DataNDC::value_type item2(2, N2); + result = data.insert(item2); + compare_data.insert(item2); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + CHECK(result.second); + CHECK(*result.first == std::make_pair(2, N2)); + + DataNDC::value_type item1(1, N1); + result = data.insert(item1); + compare_data.insert(item1); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + CHECK(result.second); + CHECK(*result.first == item1); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_changed) + { + Compare_DataNDC compare_data; + DataNDC data; + + std::pair result1; + std::pair result2; + + DataNDC::value_type item(0, N0); + result1 = data.insert(item); + result2 = compare_data.insert(item); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + CHECK(result1.second); + CHECK(*result1.first == item); + + DataNDC::value_type item2(0, N2); + result1 = data.insert(item2); + result2 = compare_data.insert(item2); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + CHECK(!result1.second); + CHECK(*result1.first != item2); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_multiple) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(std::make_pair(0, N0)); + compare_data.insert(std::make_pair(0, N0)); + + data.insert(std::make_pair(1, N1)); + compare_data.insert(std::make_pair(1, N1)); + + data.insert(std::make_pair(2, N2)); + compare_data.insert(std::make_pair(2, N2)); + + // Do it again. + data.insert(std::make_pair(0, N0)); + compare_data.insert(std::make_pair(0, N0)); + + data.insert(std::make_pair(1, N1)); + compare_data.insert(std::make_pair(1, N1)); + + data.insert(std::make_pair(2, N2)); + compare_data.insert(std::make_pair(2, N2)); + + CHECK_EQUAL(compare_data.size(), data.size()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_excess) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.insert(std::make_pair(10, N10)), etl::intrusive_flat_map_full); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(initial_data.begin(), initial_data.end()); + compare_data.insert(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range_excess) + { + DataNDC data; + + CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::intrusive_flat_map_full); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_key) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + size_t count_compare = compare_data.erase(5); + size_t count = data.erase(5); + + CHECK_EQUAL(count_compare, count); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + compare_data.erase(i_compare); + data.erase(i_data); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + Compare_DataNDC::iterator i_compare_end = compare_data.begin(); + DataNDC::iterator i_data_end = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + std::advance(i_compare_end, 4); + std::advance(i_data_end, 4); + + compare_data.erase(i_compare, i_compare_end); + data.erase(i_data, i_data_end); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_clear) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + data.clear(); + + CHECK_EQUAL(data.size(), size_t(0)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.cbegin(), + data.cend(), + compare_data.cbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_reverse_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.rbegin(), + data.rend(), + compare_data.rbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_reverse_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.crbegin(), + data.crend(), + compare_data.crbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator it = data.find(3); + CHECK_EQUAL(N3, it->second); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_not_present) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator it = data.find(-1); + CHECK_EQUAL(data.end(), it); + + it = data.find(10); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::const_iterator it = data.find(3); + CHECK_EQUAL(N3, it->second); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const_not_present) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::const_iterator it = data.find(-1); + CHECK_EQUAL(data.end(), it); + + it = data.find(10); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_lower_bound) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.lower_bound(5); + DataNDC::iterator i_data = data.lower_bound(5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare), std::distance(data.begin(), i_data)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_upper_bound) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.upper_bound(5); + DataNDC::iterator i_data = data.upper_bound(5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare), std::distance(data.begin(), i_data)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + std::pair i_compare = compare_data.equal_range(5); + std::pair i_data = data.equal_range(5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare.first), std::distance(data.begin(), i_data.first)); + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare.second), std::distance(data.begin(), i_data.second)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range_not_present) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + std::pair i_compare; + + std::pair i_data; + + i_data = data.equal_range(-1); + CHECK_EQUAL(data.begin(), i_data.first); + CHECK_EQUAL(data.begin(), i_data.second); + + i_data = data.equal_range(99); + CHECK_EQUAL(data.end(), i_data.first); + CHECK_EQUAL(data.end(), i_data.second); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal) + { + const DataNDC initial1(initial_data.begin(), initial_data.end()); + const DataNDC initial2(initial_data.begin(), initial_data.end()); + + CHECK(initial1 == initial2); + + const DataNDC different(different_data.begin(), different_data.end()); + + CHECK(!(initial1 == different)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_not_equal) + { + const DataNDC initial1(initial_data.begin(), initial_data.end()); + const DataNDC initial2(initial_data.begin(), initial_data.end()); + + CHECK(!(initial1 != initial2)); + + const DataNDC different(different_data.begin(), different_data.end()); + + CHECK(initial1 != different); + } + }; +} diff --git a/test/test_intrusive_flat_multimap.cpp b/test/test_intrusive_flat_multimap.cpp new file mode 100644 index 00000000..6a7851aa --- /dev/null +++ b/test/test_intrusive_flat_multimap.cpp @@ -0,0 +1,685 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "data.h" + +#include "../src/intrusive_flat_multimap.h" + +namespace +{ + static const size_t SIZE = 10; + + typedef TestDataDC DC; + typedef TestDataNDC NDC; + + typedef std::pair ElementDC; + typedef std::pair ElementNDC; + + typedef etl::intrusive_flat_multimap DataDC; + typedef etl::intrusive_flat_multimap DataNDC; + typedef etl::iintrusive_flat_multimap IDataDC; + typedef etl::iintrusive_flat_multimap IDataNDC; + + typedef std::multimap Compare_DataDC; + typedef std::multimap Compare_DataNDC; + + NDC N0 = NDC("A"); + NDC N1 = NDC("B"); + NDC N2 = NDC("C"); + NDC N3 = NDC("D"); + NDC N4 = NDC("E"); + NDC N5 = NDC("F"); + NDC N6 = NDC("G"); + NDC N7 = NDC("H"); + NDC N8 = NDC("I"); + NDC N9 = NDC("J"); + NDC N10 = NDC("K"); + NDC N11 = NDC("L"); + NDC N12 = NDC("M"); + NDC N13 = NDC("N"); + NDC N14 = NDC("O"); + NDC N15 = NDC("P"); + NDC N16 = NDC("Q"); + NDC N17 = NDC("R"); + NDC N18 = NDC("S"); + NDC N19 = NDC("T"); + + std::vector initial_data; + std::vector excess_data; + std::vector different_data; + std::vector multi_data; + + //************************************************************************* + template + bool Check_Equal(T1 begin1, T1 end1, T2 begin2) + { + while (begin1 != end1) + { + if ((begin1->first != begin2->first) || (begin1->second != begin2->second)) + { + return false; + } + + ++begin1; + ++begin2; + } + + return true; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataDC::iterator& itr) + { + os << itr->first; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataDC::const_iterator& itr) + { + os << itr->first; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataNDC::iterator& itr) + { + os << itr->first; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataNDC::const_iterator& itr) + { + os << itr->first; + + return os; + } + + SUITE(test_intrusive_flat_multimap) + { + //************************************************************************* + struct SetupFixture + { + SetupFixture() + { + ElementNDC n[] = + { + ElementNDC(0, N0), ElementNDC(1, N1), ElementNDC(2, N2), ElementNDC(3, N3), ElementNDC(4, N4), + ElementNDC(5, N5), ElementNDC(6, N6), ElementNDC(7, N7), ElementNDC(8, N8), ElementNDC(9, N9) + }; + + ElementNDC n2[] = + { + ElementNDC(0, N0), ElementNDC(1, N1), ElementNDC(2, N2), ElementNDC(3, N3), ElementNDC(4, N4), + ElementNDC(5, N5), ElementNDC(6, N6), ElementNDC(7, N7), ElementNDC(8, N8), ElementNDC(9, N9), + ElementNDC(10, N10) + }; + + ElementNDC n3[] = + { + ElementNDC(10, N10), ElementNDC(11, N11), ElementNDC(12, N12), ElementNDC(13, N13), ElementNDC(14, N14), + ElementNDC(15, N15), ElementNDC(16, N16), ElementNDC(17, N17), ElementNDC(18, N18), ElementNDC(19, N19) + }; + + ElementNDC n4[] = + { + ElementNDC(0, N0), ElementNDC(1, N1), ElementNDC(2, N2), ElementNDC(1, N3), ElementNDC(3, N4), + ElementNDC(4, N5), ElementNDC(4, N6), ElementNDC(5, N7), ElementNDC(4, N8), ElementNDC(0, N9) + }; + + initial_data.assign(std::begin(n), std::end(n)); + excess_data.assign(std::begin(n2), std::end(n2)); + different_data.assign(std::begin(n3), std::end(n3)); + multi_data.assign(std::begin(n4), std::end(n4)); + } + }; + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_default_constructor) + { + DataDC data; + + CHECK_EQUAL(data.size(), size_t(0)); + CHECK(data.empty()); + CHECK_EQUAL(data.capacity(), SIZE); + CHECK_EQUAL(data.max_size(), SIZE); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK(data.size() == SIZE); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_begin) + { + DataNDC data(initial_data.begin(), initial_data.end()); + const DataNDC constData(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.begin(), std::begin(data)); + CHECK_EQUAL(constData.begin(), std::begin(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_end) + { + DataNDC data(initial_data.begin(), initial_data.end()); + const DataNDC constData(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.end(), std::end(data)); + CHECK_EQUAL(constData.end(), std::end(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_empty) + { + DataNDC data; + data.insert(initial_data.begin(), initial_data.end()); + + CHECK(data.full()); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_full) + { + DataDC data; + + CHECK(!data.full()); + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data; + + data.assign(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value) + { + Compare_DataNDC compare_data; + DataNDC data; + + DataNDC::value_type item0(0, N0); + data.insert(item0); + compare_data.insert(item0); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + DataNDC::value_type item2(2, N2); + data.insert(item2); + compare_data.insert(item2); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + DataNDC::value_type item1(1, N1); + data.insert(item1); + compare_data.insert(item1); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_multiple) + { + Compare_DataNDC compare_data; + DataNDC data; + + DataNDC::value_type item0(0, N0); + data.insert(item0); + compare_data.insert(item0); + + DataNDC::value_type item1(1, N1); + data.insert(item1); + compare_data.insert(item1); + + DataNDC::value_type item2(2, N2); + data.insert(item2); + compare_data.insert(item2); + + // Do it again. + data.insert(item0); + compare_data.insert(item0); + + data.insert(item1); + compare_data.insert(item1); + + data.insert(item2); + compare_data.insert(item2); + + CHECK_EQUAL(compare_data.size(), data.size()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_excess) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::value_type item10(10, N10); + CHECK_THROW(data.insert(item10), etl::intrusive_flat_multimap_full); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(initial_data.begin(), initial_data.end()); + compare_data.insert(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range_excess) + { + DataNDC data; + + CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::intrusive_flat_multimap_full); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_key) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + size_t count_compare = compare_data.erase(5); + size_t count = data.erase(5); + + CHECK_EQUAL(count_compare, count); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + compare_data.erase(i_compare); + data.erase(i_data); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + Compare_DataNDC::iterator i_compare_end = compare_data.begin(); + DataNDC::iterator i_data_end = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + std::advance(i_compare_end, 4); + std::advance(i_data_end, 4); + + compare_data.erase(i_compare, i_compare_end); + data.erase(i_data, i_data_end); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_clear) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + data.clear(); + + CHECK_EQUAL(data.size(), size_t(0)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.cbegin(), + data.cend(), + compare_data.cbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_reverse_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.rbegin(), + data.rend(), + compare_data.rbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_reverse_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.crbegin(), + data.crend(), + compare_data.crbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator it = data.find(3); + CHECK_EQUAL(N3, it->second); + + it = data.find(19); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_not_present) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator it = data.find(-1); + CHECK_EQUAL(data.end(), it); + + it = data.find(10); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::const_iterator it = data.find(3); + CHECK_EQUAL(N3, it->second); + + it = data.find(19); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const_not_present) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::const_iterator it = data.find(-1); + CHECK_EQUAL(data.end(), it); + + it = data.find(10); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_lower_bound) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.lower_bound(5); + DataNDC::iterator i_data = data.lower_bound(5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare), std::distance(data.begin(), i_data)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_upper_bound) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.upper_bound(5); + DataNDC::iterator i_data = data.upper_bound(5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare), std::distance(data.begin(), i_data)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + std::pair i_compare = compare_data.equal_range(5); + std::pair i_data = data.equal_range(5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare.first), std::distance(data.begin(), i_data.first)); + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare.second), std::distance(data.begin(), i_data.second)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range_not_present) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + std::pair i_data; + + i_data = data.equal_range(-1); + CHECK_EQUAL(data.begin(), i_data.first); + CHECK_EQUAL(data.begin(), i_data.second); + + i_data = data.equal_range(99); + CHECK_EQUAL(data.end(), i_data.first); + CHECK_EQUAL(data.end(), i_data.second); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal) + { + const DataNDC initial1(initial_data.begin(), initial_data.end()); + const DataNDC initial2(initial_data.begin(), initial_data.end()); + + CHECK(initial1 == initial2); + + const DataNDC different(different_data.begin(), different_data.end()); + + CHECK(!(initial1 == different)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_not_equal) + { + const DataNDC initial1(initial_data.begin(), initial_data.end()); + const DataNDC initial2(initial_data.begin(), initial_data.end()); + + CHECK(!(initial1 != initial2)); + + const DataNDC different(different_data.begin(), different_data.end()); + + CHECK(initial1 != different); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_multi) + { + Compare_DataNDC compare_data(multi_data.begin(), multi_data.end()); + DataNDC data(multi_data.begin(), multi_data.end()); + + std::pair compare_range; + std::pair test_range; + + compare_range = compare_data.equal_range(0); + test_range = data.equal_range(0); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(1); + test_range = data.equal_range(1); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(2); + test_range = data.equal_range(2); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(3); + test_range = data.equal_range(3); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(4); + test_range = data.equal_range(4); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(5); + test_range = data.equal_range(5); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_count) + { + Compare_DataNDC compare_data(multi_data.begin(), multi_data.end()); + DataNDC data(multi_data.begin(), multi_data.end()); + + CHECK_EQUAL(compare_data.count(0), data.count(0)); + CHECK_EQUAL(compare_data.count(1), data.count(1)); + CHECK_EQUAL(compare_data.count(2), data.count(2)); + CHECK_EQUAL(compare_data.count(3), data.count(3)); + CHECK_EQUAL(compare_data.count(4), data.count(4)); + CHECK_EQUAL(compare_data.count(5), data.count(5)); + } + }; +} diff --git a/test/test_intrusive_flat_multiset.cpp b/test/test_intrusive_flat_multiset.cpp new file mode 100644 index 00000000..6056bdda --- /dev/null +++ b/test/test_intrusive_flat_multiset.cpp @@ -0,0 +1,649 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "data.h" + +#include "../src/intrusive_flat_multiset.h" + +namespace +{ + static const size_t SIZE = 10; + + typedef TestDataDC DC; + typedef TestDataNDC NDC; + + typedef etl::intrusive_flat_multiset DataDC; + typedef etl::intrusive_flat_multiset DataNDC; + typedef etl::iintrusive_flat_multiset IDataNDC; + + typedef std::multiset Compare_DataDC; + typedef std::multiset Compare_DataNDC; + + NDC NX = NDC("@"); + NDC NY = NDC("["); + + NDC N0 = NDC("A"); + NDC N1 = NDC("B"); + NDC N2 = NDC("C"); + NDC N3 = NDC("D"); + NDC N4 = NDC("E"); + NDC N5 = NDC("F"); + NDC N6 = NDC("G"); + NDC N7 = NDC("H"); + NDC N8 = NDC("I"); + NDC N9 = NDC("J"); + NDC N10 = NDC("K"); + NDC N11 = NDC("L"); + NDC N12 = NDC("M"); + NDC N13 = NDC("N"); + NDC N14 = NDC("O"); + NDC N15 = NDC("P"); + NDC N16 = NDC("Q"); + NDC N17 = NDC("R"); + NDC N18 = NDC("S"); + NDC N19 = NDC("T"); + + std::vector initial_data; + std::vector excess_data; + std::vector different_data; + std::vector multi_data; + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataDC::iterator& itr) + { + os << itr->value; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataDC::const_iterator& itr) + { + os << itr->value; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataNDC::iterator& itr) + { + os << itr->value; + + return os; + } + + //************************************************************************* + std::ostream& operator <<(std::ostream& os, const DataNDC::const_iterator& itr) + { + os << itr->value; + + return os; + } + + SUITE(test_flat_multiset) + { + //************************************************************************* + struct SetupFixture + { + SetupFixture() + { + NDC n[] = + { + N0, N1, N2, N3, N4, N5, N6, N7, N8, N9 + }; + + NDC n2[] = + { + N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, N10 + }; + + NDC n3[] = + { + N10, N11, N12, N13, N14, N15, N16, N17, N18, N19 + }; + + NDC n4[] = + { + N0, N0, N1, N2, N3, N1, N3, N3, N4, N2 + }; + + initial_data.assign(std::begin(n), std::end(n)); + excess_data.assign(std::begin(n2), std::end(n2)); + different_data.assign(std::begin(n3), std::end(n3)); + multi_data.assign(std::begin(n4), std::end(n4)); + } + }; + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_default_constructor) + { + DataDC data; + + CHECK_EQUAL(data.size(), size_t(0)); + CHECK(data.empty()); + CHECK_EQUAL(data.capacity(), SIZE); + CHECK_EQUAL(data.max_size(), SIZE); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK(data.size() == SIZE); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_begin) + { + DataNDC data(initial_data.begin(), initial_data.end()); + const DataNDC constData(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.begin(), std::begin(data)); + CHECK_EQUAL(constData.begin(), std::begin(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_end) + { + DataNDC data(initial_data.begin(), initial_data.end()); + const DataNDC constData(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.end(), std::end(data)); + CHECK_EQUAL(constData.end(), std::end(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_empty) + { + DataNDC data; + data.insert(initial_data.begin(), initial_data.end()); + + CHECK(data.full()); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_full) + { + DataNDC data; + + CHECK(!data.full()); + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data; + + data.assign(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(N0); + compare_data.insert(N0); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + data.insert(N2); + compare_data.insert(N2); + + isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + data.insert(N1); + compare_data.insert(N1); + + isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_multiple) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(N0); + compare_data.insert(N0); + + data.insert(N1); + compare_data.insert(N1); + + data.insert(N2); + compare_data.insert(N2); + + // Do it again. + data.insert(N0); + compare_data.insert(N0); + + data.insert(N1); + compare_data.insert(N1); + + data.insert(N2); + compare_data.insert(N2); + + CHECK_EQUAL(compare_data.size(), data.size()); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_excess) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.insert(N10), etl::intrusive_flat_multiset_full); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(initial_data.begin(), initial_data.end()); + compare_data.insert(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range_excess) + { + DataNDC data; + + CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::intrusive_flat_multiset_full); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_key) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + size_t count_compare = compare_data.erase(N5); + size_t count = data.erase(N5); + + CHECK_EQUAL(count_compare, count); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + compare_data.erase(i_compare); + data.erase(i_data); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + Compare_DataNDC::iterator i_compare_end = compare_data.begin(); + DataNDC::iterator i_data_end = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + std::advance(i_compare_end, 4); + std::advance(i_data_end, 4); + + compare_data.erase(i_compare, i_compare_end); + data.erase(i_data, i_data_end); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_clear) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + data.clear(); + + CHECK_EQUAL(data.size(), size_t(0)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.cbegin(), + data.cend(), + compare_data.cbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_reverse_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.rbegin(), + data.rend(), + compare_data.rbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_reverse_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.crbegin(), + data.crend(), + compare_data.crbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator it = data.find(N3); + CHECK_EQUAL(N3, *it); + + it = data.find(N19); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_not_present) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator it = data.find(NX); + CHECK_EQUAL(data.end(), it); + + it = data.find(NY); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::const_iterator it = data.find(N3); + CHECK_EQUAL(N3, *it); + + it = data.find(N19); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const_not_present) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::const_iterator it = data.find(NX); + CHECK_EQUAL(data.end(), it); + + it = data.find(NY); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_lower_bound) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.lower_bound(N5); + DataNDC::iterator i_data = data.lower_bound(N5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare), std::distance(data.begin(), i_data)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_upper_bound) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.upper_bound(N5); + DataNDC::iterator i_data = data.upper_bound(N5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare), std::distance(data.begin(), i_data)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + std::pair i_compare = compare_data.equal_range(N5); + std::pair i_data = data.equal_range(N5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare.first), std::distance(data.begin(), i_data.first)); + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare.second), std::distance(data.begin(), i_data.second)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range_not_present) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + std::pair i_data; + + i_data = data.equal_range(NX); + CHECK_EQUAL(data.begin(), i_data.first); + CHECK_EQUAL(data.begin(), i_data.second); + + i_data = data.equal_range(NY); + CHECK_EQUAL(data.end(), i_data.first); + CHECK_EQUAL(data.end(), i_data.second); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal) + { + const DataNDC initial1(initial_data.begin(), initial_data.end()); + const DataNDC initial2(initial_data.begin(), initial_data.end()); + + CHECK(initial1 == initial2); + + const DataNDC different(different_data.begin(), different_data.end()); + + CHECK(!(initial1 == different)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_not_equal) + { + const DataNDC initial1(initial_data.begin(), initial_data.end()); + const DataNDC initial2(initial_data.begin(), initial_data.end()); + + CHECK(!(initial1 != initial2)); + + const DataNDC different(different_data.begin(), different_data.end()); + + CHECK(initial1 != different); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_multi) + { + Compare_DataNDC compare_data(multi_data.begin(), multi_data.end()); + DataNDC data(multi_data.begin(), multi_data.end()); + + std::pair compare_range; + std::pair test_range; + + compare_range = compare_data.equal_range(N0); + test_range = data.equal_range(N0); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(N1); + test_range = data.equal_range(N1); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(N2); + test_range = data.equal_range(N2); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(N3); + test_range = data.equal_range(N3); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + + compare_range = compare_data.equal_range(N4); + test_range = data.equal_range(N4); + CHECK_EQUAL(std::distance(compare_range.first, compare_range.second), std::distance(test_range.first, test_range.second)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_count) + { + Compare_DataNDC compare_data(multi_data.begin(), multi_data.end()); + DataNDC data(multi_data.begin(), multi_data.end()); + + CHECK_EQUAL(compare_data.count(N0), data.count(N0)); + CHECK_EQUAL(compare_data.count(N1), data.count(N1)); + CHECK_EQUAL(compare_data.count(N2), data.count(N2)); + CHECK_EQUAL(compare_data.count(N3), data.count(N3)); + CHECK_EQUAL(compare_data.count(N4), data.count(N4)); + } + }; +} diff --git a/test/test_intrusive_flat_set.cpp b/test/test_intrusive_flat_set.cpp new file mode 100644 index 00000000..a94228f4 --- /dev/null +++ b/test/test_intrusive_flat_set.cpp @@ -0,0 +1,592 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "data.h" + +#include "../src/intrusive_flat_set.h" + +namespace +{ + static const size_t SIZE = 10; + + typedef TestDataDC DC; + typedef TestDataNDC NDC; + + typedef etl::intrusive_flat_set DataDC; + typedef etl::intrusive_flat_set DataNDC; + typedef etl::iintrusive_flat_set IDataNDC; + + typedef std::set Compare_DataDC; + typedef std::set Compare_DataNDC; + + NDC NX = NDC("@"); + NDC NY = NDC("["); + + NDC N0 = NDC("A"); + NDC N1 = NDC("B"); + NDC N2 = NDC("C"); + NDC N3 = NDC("D"); + NDC N4 = NDC("E"); + NDC N5 = NDC("F"); + NDC N6 = NDC("G"); + NDC N7 = NDC("H"); + NDC N8 = NDC("I"); + NDC N9 = NDC("J"); + NDC N10 = NDC("K"); + NDC N11 = NDC("L"); + NDC N12 = NDC("M"); + NDC N13 = NDC("N"); + NDC N14 = NDC("O"); + NDC N15 = NDC("P"); + NDC N16 = NDC("Q"); + NDC N17 = NDC("R"); + NDC N18 = NDC("S"); + NDC N19 = NDC("T"); + + std::vector initial_data; + std::vector excess_data; + std::vector different_data; +} + +//************************************************************************* +std::ostream& operator <<(std::ostream& os, const DataDC::iterator& itr) +{ + os << itr->value; + + return os; +} + +//************************************************************************* +std::ostream& operator <<(std::ostream& os, const DataDC::const_iterator& itr) +{ + os << itr->value; + + return os; +} + +//************************************************************************* +std::ostream& operator <<(std::ostream& os, const DataNDC::iterator& itr) +{ + os << itr->value; + + return os; +} + +//************************************************************************* +std::ostream& operator <<(std::ostream& os, const DataNDC::const_iterator& itr) +{ + os << itr->value; + + return os; +} + +namespace +{ + SUITE(test_flat_set) + { + //************************************************************************* + struct SetupFixture + { + SetupFixture() + { + NDC n[] = + { + N0, N1, N2, N3, N4, N5, N6, N7, N8, N9 + }; + + NDC n2[] = + { + N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, N10 + }; + + NDC n3[] = + { + N10, N11, N12, N13, N14, N15, N16, N17, N18, N19 + }; + + initial_data.assign(std::begin(n), std::end(n)); + excess_data.assign(std::begin(n2), std::end(n2)); + different_data.assign(std::begin(n3), std::end(n3)); + } + }; + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_default_constructor) + { + DataDC data; + + CHECK_EQUAL(data.size(), size_t(0)); + CHECK(data.empty()); + CHECK_EQUAL(data.capacity(), SIZE); + CHECK_EQUAL(data.max_size(), SIZE); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK(data.size() == SIZE); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_begin) + { + DataNDC data(initial_data.begin(), initial_data.end()); + const DataNDC constData(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.begin(), std::begin(data)); + CHECK_EQUAL(constData.begin(), std::begin(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_end) + { + DataNDC data(initial_data.begin(), initial_data.end()); + const DataNDC constData(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.end(), std::end(data)); + CHECK_EQUAL(constData.end(), std::end(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_empty) + { + DataNDC data; + data.insert(initial_data.begin(), initial_data.end()); + + CHECK(data.full()); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_full) + { + DataNDC data; + + CHECK(!data.full()); + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data; + + data.assign(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(N0); + compare_data.insert(N0); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + data.insert(N2); + compare_data.insert(N2); + + isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + data.insert(N1); + compare_data.insert(N1); + + std::vector test(data.begin(), data.end()); + + isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_multiple) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(N0); + compare_data.insert(N0); + + data.insert(N1); + compare_data.insert(N1); + + data.insert(N2); + compare_data.insert(N2); + + // Do it again. + data.insert(N0); + compare_data.insert(N0); + + data.insert(N1); + compare_data.insert(N1); + + data.insert(N2); + compare_data.insert(N2); + + CHECK_EQUAL(compare_data.size(), data.size()); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_excess) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.insert(N10), etl::intrusive_flat_set_full); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range) + { + Compare_DataNDC compare_data; + DataNDC data; + + data.insert(initial_data.begin(), initial_data.end()); + compare_data.insert(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range_excess) + { + DataNDC data; + + CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::intrusive_flat_set_full); + + CHECK(std::is_sorted(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_key) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + size_t count_compare = compare_data.erase(N5); + size_t count = data.erase(N5); + + CHECK_EQUAL(count_compare, count); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + compare_data.erase(i_compare); + data.erase(i_data); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.begin(); + DataNDC::iterator i_data = data.begin(); + + Compare_DataNDC::iterator i_compare_end = compare_data.begin(); + DataNDC::iterator i_data_end = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + std::advance(i_compare_end, 4); + std::advance(i_data_end, 4); + + compare_data.erase(i_compare, i_compare_end); + data.erase(i_data, i_data_end); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_clear) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + data.clear(); + + CHECK_EQUAL(data.size(), size_t(0)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.cbegin(), + data.cend(), + compare_data.cbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_reverse_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.rbegin(), + data.rend(), + compare_data.rbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_reverse_iterator) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + + DataNDC data(initial_data.begin(), initial_data.end()); + + bool isEqual = std::equal(data.crbegin(), + data.crend(), + compare_data.crbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator it = data.find(N3); + CHECK_EQUAL(N3, *it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_not_present) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator it = data.find(NX); + CHECK_EQUAL(data.end(), it); + + it = data.find(NY); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::const_iterator it = data.find(N3); + CHECK_EQUAL(N3, *it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const_not_present) + { + const DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::const_iterator it = data.find(NX); + CHECK_EQUAL(data.end(), it); + + it = data.find(NY); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_lower_bound) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.lower_bound(N5); + DataNDC::iterator i_data = data.lower_bound(N5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare), std::distance(data.begin(), i_data)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_upper_bound) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + Compare_DataNDC::iterator i_compare = compare_data.upper_bound(N5); + DataNDC::iterator i_data = data.upper_bound(N5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare), std::distance(data.begin(), i_data)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range) + { + Compare_DataNDC compare_data(initial_data.begin(), initial_data.end()); + DataNDC data(initial_data.begin(), initial_data.end()); + + std::pair i_compare = compare_data.equal_range(N5); + std::pair i_data = data.equal_range(N5); + + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare.first), std::distance(data.begin(), i_data.first)); + CHECK_EQUAL(std::distance(compare_data.begin(), i_compare.second), std::distance(data.begin(), i_data.second)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range_not_present) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + std::pair i_data; + + i_data = data.equal_range(NX); + CHECK_EQUAL(data.begin(), i_data.first); + CHECK_EQUAL(data.begin(), i_data.second); + + i_data = data.equal_range(NY); + CHECK_EQUAL(data.end(), i_data.first); + CHECK_EQUAL(data.end(), i_data.second); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal) + { + const DataNDC initial1(initial_data.begin(), initial_data.end()); + const DataNDC initial2(initial_data.begin(), initial_data.end()); + + CHECK(initial1 == initial2); + + const DataNDC different(different_data.begin(), different_data.end()); + + CHECK(!(initial1 == different)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_not_equal) + { + const DataNDC initial1(initial_data.begin(), initial_data.end()); + const DataNDC initial2(initial_data.begin(), initial_data.end()); + + CHECK(!(initial1 != initial2)); + + const DataNDC different(different_data.begin(), different_data.end()); + + CHECK(initial1 != different); + } + }; +}