20
20
#include < utility>
21
21
22
22
#include " Debug.h"
23
+ #include " DeterministicContainers.h"
23
24
#include " Timer.h"
24
25
25
26
namespace cc_impl {
@@ -985,6 +986,12 @@ class ConcurrentContainer {
985
986
using const_iterator =
986
987
cc_impl::ConcurrentContainerIterator<const ConcurrentHashtable, n_slots>;
987
988
989
+ using key_type = typename Container::key_type;
990
+ using value_type = typename iterator::value_type;
991
+ using hasher = typename Container::hasher;
992
+ using key_equal = typename Container::key_equal;
993
+ using difference_type = typename Container::difference_type;
994
+
988
995
virtual ~ConcurrentContainer () {
989
996
auto timer_scope = cc_impl::s_destructor.scope ();
990
997
if (!cc_impl::is_thread_pool_active () ||
@@ -998,41 +1005,180 @@ class ConcurrentContainer {
998
1005
0 , n_slots, [this ](size_t slot) { m_slots[slot].destroy (); });
999
1006
}
1000
1007
1008
+ class FixedIterator ;
1009
+
1010
+ class ConstFixedIterator {
1011
+ const_iterator m_entry;
1012
+ friend class FixedIterator ;
1013
+
1014
+ public:
1015
+ const value_type* operator ->() const { return &*m_entry; }
1016
+
1017
+ const value_type& operator *() const { return *m_entry; }
1018
+
1019
+ bool operator ==(const FixedIterator& other) const {
1020
+ return m_entry == other.m_entry ;
1021
+ }
1022
+
1023
+ bool operator !=(const FixedIterator& other) const {
1024
+ return m_entry != other.m_entry ;
1025
+ }
1026
+
1027
+ bool operator ==(const ConstFixedIterator& other) const {
1028
+ return m_entry == other.m_entry ;
1029
+ }
1030
+
1031
+ bool operator !=(const ConstFixedIterator& other) const {
1032
+ return m_entry != other.m_entry ;
1033
+ }
1034
+
1035
+ explicit ConstFixedIterator (const_iterator entry) : m_entry(entry) {}
1036
+
1037
+ const_iterator _internal_unsafe_unwrap () { return m_entry; }
1038
+ };
1039
+
1040
+ class FixedIterator {
1041
+ iterator m_entry;
1042
+ friend class ConstFixedIterator ;
1043
+
1044
+ public:
1045
+ value_type* operator ->() { return &*m_entry; }
1046
+
1047
+ value_type& operator *() { return *m_entry; }
1048
+
1049
+ bool operator ==(const FixedIterator& other) const {
1050
+ return m_entry == other.m_entry ;
1051
+ }
1052
+
1053
+ bool operator !=(const FixedIterator& other) const {
1054
+ return m_entry != other.m_entry ;
1055
+ }
1056
+
1057
+ bool operator ==(const ConstFixedIterator& other) const {
1058
+ return m_entry == other.m_entry ;
1059
+ }
1060
+
1061
+ bool operator !=(const ConstFixedIterator& other) const {
1062
+ return m_entry != other.m_entry ;
1063
+ }
1064
+
1065
+ explicit FixedIterator (iterator entry) : m_entry(entry) {}
1066
+
1067
+ iterator _internal_unsafe_unwrap () { return m_entry; }
1068
+ };
1069
+
1070
+ // TODO: Make extra non-deterministic in debug builds
1071
+ class UnorderedIterable {
1072
+ ConcurrentHashtable* m_slots;
1073
+
1074
+ public:
1075
+ explicit UnorderedIterable (ConcurrentHashtable* slots) : m_slots(slots) {}
1076
+
1077
+ iterator begin () { return iterator (&m_slots[0 ], 0 , m_slots[0 ].begin ()); }
1078
+
1079
+ iterator end () { return iterator (&m_slots[0 ]); }
1080
+
1081
+ const_iterator begin () const {
1082
+ const auto * cslots = m_slots;
1083
+ return const_iterator (&cslots[0 ], 0 , cslots[0 ].begin ());
1084
+ }
1085
+
1086
+ const_iterator end () const {
1087
+ const auto * cslots = m_slots;
1088
+ return const_iterator (&cslots[0 ]);
1089
+ }
1090
+
1091
+ const_iterator cbegin () const { return begin (); }
1092
+
1093
+ const_iterator cend () const { return end (); }
1094
+
1095
+ iterator find (const Key& key) {
1096
+ size_t slot = Hash ()(key) % n_slots;
1097
+ const auto & it = m_slots[slot].find (key);
1098
+ if (it == m_slots[slot].end ()) {
1099
+ return end ();
1100
+ }
1101
+ return iterator (&m_slots[0 ], slot, it);
1102
+ }
1103
+
1104
+ const_iterator find (const Key& key) const {
1105
+ size_t slot = Hash ()(key) % n_slots;
1106
+ const auto * cslots = m_slots;
1107
+ const auto & it = cslots[slot].find (key);
1108
+ if (it == cslots[slot].end ()) {
1109
+ return end ();
1110
+ }
1111
+ return const_iterator (&cslots[0 ], slot, it);
1112
+ }
1113
+ };
1114
+
1115
+ // TODO: Make extra non-deterministic in debug builds
1116
+ class ConstUnorderedIterable {
1117
+ const ConcurrentHashtable* m_slots;
1118
+
1119
+ public:
1120
+ explicit ConstUnorderedIterable (const ConcurrentHashtable* slots)
1121
+ : m_slots(slots) {}
1122
+
1123
+ const_iterator begin () const {
1124
+ return const_iterator (&m_slots[0 ], 0 , m_slots[0 ].begin ());
1125
+ }
1126
+
1127
+ const_iterator end () const { return const_iterator (&m_slots[0 ]); }
1128
+
1129
+ const_iterator cbegin () const { return begin (); }
1130
+
1131
+ const_iterator cend () const { return end (); }
1132
+
1133
+ const_iterator find (const Key& key) const {
1134
+ size_t slot = Hash ()(key) % n_slots;
1135
+ const auto & it = m_slots[slot].find (key);
1136
+ if (it == m_slots[slot].end ()) {
1137
+ return end ();
1138
+ }
1139
+ return const_iterator (&m_slots[0 ], slot, it);
1140
+ }
1141
+ };
1142
+
1001
1143
/*
1002
1144
* Using iterators or accessor functions while the container is concurrently
1003
1145
* modified will result in undefined behavior.
1004
1146
*/
1005
1147
1006
- iterator begin () { return iterator (&m_slots[0 ], 0 , m_slots[0 ].begin ()); }
1148
+ UnorderedIterable _internal_unordered_iterable () {
1149
+ return UnorderedIterable (m_slots);
1150
+ }
1007
1151
1008
- iterator end () { return iterator (&m_slots[0 ]); }
1152
+ ConstUnorderedIterable _internal_unordered_iterable () const {
1153
+ return ConstUnorderedIterable (m_slots);
1154
+ }
1009
1155
1010
- const_iterator begin () const {
1011
- return const_iterator (&m_slots[0 ], 0 , m_slots[0 ].begin ());
1156
+ FixedIterator _internal_unordered_any () {
1157
+ return FixedIterator (_internal_unordered_iterable ().begin ());
1158
+ }
1159
+
1160
+ ConstFixedIterator _internal_unordered_any () const {
1161
+ return ConstFixedIterator (_internal_unordered_iterable ().begin ());
1012
1162
}
1013
1163
1014
- const_iterator end () const { return const_iterator (&m_slots[0 ]); }
1164
+ FixedIterator find (const Key& key) {
1165
+ return FixedIterator (_internal_unordered_iterable ().find (key));
1166
+ }
1015
1167
1016
- const_iterator cbegin () const { return begin (); }
1168
+ ConstFixedIterator find (const Key& key) const {
1169
+ return ConstFixedIterator (_internal_unordered_iterable ().find (key));
1170
+ }
1017
1171
1018
- const_iterator cend () const { return end (); }
1172
+ ConstFixedIterator end () const {
1173
+ return ConstFixedIterator (_internal_unordered_iterable ().cend ());
1174
+ }
1019
1175
1020
- iterator find (const Key& key) {
1021
- size_t slot = Hash ()(key) % n_slots;
1022
- const auto & it = m_slots[slot].find (key);
1023
- if (it == m_slots[slot].end ()) {
1024
- return end ();
1025
- }
1026
- return iterator (&m_slots[0 ], slot, it);
1176
+ FixedIterator end () {
1177
+ return FixedIterator (_internal_unordered_iterable ().end ());
1027
1178
}
1028
1179
1029
- const_iterator find (const Key& key) const {
1030
- size_t slot = Hash ()(key) % n_slots;
1031
- const auto & it = m_slots[slot].find (key);
1032
- if (it == m_slots[slot].end ()) {
1033
- return end ();
1034
- }
1035
- return const_iterator (&m_slots[0 ], slot, it);
1180
+ ConstFixedIterator cend () const {
1181
+ return ConstFixedIterator (_internal_unordered_iterable ().cend ());
1036
1182
}
1037
1183
1038
1184
/*
@@ -1167,7 +1313,8 @@ template <typename Key,
1167
1313
size_t n_slots = cc_impl::kDefaultSlots >
1168
1314
class ConcurrentMap final
1169
1315
: public ConcurrentContainer<std::unordered_map<Key, Value, Hash, KeyEqual>,
1170
- n_slots> {
1316
+ n_slots>,
1317
+ public UnorderedBase<ConcurrentMap<Key, Value, Hash, KeyEqual, n_slots>> {
1171
1318
public:
1172
1319
using Base =
1173
1320
ConcurrentContainer<std::unordered_map<Key, Value, Hash, KeyEqual>,
@@ -1181,6 +1328,8 @@ class ConcurrentMap final
1181
1328
1182
1329
using KeyValuePair = typename Base::Value;
1183
1330
1331
+ using mapped_type = Value;
1332
+
1184
1333
ConcurrentMap () = default ;
1185
1334
1186
1335
ConcurrentMap (const ConcurrentMap& container) noexcept : Base(container) {}
@@ -1482,7 +1631,9 @@ template <typename Key,
1482
1631
size_t n_slots = cc_impl::kDefaultSlots >
1483
1632
class InsertOnlyConcurrentMap final
1484
1633
: public ConcurrentContainer<std::unordered_map<Key, Value, Hash, KeyEqual>,
1485
- n_slots> {
1634
+ n_slots>,
1635
+ public UnorderedBase<
1636
+ InsertOnlyConcurrentMap<Key, Value, Hash, KeyEqual, n_slots>> {
1486
1637
public:
1487
1638
using Base =
1488
1639
ConcurrentContainer<std::unordered_map<Key, Value, Hash, KeyEqual>,
@@ -1495,6 +1646,8 @@ class InsertOnlyConcurrentMap final
1495
1646
1496
1647
using KeyValuePair = typename Base::Value;
1497
1648
1649
+ using mapped_type = Value;
1650
+
1498
1651
InsertOnlyConcurrentMap () = default ;
1499
1652
1500
1653
InsertOnlyConcurrentMap (const InsertOnlyConcurrentMap& container) noexcept
@@ -1782,7 +1935,8 @@ template <typename Key,
1782
1935
class AtomicMap final
1783
1936
: public ConcurrentContainer<
1784
1937
std::unordered_map<Key, std::atomic<Value>, Hash, KeyEqual>,
1785
- n_slots> {
1938
+ n_slots>,
1939
+ public UnorderedBase<AtomicMap<Key, Value, Hash, KeyEqual, n_slots>> {
1786
1940
public:
1787
1941
using Base = ConcurrentContainer<
1788
1942
std::unordered_map<Key, std::atomic<Value>, Hash, KeyEqual>,
@@ -1975,7 +2129,8 @@ template <typename Key,
1975
2129
size_t n_slots = cc_impl::kDefaultSlots >
1976
2130
class ConcurrentSet final
1977
2131
: public ConcurrentContainer<std::unordered_set<Key, Hash, KeyEqual>,
1978
- n_slots> {
2132
+ n_slots>,
2133
+ public UnorderedBase<ConcurrentSet<Key, Hash, KeyEqual, n_slots>> {
1979
2134
public:
1980
2135
using Base =
1981
2136
ConcurrentContainer<std::unordered_set<Key, Hash, KeyEqual>, n_slots>;
@@ -2056,7 +2211,9 @@ template <typename Key,
2056
2211
size_t n_slots = cc_impl::kDefaultSlots >
2057
2212
class InsertOnlyConcurrentSet final
2058
2213
: public ConcurrentContainer<std::unordered_set<Key, Hash, KeyEqual>,
2059
- n_slots> {
2214
+ n_slots>,
2215
+ public UnorderedBase<
2216
+ InsertOnlyConcurrentSet<Key, Hash, KeyEqual, n_slots>> {
2060
2217
public:
2061
2218
using Base =
2062
2219
ConcurrentContainer<std::unordered_set<Key, Hash, KeyEqual>, n_slots>;
0 commit comments