mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Permit non-default-constructable hashes and key-equals (#583)
Co-authored-by: Jesse <jli@planarmotor.com>
This commit is contained in:
parent
868329f9e4
commit
aab900f002
@ -792,7 +792,7 @@ namespace etl
|
||||
while (inode != bucket.end())
|
||||
{
|
||||
// Do we already have this key?
|
||||
if (inode->key_value_pair.first == key)
|
||||
if (key_equal_function(inode->key_value_pair.first, key))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -851,8 +851,8 @@ namespace etl
|
||||
::new (&node.key_value_pair) value_type(etl::move(key_value_pair));
|
||||
ETL_INCREMENT_DEBUG_COUNT
|
||||
|
||||
// Just add the pointer to the bucket;
|
||||
bucket.insert_after(bucket.before_begin(), node);
|
||||
// Just add the pointer to the bucket;
|
||||
bucket.insert_after(bucket.before_begin(), node);
|
||||
|
||||
adjust_first_last_markers_after_insert(pbucket);
|
||||
|
||||
@ -868,7 +868,7 @@ namespace etl
|
||||
while (inode != bucket.end())
|
||||
{
|
||||
// Do we already have this key?
|
||||
if (inode->key_value_pair.first == key)
|
||||
if (key_equal_function(inode->key_value_pair.first, key))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -885,8 +885,8 @@ namespace etl
|
||||
::new (&node.key_value_pair) value_type(etl::move(key_value_pair));
|
||||
ETL_INCREMENT_DEBUG_COUNT
|
||||
|
||||
// Add the node to the end of the bucket;
|
||||
bucket.insert_after(inode_previous, node);
|
||||
// Add the node to the end of the bucket;
|
||||
bucket.insert_after(inode_previous, node);
|
||||
adjust_first_last_markers_after_insert(&bucket);
|
||||
++inode_previous;
|
||||
|
||||
@ -1278,6 +1278,8 @@ namespace etl
|
||||
// Skip if doing self assignment
|
||||
if (this != &rhs)
|
||||
{
|
||||
key_hash_function = rhs.hash_function();
|
||||
key_equal_function = rhs.key_eq();
|
||||
assign(rhs.cbegin(), rhs.cend());
|
||||
}
|
||||
|
||||
@ -1292,6 +1294,8 @@ namespace etl
|
||||
// Skip if doing self assignment
|
||||
if (this != &rhs)
|
||||
{
|
||||
key_hash_function = rhs.hash_function();
|
||||
key_equal_function = rhs.key_eq();
|
||||
this->move(rhs.begin(), rhs.end());
|
||||
}
|
||||
|
||||
@ -1304,12 +1308,14 @@ namespace etl
|
||||
//*********************************************************************
|
||||
/// Constructor.
|
||||
//*********************************************************************
|
||||
iunordered_map(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_)
|
||||
iunordered_map(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_, hasher key_hash_function_, key_equal key_equal_function_)
|
||||
: pnodepool(&node_pool_)
|
||||
, pbuckets(pbuckets_)
|
||||
, number_of_buckets(number_of_buckets_)
|
||||
, first(pbuckets)
|
||||
, last(pbuckets)
|
||||
, key_hash_function(key_hash_function_)
|
||||
, key_equal_function(key_equal_function_)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1528,8 +1534,8 @@ namespace etl
|
||||
//*************************************************************************
|
||||
/// Default constructor.
|
||||
//*************************************************************************
|
||||
unordered_map()
|
||||
: base(node_pool, buckets, MAX_BUCKETS_)
|
||||
unordered_map(const THash& hash = THash(), const TKeyEqual equal = TKeyEqual())
|
||||
: base(node_pool, buckets, MAX_BUCKETS_, hash, equal)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1537,7 +1543,7 @@ namespace etl
|
||||
/// Copy constructor.
|
||||
//*************************************************************************
|
||||
unordered_map(const unordered_map& other)
|
||||
: base(node_pool, buckets, MAX_BUCKETS_)
|
||||
: base(node_pool, buckets, MAX_BUCKETS_, other.hash_function(), other.key_eq())
|
||||
{
|
||||
base::assign(other.cbegin(), other.cend());
|
||||
}
|
||||
@ -1547,7 +1553,7 @@ namespace etl
|
||||
/// Move constructor.
|
||||
//*************************************************************************
|
||||
unordered_map(unordered_map&& other)
|
||||
: base(node_pool, buckets, MAX_BUCKETS_)
|
||||
: base(node_pool, buckets, MAX_BUCKETS_, other.hash_function(), other.key_eq())
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
@ -1564,7 +1570,7 @@ namespace etl
|
||||
//*************************************************************************
|
||||
template <typename TIterator>
|
||||
unordered_map(TIterator first_, TIterator last_)
|
||||
: base(node_pool, buckets, MAX_BUCKETS_)
|
||||
: unordered_map()
|
||||
{
|
||||
base::assign(first_, last_);
|
||||
}
|
||||
@ -1574,7 +1580,7 @@ namespace etl
|
||||
/// Construct from initializer_list.
|
||||
//*************************************************************************
|
||||
unordered_map(std::initializer_list<ETL_OR_STD::pair<TKey, TValue>> init)
|
||||
: base(node_pool, buckets, MAX_BUCKETS_)
|
||||
: unordered_map()
|
||||
{
|
||||
base::assign(init.begin(), init.end());
|
||||
}
|
||||
@ -1593,12 +1599,7 @@ namespace etl
|
||||
//*************************************************************************
|
||||
unordered_map& operator = (const unordered_map& rhs)
|
||||
{
|
||||
// Skip if doing self assignment
|
||||
if (this != &rhs)
|
||||
{
|
||||
base::assign(rhs.cbegin(), rhs.cend());
|
||||
}
|
||||
|
||||
base::operator=(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1608,13 +1609,7 @@ namespace etl
|
||||
//*************************************************************************
|
||||
unordered_map& operator = (unordered_map&& rhs)
|
||||
{
|
||||
// Skip if doing self assignment
|
||||
if (this != &rhs)
|
||||
{
|
||||
base::clear();
|
||||
base::move(rhs.begin(), rhs.end());
|
||||
}
|
||||
|
||||
base::operator=(etl::move(rhs));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -56,6 +56,61 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
// Non-default-constructible hasher
|
||||
struct ndc_hash
|
||||
{
|
||||
int id;
|
||||
ndc_hash(int id_) : id(id_){}
|
||||
|
||||
size_t operator()(size_t val) const
|
||||
{
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
// Non-default-constructible equality checker
|
||||
struct ndc_key_eq
|
||||
{
|
||||
int id;
|
||||
ndc_key_eq(int id_) : id(id_){}
|
||||
|
||||
bool operator()(size_t val1, size_t val2) const
|
||||
{
|
||||
return val1 == val2;
|
||||
}
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
// Hasher whose hash behaviour depends on provided data.
|
||||
struct parameterized_hash
|
||||
{
|
||||
size_t modulus;
|
||||
|
||||
parameterized_hash(size_t modulus_ = 2) : modulus(modulus_){}
|
||||
|
||||
size_t operator()(size_t val) const
|
||||
{
|
||||
return val % modulus;
|
||||
}
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
// Equality checker whose behaviour depends on provided data.
|
||||
struct parameterized_equal
|
||||
{
|
||||
size_t modulus;
|
||||
|
||||
// Hasher whose hash behaviour depends on provided data.
|
||||
parameterized_equal(size_t modulus_ = 2) : modulus(modulus_){}
|
||||
|
||||
bool operator()(size_t lhs, size_t rhs) const
|
||||
{
|
||||
return (lhs % modulus) == (rhs % modulus);
|
||||
}
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
template <typename T1, typename T2>
|
||||
bool Check_Equal(T1 begin1, T1 end1, T2 begin2)
|
||||
@ -350,9 +405,9 @@ namespace
|
||||
DataNDC data(initial_data.begin(), initial_data.end());
|
||||
DataNDC other_data(data);
|
||||
|
||||
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
|
||||
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
|
||||
other_data = other_data;
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
|
||||
bool isEqual = std::equal(data.begin(),
|
||||
data.end(),
|
||||
@ -894,5 +949,68 @@ namespace
|
||||
CHECK_EQUAL('c', map[2]);
|
||||
CHECK_EQUAL('d', map[3]);
|
||||
}
|
||||
|
||||
TEST(test_ndc_hasher_and_key_eq) {
|
||||
typedef etl::unordered_map<size_t, int, 10, 10, ndc_hash, ndc_key_eq> Map;
|
||||
ndc_hash hasher1(1);
|
||||
ndc_hash hasher2(2);
|
||||
ndc_key_eq eq1(1);
|
||||
ndc_key_eq eq2(2);
|
||||
|
||||
Map map1(hasher1, eq1);
|
||||
CHECK_EQUAL(map1.hash_function().id, 1);
|
||||
CHECK_EQUAL(map1.key_eq().id, 1);
|
||||
|
||||
Map map2(hasher2, eq2);
|
||||
|
||||
Map copyConstructed(map1);
|
||||
CHECK_EQUAL(copyConstructed.hash_function().id, 1);
|
||||
CHECK_EQUAL(copyConstructed.key_eq().id, 1);
|
||||
|
||||
Map copyAssigned(hasher2, eq2);
|
||||
CHECK_EQUAL(copyAssigned.hash_function().id, 2);
|
||||
CHECK_EQUAL(copyAssigned.key_eq().id, 2);
|
||||
copyAssigned = map1;
|
||||
CHECK_EQUAL(copyAssigned.hash_function().id, 1);
|
||||
CHECK_EQUAL(copyAssigned.key_eq().id, 1);
|
||||
|
||||
Map moveConstructed = std::move(map1);
|
||||
CHECK_EQUAL(moveConstructed.hash_function().id, 1);
|
||||
CHECK_EQUAL(moveConstructed.key_eq().id, 1);
|
||||
|
||||
Map moveAssigned(hasher1, eq1);
|
||||
CHECK_EQUAL(moveAssigned.hash_function().id, 1);
|
||||
CHECK_EQUAL(moveAssigned.key_eq().id, 1);
|
||||
moveAssigned = std::move(map2);
|
||||
CHECK_EQUAL(moveAssigned.hash_function().id, 2);
|
||||
CHECK_EQUAL(moveAssigned.key_eq().id, 2);
|
||||
|
||||
// make sure that map operations still work
|
||||
moveAssigned[5] = 7;
|
||||
CHECK_EQUAL(7, moveAssigned[5]);
|
||||
}
|
||||
|
||||
TEST(test_parameterized_eq) {
|
||||
constexpr std::size_t MODULO = 4;
|
||||
parameterized_hash hash{MODULO};
|
||||
parameterized_equal eq{MODULO};
|
||||
// values are equal modulo 4
|
||||
etl::unordered_map<std::size_t, int, 10, 10, parameterized_hash, parameterized_equal> map;
|
||||
map.insert(etl::make_pair(2, 3));
|
||||
|
||||
const auto& constmap = map;
|
||||
|
||||
CHECK_EQUAL(map[10], 3);
|
||||
CHECK_EQUAL(map.at(10), 3);
|
||||
CHECK_EQUAL(constmap.at(10), 3);
|
||||
|
||||
CHECK_FALSE(map.insert(etl::make_pair(6, 7)).second);
|
||||
|
||||
CHECK(map.find(14) != map.end());
|
||||
CHECK(constmap.find(14) != constmap.end());
|
||||
|
||||
map.erase(2);
|
||||
CHECK(map.find(6) == map.end());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user