insert(P &&value)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(value.first) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == value.first)
return std::make_pair(iterator(buckets, buckets.begin() + index, it), false);
}
bucket.push_back(std::forward(value));
++elementsCount;
if (elementsCount > max_load_factor() * buckets.size())
{
rehash(buckets.size() * 2);
index = hashFunction(value.first) % buckets.size();
}
return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true);
}
iterator insert(const_iterator hint, const value_type &value)
{
fixme("hint %p", &hint);
return insert(value).first;
}
iterator insert(const_iterator hint, value_type &&value)
{
fixme("hint %p", &hint);
return insert(std::move(value)).first;
}
template
iterator insert(const_iterator hint, P &&value)
{
fixme("hint %p", &hint);
return insert(std::forward(value)).first;
}
template
void insert(InputIt first, InputIt last)
{
for (auto it = first; it != last; ++it)
insert(*it);
}
void insert(std::initializer_list ilist)
{
foreach (const auto &value in ilist)
insert(value);
}
insert_return_type insert(node_type &&nh)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(nh.front().first) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == nh.front().first)
return {iterator(buckets, buckets.begin() + index, it), false, std::move(nh)};
}
bucket.splice(bucket.end(), nh);
++elementsCount;
if (elementsCount > max_load_factor() * buckets.size())
{
rehash(buckets.size() * 2);
index = hashFunction(nh.front().first) % buckets.size();
}
return {iterator(buckets, buckets.begin() + index, --bucket.end()), true, std::move(nh)};
}
iterator insert(const_iterator hint, node_type &&nh)
{
fixme("hint %p", &hint);
return insert(std::move(nh)).position;
}
template
std::pair insert_or_assign(const Key &k, M &&obj)
{
if (auto it = find(k); it != end())
{
it->second = std::forward(obj);
return std::make_pair(it, false);
}
if (buckets.empty())
rehash(16);
size_type index = hashFunction(k) % buckets.size();
auto &bucket = buckets[index];
bucket.push_back(std::make_pair(k, std::forward(obj)));
++elementsCount;
if (elementsCount > max_load_factor() * buckets.size())
{
rehash(buckets.size() * 2);
index = hashFunction(k) % buckets.size();
}
return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true);
}
template
std::pair insert_or_assign(Key &&k, M &&obj)
{
if (auto it = find(k); it != end())
{
it->second = std::forward(obj);
return std::make_pair(it, false);
}
if (buckets.empty())
rehash(16);
size_type index = hashFunction(k) % buckets.size();
auto &bucket = buckets[index];
bucket.push_back(std::make_pair(std::move(k), std::forward(obj)));
++elementsCount;
if (elementsCount > max_load_factor() * buckets.size())
{
rehash(buckets.size() * 2);
index = hashFunction(k) % buckets.size();
}
return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true);
}
template
iterator insert_or_assign(const_iterator hint, const Key &k, M &&obj)
{
fixme("hint %p", &hint);
return insert_or_assign(k, std::forward(obj)).first;
}
template
iterator insert_or_assign(const_iterator hint, Key &&k, M &&obj)
{
fixme("hint %p", &hint);
return insert_or_assign(std::move(k), std::forward(obj)).first;
}
template
__deprecated_msg("Function not implemented") std::pair emplace(Args &&...args)
{
assert(!"std::tuple : Function not implemented");
// size_type index = hashFunction(std::get<0>(std::forward_as_tuple(args...))) % buckets.size();
// auto &bucket = buckets[index];
// for (auto it = bucket.begin(); it != bucket.end(); ++it)
// {
// if (it->first == std::get<0>(std::forward_as_tuple(args...)))
// return std::make_pair(iterator(buckets, buckets.begin() + index, it), false);
// }
// bucket.push_back(std::make_pair(std::get<0>(std::forward_as_tuple(args...)), std::get<1>(std::forward_as_tuple(args...))));
// ++elementsCount;
// if (elementsCount > max_load_factor() * buckets.size())
// {
// rehash(buckets.size() * 2);
// index = hashFunction(std::get<0>(std::forward_as_tuple(args...))) % buckets.size();
// }
// return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true);
}
template
__deprecated_msg("Function not implemented") iterator emplace_hint(const_iterator hint, Args &&...args)
{
fixme("hint %p", &hint);
return emplace(std::forward(args)...).first;
}
template
__deprecated_msg("Function not implemented") std::pair try_emplace(const Key &k, Args &&...args)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") std::pair try_emplace(Key &&k, Args &&...args)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") std::pair try_emplace(K &&k, Args &&...args)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") iterator try_emplace(const_iterator hint, const Key &k, Args &&...args)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") iterator try_emplace(const_iterator hint, Key &&k, Args &&...args)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") iterator try_emplace(const_iterator hint, K &&k, Args &&...args)
{
assert(!"Function not implemented");
}
iterator erase(iterator pos)
{
auto &bucket = *pos.bucket;
auto it = bucket.erase(pos.element);
--elementsCount;
return iterator(buckets, pos.bucket, it);
}
__deprecated_msg("Function not implemented") iterator erase(const_iterator pos)
{
assert(!"Function not implemented");
// auto &bucket = *pos.bucket;
// auto it = bucket.erase(pos.element);
// --elementsCount;
// return iterator(pos.bucket, it);
}
__deprecated_msg("Function not implemented") iterator erase(const_iterator first, const_iterator last)
{
assert(!"Function not implemented");
// for (auto it = first; it != last; ++it)
// erase(it);
// return iterator(last.bucket, last.element);
}
size_type erase(const Key &key)
{
if (buckets.empty())
return 0;
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
{
bucket.erase(it);
--elementsCount;
return 1;
}
}
return 0;
}
void swap(unordered_map &other) /* noexcept(std::allocator_traits::is_always_equal::value && std::is_nothrow_swappable::value && std::is_nothrow_swappable::value) */
{
std::swap(buckets, other.buckets);
}
__deprecated_msg("Function not implemented") node_type extract(const_iterator position)
{
assert(!"Function not implemented");
}
__deprecated_msg("Function not implemented") node_type extract(const Key &k)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") void merge(std::unordered_map &source)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") void merge(std::unordered_map &&source)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") void merge(std::unordered_multimap &source)
{
assert(!"Function not implemented");
}
template
__deprecated_msg("Function not implemented") void merge(std::unordered_multimap &&source)
{
assert(!"Function not implemented");
}
#pragma endregion Modifiers
#pragma region Lookup
T &at(const Key &key)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return it->second;
}
throw std::out_of_range("Key not found");
}
const T &at(const Key &key) const
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return it->second;
}
throw std::out_of_range("Key not found");
}
T &operator[](const Key &key)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return it->second;
}
bucket.push_back(std::make_pair(key, T()));
++elementsCount;
if (elementsCount > max_load_factor() * buckets.size())
{
rehash(buckets.size() * 2);
index = hashFunction(key) % buckets.size();
}
return bucket.back().second;
}
T &operator[](Key &&key)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return it->second;
}
bucket.push_back(std::make_pair(std::move(key), T()));
++elementsCount;
if (elementsCount > max_load_factor() * buckets.size())
{
rehash(buckets.size() * 2);
index = hashFunction(key) % buckets.size();
}
return bucket.back().second;
}
size_type count(const Key &key) const
{
if (buckets.empty())
return 0;
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return 1;
}
return 0;
}
template
size_type count(const K &x) const
{
if (buckets.empty())
return 0;
size_type index = hashFunction(x) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == x)
return 1;
}
return 0;
}
iterator find(const Key &key)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return iterator(buckets, buckets.begin() + index, it);
}
return end();
}
const_iterator find(const Key &key) const
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return const_iterator(buckets, buckets.begin() + index, it);
}
return end();
}
template
iterator find(const K &x)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(x) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == (Key)x)
return iterator(buckets, buckets.begin() + index, it);
}
return end();
}
template
const_iterator find(const K &x) const
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(x) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == x)
return const_iterator(buckets, buckets.begin() + index, it);
}
return end();
}
bool contains(const Key &key) const
{
if (buckets.empty())
return false;
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return true;
}
return false;
}
template
bool contains(const K &x) const
{
if (buckets.empty())
return false;
size_type index = hashFunction(x) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == x)
return true;
}
return false;
}
std::pair equal_range(const Key &key)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return std::make_pair(iterator(buckets, buckets.begin() + index, it), iterator(buckets, buckets.begin() + index, it));
}
return std::make_pair(end(), end());
}
std::pair equal_range(const Key &key) const
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(key) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == key)
return std::make_pair(const_iterator(buckets, buckets.begin() + index, it), const_iterator(buckets, buckets.begin() + index, it));
}
return std::make_pair(end(), end());
}
template
std::pair equal_range(const K &x)
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(x) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == x)
return std::make_pair(iterator(buckets, buckets.begin() + index, it), iterator(buckets, buckets.begin() + index, it));
}
return std::make_pair(end(), end());
}
template
std::pair equal_range(const K &x) const
{
if (buckets.empty())
rehash(16);
size_type index = hashFunction(x) % buckets.size();
auto &bucket = buckets[index];
for (auto it = bucket.begin(); it != bucket.end(); ++it)
{
if (it->first == x)
return std::make_pair(const_iterator(buckets, buckets.begin() + index, it), const_iterator(buckets, buckets.begin() + index, it));
}
return std::make_pair(end(), end());
}
#pragma endregion Lookup
#pragma region Bucket Interface
local_iterator begin(size_type n)
{
return buckets[n].begin();
}
const_local_iterator begin(size_type n) const
{
return buckets[n].begin();
}
const_local_iterator cbegin(size_type n) const
{
return buckets[n].begin();
}
local_iterator end(size_type n)
{
return buckets[n].end();
}
const_local_iterator end(size_type n) const
{
return buckets[n].end();
}
const_local_iterator cend(size_type n) const
{
return buckets[n].end();
}
size_type bucket_count() const
{
return buckets.size();
}
size_type max_bucket_count() const
{
return buckets.max_size();
}
size_type bucket_size(size_type n) const
{
if (n >= buckets.size())
return 0;
return buckets[n].size();
}
size_type bucket(const Key &key) const
{
assert(!buckets.empty());
return hashFunction(key) % buckets.size();
}
#pragma endregion Bucket Interface
#pragma region Hash Policy
float load_factor() const
{
return static_cast(size()) / static_cast(bucket_count());
}
float max_load_factor() const
{
return maxLoadFactor;
}
void max_load_factor(float ml)
{
maxLoadFactor = ml;
}
void rehash(size_type count)
{
debug("Rehashing to %d", count);
size_type currentLoadFactor = size() / max_load_factor();
if (count < currentLoadFactor)
{
debug("count %d => %d", count, currentLoadFactor);
count = currentLoadFactor;
}
std::vector newBuckets(count);
for (const auto &bucket : buckets)
{
for (const auto &element : bucket)
{
size_type newIndex = hashFunction(element.first) % count;
newBuckets[newIndex].push_back(element);
}
}
buckets = std::move(newBuckets);
}
void reserve(size_type count)
{
rehash(std::ceil(count / max_load_factor()));
}
#pragma endregion Hash Policy
#pragma region Observers
hasher hash_function() const
{
return hashFunction;
}
key_equal key_eq() const
{
return key_equal();
}
#pragma endregion Observers
};
template
bool operator==(const std::unordered_map &lhs,
const std::unordered_map &rhs)
{
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
}