From d2acc273fd65b8872a0142a57098782f07a3fdd9 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 17 Apr 2017 18:47:14 +0100 Subject: [PATCH] Combined unordered_multimap.h & iunordered_multimap.h Deleted iunordered_multimap.h --- src/unordered_multimap.h | 1181 +++++++++++++++++++++++++++++++++++++- 1 file changed, 1177 insertions(+), 4 deletions(-) diff --git a/src/unordered_multimap.h b/src/unordered_multimap.h index 6c264bee..16c8d069 100644 --- a/src/unordered_multimap.h +++ b/src/unordered_multimap.h @@ -34,13 +34,27 @@ SOFTWARE. #include #include #include +#include +#include +#include -#include "iunordered_multimap.h" +#include "platform.h" #include "container.h" #include "pool.h" #include "vector.h" #include "intrusive_forward_list.h" #include "hash.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "nullptr.h" +#include "pool.h" +#include "error_handler.h" +#include "intrusive_forward_list.h" +#include "exception.h" +#include "debug_count.h" + +#undef ETL_FILE +#define ETL_FILE "25" //***************************************************************************** ///\defgroup unordered_multimap unordered_multimap @@ -50,15 +64,1173 @@ SOFTWARE. namespace etl { + //*************************************************************************** + /// Exception for the unordered_multimap. + ///\ingroup unordered_multimap + //*************************************************************************** + class unordered_multimap_exception : public etl::exception + { + public: + + unordered_multimap_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Full exception for the unordered_multimap. + ///\ingroup unordered_multimap + //*************************************************************************** + class unordered_multimap_full : public etl::unordered_multimap_exception + { + public: + + unordered_multimap_full(string_type file_name, numeric_type line_number) + : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:full", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Out of range exception for the unordered_multimap. + ///\ingroup unordered_multimap + //*************************************************************************** + class unordered_multimap_out_of_range : public etl::unordered_multimap_exception + { + public: + + unordered_multimap_out_of_range(string_type file_name, numeric_type line_number) + : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:range", ETL_FILE"B"), file_name, line_number) + {} + }; + + //*************************************************************************** + /// Iterator exception for the unordered_multimap. + ///\ingroup unordered_multimap + //*************************************************************************** + class unordered_multimap_iterator : public etl::unordered_multimap_exception + { + public: + + unordered_multimap_iterator(string_type file_name, numeric_type line_number) + : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:iterator", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized unordered_multimap. + /// Can be used as a reference type for all unordered_multimap containing a specific type. + ///\ingroup unordered_multimap + //*************************************************************************** + template , typename TKeyEqual = std::equal_to > + class iunordered_multimap + { + public: + + typedef std::pair value_type; + + typedef TKey key_type; + typedef T mapped_type; + typedef THash hasher; + typedef TKeyEqual key_equal; + 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; + + + typedef typename etl::parameter_type::type key_value_parameter_t; + + typedef etl::forward_link<0> link_t; // Default link. + + struct node_t : public link_t // The nodes that store the elements. + { + node_t(const value_type& key_value_pair) + : key_value_pair(key_value_pair) + { + } + + value_type key_value_pair; + }; + + private: + + typedef etl::intrusive_forward_list bucket_t; + typedef etl::ipool pool_t; + + public: + + // Local iterators iterate over one bucket. + typedef typename bucket_t::iterator local_iterator; + typedef typename bucket_t::const_iterator local_const_iterator; + + //********************************************************************* + class iterator : public std::iterator + { + public: + + typedef typename iunordered_multimap::value_type value_type; + typedef typename iunordered_multimap::key_type key_type; + typedef typename iunordered_multimap::mapped_type mapped_type; + typedef typename iunordered_multimap::hasher hasher; + typedef typename iunordered_multimap::key_equal key_equal; + typedef typename iunordered_multimap::reference reference; + typedef typename iunordered_multimap::const_reference const_reference; + typedef typename iunordered_multimap::pointer pointer; + typedef typename iunordered_multimap::const_pointer const_pointer; + typedef typename iunordered_multimap::size_type size_type; + + friend class iunordered_multimap; + + //********************************* + iterator() + { + } + + //********************************* + iterator(const iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + iterator operator ++(int) + { + iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + iterator operator =(const iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + std::pair operator *() + { + return inode->key_value_pair; + } + + //********************************* + const_reference operator *() const + { + return inode->key_value_pair; + } + + //********************************* + pointer operator &() + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key_value_pair); + } + + //********************************* + pointer operator ->() + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key_value_pair); + } + + //********************************* + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + iterator(bucket_t* pbuckets_end, bucket_t* pbucket, local_iterator inode) + : pbuckets_end(pbuckets_end), + pbucket(pbucket), + inode(inode) + { + } + + //********************************* + bool compare(const iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t*& get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + //********************************************************************* + class const_iterator : public std::iterator + { + public: + + typedef typename iunordered_multimap::value_type value_type; + typedef typename iunordered_multimap::key_type key_type; + typedef typename iunordered_multimap::mapped_type mapped_type; + typedef typename iunordered_multimap::hasher hasher; + typedef typename iunordered_multimap::key_equal key_equal; + typedef typename iunordered_multimap::reference reference; + typedef typename iunordered_multimap::const_reference const_reference; + typedef typename iunordered_multimap::pointer pointer; + typedef typename iunordered_multimap::const_pointer const_pointer; + typedef typename iunordered_multimap::size_type size_type; + + friend class iunordered_multimap; + friend class iterator; + + //********************************* + const_iterator() + { + } + + //********************************* + const_iterator(const typename iunordered_multimap::iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator(const const_iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + const_iterator operator ++(int) + { + const_iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + const_iterator operator =(const const_iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + const_reference operator *() const + { + return inode->key_value_pair; + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key_value_pair); + } + + //********************************* + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + const_iterator(bucket_t* pbuckets_end, bucket_t* pbucket, local_iterator inode) + : pbuckets_end(pbuckets_end), + pbucket(pbucket), + inode(inode) + { + } + + //********************************* + bool compare(const const_iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t*& get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + typedef typename std::iterator_traits::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_multimap. + ///\return An iterator to the beginning of the unordered_multimap. + //********************************************************************* + iterator begin() + { + return iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multimap. + ///\return A const iterator to the beginning of the unordered_multimap. + //********************************************************************* + const_iterator begin() const + { + return const_iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multimap. + ///\return A const iterator to the beginning of the unordered_multimap. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_multimap bucket. + ///\return An iterator to the beginning of the unordered_multimap bucket. + //********************************************************************* + local_iterator begin(size_t i) + { + return pbuckets[i].begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multimap bucket. + ///\return A const iterator to the beginning of the unordered_multimap bucket. + //********************************************************************* + local_const_iterator begin(size_t i) const + { + return pbuckets[i].cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multimap bucket. + ///\return A const iterator to the beginning of the unordered_multimap bucket. + //********************************************************************* + local_const_iterator cbegin(size_t i) const + { + return pbuckets[i].cbegin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_multimap. + ///\return An iterator to the end of the unordered_multimap. + //********************************************************************* + iterator end() + { + return iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multimap. + ///\return A const iterator to the end of the unordered_multimap. + //********************************************************************* + const_iterator end() const + { + return const_iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multimap. + ///\return A const iterator to the end of the unordered_multimap. + //********************************************************************* + const_iterator cend() const + { + return const_iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_multimap bucket. + ///\return An iterator to the end of the unordered_multimap bucket. + //********************************************************************* + local_iterator end(size_t i) + { + return pbuckets[i].end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multimap bucket. + ///\return A const iterator to the end of the unordered_multimap bucket. + //********************************************************************* + local_const_iterator end(size_t i) const + { + return pbuckets[i].cend(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multimap bucket. + ///\return A const iterator to the end of the unordered_multimap bucket. + //********************************************************************* + local_const_iterator cend(size_t i) const + { + return pbuckets[i].cend(); + } + + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + size_type bucket(key_value_parameter_t key) const + { + return key_hash_function(key) % number_of_buckets; + } + + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + size_type bucket_size(key_value_parameter_t key) const + { + size_t index = bucket(key); + + return std::distance(pbuckets[index].begin(), pbuckets[index].end()); + } + + //********************************************************************* + /// Returns the maximum number of the buckets the container can hold. + ///\return The maximum number of the buckets the container can hold. + //********************************************************************* + size_type max_bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Returns the number of the buckets the container holds. + ///\return The number of the buckets the container holds. + //********************************************************************* + size_type bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Assigns values to the unordered_multimap. + /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap does not have enough free space. + /// If asserts or exceptions are enabled, emits unordered_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 >= 0, ETL_ERROR(unordered_multimap_iterator)); + ETL_ASSERT(size_t(count) <= max_size(), ETL_ERROR(unordered_multimap_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the unordered_multimap. + /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap is already full. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const value_type& key_value_pair) + { + iterator result = end(); + + ETL_ASSERT(!full(), ETL_ERROR(unordered_multimap_full)); + + const key_type& key = key_value_pair.first; + const mapped_type& mapped = key_value_pair.second; + + // Get the hash index. + size_t index = bucket(key); + + // Get the bucket & bucket iterator. + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // The first one in the bucket? + if (bucket.empty()) + { + // Get a new node. + node_t& node = *pnodepool->allocate(); + ::new (&node.key_value_pair) value_type(key_value_pair); + ++construct_count; + + // Just add the pointer to the bucket; + bucket.insert_after(bucket.before_begin(), node); + + result = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin()); + + adjust_first_last_markers(pbucket); + } + else + { + // Step though the bucket looking for a place to insert. + local_iterator inode_previous = bucket.before_begin(); + local_iterator inode = bucket.begin(); + + while (inode != bucket.end()) + { + // Do we already have this key? + if (inode->key_value_pair.first == key) + { + break; + } + + ++inode_previous; + ++inode; + } + + // Get a new node. + node_t& node = *pnodepool->allocate(); + ::new (&node.key_value_pair) value_type(key_value_pair); + ++construct_count; + + // Add the node to the end of the bucket; + bucket.insert_after(inode_previous, node); + ++inode_previous; + + result = iterator((pbuckets + number_of_buckets), pbucket, inode_previous); + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the unordered_multimap. + /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, const value_type& key_value_pair) + { + return insert(key_value_pair); + } + + //********************************************************************* + /// Inserts a range of values to the unordered_multimap. + /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_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. + //********************************************************************* + size_t erase(key_value_parameter_t key) + { + size_t count = 0; + size_t bucket_id = bucket(key); + + bucket_t& bucket = pbuckets[bucket_id]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + while (icurrent != bucket.end()) + { + if (icurrent->key_value_pair.first == key) + { + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + ++count; + icurrent = iprevious; + --construct_count; + } + else + { + ++iprevious; + } + + ++icurrent; + } + + return count; + } + + //********************************************************************* + /// Erases an element. + ///\param ielement Iterator to the element. + //********************************************************************* + iterator erase(const_iterator ielement) + { + // Make a note of the next one. + iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator()); + ++inext; + + bucket_t& bucket = ielement.get_bucket(); + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = ielement.get_local_iterator(); + + // Find the node previous to the one we're interested in. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + return inext; + } + + //********************************************************************* + /// 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 to by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + // Make a note of the last. + iterator result((pbuckets + number_of_buckets), last.get_bucket_list_iterator(), last.get_local_iterator()); + + // Get the starting point. + bucket_t* pbucket = first.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first.get_local_iterator(); + local_iterator iend = last.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + + // Find the node previous to the first one. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + while (icurrent != iend) + { + + local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + icurrent = inext; + + // Are we there yet? + if (icurrent != iend) + { + // At the end of this bucket? + if ((icurrent == pbucket->end())) + { + // Find the next non-empty one. + do + { + ++pbucket; + } while (pbucket->empty()); + + iprevious = pbucket->before_begin(); + icurrent = pbucket->begin(); + } + } + } + + return result; + } + + //************************************************************************* + /// Clears the unordered_multimap. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// 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 + { + size_t n = 0; + const_iterator first = find(key); + const_iterator last = first; + + if (last != end()) + { + ++last; + ++n; + + while ((last != end()) && (key == last->first)) + { + ++last; + ++n; + } + } + + return n; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + iterator find(key_value_parameter_t key) + { + size_t index = bucket(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key_value_pair.first)) + { + return iterator((pbuckets + number_of_buckets), pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + const_iterator find(key_value_parameter_t key) const + { + size_t index = bucket(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key_value_pair.first)) + { + return const_iterator((pbuckets + number_of_buckets), pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Returns a range containing all elements with key key in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return An iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair equal_range(const key_value_parameter_t& key) + { + iterator first = find(key); + iterator last = first; + + if (last != end()) + { + ++last; + + while ((last != end()) && (key == last->first)) + { + ++last; + } + } + + return std::pair(first, last); + } + + //********************************************************************* + /// Returns a range containing all elements with key key in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return A const iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair equal_range(const key_value_parameter_t& key) const + { + const_iterator first = find(key); + const_iterator last = first; + + if (last != end()) + { + ++last; + + while ((last != end()) && (key == last->first)) + { + ++last; + } + } + + return std::pair(first, last); + } + + //************************************************************************* + /// Gets the size of the unordered_multimap. + //************************************************************************* + size_type size() const + { + return pnodepool->size(); + } + + //************************************************************************* + /// Gets the maximum possible size of the unordered_multimap. + //************************************************************************* + size_type max_size() const + { + return pnodepool->max_items(); + } + + //************************************************************************* + /// Checks to see if the unordered_multimap is empty. + //************************************************************************* + bool empty() const + { + return pnodepool->empty(); + } + + //************************************************************************* + /// Checks to see if the unordered_multimap is full. + //************************************************************************* + bool full() const + { + return pnodepool->full(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return pnodepool->available(); + } + + //************************************************************************* + /// Returns the load factor = size / bucket_count. + ///\return The load factor = size / bucket_count. + //************************************************************************* + float load_factor() const + { + return static_cast(size()) / static_cast(bucket_count()); + } + + //************************************************************************* + /// Returns the function that hashes the keys. + ///\return The function that hashes the keys.. + //************************************************************************* + hasher hash_function() const + { + return key_hash_function; + } + + //************************************************************************* + /// Returns the function that compares the keys. + ///\return The function that compares the keys.. + //************************************************************************* + key_equal key_eq() const + { + return key_equal_function; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iunordered_multimap& operator = (const iunordered_multimap& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iunordered_multimap(pool_t& node_pool, bucket_t* pbuckets_, size_t number_of_buckets) + : pnodepool(&node_pool), + pbuckets(pbuckets_), + number_of_buckets(number_of_buckets) + { + } + + //********************************************************************* + /// Initialise the unordered_multimap. + //********************************************************************* + void initialise() + { + if (!empty()) + { + // For each bucket... + for (size_t i = 0; i < number_of_buckets; ++i) + { + bucket_t& bucket = pbuckets[i]; + + if (!bucket.empty()) + { + // For each item in the bucket... + local_iterator it = bucket.begin(); + + while (it != bucket.end()) + { + // Destroy the value contents. + it->key_value_pair.~value_type(); + ++it; + --construct_count; + } + + // Now it's safe to clear the bucket. + bucket.clear(); + } + } + + // Now it's safe to clear the entire pool in one go. + pnodepool->release_all(); + } + + first = pbuckets; + last = first; + } + + private: + + //********************************************************************* + /// Adjust the first and last markers according to the new entry. + //********************************************************************* + void adjust_first_last_markers(bucket_t* pbucket) + { + if (pbucket < first) + { + first = pbucket; + } + else if (pbucket > last) + { + last = pbucket; + } + } + + // Disable copy construction. + iunordered_multimap(const iunordered_multimap&); + + /// The pool of data nodes used in the list. + pool_t* pnodepool; + + /// The bucket list. + bucket_t* pbuckets; + + /// The number of buckets. + const size_t number_of_buckets; + + /// The first and last iterators to buckets with values. + bucket_t* first; + bucket_t* last; + + /// The function that creates the hashes. + hasher key_hash_function; + + /// The function that compares the keys for equality. + key_equal key_equal_function; + + /// For library debugging purposes only. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first unordered_multimap. + ///\param rhs Reference to the second unordered_multimap. + ///\return true if the arrays are equal, otherwise false + ///\ingroup unordered_multimap + //*************************************************************************** + template + bool operator ==(const etl::iunordered_multimap& lhs, const etl::iunordered_multimap& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first unordered_multimap. + ///\param rhs Reference to the second unordered_multimap. + ///\return true if the arrays are not equal, otherwise false + ///\ingroup unordered_multimap + //*************************************************************************** + template + bool operator !=(const etl::iunordered_multimap& lhs, const etl::iunordered_multimap& rhs) + { + return !(lhs == rhs); + } + //************************************************************************* /// A templated unordered_multimap implementation that uses a fixed size buffer. //************************************************************************* template , typename TKeyEqual = std::equal_to > - class unordered_multimap : public iunordered_multimap + class unordered_multimap : public etl::iunordered_multimap { private: - typedef iunordered_multimap base; + typedef etl::iunordered_multimap base; public: @@ -126,7 +1298,8 @@ namespace etl /// The buckets of node lists. etl::intrusive_forward_list buckets[MAX_BUCKETS_]; }; - } +#undef ETL_FILE + #endif