diff --git a/include/etl/unordered_map.h b/include/etl/unordered_map.h index 8dd01af0..359218de 100644 --- a/include/etl/unordered_map.h +++ b/include/etl/unordered_map.h @@ -52,6 +52,8 @@ SOFTWARE. #include "placement_new.h" #include "initializer_list.h" +#include "private/comparator_is_transparent.h" + #include //***************************************************************************** @@ -599,6 +601,18 @@ namespace etl return key_hash_function(key) % number_of_buckets; } +#if ETL_USING_CPP11 + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + template ::value, int> = 0> + size_type get_bucket_index(const K& key) const + { + return key_hash_function(key) % number_of_buckets; + } +#endif + //********************************************************************* /// Returns the size of the bucket key. ///\return The bucket size of the bucket key. @@ -610,6 +624,20 @@ namespace etl return etl::distance(pbuckets[index].begin(), pbuckets[index].end()); } +#if ETL_USING_CPP11 + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + template ::value, int> = 0> + size_type bucket_size(const K& key) const + { + size_t index = bucket(key); + + return etl::distance(pbuckets[index].begin(), pbuckets[index].end()); + } +#endif + //********************************************************************* /// Returns the maximum number of the buckets the container can hold. ///\return The maximum number of the buckets the container can hold. @@ -716,6 +744,52 @@ namespace etl return pbucket->begin()->key_value_pair.second; } + //********************************************************************* + /// Returns a reference to the value at index 'key' + ///\param key The key. + ///\return A reference to the value at index 'key' + //********************************************************************* +#if ETL_USING_CPP11 + template ::value, int> = 0> + mapped_reference operator [](const K& key) + { + // Find the bucket. + bucket_t* pbucket = pbuckets + get_bucket_index(key); + + // Find the first node in the bucket. + local_iterator inode = pbucket->begin(); + + // Walk the list looking for the right one. + while (inode != pbucket->end()) + { + // Equal keys? + if (key_equal_function(key, inode->key_value_pair.first)) + { + // Found a match. + return inode->key_value_pair.second; + } + else + { + ++inode; + } + } +#endif + + // Doesn't exist, so add a new one. + // Get a new node. + node_t* node = allocate_data_node(); + node->clear(); + ::new ((void*)etl::addressof(node->key_value_pair.first)) key_type(key); + ::new ((void*)etl::addressof(node->key_value_pair.second)) mapped_type(); + ETL_INCREMENT_DEBUG_COUNT; + + pbucket->insert_after(pbucket->before_begin(), *node); + + adjust_first_last_markers_after_insert(pbucket); + + return pbucket->begin()->key_value_pair.second; + } + //********************************************************************* /// Returns a reference to the value at index 'key' /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range. @@ -786,6 +860,82 @@ namespace etl return begin()->second; } + //********************************************************************* + /// Returns a reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range. + ///\param key The key. + ///\return A reference to the value at index 'key' + //********************************************************************* +#if ETL_USING_CPP11 + template ::value, int> = 0> + mapped_reference at(const K& key) + { + // Find the bucket. + bucket_t* pbucket = pbuckets + get_bucket_index(key); + + // Find the first node in the bucket. + local_iterator inode = pbucket->begin(); + + // Walk the list looking for the right one. + while (inode != pbucket->end()) + { + // Equal keys? + if (key_equal_function(key, inode->key_value_pair.first)) + { + // Found a match. + return inode->key_value_pair.second; + } + else + { + ++inode; + } + } + + // Doesn't exist. + ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range)); + + return begin()->second; + } +#endif + +#if ETL_USING_CPP11 + //********************************************************************* + /// Returns a const reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range. + ///\param key The key. + ///\return A const reference to the value at index 'key' + //********************************************************************* + template ::value, int> = 0> + const_mapped_reference at(const K& key) const + { + // Find the bucket. + bucket_t* pbucket = pbuckets + get_bucket_index(key); + + // Find the first node in the bucket. + local_iterator inode = pbucket->begin(); + + // Walk the list looking for the right one. + while (inode != pbucket->end()) + { + // Equal keys? + if (key_equal_function(key, inode->key_value_pair.first)) + { + // Found a match. + return inode->key_value_pair.second; + } + else + { + ++inode; + } + } + + // Doesn't exist. + ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range)); + + return begin()->second; + } +#endif + //********************************************************************* /// Assigns values to the unordered_map. /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map does not have enough free space. @@ -1040,6 +1190,41 @@ namespace etl return n; } + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* +#if ETL_USING_CPP11 + template ::value, int> = 0> + size_t erase(const K& key) + { + size_t n = 0UL; + size_t index = get_bucket_index(key); + + bucket_t& bucket = pbuckets[index]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + // Search for the key, if we have it. + while ((icurrent != bucket.end()) && (!key_equal_function(icurrent->key_value_pair.first, key))) + { + ++iprevious; + ++icurrent; + } + + // Did we find it? + if (icurrent != bucket.end()) + { + delete_data_node(iprevious, icurrent, bucket); + n = 1; + } + + return n; + } +#endif + //********************************************************************* /// Erases an element. ///\param ielement Iterator to the element. @@ -1141,6 +1326,19 @@ namespace etl return (find(key) == end()) ? 0 : 1; } + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* +#if ETL_USING_CPP11 + template ::value, int> = 0> + size_t count(const K& key) const + { + return (find(key) == end()) ? 0 : 1; + } +#endif + //********************************************************************* /// Finds an element. ///\param key The key to search for. @@ -1209,6 +1407,80 @@ namespace etl return end(); } + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* +#if ETL_USING_CPP11 + template ::value, int> = 0> + iterator find(const K& key) + { + size_t index = get_bucket_index(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(); + } +#endif + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* +#if ETL_USING_CPP11 + template ::value, int> = 0> + const_iterator find(const K& key) const + { + size_t index = get_bucket_index(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(); + } +#endif + //********************************************************************* /// 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 @@ -1251,6 +1523,54 @@ namespace etl return ETL_OR_STD::pair(f, l); } + //********************************************************************* + /// 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(). + //********************************************************************* +#if ETL_USING_CPP11 + template ::value, int> = 0> + ETL_OR_STD::pair equal_range(const K& key) + { + iterator f = find(key); + iterator l = f; + + if (l != end()) + { + ++l; + } + + return ETL_OR_STD::pair(f, l); + } +#endif + + //********************************************************************* + /// 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(). + //********************************************************************* +#if ETL_USING_CPP11 + template ::value, int> = 0> + ETL_OR_STD::pair equal_range(const K& key) const + { + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + } + + return ETL_OR_STD::pair(f, l); + } +#endif + //************************************************************************* /// Gets the size of the unordered_map. //************************************************************************* diff --git a/include/etl/unordered_multimap.h b/include/etl/unordered_multimap.h index 463e1cd9..c4eaff6b 100644 --- a/include/etl/unordered_multimap.h +++ b/include/etl/unordered_multimap.h @@ -52,6 +52,8 @@ SOFTWARE. #include "placement_new.h" #include "initializer_list.h" +#include "private/comparator_is_transparent.h" + #include //***************************************************************************** @@ -597,6 +599,16 @@ namespace etl return key_hash_function(key) % number_of_buckets; } + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + template ::value, int> = 0> + size_type get_bucket_index(const K& 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. @@ -608,6 +620,18 @@ namespace etl return etl::distance(pbuckets[index].begin(), pbuckets[index].end()); } + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + template ::value, int> = 0> + size_type bucket_size(const K& key) const + { + size_t index = bucket(key); + + return etl::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. @@ -868,6 +892,41 @@ namespace etl return n; } + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. + //********************************************************************* + template ::value, int> = 0> + size_t erase(const K& key) + { + size_t n = 0UL; + size_t bucket_id = get_bucket_index(key); + + bucket_t& bucket = pbuckets[bucket_id]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + while (icurrent != bucket.end()) + { + if (key_equal_function(icurrent->key_value_pair.first, key)) + { + delete_data_node(iprevious, icurrent, bucket); + ++n; + icurrent = iprevious; + } + else + { + ++iprevious; + } + + ++icurrent; + } + + return n; + } + //********************************************************************* /// Erases an element. ///\param ielement Iterator to the element. @@ -985,6 +1044,33 @@ namespace etl return n; } + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + template ::value, int> = 0> + size_t count(const K& key) const + { + size_t n = 0UL; + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + ++n; + + while ((l != end()) && key_equal_function(key, l->first)) + { + ++l; + ++n; + } + } + + return n; + } + //********************************************************************* /// Finds an element. ///\param key The key to search for. @@ -1053,6 +1139,76 @@ namespace etl return end(); } + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + template ::value, int> = 0> + iterator find(const K& key) + { + size_t index = get_bucket_index(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(). + //********************************************************************* + template ::value, int> = 0> + const_iterator find(const K& key) const + { + size_t index = get_bucket_index(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 @@ -1105,6 +1261,60 @@ namespace etl return ETL_OR_STD::pair(f, l); } + //********************************************************************* + /// 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(). + //********************************************************************* + template ::value, int> = 0> + ETL_OR_STD::pair equal_range(const K& key) + { + iterator f = find(key); + iterator l = f; + + if (l != end()) + { + ++l; + + while ((l != end()) && key_equal_function(key, l->first)) + { + ++l; + } + } + + return ETL_OR_STD::pair(f, l); + } + + //********************************************************************* + /// 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(). + //********************************************************************* + template ::value, int> = 0> + ETL_OR_STD::pair equal_range(const K& key) const + { + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + + while ((l != end()) && key_equal_function(key, l->first)) + { + ++l; + } + } + + return ETL_OR_STD::pair(f, l); + } + //************************************************************************* /// Gets the size of the unordered_multimap. //************************************************************************* diff --git a/include/etl/unordered_multiset.h b/include/etl/unordered_multiset.h index 304dc4bc..ea2fba38 100644 --- a/include/etl/unordered_multiset.h +++ b/include/etl/unordered_multiset.h @@ -51,6 +51,8 @@ SOFTWARE. #include "placement_new.h" #include "initializer_list.h" +#include "private/comparator_is_transparent.h" + #include //***************************************************************************** @@ -588,6 +590,16 @@ namespace etl return key_hash_function(key) % number_of_buckets; } + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + template ::value, int> = 0> + size_type get_bucket_index(const K& 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. @@ -599,6 +611,18 @@ namespace etl return etl::distance(pbuckets[index].begin(), pbuckets[index].end()); } + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + template ::value, int> = 0> + size_type bucket_size(const K& key) const + { + size_t index = bucket(key); + + return etl::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. @@ -712,6 +736,77 @@ namespace etl return result; } + //********************************************************************* + /// Inserts a value to the unordered_multiset. + /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset is already full. + ///\param value The value to insert. + //********************************************************************* + template ::value, int> = 0> + ETL_OR_STD::pair insert(const K& key) + { + ETL_OR_STD::pair result(end(), false); + + ETL_ASSERT(!full(), ETL_ERROR(unordered_multiset_full)); + + // Get the hash index. + size_t index = get_bucket_index(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 = allocate_data_node(); + node->clear(); + ::new (&node->key) value_type(key); + ETL_INCREMENT_DEBUG_COUNT; + + // Just add the pointer to the bucket; + bucket.insert_after(bucket.before_begin(), *node); + adjust_first_last_markers_after_insert(&bucket); + + result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin()); + result.second = true; + } + 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 (key_equal_function(inode->key, key)) + { + break; + } + + ++inode_previous; + ++inode; + } + + // Get a new node. + node_t* node = allocate_data_node(); + node->clear(); + ::new (&node->key) value_type(key); + ETL_INCREMENT_DEBUG_COUNT; + + // Add the node to the end of the bucket; + bucket.insert_after(inode_previous, *node); + adjust_first_last_markers_after_insert(&bucket); + ++inode_previous; + + result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous); + result.second = true; + } + + return result; + } + #if ETL_USING_CPP11 //********************************************************************* /// Inserts a value to the unordered_multiset. @@ -846,6 +941,41 @@ namespace etl return n; } + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + template ::value, int> = 0> + size_t erase(const K& key) + { + size_t n = 0UL; + size_t bucket_id = get_bucket_index(key); + + bucket_t& bucket = pbuckets[bucket_id]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + while (icurrent != bucket.end()) + { + if (key_equal_function(icurrent->key, key)) + { + delete_data_node(iprevious, icurrent, bucket); + ++n; + icurrent = iprevious; + } + else + { + ++iprevious; + } + + ++icurrent; + } + + return n; + } + //********************************************************************* /// Erases an element. ///\param ielement Iterator to the element. @@ -963,6 +1093,33 @@ namespace etl return n; } + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + template ::value, int> = 0> + size_t count(const K& key) const + { + size_t n = 0UL; + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + ++n; + + while ((l != end()) && key_equal_function(key, *l)) + { + ++l; + ++n; + } + } + + return n; + } + //********************************************************************* /// Finds an element. ///\param key The key to search for. @@ -1031,6 +1188,76 @@ namespace etl return end(); } + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + template ::value, int> = 0> + iterator find(const K& key) + { + size_t index = get_bucket_index(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)) + { + 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(). + //********************************************************************* + template ::value, int> = 0> + const_iterator find(const K& key) const + { + size_t index = get_bucket_index(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)) + { + return 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 diff --git a/include/etl/unordered_set.h b/include/etl/unordered_set.h index 1f9a7e6e..ec983b3a 100644 --- a/include/etl/unordered_set.h +++ b/include/etl/unordered_set.h @@ -52,6 +52,8 @@ SOFTWARE. #include "placement_new.h" #include "initializer_list.h" +#include "private/comparator_is_transparent.h" + #include //***************************************************************************** @@ -589,6 +591,16 @@ namespace etl return key_hash_function(key) % number_of_buckets; } + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + template ::value, int> = 0> + size_type get_bucket_index(const K& 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. @@ -600,6 +612,18 @@ namespace etl return etl::distance(pbuckets[index].begin(), pbuckets[index].end()); } + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + template ::value, int> = 0> + size_type bucket_size(const K& key) const + { + size_t index = bucket(key); + + return etl::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. @@ -730,6 +754,94 @@ namespace etl return result; } + //********************************************************************* + /// Inserts a value to the unordered_set. + /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full. + ///\param value The value to insert. + //********************************************************************* + template ::value, int> = 0> + ETL_OR_STD::pair insert(const K& key) + { + ETL_OR_STD::pair result(end(), false); + + if (full()) + { + iterator iter = find(key); + if (iter == end()) + { + ETL_ASSERT_FAIL(ETL_ERROR(unordered_set_full)); + } + else + { + result.first = iter; + result.second = false; + return result; + } + } + + // Get the hash index. + size_t index = get_bucket_index(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 = allocate_data_node(); + node->clear(); + ::new (&node->key) value_type(key); + ETL_INCREMENT_DEBUG_COUNT; + + // Just add the pointer to the bucket; + bucket.insert_after(bucket.before_begin(), *node); + adjust_first_last_markers_after_insert(&bucket); + + result.first = iterator(pbuckets + number_of_buckets, pbucket, pbucket->begin()); + result.second = true; + } + 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 (key_equal_function(inode->key, key)) + { + break; + } + + ++inode_previous; + ++inode; + } + + // Not already there? + if (inode == bucket.end()) + { + // Get a new node. + node_t* node = allocate_data_node(); + node->clear(); + ::new (&node->key) value_type(key); + ETL_INCREMENT_DEBUG_COUNT; + + // Add the node to the end of the bucket; + bucket.insert_after(inode_previous, *node); + adjust_first_last_markers_after_insert(&bucket); + ++inode_previous; + + result.first = iterator(pbuckets + number_of_buckets, pbucket, inode_previous); + result.second = true; + } + } + + return result; + } + #if ETL_USING_CPP11 //********************************************************************* /// Inserts a value to the unordered_set. @@ -892,6 +1004,39 @@ namespace etl return n; } + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + template ::value, int> = 0> + size_t erase(const K& key) + { + size_t n = 0UL; + size_t index = get_bucket_index(key); + + bucket_t& bucket = pbuckets[index]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + // Search for the key, if we have it. + while ((icurrent != bucket.end()) && (!key_equal_function(icurrent->key, key))) + { + ++iprevious; + ++icurrent; + } + + // Did we find it? + if (icurrent != bucket.end()) + { + delete_data_node(iprevious, icurrent, bucket); + n = 1; + } + + return n; + } + //********************************************************************* /// Erases an element. ///\param ielement Iterator to the element. @@ -993,6 +1138,17 @@ namespace etl return (find(key) == end()) ? 0 : 1; } + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + template ::value, int> = 0> + size_t count(const K& key) const + { + return (find(key) == end()) ? 0 : 1; + } + //********************************************************************* /// Finds an element. ///\param key The key to search for. @@ -1061,6 +1217,76 @@ namespace etl return end(); } + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + template ::value, int> = 0> + iterator find(const K& key) + { + size_t index = get_bucket_index(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)) + { + 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(). + //********************************************************************* + template ::value, int> = 0> + const_iterator find(const K& key) const + { + size_t index = get_bucket_index(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)) + { + return 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 @@ -1103,6 +1329,50 @@ namespace etl return ETL_OR_STD::pair(f, l); } + //********************************************************************* + /// 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(). + //********************************************************************* + template ::value, int> = 0> + ETL_OR_STD::pair equal_range(const K& key) + { + iterator f = find(key); + iterator l = f; + + if (l != end()) + { + ++l; + } + + return ETL_OR_STD::pair(f, l); + } + + //********************************************************************* + /// 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(). + //********************************************************************* + template ::value, int> = 0> + ETL_OR_STD::pair equal_range(const K& key) const + { + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + } + + return ETL_OR_STD::pair(f, l); + } + //************************************************************************* /// Gets the size of the unordered_set. //************************************************************************* diff --git a/test/test_unordered_map.cpp b/test/test_unordered_map.cpp index 4f7b1b7b..34767d69 100644 --- a/test/test_unordered_map.cpp +++ b/test/test_unordered_map.cpp @@ -130,6 +130,25 @@ namespace return true; } + //************************************************************************* + struct transparent_hash + { + typedef int is_transparent; + + size_t operator ()(const char* s) const + { + size_t sum = 0U; + size_t length = etl::strlen(s); + + return std::accumulate(s, s + length, sum); + } + + size_t operator ()(const std::string& text) const + { + return std::accumulate(text.begin(), text.end(), 0); + } + }; + typedef TestDataDC DC; typedef TestDataNDC NDC; @@ -204,17 +223,19 @@ namespace typedef etl::unordered_map DataDC; typedef etl::unordered_map DataNDC; typedef etl::iunordered_map IDataNDC; + typedef etl::unordered_map> DataNDCTransparent; + typedef etl::unordered_map> DataDCTransparent; - 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 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"); @@ -226,16 +247,16 @@ namespace 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 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"); @@ -247,26 +268,47 @@ namespace DC M18 = DC("S"); DC M19 = DC("T"); - const char* K0 = "FF"; // 0 - const char* K1 = "FG"; // 1 - const char* K2 = "FH"; // 2 - const char* K3 = "FI"; // 3 - const char* K4 = "FJ"; // 4 - const char* K5 = "FK"; // 5 - const char* K6 = "FL"; // 6 - const char* K7 = "FM"; // 7 - const char* K8 = "FN"; // 8 - const char* K9 = "FO"; // 9 - const char* K10 = "FP"; // 0 - const char* K11 = "FQ"; // 1 - const char* K12 = "FR"; // 2 - const char* K13 = "FS"; // 3 - const char* K14 = "FT"; // 4 - const char* K15 = "FU"; // 5 - const char* K16 = "FV"; // 6 - const char* K17 = "FW"; // 7 - const char* K18 = "FX"; // 8 - const char* K19 = "FY"; // 9 + const char* CK0 = "FF"; // 0 + const char* CK1 = "FG"; // 1 + const char* CK2 = "FH"; // 2 + const char* CK3 = "FI"; // 3 + const char* CK4 = "FJ"; // 4 + const char* CK5 = "FK"; // 5 + const char* CK6 = "FL"; // 6 + const char* CK7 = "FM"; // 7 + const char* CK8 = "FN"; // 8 + const char* CK9 = "FO"; // 9 + const char* CK10 = "FP"; // 0 + const char* CK11 = "FQ"; // 1 + const char* CK12 = "FR"; // 2 + const char* CK13 = "FS"; // 3 + const char* CK14 = "FT"; // 4 + const char* CK15 = "FU"; // 5 + const char* CK16 = "FV"; // 6 + const char* CK17 = "FW"; // 7 + const char* CK18 = "FX"; // 8 + const char* CK19 = "FY"; // 9 + + std::string K0 = CK0; // 0 + std::string K1 = CK1; // 1 + std::string K2 = CK2; // 2 + std::string K3 = CK3; // 3 + std::string K4 = CK4; // 4 + std::string K5 = CK5; // 5 + std::string K6 = CK6; // 6 + std::string K7 = CK7; // 7 + std::string K8 = CK8; // 8 + std::string K9 = CK9; // 9 + std::string K10 = CK10; // 0 + std::string K11 = CK11; // 1 + std::string K12 = CK12; // 2 + std::string K13 = CK13; // 3 + std::string K14 = CK14; // 4 + std::string K15 = CK15; // 5 + std::string K16 = CK16; // 6 + std::string K17 = CK17; // 7 + std::string K18 = CK18; // 8 + std::string K19 = CK19; // 9 std::string K[] = { K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, K12, K13, K14, K15, K16, K17, K18, K19 }; @@ -502,6 +544,23 @@ namespace CHECK_EQUAL(M9, data[K9]); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_index_read_using_transparent_comparator_and_hasher) + { + DataDCTransparent data(initial_data_dc.begin(), initial_data_dc.end()); + + CHECK_EQUAL(M0, data[CK0]); + CHECK_EQUAL(M1, data[CK1]); + CHECK_EQUAL(M2, data[CK2]); + CHECK_EQUAL(M3, data[CK3]); + CHECK_EQUAL(M4, data[CK4]); + CHECK_EQUAL(M5, data[CK5]); + CHECK_EQUAL(M6, data[CK6]); + CHECK_EQUAL(M7, data[CK7]); + CHECK_EQUAL(M8, data[CK8]); + CHECK_EQUAL(M9, data[CK9]); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_index_write) { @@ -530,6 +589,34 @@ namespace CHECK_EQUAL(M0, data[K9]); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_index_write_using_transparent_comparator_and_hasher) + { + DataDCTransparent data(initial_data_dc.begin(), initial_data_dc.end()); + + data[CK0] = M9; + data[CK1] = M8; + data[CK2] = M7; + data[CK3] = M6; + data[CK4] = M5; + data[CK5] = M4; + data[CK6] = M3; + data[CK7] = M2; + data[CK8] = M1; + data[CK9] = M0; + + CHECK_EQUAL(M9, data[CK0]); + CHECK_EQUAL(M8, data[CK1]); + CHECK_EQUAL(M7, data[CK2]); + CHECK_EQUAL(M6, data[CK3]); + CHECK_EQUAL(M5, data[CK4]); + CHECK_EQUAL(M4, data[CK5]); + CHECK_EQUAL(M3, data[CK6]); + CHECK_EQUAL(M2, data[CK7]); + CHECK_EQUAL(M1, data[CK8]); + CHECK_EQUAL(M0, data[CK9]); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_at) { @@ -547,6 +634,23 @@ namespace CHECK_EQUAL(data.at(K9), N9); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_at_using_transparent_comparator_and_hasher) + { + DataNDCTransparent data(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.at(CK0), N0); + CHECK_EQUAL(data.at(CK1), N1); + CHECK_EQUAL(data.at(CK2), N2); + CHECK_EQUAL(data.at(CK3), N3); + CHECK_EQUAL(data.at(CK4), N4); + CHECK_EQUAL(data.at(CK5), N5); + CHECK_EQUAL(data.at(CK6), N6); + CHECK_EQUAL(data.at(CK7), N7); + CHECK_EQUAL(data.at(CK8), N8); + CHECK_EQUAL(data.at(CK9), N9); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_at_const) { @@ -564,6 +668,23 @@ namespace CHECK_EQUAL(data.at(K9), N9); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_at_const_using_transparent_comparator_and_hasher) + { + const DataNDCTransparent data(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.at(CK0), N0); + CHECK_EQUAL(data.at(CK1), N1); + CHECK_EQUAL(data.at(CK2), N2); + CHECK_EQUAL(data.at(CK3), N3); + CHECK_EQUAL(data.at(CK4), N4); + CHECK_EQUAL(data.at(CK5), N5); + CHECK_EQUAL(data.at(CK6), N6); + CHECK_EQUAL(data.at(CK7), N7); + CHECK_EQUAL(data.at(CK8), N8); + CHECK_EQUAL(data.at(CK9), N9); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_assign_range) { @@ -687,6 +808,23 @@ namespace CHECK(!data.empty()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_key_using_transparent_comparator) + { + DataNDCTransparent data(initial_data.begin(), initial_data.end()); + + size_t count = data.erase(CK5); + + CHECK_EQUAL(1U, count); + + DataNDCTransparent::iterator idata = data.find(CK5); + CHECK(idata == data.end()); + + // Test that erase really does erase from the pool. + CHECK(!data.full()); + CHECK(!data.empty()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_single_iterator) { @@ -837,6 +975,18 @@ namespace CHECK_EQUAL(0U, count); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_count_key_using_transparent_comparator) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + size_t count = data.count(CK5); + CHECK_EQUAL(1U, count); + + count = data.count(CK12); + CHECK_EQUAL(0U, count); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_equal_range) { @@ -863,6 +1013,32 @@ namespace CHECK_EQUAL(result.first->first, K9); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range_using_transparent_comparator) + { + DataNDCTransparent data(initial_data.begin(), initial_data.end()); + + ETL_OR_STD::pair result; + + result = data.equal_range("FF"); + CHECK(result.first == data.begin()); + CHECK(result.second != data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, "FF"); + + result = data.equal_range("FJ"); + CHECK(result.first != data.begin()); + CHECK(result.second != data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, "FJ"); + + result = data.equal_range("FO"); + CHECK(result.first != data.begin()); + CHECK(result.second == data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, "FO"); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_equal_range_const) { @@ -889,6 +1065,32 @@ namespace CHECK_EQUAL(result.first->first, K9); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range_const_using_transparent_comparator) + { + const DataNDCTransparent data(initial_data.begin(), initial_data.end()); + + ETL_OR_STD::pair result; + + result = data.equal_range("FF"); + CHECK(result.first == data.begin()); + CHECK(result.second != data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, "FF"); + + result = data.equal_range("FJ"); + CHECK(result.first != data.begin()); + CHECK(result.second != data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, "FJ"); + + result = data.equal_range("FO"); + CHECK(result.first != data.begin()); + CHECK(result.second == data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, "FO"); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_equal) { diff --git a/test/test_unordered_multimap.cpp b/test/test_unordered_multimap.cpp index 60b9eb92..9789af61 100644 --- a/test/test_unordered_multimap.cpp +++ b/test/test_unordered_multimap.cpp @@ -85,6 +85,25 @@ namespace return true; } + //************************************************************************* + struct transparent_hash + { + typedef int is_transparent; + + size_t operator ()(const char* s) const + { + size_t sum = 0U; + size_t length = etl::strlen(s); + + return std::accumulate(s, s + length, sum); + } + + size_t operator ()(const std::string& text) const + { + return std::accumulate(text.begin(), text.end(), 0); + } + }; + typedef TestDataDC DC; typedef TestDataNDC NDC; @@ -175,6 +194,8 @@ namespace typedef etl::unordered_multimap DataDC; typedef etl::unordered_multimap DataNDC; typedef etl::iunordered_multimap IDataNDC; + typedef etl::unordered_multimap> DataNDCTransparent; + typedef etl::unordered_multimap> DataDCTransparent; using ItemM = TestDataM; using DataM = etl::unordered_multimap>; @@ -200,26 +221,47 @@ namespace NDC N18 = NDC("S"); NDC N19 = NDC("T"); - const char* K0 = "FF"; // 0 - const char* K1 = "FG"; // 1 - const char* K2 = "FH"; // 2 - const char* K3 = "FI"; // 3 - const char* K4 = "FJ"; // 4 - const char* K5 = "FK"; // 5 - const char* K6 = "FL"; // 6 - const char* K7 = "FM"; // 7 - const char* K8 = "FN"; // 8 - const char* K9 = "FO"; // 9 - const char* K10 = "FP"; // 0 - const char* K11 = "FQ"; // 1 - const char* K12 = "FR"; // 2 - const char* K13 = "FS"; // 3 - const char* K14 = "FT"; // 4 - const char* K15 = "FU"; // 5 - const char* K16 = "FV"; // 6 - const char* K17 = "FW"; // 7 - const char* K18 = "FX"; // 8 - const char* K19 = "FY"; // 9 + const char* CK0 = "FF"; // 0 + const char* CK1 = "FG"; // 1 + const char* CK2 = "FH"; // 2 + const char* CK3 = "FI"; // 3 + const char* CK4 = "FJ"; // 4 + const char* CK5 = "FK"; // 5 + const char* CK6 = "FL"; // 6 + const char* CK7 = "FM"; // 7 + const char* CK8 = "FN"; // 8 + const char* CK9 = "FO"; // 9 + const char* CK10 = "FP"; // 0 + const char* CK11 = "FQ"; // 1 + const char* CK12 = "FR"; // 2 + const char* CK13 = "FS"; // 3 + const char* CK14 = "FT"; // 4 + const char* CK15 = "FU"; // 5 + const char* CK16 = "FV"; // 6 + const char* CK17 = "FW"; // 7 + const char* CK18 = "FX"; // 8 + const char* CK19 = "FY"; // 9 + + std::string K0 = CK0; // 0 + std::string K1 = CK1; // 1 + std::string K2 = CK2; // 2 + std::string K3 = CK3; // 3 + std::string K4 = CK4; // 4 + std::string K5 = CK5; // 5 + std::string K6 = CK6; // 6 + std::string K7 = CK7; // 7 + std::string K8 = CK8; // 8 + std::string K9 = CK9; // 9 + std::string K10 = CK10; // 0 + std::string K11 = CK11; // 1 + std::string K12 = CK12; // 2 + std::string K13 = CK13; // 3 + std::string K14 = CK14; // 4 + std::string K15 = CK15; // 5 + std::string K16 = CK16; // 6 + std::string K17 = CK17; // 7 + std::string K18 = CK18; // 8 + std::string K19 = CK19; // 9 std::string K[] = { K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, K12, K13, K14, K15, K16, K17, K18, K19 }; @@ -572,6 +614,26 @@ namespace CHECK(idata == data.end()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_key_using_transparent_comparator) + { + DataNDCTransparent data(equal_data.begin(), equal_data.end()); + + size_t count = data.erase("FP"); + + CHECK_EQUAL(1U, count); + + DataNDCTransparent::iterator idata = data.find("FP"); + CHECK(idata == data.end()); + + count = data.erase("FQ"); + + CHECK_EQUAL(3U, count); + + idata = data.find("FQ"); + CHECK(idata == data.end()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_single_iterator) { @@ -717,7 +779,6 @@ namespace CHECK_EQUAL(data.size(), size_t(0)); } - //************************************************************************* TEST_FIXTURE(SetupFixture, test_count_key) { @@ -733,6 +794,31 @@ namespace CHECK_EQUAL(0U, count); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_count_key_using_transparent_comparator) + { + DataNDCTransparent data(equal_data.begin(), equal_data.end()); + + size_t count = data.count(K10); + CHECK_EQUAL(1U, count); + + count = data.count(K11); + CHECK_EQUAL(3U, count); + + count = data.count(K1); + CHECK_EQUAL(0U, count); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator idata = data.find(K3); + + CHECK(idata != data.end()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_find_const) { @@ -743,6 +829,26 @@ namespace CHECK(idata != data.end()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_using_transparent_comparator) + { + DataNDCTransparent data(initial_data.begin(), initial_data.end()); + + DataNDCTransparent::iterator idata = data.find(CK3); + + CHECK(idata != data.end()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const_using_transparent_comparator) + { + const DataNDCTransparent data(initial_data.begin(), initial_data.end()); + + DataNDCTransparent::const_iterator idata = data.find(CK3); + + CHECK(idata != data.end()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_equal_range) { @@ -795,6 +901,58 @@ namespace CHECK_EQUAL(result.first->first, K12); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range_using_transparent_comparator) + { + DataNDCTransparent data(equal_data.begin(), equal_data.end()); + + ETL_OR_STD::pair result; + + result = data.equal_range(CK10); + CHECK(result.first == data.begin()); + CHECK(result.second != data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, CK10); + + result = data.equal_range(CK11); + CHECK(result.first != data.begin()); + CHECK(result.second != data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 3); + CHECK_EQUAL(result.first->first, CK11); + + result = data.equal_range(CK12); + CHECK(result.first != data.begin()); + CHECK(result.second == data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, CK12); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range_const_using_transparent_comparator) + { + const DataNDCTransparent data(equal_data.begin(), equal_data.end()); + + ETL_OR_STD::pair result; + + result = data.equal_range(CK10); + CHECK(result.first == data.begin()); + CHECK(result.second != data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, CK10); + + result = data.equal_range(CK11); + CHECK(result.first != data.begin()); + CHECK(result.second != data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 3); + CHECK_EQUAL(result.first->first, CK11); + + result = data.equal_range(CK12); + CHECK(result.first != data.begin()); + CHECK(result.second == data.end()); + CHECK_EQUAL(std::distance(result.first, result.second), 1); + CHECK_EQUAL(result.first->first, CK12); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_equal) { diff --git a/test/test_unordered_multiset.cpp b/test/test_unordered_multiset.cpp index 843a490e..49b8f59f 100644 --- a/test/test_unordered_multiset.cpp +++ b/test/test_unordered_multiset.cpp @@ -135,6 +135,22 @@ namespace } }; + //************************************************************************* + struct transparent_hash + { + typedef int is_transparent; + + size_t operator ()(const char* s) const + { + return std::accumulate(s, s + etl::strlen(s), 0); + } + + size_t operator ()(const std::string& s) const + { + return std::accumulate(s.begin(), s.end(), 0); + } + }; + SUITE(test_unordered_multiset) { static const size_t SIZE = 10; @@ -165,26 +181,49 @@ namespace typedef etl::unordered_multiset DataNDC; typedef etl::iunordered_multiset IDataNDC; - NDC N0 = NDC("FF"); - NDC N1 = NDC("FG"); - NDC N2 = NDC("FH"); - NDC N3 = NDC("FI"); - NDC N4 = NDC("FJ"); - NDC N5 = NDC("FK"); - NDC N6 = NDC("FL"); - NDC N7 = NDC("FM"); - NDC N8 = NDC("FN"); - NDC N9 = NDC("FO"); - NDC N10 = NDC("FP"); - NDC N11 = NDC("FQ"); - NDC N12 = NDC("FR"); - NDC N13 = NDC("FS"); - NDC N14 = NDC("FT"); - NDC N15 = NDC("FU"); - NDC N16 = NDC("FV"); - NDC N17 = NDC("FW"); - NDC N18 = NDC("FX"); - NDC N19 = NDC("FY"); + typedef etl::unordered_multiset> DataTransparent; + + const char* CK0 = "FF"; // 0 + const char* CK1 = "FG"; // 1 + const char* CK2 = "FH"; // 2 + const char* CK3 = "FI"; // 3 + const char* CK4 = "FJ"; // 4 + const char* CK5 = "FK"; // 5 + const char* CK6 = "FL"; // 6 + const char* CK7 = "FM"; // 7 + const char* CK8 = "FN"; // 8 + const char* CK9 = "FO"; // 9 + const char* CK10 = "FP"; // 0 + const char* CK11 = "FQ"; // 1 + const char* CK12 = "FR"; // 2 + const char* CK13 = "FS"; // 3 + const char* CK14 = "FT"; // 4 + const char* CK15 = "FU"; // 5 + const char* CK16 = "FV"; // 6 + const char* CK17 = "FW"; // 7 + const char* CK18 = "FX"; // 8 + const char* CK19 = "FY"; // 9 + + NDC N0 = NDC(CK0); + NDC N1 = NDC(CK1); + NDC N2 = NDC(CK2); + NDC N3 = NDC(CK3); + NDC N4 = NDC(CK4); + NDC N5 = NDC(CK5); + NDC N6 = NDC(CK6); + NDC N7 = NDC(CK7); + NDC N8 = NDC(CK8); + NDC N9 = NDC(CK9); + NDC N10 = NDC(CK10); + NDC N11 = NDC(CK11); + NDC N12 = NDC(CK12); + NDC N13 = NDC(CK13); + NDC N14 = NDC(CK14); + NDC N15 = NDC(CK15); + NDC N16 = NDC(CK16); + NDC N17 = NDC(CK17); + NDC N18 = NDC(CK18); + NDC N19 = NDC(CK19); std::vector initial_data; std::vector excess_data; @@ -394,6 +433,24 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range_using_transparent_comparator) + { + std::array initial = { "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH" }; + + DataTransparent data; + + data.assign(initial.begin(), initial.end()); + + DataTransparent::iterator idata; + + for (size_t i = 0UL; i < 8; ++i) + { + idata = data.find(initial[i]); + CHECK(idata != data.end()); + } + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_value) { @@ -431,6 +488,38 @@ namespace CHECK(*idata == N11); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_using_transparent_comparator) + { + DataTransparent data; + + data.insert(CK0); // Inserted + data.insert(CK2); // Inserted + data.insert(CK1); // Inserted + data.insert(CK11); // Duplicate hash. Inserted + data.insert(CK3); // Inserted + + CHECK_EQUAL(5U, data.size()); + + DataTransparent::iterator idata; + + idata = data.find(CK0); + CHECK(idata != data.end()); + CHECK(*idata == CK0); + + idata = data.find(CK1); + CHECK(idata != data.end()); + CHECK(*idata == CK1); + + idata = data.find(CK2); + CHECK(idata != data.end()); + CHECK(*idata == CK2); + + idata = data.find(CK11); + CHECK(idata != data.end()); + CHECK(*idata == CK11); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_value_excess) { @@ -453,6 +542,24 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range_using_transparent_comparator) + { + std::array initial = { "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH" }; + + DataTransparent data; + + data.insert(initial.begin(), initial.end()); + + DataTransparent::iterator idata; + + for (size_t i = 0UL; i < 8; ++i) + { + idata = data.find(initial[i]); + CHECK(idata != data.end()); + } + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_range_excess) { @@ -505,6 +612,21 @@ namespace CHECK(idata == data.end()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_key_using_transparent_comparator) + { + std::array initial = { "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH" }; + + DataTransparent data(initial.begin(), initial.end()); + + size_t count = data.erase("CC"); + + CHECK_EQUAL(1U, count); + + DataTransparent::iterator idata = data.find("CC"); + CHECK(idata == data.end()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_single_iterator) { @@ -665,6 +787,20 @@ namespace CHECK_EQUAL(0U, count); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_count_key_using_transparent_comparator) + { + std::array initial = { "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH" }; + + DataTransparent data(initial.begin(), initial.end()); + + size_t count = data.count("CC"); + CHECK_EQUAL(1U, count); + + count = data.count("II"); + CHECK_EQUAL(0U, count); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_find_const) { diff --git a/test/test_unordered_set.cpp b/test/test_unordered_set.cpp index e8641155..4336b4a7 100644 --- a/test/test_unordered_set.cpp +++ b/test/test_unordered_set.cpp @@ -135,6 +135,22 @@ namespace } }; + //************************************************************************* + struct transparent_hash + { + typedef int is_transparent; + + size_t operator ()(const char* s) const + { + return std::accumulate(s, s + etl::strlen(s), 0); + } + + size_t operator ()(const std::string& s) const + { + return std::accumulate(s.begin(), s.end(), 0); + } + }; + //*************************************************************************** SUITE(test_unordered_set) { @@ -165,27 +181,49 @@ namespace typedef etl::unordered_set DataDC; typedef etl::unordered_set DataNDC; typedef etl::iunordered_set IDataNDC; + typedef etl::unordered_set> DataTransparent; - NDC N0 = NDC("FF"); - NDC N1 = NDC("FG"); - NDC N2 = NDC("FH"); - NDC N3 = NDC("FI"); - NDC N4 = NDC("FJ"); - NDC N5 = NDC("FK"); - NDC N6 = NDC("FL"); - NDC N7 = NDC("FM"); - NDC N8 = NDC("FN"); - NDC N9 = NDC("FO"); - NDC N10 = NDC("FP"); - NDC N11 = NDC("FQ"); - NDC N12 = NDC("FR"); - NDC N13 = NDC("FS"); - NDC N14 = NDC("FT"); - NDC N15 = NDC("FU"); - NDC N16 = NDC("FV"); - NDC N17 = NDC("FW"); - NDC N18 = NDC("FX"); - NDC N19 = NDC("FY"); + const char* CK0 = "FF"; // 0 + const char* CK1 = "FG"; // 1 + const char* CK2 = "FH"; // 2 + const char* CK3 = "FI"; // 3 + const char* CK4 = "FJ"; // 4 + const char* CK5 = "FK"; // 5 + const char* CK6 = "FL"; // 6 + const char* CK7 = "FM"; // 7 + const char* CK8 = "FN"; // 8 + const char* CK9 = "FO"; // 9 + const char* CK10 = "FP"; // 0 + const char* CK11 = "FQ"; // 1 + const char* CK12 = "FR"; // 2 + const char* CK13 = "FS"; // 3 + const char* CK14 = "FT"; // 4 + const char* CK15 = "FU"; // 5 + const char* CK16 = "FV"; // 6 + const char* CK17 = "FW"; // 7 + const char* CK18 = "FX"; // 8 + const char* CK19 = "FY"; // 9 + + NDC N0 = NDC(CK0); + NDC N1 = NDC(CK1); + NDC N2 = NDC(CK2); + NDC N3 = NDC(CK3); + NDC N4 = NDC(CK4); + NDC N5 = NDC(CK5); + NDC N6 = NDC(CK6); + NDC N7 = NDC(CK7); + NDC N8 = NDC(CK8); + NDC N9 = NDC(CK9); + NDC N10 = NDC(CK10); + NDC N11 = NDC(CK11); + NDC N12 = NDC(CK12); + NDC N13 = NDC(CK13); + NDC N14 = NDC(CK14); + NDC N15 = NDC(CK15); + NDC N16 = NDC(CK16); + NDC N17 = NDC(CK17); + NDC N18 = NDC(CK18); + NDC N19 = NDC(CK19); std::vector initial_data; std::vector excess_data; @@ -378,6 +416,24 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range_using_transparent_comparator) + { + std::array initial = { "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH" }; + + DataTransparent data; + + data.assign(initial.begin(), initial.end()); + + DataTransparent::iterator idata; + + for (size_t i = 0UL; i < 8; ++i) + { + idata = data.find(initial[i]); + CHECK(idata != data.end()); + } + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_value) { @@ -409,6 +465,38 @@ namespace CHECK(idata != data.end()); CHECK(*idata == N11); } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_using_transparent_comparator) + { + DataTransparent data; + + data.insert(CK0); // Inserted + data.insert(CK2); // Inserted + data.insert(CK1); // Inserted + data.insert(CK11); // Duplicate hash. Inserted + data.insert(CK3); // Inserted + + CHECK_EQUAL(5U, data.size()); + + DataTransparent::iterator idata; + + idata = data.find(CK0); + CHECK(idata != data.end()); + CHECK(*idata == CK0); + + idata = data.find(CK1); + CHECK(idata != data.end()); + CHECK(*idata == CK1); + + idata = data.find(CK2); + CHECK(idata != data.end()); + CHECK(*idata == CK2); + + idata = data.find(CK11); + CHECK(idata != data.end()); + CHECK(*idata == CK11); + } //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_value_excess) @@ -432,6 +520,24 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range_using_transparent_comparator) + { + std::array initial = { "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH" }; + + DataTransparent data; + + data.insert(initial.begin(), initial.end()); + + DataTransparent::iterator idata; + + for (size_t i = 0UL; i < 8; ++i) + { + idata = data.find(initial[i]); + CHECK(idata != data.end()); + } + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_range_excess) { @@ -508,6 +614,21 @@ namespace CHECK(idata == data.end()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_key_using_transparent_comparator) + { + std::array initial = { "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH" }; + + DataTransparent data(initial.begin(), initial.end()); + + size_t count = data.erase("CC"); + + CHECK_EQUAL(1U, count); + + DataTransparent::iterator idata = data.find("CC"); + CHECK(idata == data.end()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_single_iterator) { @@ -665,6 +786,20 @@ namespace CHECK_EQUAL(0U, count); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_count_key_using_transparent_comparator) + { + std::array initial = { "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH" }; + + DataTransparent data(initial.begin(), initial.end()); + + size_t count = data.count("CC"); + CHECK_EQUAL(1U, count); + + count = data.count("II"); + CHECK_EQUAL(0U, count); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_equal) {