[med-svn] [Git][med-team/hopscotch-map][upstream] New upstream version 2.3.0
Michael R. Crusoe
gitlab at salsa.debian.org
Mon Jun 29 12:29:10 BST 2020
Michael R. Crusoe pushed to branch upstream at Debian Med / hopscotch-map
Commits:
78ead7b6 by Michael R. Crusoe at 2020-06-29T13:19:37+02:00
New upstream version 2.3.0
- - - - -
17 changed files:
- .codecov.yml
- .travis.yml
- CMakeLists.txt
- LICENSE
- README.md
- include/tsl/bhopscotch_map.h
- include/tsl/bhopscotch_set.h
- include/tsl/hopscotch_growth_policy.h
- include/tsl/hopscotch_hash.h
- include/tsl/hopscotch_map.h
- include/tsl/hopscotch_set.h
- tests/custom_allocator_tests.cpp
- tests/hopscotch_map_tests.cpp
- tests/hopscotch_set_tests.cpp
- tests/main.cpp
- tests/policy_tests.cpp
- tests/utils.h
Changes:
=====================================
.codecov.yml
=====================================
@@ -1 +1,5 @@
comment: off
+coverage:
+ status:
+ project: off
+ patch: off
=====================================
.travis.yml
=====================================
@@ -29,7 +29,6 @@ matrix:
dist: xenial
env:
- CBUILD_TYPE="Release"
- - TYPE="sanitize"
- CXXFLAGS="-fsanitize=address,undefined"
- os: linux
@@ -37,6 +36,12 @@ matrix:
env:
- TYPE="coverage"
- CXXFLAGS="--coverage"
+
+ - os: linux
+ compiler: gcc
+ env:
+ - CBUILD_TYPE="Release"
+ - CXXFLAGS="-fno-exceptions"
addons:
apt:
=====================================
CMakeLists.txt
=====================================
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1)
include(GNUInstallDirs)
-project(tsl-hopscotch-map VERSION 2.2.1)
+project(tsl-hopscotch-map VERSION 2.3.0)
add_library(hopscotch_map INTERFACE)
# Use tsl::hopscotch_map as target, more consistent with other libraries conventions (Boost, Qt, ...)
=====================================
LICENSE
=====================================
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2016 Tessil
+Copyright (c) 2016 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
=====================================
README.md
=====================================
@@ -23,9 +23,10 @@ A **benchmark** of `tsl::hopscotch_map` against other hash maps may be found [he
- Possibility to store the hash value on insert for faster rehash and lookup if the hash or the key equal functions are expensive to compute (see the [StoreHash](https://tessil.github.io/hopscotch-map/classtsl_1_1hopscotch__map.html#details) template parameter).
- If the hash is known before a lookup, it is possible to pass it as parameter to speed-up the lookup (see `precalculated_hash` parameter in [API](https://tessil.github.io/hopscotch-map/classtsl_1_1hopscotch__map.html#a74d83c67c50bc8385bb11f78142eaa86)).
- The `tsl::bhopscotch_map` and `tsl::bhopscotch_set` provide a worst-case of O(log n) on lookups and deletions making these classes resistant to hash table Deny of Service (DoS) attacks (see [details](#deny-of-service-dos-attack) in example).
+- The library can be used with exceptions disabled (through `-fno-exceptions` option on Clang and GCC, without an `/EH` option on MSVC or simply by defining `TSL_NO_EXCEPTIONS`). `std::terminate` is used in replacement of the `throw` instruction when exceptions are disabled.
- API closely similar to `std::unordered_map` and `std::unordered_set`.
-### Differences compare to `std::unordered_map`
+### Differences compared to `std::unordered_map`
`tsl::hopscotch_map` tries to have an interface similar to `std::unordered_map`, but some differences exist.
- Iterator invalidation on insert doesn't behave in the same way. In general any operation modifying the hash table, except `erase`, invalidate all the iterators (see [API](https://tessil.github.io/hopscotch-map/classtsl_1_1hopscotch__map.html#details) for details).
- References and pointers to keys or values in the map are invalidated in the same way as iterators to these keys-values on insert.
@@ -274,7 +275,7 @@ int main() {
```
#### Deny of Service (DoS) attack
-In addition to `tsl::hopscotch_map` and `tsl::hopscotch_set`, the library provides two more "secure" options: `tsl::bhopscotch_map` and `tsl::bhopscotch_set` (all with their `pg` counterpars).
+In addition to `tsl::hopscotch_map` and `tsl::hopscotch_set`, the library provides two more "secure" options: `tsl::bhopscotch_map` and `tsl::bhopscotch_set` (all with their `pg` counterparts).
These two additions have a worst-case asymptotic complexity of O(log n) for lookups and deletions and an amortized worst case of O(log n) for insertions (amortized due to the possibility of rehash which would be in O(n)). Even if the hash function maps all the elements to the same bucket, the O(log n) would still hold.
=====================================
include/tsl/bhopscotch_map.h
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2017 Tessil
+ * Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -88,7 +88,7 @@ private:
return key_value.second;
}
- value_type& operator()(std::pair<Key, T>& key_value) {
+ value_type& operator()(std::pair<const Key, T>& key_value) {
return key_value.second;
}
};
@@ -359,7 +359,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash.
*/
size_type erase(const key_type& key, std::size_t precalculated_hash) {
return m_ht.erase(key, precalculated_hash);
@@ -378,7 +378,7 @@ public:
* @copydoc erase(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
@@ -396,7 +396,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
@@ -420,7 +420,7 @@ public:
* @copydoc at(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
@@ -453,7 +453,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
@@ -470,7 +470,7 @@ public:
* @copydoc count(const K& key) const
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
@@ -483,7 +483,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
@@ -507,7 +507,7 @@ public:
* @copydoc find(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
@@ -530,11 +530,42 @@ public:
+ bool contains(const Key& key) const { return m_ht.contains(key); }
+
+ /**
+ * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
+ */
+ bool contains(const Key& key, std::size_t precalculated_hash) const {
+ return m_ht.contains(key, precalculated_hash);
+ }
+
+ /**
+ * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
+ * If so, K must be hashable and comparable to Key.
+ */
+ template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
+ bool contains(const K& key) const { return m_ht.contains(key); }
+
+ /**
+ * @copydoc contains(const K& key) const
+ *
+ * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
+ */
+ template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
+ bool contains(const K& key, std::size_t precalculated_hash) const {
+ return m_ht.contains(key, precalculated_hash);
+ }
+
+
+
+
std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) {
return m_ht.equal_range(key, precalculated_hash);
@@ -562,7 +593,7 @@ public:
* @copydoc equal_range(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
=====================================
include/tsl/bhopscotch_set.h
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2017 Tessil
+ * Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -268,7 +268,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash.
*/
size_type erase(const key_type& key, std::size_t precalculated_hash) {
return m_ht.erase(key, precalculated_hash);
@@ -287,7 +287,7 @@ public:
* @copydoc erase(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
@@ -306,7 +306,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
@@ -323,7 +323,7 @@ public:
* @copydoc count(const K& key) const
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
@@ -336,7 +336,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
@@ -360,7 +360,7 @@ public:
* @copydoc find(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
@@ -377,7 +377,7 @@ public:
* @copydoc find(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
@@ -386,11 +386,42 @@ public:
+ bool contains(const Key& key) const { return m_ht.contains(key); }
+
+ /**
+ * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
+ */
+ bool contains(const Key& key, std::size_t precalculated_hash) const {
+ return m_ht.contains(key, precalculated_hash);
+ }
+
+ /**
+ * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
+ * If so, K must be hashable and comparable to Key.
+ */
+ template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
+ bool contains(const K& key) const { return m_ht.contains(key); }
+
+ /**
+ * @copydoc contains(const K& key) const
+ *
+ * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
+ */
+ template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
+ bool contains(const K& key, std::size_t precalculated_hash) const {
+ return m_ht.contains(key, precalculated_hash);
+ }
+
+
+
+
std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) {
return m_ht.equal_range(key, precalculated_hash);
@@ -418,7 +449,7 @@ public:
* @copydoc equal_range(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, class CP = Compare,
typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr>
=====================================
include/tsl/hopscotch_growth_policy.h
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2018 Tessil
+ * Copyright (c) 2018 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,12 +30,41 @@
#include <climits>
#include <cmath>
#include <cstddef>
+#include <cstdint>
#include <iterator>
#include <limits>
#include <ratio>
#include <stdexcept>
+/**
+ * Only activate tsl_hh_assert if TSL_DEBUG is defined.
+ * This way we avoid the performance hit when NDEBUG is not defined with assert as tsl_hh_assert is used a lot
+ * (people usually compile with "-O3" and not "-O3 -DNDEBUG").
+ */
+#ifdef TSL_DEBUG
+# define tsl_hh_assert(expr) assert(expr)
+#else
+# define tsl_hh_assert(expr) (static_cast<void>(0))
+#endif
+
+
+/**
+ * If exceptions are enabled, throw the exception passed in parameter, otherwise call std::terminate.
+ */
+#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (defined (_MSC_VER) && defined (_CPPUNWIND))) && !defined(TSL_NO_EXCEPTIONS)
+# define TSL_HH_THROW_OR_TERMINATE(ex, msg) throw ex(msg)
+#else
+# define TSL_HH_NO_EXCEPTIONS
+# ifdef NDEBUG
+# define TSL_HH_THROW_OR_TERMINATE(ex, msg) std::terminate()
+# else
+# include <iostream>
+# define TSL_HH_THROW_OR_TERMINATE(ex, msg) do { std::cerr << msg << std::endl; std::terminate(); } while(0)
+# endif
+#endif
+
+
namespace tsl {
namespace hh {
@@ -57,7 +86,7 @@ public:
*/
explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) {
if(min_bucket_count_in_out > max_bucket_count()) {
- throw std::length_error("The hash table exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maximum size.");
}
if(min_bucket_count_in_out > 0) {
@@ -82,7 +111,7 @@ public:
*/
std::size_t next_bucket_count() const {
if((m_mask + 1) > max_bucket_count() / GrowthFactor) {
- throw std::length_error("The hash table exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maximum size.");
}
return (m_mask + 1) * GrowthFactor;
@@ -142,7 +171,7 @@ class mod_growth_policy {
public:
explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) {
if(min_bucket_count_in_out > max_bucket_count()) {
- throw std::length_error("The hash table exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maximum size.");
}
if(min_bucket_count_in_out > 0) {
@@ -159,12 +188,12 @@ public:
std::size_t next_bucket_count() const {
if(m_mod == max_bucket_count()) {
- throw std::length_error("The hash table exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maximum size.");
}
const double next_bucket_count = std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
if(!std::isnormal(next_bucket_count)) {
- throw std::length_error("The hash table exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maximum size.");
}
if(next_bucket_count > double(max_bucket_count())) {
@@ -199,11 +228,26 @@ private:
namespace detail {
-static constexpr const std::array<std::size_t, 40> PRIMES = {{
- 1ul, 5ul, 17ul, 29ul, 37ul, 53ul, 67ul, 79ul, 97ul, 131ul, 193ul, 257ul, 389ul, 521ul, 769ul, 1031ul,
- 1543ul, 2053ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
- 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul,
- 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul
+#if SIZE_MAX >= ULLONG_MAX
+#define TSL_HH_NB_PRIMES 51
+#elif SIZE_MAX >= ULONG_MAX
+#define TSL_HH_NB_PRIMES 40
+#else
+#define TSL_HH_NB_PRIMES 23
+#endif
+
+static constexpr const std::array<std::size_t, TSL_HH_NB_PRIMES> PRIMES = {{
+ 1u, 5u, 17u, 29u, 37u, 53u, 67u, 79u, 97u, 131u, 193u, 257u, 389u, 521u, 769u, 1031u,
+ 1543u, 2053u, 3079u, 6151u, 12289u, 24593u, 49157u,
+#if SIZE_MAX >= ULONG_MAX
+ 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul,
+ 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul,
+ 3221225473ul, 4294967291ul,
+#endif
+#if SIZE_MAX >= ULLONG_MAX
+ 6442450939ull, 12884901893ull, 25769803751ull, 51539607551ull, 103079215111ull, 206158430209ull,
+ 412316860441ull, 824633720831ull, 1649267441651ull, 3298534883309ull, 6597069766657ull,
+#endif
}};
template<unsigned int IPrime>
@@ -211,11 +255,18 @@ static constexpr std::size_t mod(std::size_t hash) { return hash % PRIMES[IPrime
// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for faster modulo as the
// compiler can optimize the modulo code better with a constant known at the compilation.
-static constexpr const std::array<std::size_t(*)(std::size_t), 40> MOD_PRIME = {{
+static constexpr const std::array<std::size_t(*)(std::size_t), TSL_HH_NB_PRIMES> MOD_PRIME = {{
&mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>, &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>,
&mod<11>, &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>, &mod<18>, &mod<19>, &mod<20>,
- &mod<21>, &mod<22>, &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, &mod<29>, &mod<30>,
- &mod<31>, &mod<32>, &mod<33>, &mod<34>, &mod<35>, &mod<36>, &mod<37> , &mod<38>, &mod<39>
+ &mod<21>, &mod<22>,
+#if SIZE_MAX >= ULONG_MAX
+ &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, &mod<29>, &mod<30>, &mod<31>, &mod<32>,
+ &mod<33>, &mod<34>, &mod<35>, &mod<36>, &mod<37> , &mod<38>, &mod<39>,
+#endif
+#if SIZE_MAX >= ULLONG_MAX
+ &mod<40>, &mod<41>, &mod<42>, &mod<43>, &mod<44>, &mod<45>, &mod<46>, &mod<47>, &mod<48>, &mod<49>,
+ &mod<50>,
+#endif
}};
}
@@ -242,7 +293,7 @@ static constexpr const std::array<std::size_t(*)(std::size_t), 40> MOD_PRIME = {
* Due to the constant variable in the modulo the compiler is able to optimize the operation
* by a series of multiplications, substractions and shifts.
*
- * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) * 5' in a 64 bits environement.
+ * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) * 5' in a 64 bits environment.
*/
class prime_growth_policy {
public:
@@ -250,7 +301,7 @@ public:
auto it_prime = std::lower_bound(detail::PRIMES.begin(),
detail::PRIMES.end(), min_bucket_count_in_out);
if(it_prime == detail::PRIMES.end()) {
- throw std::length_error("The hash table exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maximum size.");
}
m_iprime = static_cast<unsigned int>(std::distance(detail::PRIMES.begin(), it_prime));
@@ -268,7 +319,7 @@ public:
std::size_t next_bucket_count() const {
if(m_iprime + 1 >= detail::PRIMES.size()) {
- throw std::length_error("The hash table exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maximum size.");
}
return detail::PRIMES[m_iprime + 1];
=====================================
include/tsl/hopscotch_hash.h
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2017 Tessil
+ * Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -44,26 +44,12 @@
#include "hopscotch_growth_policy.h"
-
#if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 9))
# define TSL_HH_NO_RANGE_ERASE_WITH_CONST_ITERATOR
#endif
-/*
- * Only activate tsl_hh_assert if TSL_DEBUG is defined.
- * This way we avoid the performance hit when NDEBUG is not defined with assert as tsl_hh_assert is used a lot
- * (people usually compile with "-O3" and not "-O3 -DNDEBUG").
- */
-#ifdef TSL_DEBUG
-# define tsl_hh_assert(expr) assert(expr)
-#else
-# define tsl_hh_assert(expr) (static_cast<void>(0))
-#endif
-
-
namespace tsl {
-
namespace detail_hopscotch_hash {
@@ -100,7 +86,21 @@ struct is_power_of_two_policy<tsl::hh::power_of_two_growth_policy<GrowthFactor>>
};
-
+template<typename T, typename U>
+static T numeric_cast(U value, const char* error_message = "numeric_cast() failed.") {
+ T ret = static_cast<T>(value);
+ if(static_cast<U>(ret) != value) {
+ TSL_HH_THROW_OR_TERMINATE(std::runtime_error, error_message);
+ }
+
+ const bool is_same_signedness = (std::is_unsigned<T>::value && std::is_unsigned<U>::value) ||
+ (std::is_signed<T>::value && std::is_signed<U>::value);
+ if(!is_same_signedness && (ret < T{}) != (value < U{})) {
+ TSL_HH_THROW_OR_TERMINATE(std::runtime_error, error_message);
+ }
+
+ return ret;
+}
/*
@@ -607,7 +607,7 @@ public:
m_nb_elements(0)
{
if(bucket_count > max_bucket_count()) {
- throw std::length_error("The map exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The map exceeds its maximum size.");
}
if(bucket_count > 0) {
@@ -623,7 +623,7 @@ public:
this->max_load_factor(max_load_factor);
- // Check in the constructor instead of outside of a function to avoi compilation issues
+ // Check in the constructor instead of outside of a function to avoid compilation issues
// when value_type is not complete.
static_assert(std::is_nothrow_move_constructible<value_type>::value ||
std::is_copy_constructible<value_type>::value,
@@ -646,7 +646,7 @@ public:
{
if(bucket_count > max_bucket_count()) {
- throw std::length_error("The map exceeds its maxmimum size.");
+ TSL_HH_THROW_OR_TERMINATE(std::length_error, "The map exceeds its maximum size.");
}
if(bucket_count > 0) {
@@ -662,7 +662,7 @@ public:
this->max_load_factor(max_load_factor);
- // Check in the constructor instead of outside of a function to avoi compilation issues
+ // Check in the constructor instead of outside of a function to avoid compilation issues
// when value_type is not complete.
static_assert(std::is_nothrow_move_constructible<value_type>::value ||
std::is_copy_constructible<value_type>::value,
@@ -678,9 +678,9 @@ public:
m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr():
m_buckets_data.data()),
m_nb_elements(other.m_nb_elements),
- m_max_load_factor(other.m_max_load_factor),
+ m_min_load_threshold_rehash(other.m_min_load_threshold_rehash),
m_max_load_threshold_rehash(other.m_max_load_threshold_rehash),
- m_min_load_threshold_rehash(other.m_min_load_threshold_rehash)
+ m_max_load_factor(other.m_max_load_factor)
{
}
@@ -700,17 +700,17 @@ public:
m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr():
m_buckets_data.data()),
m_nb_elements(other.m_nb_elements),
- m_max_load_factor(other.m_max_load_factor),
+ m_min_load_threshold_rehash(other.m_min_load_threshold_rehash),
m_max_load_threshold_rehash(other.m_max_load_threshold_rehash),
- m_min_load_threshold_rehash(other.m_min_load_threshold_rehash)
+ m_max_load_factor(other.m_max_load_factor)
{
other.GrowthPolicy::clear();
other.m_buckets_data.clear();
other.m_overflow_elements.clear();
other.m_buckets = static_empty_bucket_ptr();
other.m_nb_elements = 0;
- other.m_max_load_threshold_rehash = 0;
other.m_min_load_threshold_rehash = 0;
+ other.m_max_load_threshold_rehash = 0;
}
hopscotch_hash& operator=(const hopscotch_hash& other) {
@@ -724,9 +724,10 @@ public:
m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr():
m_buckets_data.data();
m_nb_elements = other.m_nb_elements;
- m_max_load_factor = other.m_max_load_factor;
- m_max_load_threshold_rehash = other.m_max_load_threshold_rehash;
+
m_min_load_threshold_rehash = other.m_min_load_threshold_rehash;
+ m_max_load_threshold_rehash = other.m_max_load_threshold_rehash;
+ m_max_load_factor = other.m_max_load_factor;
}
return *this;
@@ -1017,9 +1018,9 @@ public:
swap(m_overflow_elements, other.m_overflow_elements);
swap(m_buckets, other.m_buckets);
swap(m_nb_elements, other.m_nb_elements);
- swap(m_max_load_factor, other.m_max_load_factor);
- swap(m_max_load_threshold_rehash, other.m_max_load_threshold_rehash);
swap(m_min_load_threshold_rehash, other.m_min_load_threshold_rehash);
+ swap(m_max_load_threshold_rehash, other.m_max_load_threshold_rehash);
+ swap(m_max_load_factor, other.m_max_load_factor);
}
@@ -1048,7 +1049,7 @@ public:
const T* value = find_value_impl(key, hash, m_buckets + bucket_for_hash(hash));
if(value == nullptr) {
- throw std::out_of_range("Couldn't find key.");
+ TSL_HH_THROW_OR_TERMINATE(std::out_of_range, "Couldn't find key.");
}
else {
return *value;
@@ -1108,6 +1109,17 @@ public:
}
+ template<class K>
+ bool contains(const K& key) const {
+ return contains(key, hash_key(key));
+ }
+
+ template<class K>
+ bool contains(const K& key, std::size_t hash) const {
+ return count(key, hash) != 0;
+ }
+
+
template<class K>
std::pair<iterator, iterator> equal_range(const K& key) {
return equal_range(key, hash_key(key));
@@ -1170,8 +1182,8 @@ public:
void max_load_factor(float ml) {
m_max_load_factor = std::max(0.1f, std::min(ml, 0.95f));
- m_max_load_threshold_rehash = size_type(float(bucket_count())*m_max_load_factor);
m_min_load_threshold_rehash = size_type(float(bucket_count())*MIN_LOAD_FACTOR_FOR_REHASH);
+ m_max_load_threshold_rehash = size_type(float(bucket_count())*m_max_load_factor);
}
void rehash(size_type count_) {
@@ -1254,7 +1266,9 @@ private:
}
}
+#ifndef TSL_HH_NO_EXCEPTIONS
try {
+#endif
const bool use_stored_hash = USE_STORED_HASH_ON_REHASH(new_map.bucket_count());
for(auto it_bucket = m_buckets_data.begin(); it_bucket != m_buckets_data.end(); ++it_bucket) {
if(it_bucket->empty()) {
@@ -1271,10 +1285,11 @@ private:
erase_from_bucket(*it_bucket, bucket_for_hash(hash));
}
- }
+#ifndef TSL_HH_NO_EXCEPTIONS
+ }
/*
* The call to insert_value may throw an exception if an element is added to the overflow
- * list. Rollback the elements in this case.
+ * list and the memory allocation fails. Rollback the elements in this case.
*/
catch(...) {
m_overflow_elements.swap(new_map.m_overflow_elements);
@@ -1297,6 +1312,7 @@ private:
throw;
}
+#endif
new_map.swap(*this);
}
@@ -1743,6 +1759,18 @@ private:
static const std::size_t MAX_PROBES_FOR_EMPTY_BUCKET = 12*NeighborhoodSize;
static constexpr float MIN_LOAD_FACTOR_FOR_REHASH = 0.1f;
+ /**
+ * We can only use the hash on rehash if the size of the hash type is the same as the stored one or
+ * if we use a power of two modulo. In the case of the power of two modulo, we just mask
+ * the least significant bytes, we just have to check that the truncated_hash_type didn't truncated
+ * too much bytes.
+ */
+ template<class T = size_type, typename std::enable_if<std::is_same<T, truncated_hash_type>::value>::type* = nullptr>
+ static bool USE_STORED_HASH_ON_REHASH(size_type /*bucket_count*/) {
+ return StoreHash;
+ }
+
+ template<class T = size_type, typename std::enable_if<!std::is_same<T, truncated_hash_type>::value>::type* = nullptr>
static bool USE_STORED_HASH_ON_REHASH(size_type bucket_count) {
(void) bucket_count;
if(StoreHash && is_power_of_two_policy<GrowthPolicy>::value) {
@@ -1777,18 +1805,18 @@ private:
size_type m_nb_elements;
- float m_max_load_factor;
+ /**
+ * Min size of the hash table before a rehash can occurs automatically (except if m_max_load_threshold_rehash os reached).
+ * If the neighborhood of a bucket is full before the min is reacher, the elements are put into m_overflow_elements.
+ */
+ size_type m_min_load_threshold_rehash;
/**
* Max size of the hash table before a rehash occurs automatically to grow the table.
*/
size_type m_max_load_threshold_rehash;
- /**
- * Min size of the hash table before a rehash can occurs automatically (except if m_max_load_threshold_rehash os reached).
- * If the neighborhood of a bucket is full before the min is reacher, the elements are put into m_overflow_elements.
- */
- size_type m_min_load_threshold_rehash;
+ float m_max_load_factor;
};
} // end namespace detail_hopscotch_hash
=====================================
include/tsl/hopscotch_map.h
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2017 Tessil
+ * Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,7 @@ namespace tsl {
/**
* Implementation of a hash map using the hopscotch hashing algorithm.
*
- * The Key and the value T must be either nothrow move-constructible, copy-constuctible or both.
+ * The Key and the value T must be either nothrow move-constructible, copy-constructible or both.
*
* The size of the neighborhood (NeighborhoodSize) must be > 0 and <= 62 if StoreHash is false.
* When StoreHash is true, 32-bits of the hash will be stored alongside the neighborhood limiting
@@ -371,7 +371,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash.
*/
size_type erase(const key_type& key, std::size_t precalculated_hash) {
return m_ht.erase(key, precalculated_hash);
@@ -388,7 +388,7 @@ public:
* @copydoc erase(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
size_type erase(const K& key, std::size_t precalculated_hash) {
@@ -407,7 +407,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
@@ -431,7 +431,7 @@ public:
* @copydoc at(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
@@ -462,7 +462,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
size_type count(const Key& key, std::size_t precalculated_hash) const {
return m_ht.count(key, precalculated_hash);
@@ -479,7 +479,7 @@ public:
* @copydoc count(const K& key) const
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
@@ -491,7 +491,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
@@ -515,7 +515,7 @@ public:
* @copydoc find(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
@@ -530,7 +530,7 @@ public:
* @copydoc find(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
const_iterator find(const K& key, std::size_t precalculated_hash) const {
@@ -540,11 +540,42 @@ public:
+ bool contains(const Key& key) const { return m_ht.contains(key); }
+
+ /**
+ * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
+ */
+ bool contains(const Key& key, std::size_t precalculated_hash) const {
+ return m_ht.contains(key, precalculated_hash);
+ }
+
+ /**
+ * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
+ * If so, K must be hashable and comparable to Key.
+ */
+ template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
+ bool contains(const K& key) const { return m_ht.contains(key); }
+
+ /**
+ * @copydoc contains(const K& key) const
+ *
+ * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
+ */
+ template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
+ bool contains(const K& key, std::size_t precalculated_hash) const {
+ return m_ht.contains(key, precalculated_hash);
+ }
+
+
+
+
std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) {
return m_ht.equal_range(key, precalculated_hash);
@@ -571,7 +602,7 @@ public:
* @copydoc equal_range(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) {
=====================================
include/tsl/hopscotch_set.h
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2017 Tessil
+ * Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,7 @@ namespace tsl {
/**
* Implementation of a hash set using the hopscotch hashing algorithm.
*
- * The Key must be either nothrow move-constructible, copy-constuctible or both.
+ * The Key must be either nothrow move-constructible, copy-constructible or both.
*
* The size of the neighborhood (NeighborhoodSize) must be > 0 and <= 62 if StoreHash is false.
* When StoreHash is true, 32-bits of the hash will be stored alongside the neighborhood limiting
@@ -280,7 +280,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash.
*/
size_type erase(const key_type& key, std::size_t precalculated_hash) {
return m_ht.erase(key, precalculated_hash);
@@ -297,7 +297,7 @@ public:
* @copydoc erase(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
size_type erase(const K& key, std::size_t precalculated_hash) {
@@ -317,7 +317,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
@@ -332,7 +332,7 @@ public:
* @copydoc count(const K& key) const
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
@@ -344,7 +344,7 @@ public:
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
@@ -366,7 +366,7 @@ public:
* @copydoc find(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
@@ -381,7 +381,7 @@ public:
* @copydoc find(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
const_iterator find(const K& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
@@ -389,11 +389,42 @@ public:
+ bool contains(const Key& key) const { return m_ht.contains(key); }
+
+ /**
+ * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
+ */
+ bool contains(const Key& key, std::size_t precalculated_hash) const {
+ return m_ht.contains(key, precalculated_hash);
+ }
+
+ /**
+ * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
+ * If so, K must be hashable and comparable to Key.
+ */
+ template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
+ bool contains(const K& key) const { return m_ht.contains(key); }
+
+ /**
+ * @copydoc contains(const K& key) const
+ *
+ * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
+ */
+ template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
+ bool contains(const K& key, std::size_t precalculated_hash) const {
+ return m_ht.contains(key, precalculated_hash);
+ }
+
+
+
+
std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
/**
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) {
return m_ht.equal_range(key, precalculated_hash);
@@ -419,7 +450,7 @@ public:
* @copydoc equal_range(const K& key)
*
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
- * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
+ * as hash_function()(key). Useful to speed-up the lookup if you already have the hash.
*/
template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) {
=====================================
tests/custom_allocator_tests.cpp
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2018 Tessil
+ * Copyright (c) 2018 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -74,7 +74,11 @@ public:
pointer ptr = static_cast<pointer>(std::malloc(n * sizeof(T)));
if(ptr == nullptr) {
+#ifdef TSL_HH_NO_EXCEPTIONS
+ std::abort();
+#else
throw std::bad_alloc();
+#endif
}
return ptr;
=====================================
tests/hopscotch_map_tests.cpp
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2018 Tessil
+ * Copyright (c) 2018 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -77,7 +77,7 @@ using test_types = boost::mpl::list<
tsl::hopscotch_map<std::string, std::string, mod_hash<9>, std::equal_to<std::string>,
std::allocator<std::pair<std::string, std::string>>, 62, false, tsl::hh::mod_growth_policy<>>,
tsl::hopscotch_map<std::string, std::string, mod_hash<9>, std::equal_to<std::string>,
- std::allocator<std::pair<std::string, std::string>>, 62, false, tsl::hh::mod_growth_policy<std::ratio<4, 3>>>
+ std::allocator<std::pair<std::string, std::string>>, 30, true, tsl::hh::mod_growth_policy<std::ratio<4, 3>>>
>;
@@ -122,14 +122,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_insert, HMap, test_types) {
}
-// Get nothrow_move_construbtible elements into the overflow list before rehash.
+// Get nothrow_move_constructible elements into the overflow list before rehash.
static const unsigned int overflow_mod = 50;
using test_overflow_rehash_types = boost::mpl::list<
tsl::hopscotch_map<std::int64_t, move_only_test, mod_hash<overflow_mod>, std::equal_to<std::int64_t>,
std::allocator<std::pair<std::int64_t, move_only_test>>, 6>,
tsl::bhopscotch_map<std::int64_t, move_only_test, mod_hash<overflow_mod>, std::equal_to<std::int64_t>,
std::less<std::int64_t>, std::allocator<std::pair<const std::int64_t, move_only_test>>, 6>>;
-BOOST_AUTO_TEST_CASE_TEMPLATE(test_insert_overflow_rehash_nothrow_move_construbtible, HMap, test_overflow_rehash_types) {
+BOOST_AUTO_TEST_CASE_TEMPLATE(test_insert_overflow_rehash_nothrow_move_constructible, HMap, test_overflow_rehash_types) {
// insert x/mod values, insert x values, check values
static_assert(std::is_nothrow_move_constructible<typename HMap::value_type>::value, "");
@@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_insert_overflow_rehash_nothrow_move_construbt
}
}
-// Get !nothrow_move_construbtible elements into the overflow list before rehash.
+// Get !nothrow_move_constructible elements into the overflow list before rehash.
using test_overflow_rehash_copy_only_types = boost::mpl::list<
tsl::hopscotch_map<std::int64_t, copy_only_test, mod_hash<overflow_mod>, std::equal_to<std::int64_t>,
std::allocator<std::pair<std::int64_t, copy_only_test>>, 6>,
@@ -721,31 +721,31 @@ BOOST_AUTO_TEST_CASE(test_modify_value_through_iterator) {
* constructor
*/
BOOST_AUTO_TEST_CASE(test_extreme_bucket_count_value_construction) {
- BOOST_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
+ TSL_HH_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
std::allocator<std::pair<int, int>>, 62, false,
tsl::hh::power_of_two_growth_policy<2>>
(std::numeric_limits<std::size_t>::max())), std::length_error);
- BOOST_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
+ TSL_HH_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
std::allocator<std::pair<int, int>>, 62, false,
tsl::hh::power_of_two_growth_policy<2>>
(std::numeric_limits<std::size_t>::max()/2 + 1)), std::length_error);
- BOOST_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
+ TSL_HH_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
std::allocator<std::pair<int, int>>, 62, false,
tsl::hh::prime_growth_policy>
(std::numeric_limits<std::size_t>::max())), std::length_error);
- BOOST_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
+ TSL_HH_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
std::allocator<std::pair<int, int>>, 62, false,
tsl::hh::prime_growth_policy>
(std::numeric_limits<std::size_t>::max()/2)), std::length_error);
- BOOST_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
+ TSL_HH_CHECK_THROW((tsl::hopscotch_map<int, int, std::hash<int>, std::equal_to<int>,
std::allocator<std::pair<int, int>>, 62, false,
tsl::hh::mod_growth_policy<>>
(std::numeric_limits<std::size_t>::max())), std::length_error);
@@ -945,6 +945,29 @@ BOOST_AUTO_TEST_CASE(test_copy_constructor_and_operator) {
BOOST_CHECK(map_copy == map_copy3);
}
+BOOST_AUTO_TEST_CASE(test_copy_constructor_empty) {
+ tsl::hopscotch_map<std::string, int> map(0);
+ tsl::hopscotch_map<std::string, int> map_copy(map);
+
+ BOOST_CHECK(map.empty());
+ BOOST_CHECK(map_copy.empty());
+
+ BOOST_CHECK(map.find("") == map.end());
+ BOOST_CHECK(map_copy.find("") == map_copy.end());
+}
+
+BOOST_AUTO_TEST_CASE(test_copy_operator_empty) {
+ tsl::hopscotch_map<std::string, int> map(0);
+ tsl::hopscotch_map<std::string, int> map_copy(16);
+ map_copy = map;
+
+ BOOST_CHECK(map.empty());
+ BOOST_CHECK(map_copy.empty());
+
+ BOOST_CHECK(map.find("") == map.end());
+ BOOST_CHECK(map_copy.find("") == map_copy.end());
+}
+
/**
* at
*/
@@ -954,7 +977,18 @@ BOOST_AUTO_TEST_CASE(test_at) {
BOOST_CHECK_EQUAL(map.at(0), 10);
BOOST_CHECK_EQUAL(map.at(-2), 20);
- BOOST_CHECK_THROW(map.at(1), std::out_of_range);
+ TSL_HH_CHECK_THROW(map.at(1), std::out_of_range);
+}
+
+/**
+ * contains
+ */
+BOOST_AUTO_TEST_CASE(test_contains) {
+ tsl::hopscotch_map<std::int64_t, std::int64_t> map = {{0, 10}, {-2, 20}};
+
+ BOOST_CHECK(map.contains(0));
+ BOOST_CHECK(map.contains(-2));
+ BOOST_CHECK(!map.contains(-3));
}
/**
@@ -976,9 +1010,11 @@ BOOST_AUTO_TEST_CASE(test_equal_range) {
/**
* operator[]
*/
-BOOST_AUTO_TEST_CASE(test_access_operator) {
+using test_access_operator_types = boost::mpl::list<tsl::hopscotch_map<std::int64_t, std::int64_t>,
+ tsl::bhopscotch_map<std::int64_t, std::int64_t>>;
+BOOST_AUTO_TEST_CASE_TEMPLATE(test_access_operator, HMap, test_access_operator_types) {
// insert x values, use at for known and unknown values.
- tsl::hopscotch_map<std::int64_t, std::int64_t> map = {{0, 10}, {-2, 20}};
+ HMap map = {{0, 10}, {-2, 20}};
BOOST_CHECK_EQUAL(map[0], 10);
BOOST_CHECK_EQUAL(map[-2], 20);
@@ -1146,7 +1182,7 @@ BOOST_AUTO_TEST_CASE(test_heterogeneous_lookups) {
BOOST_CHECK_EQUAL(map.at(addr1), 4);
BOOST_CHECK_EQUAL(map.at(addr2), 5);
- BOOST_CHECK_THROW(map.at(addr_unknown), std::out_of_range);
+ TSL_HH_CHECK_THROW(map.at(addr_unknown), std::out_of_range);
BOOST_REQUIRE(map.find(addr1) != map.end());
@@ -1194,8 +1230,11 @@ BOOST_AUTO_TEST_CASE(test_empty_map) {
BOOST_CHECK_EQUAL(map.count(""), 0);
BOOST_CHECK_EQUAL(map.count("test"), 0);
- BOOST_CHECK_THROW(map.at(""), std::out_of_range);
- BOOST_CHECK_THROW(map.at("test"), std::out_of_range);
+ BOOST_CHECK(!map.contains(""));
+ BOOST_CHECK(!map.contains("test"));
+
+ TSL_HH_CHECK_THROW(map.at(""), std::out_of_range);
+ TSL_HH_CHECK_THROW(map.at("test"), std::out_of_range);
auto range = map.equal_range("test");
BOOST_CHECK(range.first == range.second);
@@ -1232,7 +1271,16 @@ BOOST_AUTO_TEST_CASE(test_precalculated_hash) {
BOOST_CHECK_EQUAL(map_const.at(3, map_const.hash_function()(3)), -3);
BOOST_REQUIRE_NE(map.hash_function()(2), map.hash_function()(3));
- BOOST_CHECK_THROW(map.at(3, map.hash_function()(2)), std::out_of_range);
+ TSL_HH_CHECK_THROW(map.at(3, map.hash_function()(2)), std::out_of_range);
+
+ /**
+ * count
+ */
+ BOOST_CHECK(map.contains(3, map.hash_function()(3)));
+ BOOST_CHECK(map_const.contains(3, map_const.hash_function()(3)));
+
+ BOOST_REQUIRE_NE(map.hash_function()(2), map.hash_function()(3));
+ BOOST_CHECK(!map.contains(3, map.hash_function()(2)));
/**
* count
=====================================
tests/hopscotch_set_tests.cpp
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2018 Tessil
+ * Copyright (c) 2018 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
=====================================
tests/main.cpp
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2018 Tessil
+ * Copyright (c) 2018 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
=====================================
tests/policy_tests.cpp
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2018 Tessil
+ * Copyright (c) 2018 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,6 +31,7 @@
#include <stdexcept>
#include <tsl/hopscotch_growth_policy.h>
+#include "utils.h"
BOOST_AUTO_TEST_SUITE(test_policy)
@@ -44,14 +45,14 @@ using test_types = boost::mpl::list<tsl::hh::power_of_two_growth_policy<2>,
BOOST_AUTO_TEST_CASE_TEMPLATE(test_policy, Policy, test_types) {
// Call next_bucket_count() on the policy until we reach its max_bucket_count()
- bool exception_thrown = false;
-
std::size_t bucket_count = 0;
Policy policy(bucket_count);
BOOST_CHECK_EQUAL(policy.bucket_for_hash(0), 0);
BOOST_CHECK_EQUAL(bucket_count, 0);
+#ifndef TSL_HH_NO_EXCEPTIONS
+ bool exception_thrown = false;
try {
while(true) {
const std::size_t previous_bucket_count = bucket_count;
@@ -68,10 +69,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_policy, Policy, test_types) {
}
BOOST_CHECK(exception_thrown);
+#endif
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_policy_min_bucket_count, Policy, test_types) {
- // Check polcy when a bucket_count of 0 is asked.
+ // Check policy when a bucket_count of 0 is asked.
std::size_t bucket_count = 0;
Policy policy(bucket_count);
@@ -89,11 +91,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_policy_max_bucket_count, Policy, test_types)
bucket_count = std::numeric_limits<std::size_t>::max();
- BOOST_CHECK_THROW((Policy(bucket_count)), std::length_error);
+ TSL_HH_CHECK_THROW((Policy(bucket_count)), std::length_error);
bucket_count = policy.max_bucket_count() + 1;
- BOOST_CHECK_THROW((Policy(bucket_count)), std::length_error);
+ TSL_HH_CHECK_THROW((Policy(bucket_count)), std::length_error);
}
=====================================
tests/utils.h
=====================================
@@ -1,7 +1,7 @@
/**
* MIT License
*
- * Copyright (c) 2018 Tessil
+ * Copyright (c) 2018 Thibaut Goetghebuer-Planchon <tessil at gmx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,13 +25,19 @@
#define TSL_UTILS_H
-#include <boost/numeric/conversion/cast.hpp>
#include <cstdint>
#include <functional>
#include <memory>
#include <ostream>
#include <string>
#include <utility>
+#include <tsl/hopscotch_hash.h>
+
+#ifdef TSL_HH_NO_EXCEPTIONS
+#define TSL_HH_CHECK_THROW(S, E)
+#else
+#define TSL_HH_CHECK_THROW(S, E) BOOST_CHECK_THROW(S, E)
+#endif
template<typename T>
@@ -250,12 +256,12 @@ public:
template<>
inline std::int64_t utils::get_key<std::int64_t>(std::size_t counter) {
- return boost::numeric_cast<std::int64_t>(counter);
+ return tsl::detail_hopscotch_hash::numeric_cast<std::int64_t>(counter);
}
template<>
inline self_reference_member_test utils::get_key<self_reference_member_test>(std::size_t counter) {
- return self_reference_member_test(boost::numeric_cast<std::int64_t>(counter));
+ return self_reference_member_test(tsl::detail_hopscotch_hash::numeric_cast<std::int64_t>(counter));
}
template<>
@@ -265,12 +271,12 @@ inline std::string utils::get_key<std::string>(std::size_t counter) {
template<>
inline move_only_test utils::get_key<move_only_test>(std::size_t counter) {
- return move_only_test(boost::numeric_cast<std::int64_t>(counter));
+ return move_only_test(tsl::detail_hopscotch_hash::numeric_cast<std::int64_t>(counter));
}
template<>
inline copy_only_test utils::get_key<copy_only_test>(std::size_t counter) {
- return copy_only_test(boost::numeric_cast<std::int64_t>(counter));
+ return copy_only_test(tsl::detail_hopscotch_hash::numeric_cast<std::int64_t>(counter));
}
@@ -278,12 +284,12 @@ inline copy_only_test utils::get_key<copy_only_test>(std::size_t counter) {
template<>
inline std::int64_t utils::get_value<std::int64_t>(std::size_t counter) {
- return boost::numeric_cast<std::int64_t>(counter*2);
+ return tsl::detail_hopscotch_hash::numeric_cast<std::int64_t>(counter*2);
}
template<>
inline self_reference_member_test utils::get_value<self_reference_member_test>(std::size_t counter) {
- return self_reference_member_test(boost::numeric_cast<std::int64_t>(counter*2));
+ return self_reference_member_test(tsl::detail_hopscotch_hash::numeric_cast<std::int64_t>(counter*2));
}
template<>
@@ -293,12 +299,12 @@ inline std::string utils::get_value<std::string>(std::size_t counter) {
template<>
inline move_only_test utils::get_value<move_only_test>(std::size_t counter) {
- return move_only_test(boost::numeric_cast<std::int64_t>(counter*2));
+ return move_only_test(tsl::detail_hopscotch_hash::numeric_cast<std::int64_t>(counter*2));
}
template<>
inline copy_only_test utils::get_value<copy_only_test>(std::size_t counter) {
- return copy_only_test(boost::numeric_cast<std::int64_t>(counter*2));
+ return copy_only_test(tsl::detail_hopscotch_hash::numeric_cast<std::int64_t>(counter*2));
}
View it on GitLab: https://salsa.debian.org/med-team/hopscotch-map/-/commit/78ead7b668a714e308e63bc21198748cff1ef233
--
View it on GitLab: https://salsa.debian.org/med-team/hopscotch-map/-/commit/78ead7b668a714e308e63bc21198748cff1ef233
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20200629/55bae744/attachment-0001.html>
More information about the debian-med-commit
mailing list