#957 Support heterogenous lookup for maps

This commit is contained in:
John Wellbelove 2024-11-10 11:50:33 +00:00
parent d0a9d696fe
commit 4a1712b733
8 changed files with 1759 additions and 101 deletions

View File

@ -52,6 +52,8 @@ SOFTWARE.
#include "placement_new.h"
#include "initializer_list.h"
#include "private/comparator_is_transparent.h"
#include <stddef.h>
//*****************************************************************************
@ -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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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<const_iterator, const_iterator>(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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
ETL_OR_STD::pair<iterator, iterator> equal_range(const K& key)
{
iterator f = find(key);
iterator l = f;
if (l != end())
{
++l;
}
return ETL_OR_STD::pair<iterator, iterator>(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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const K& key) const
{
const_iterator f = find(key);
const_iterator l = f;
if (l != end())
{
++l;
}
return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
}
#endif
//*************************************************************************
/// Gets the size of the unordered_map.
//*************************************************************************

View File

@ -52,6 +52,8 @@ SOFTWARE.
#include "placement_new.h"
#include "initializer_list.h"
#include "private/comparator_is_transparent.h"
#include <stddef.h>
//*****************************************************************************
@ -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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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<const_iterator, const_iterator>(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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
ETL_OR_STD::pair<iterator, iterator> 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<iterator, iterator>(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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
ETL_OR_STD::pair<const_iterator, const_iterator> 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<const_iterator, const_iterator>(f, l);
}
//*************************************************************************
/// Gets the size of the unordered_multimap.
//*************************************************************************

View File

@ -51,6 +51,8 @@ SOFTWARE.
#include "placement_new.h"
#include "initializer_list.h"
#include "private/comparator_is_transparent.h"
#include <stddef.h>
//*****************************************************************************
@ -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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
ETL_OR_STD::pair<iterator, bool> insert(const K& key)
{
ETL_OR_STD::pair<iterator, bool> 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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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

View File

@ -52,6 +52,8 @@ SOFTWARE.
#include "placement_new.h"
#include "initializer_list.h"
#include "private/comparator_is_transparent.h"
#include <stddef.h>
//*****************************************************************************
@ -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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
ETL_OR_STD::pair<iterator, bool> insert(const K& key)
{
ETL_OR_STD::pair<iterator, bool> 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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::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<const_iterator, const_iterator>(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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
ETL_OR_STD::pair<iterator, iterator> equal_range(const K& key)
{
iterator f = find(key);
iterator l = f;
if (l != end())
{
++l;
}
return ETL_OR_STD::pair<iterator, iterator>(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 <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const K& key) const
{
const_iterator f = find(key);
const_iterator l = f;
if (l != end())
{
++l;
}
return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
}
//*************************************************************************
/// Gets the size of the unordered_set.
//*************************************************************************

View File

@ -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<std::string> DC;
typedef TestDataNDC<std::string> NDC;
@ -204,17 +223,19 @@ namespace
typedef etl::unordered_map<std::string, DC, SIZE, SIZE / 2, simple_hash> DataDC;
typedef etl::unordered_map<std::string, NDC, SIZE, SIZE / 2, simple_hash> DataNDC;
typedef etl::iunordered_map<std::string, NDC, simple_hash> IDataNDC;
typedef etl::unordered_map<std::string, NDC, SIZE, SIZE / 2, transparent_hash, etl::equal_to<>> DataNDCTransparent;
typedef etl::unordered_map<std::string, DC, SIZE, SIZE / 2, transparent_hash, etl::equal_to<>> 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<DataNDCTransparent::iterator, DataNDCTransparent::iterator> 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<DataNDCTransparent::const_iterator, DataNDCTransparent::const_iterator> 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)
{

View File

@ -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<std::string> DC;
typedef TestDataNDC<std::string> NDC;
@ -175,6 +194,8 @@ namespace
typedef etl::unordered_multimap<std::string, DC, SIZE, SIZE / 2, simple_hash> DataDC;
typedef etl::unordered_multimap<std::string, NDC, SIZE, SIZE / 2, simple_hash> DataNDC;
typedef etl::iunordered_multimap<std::string, NDC, simple_hash> IDataNDC;
typedef etl::unordered_multimap<std::string, NDC, SIZE, SIZE / 2, transparent_hash, etl::equal_to<>> DataNDCTransparent;
typedef etl::unordered_multimap<std::string, DC, SIZE, SIZE / 2, transparent_hash, etl::equal_to<>> DataDCTransparent;
using ItemM = TestDataM<int>;
using DataM = etl::unordered_multimap<std::string, ItemM, SIZE, SIZE, std::hash<std::string>>;
@ -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<DataNDCTransparent::iterator, DataNDCTransparent::iterator> 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<DataNDCTransparent::const_iterator, DataNDCTransparent::const_iterator> 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)
{

View File

@ -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<NDC, SIZE, SIZE / 2, simple_hash> DataNDC;
typedef etl::iunordered_multiset<NDC, simple_hash> 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<std::string, SIZE, SIZE / 2, transparent_hash, etl::equal_to<>> 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<NDC> initial_data;
std::vector<NDC> excess_data;
@ -394,6 +433,24 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_assign_range_using_transparent_comparator)
{
std::array<const char*, 8> 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<const char*, 8> 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<std::string, 8> 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<std::string, 8> 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)
{

View File

@ -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<DC, SIZE, SIZE / 2, simple_hash> DataDC;
typedef etl::unordered_set<NDC, SIZE, SIZE / 2, simple_hash> DataNDC;
typedef etl::iunordered_set<NDC, simple_hash> IDataNDC;
typedef etl::unordered_set<std::string, SIZE, SIZE / 2, transparent_hash, etl::equal_to<>> 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<NDC> initial_data;
std::vector<NDC> excess_data;
@ -378,6 +416,24 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_assign_range_using_transparent_comparator)
{
std::array<const char*, 8> 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<const char*, 8> 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<std::string, 8> 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<std::string, 8> 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)
{