45 #include <type_traits>
55 #define __sync_synchronize MemoryBarrier
56 #define __sync_bool_compare_and_swap(ptr, oldval, newval) \
57 (InterlockedCompareExchangePointer((void* volatile*)ptr, (void*)newval, (void*)oldval) == (void*)oldval)
62 template <
unsigned Dim>
65 namespace detail::brie {
81 template <
typename A,
size_t arity>
83 std::array<std::decay_t<A>, arity> cpy;
84 std::copy_n(s.begin(), arity, cpy.begin());
88 template <
size_t offset,
typename A,
size_t arity>
90 return {s.begin() + offset, s.end()};
102 template <
typename T>
112 template <
typename T>
123 template <
typename T>
131 return (a != def()) ? a :
b;
138 template <
typename SparseArray>
160 value.second = first->cell[0].value;
167 return (
node ==
nullptr && other.
node ==
nullptr) ||
173 return !(*
this == other);
213 while (level > 0 &&
node) {
216 if (
node->cell[x].ptr !=
nullptr) {
242 if (
node ==
nullptr) {
268 return node ==
nullptr;
272 void print(std::ostream& out)
const {
275 out <<
"SparseArrayIter(" <<
node <<
" @ (" <<
value.first <<
", " <<
value.second <<
"))";
293 using namespace detail::brie;
322 template <
typename T,
unsigned BITS = 6,
typename merge_op = default_merge<T>,
typename copy_op =
identity<T>>
324 template <
typename A>
328 using key_type = uint64_t;
331 static constexpr
int BIT_PER_STEP = BITS;
332 static constexpr
int NUM_CELLS = 1 << BIT_PER_STEP;
333 static constexpr key_type INDEX_MASK = NUM_CELLS - 1;
354 std::atomic<Node*> aptr;
403 SparseArray() : unsynced(
RootInfo{
nullptr, 0, 0,
nullptr, std::numeric_limits<index_type>::max()}) {}
414 unsynced.root->parent =
nullptr;
415 unsynced.first = findFirst(unsynced.root, unsynced.levels);
425 : unsynced(RootInfo{other.unsynced.root, other.unsynced.levels, other.unsynced.offset,
426 other.unsynced.first, other.unsynced.firstOffset}) {
427 other.unsynced.root =
nullptr;
428 other.unsynced.levels = 0;
429 other.unsynced.first =
nullptr;
446 if (
this == &other)
return *
this;
455 unsynced.root->parent =
nullptr;
458 unsynced.first = (unsynced.root) ? findFirst(unsynced.root, unsynced.levels) :
nullptr;
494 return unsynced.root ==
nullptr;
501 std::size_t
size()
const {
503 if (empty())
return 0;
507 for (
auto it = begin(); it != end(); ++it) {
517 static std::size_t getMemoryUsage(
const Node* node,
int level) {
522 std::size_t res =
sizeof(Node);
526 for (
int i = 0;
i < NUM_CELLS;
i++) {
527 res += getMemoryUsage(node->cell[
i].ptr, level - 1);
539 std::size_t getMemoryUsage()
const {
541 std::size_t res =
sizeof(*this);
545 res += getMemoryUsage(unsynced.root, unsynced.levels);
558 unsynced.root =
nullptr;
560 unsynced.first =
nullptr;
561 unsynced.firstOffset = std::numeric_limits<index_type>::max();
569 index_type lastIndex{0};
570 Node* lastNode{
nullptr};
571 op_context() =
default;
582 struct RootInfoSnapshot {
596 uint64_t getRootVersion()
const {
598 return (uint64_t)synced.root;
610 res.
version = getRootVersion();
611 }
while (res.version % 2);
614 res.root = synced.root;
615 res.levels = synced.levels;
616 res.offset = synced.offset;
619 }
while (res.version != getRootVersion());
634 bool tryUpdateRootInfo(
const RootInfoSnapshot& info) {
636 uintptr_t version = info.version;
639 if (!__sync_bool_compare_and_swap(&synced.root, (Node*)version, (Node*)(version + 1))) {
644 synced.levels = info.levels;
645 synced.offset = info.offset;
648 __sync_synchronize();
649 synced.root = info.root;
658 struct FirstInfoSnapshot {
670 uint64_t getFirstVersion()
const {
672 return (uint64_t)synced.first;
683 res.
version = getFirstVersion();
684 }
while (res.version % 2);
687 res.node = synced.first;
688 res.offset = synced.firstOffset;
690 }
while (res.version != getFirstVersion());
701 bool tryUpdateFirstInfo(
const FirstInfoSnapshot& info) {
703 uintptr_t version = info.version;
706 if (!__sync_bool_compare_and_swap(&synced.first, (Node*)version, (Node*)(version + 1))) {
711 synced.firstOffset = info.offset;
714 __sync_synchronize();
715 synced.first = info.node;
728 value_type&
get(index_type
i) {
740 value_type&
get(index_type
i, op_context& ctxt) {
741 return getLeaf(
i, ctxt).value;
752 return getAtomic(
i, ctxt);
763 return getLeaf(
i, ctxt).avalue;
775 inline Cell& getLeaf(
index_type i, op_context& ctxt) {
777 if (ctxt.lastNode && (ctxt.lastIndex == (
i & ~INDEX_MASK))) {
779 return ctxt.lastNode->cell[
i & INDEX_MASK];
783 auto info = getRootInfo();
786 if (info.root ==
nullptr) {
788 info.root = newNode();
791 info.root->parent =
nullptr;
792 info.offset =
i & ~(INDEX_MASK);
795 if (tryUpdateRootInfo(info)) {
799 auto firstInfo = getFirstInfo();
800 while (info.offset < firstInfo.offset) {
801 firstInfo.node = info.root;
802 firstInfo.offset = info.offset;
803 if (!tryUpdateFirstInfo(firstInfo)) {
805 firstInfo = getFirstInfo();
810 return info.root->cell[
i & INDEX_MASK];
817 info = getRootInfo();
829 while (!inBoundaries(
i, info.levels, info.offset)) {
833 info = getRootInfo();
837 Node* node = info.root;
838 unsigned level = info.levels;
847 std::atomic<Node*>& aNext = node->cell[x].aptr;
851 Node* newNext = newNode();
852 newNext->parent = node;
855 if (!aNext.compare_exchange_strong(next, newNext)) {
865 auto off =
i & ~INDEX_MASK;
868 if (off < unsynced.firstOffset) {
870 auto first_info = getFirstInfo();
871 while (off < first_info.offset) {
872 first_info.node = next;
873 first_info.offset = off;
874 if (!tryUpdateFirstInfo(first_info)) {
876 first_info = getFirstInfo();
892 ctxt.lastIndex = (
i & ~INDEX_MASK);
893 ctxt.lastNode = node;
896 return node->cell[
i & INDEX_MASK];
903 void update(index_type
i,
const value_type& val) {
905 update(
i, val, ctxt);
912 void update(index_type
i,
const value_type& val, op_context& ctxt) {
932 return lookup(
i, ctxt);
949 if (ctxt.lastNode && ctxt.lastIndex == (
i & ~INDEX_MASK)) {
950 return ctxt.lastNode->cell[
i & INDEX_MASK].value;
954 Node* node = unsynced.root;
955 unsigned level = unsynced.levels;
964 Node* next = node->cell[x].ptr;
974 ctxt.lastIndex = (
i & ~INDEX_MASK);
975 ctxt.lastNode = node;
978 return node->cell[
i & INDEX_MASK].value;
990 static void merge(
const Node* parent, Node*& trg,
const Node* src,
int levels) {
992 if (src ==
nullptr) {
997 if (trg ==
nullptr) {
998 trg =
clone(src, levels);
999 if (trg !=
nullptr) {
1000 trg->parent = parent;
1010 for (
int i = 0;
i < NUM_CELLS; ++
i) {
1011 trg->cell[
i].value = merg(trg->cell[
i].value, src->cell[
i].value);
1017 for (
int i = 0;
i < NUM_CELLS; ++
i) {
1018 merge(trg, trg->cell[
i].ptr, src->cell[
i].ptr, levels - 1);
1026 void addAll(
const SparseArray& other) {
1028 if (other.empty()) {
1040 while (unsynced.levels < other.unsynced.levels || !inBoundaries(other.unsynced.offset)) {
1045 auto level = unsynced.levels;
1046 Node** node = &unsynced.root;
1047 while (level > other.unsynced.levels) {
1055 Node*& next = (*node)->cell[x].ptr;
1059 next->parent = *node;
1067 merge((*node)->parent, *node, other.unsynced.root, level);
1070 if (unsynced.firstOffset > other.unsynced.firstOffset) {
1071 unsynced.first = findFirst(*node, level);
1072 unsynced.firstOffset = other.unsynced.firstOffset;
1080 using iterator = SparseArrayIter<this_t>;
1086 iterator begin()
const {
1087 return iterator(unsynced.first, unsynced.firstOffset);
1093 iterator end()
const {
1104 return find(
i, ctxt);
1115 if (!unsynced.root)
return end();
1118 if (!inBoundaries(
i))
return end();
1121 if (ctxt.lastNode && ctxt.lastIndex == (
i & ~INDEX_MASK)) {
1122 Node* node = ctxt.lastNode;
1125 value_type value = node->cell[
i & INDEX_MASK].value;
1130 return iterator(node, std::make_pair(
i, value));
1134 Node* node = unsynced.root;
1135 unsigned level = unsynced.levels;
1136 while (level != 0) {
1138 auto x = getIndex(
i, level);
1144 Node* next = node->cell[x].ptr;
1147 if (!next)
return end();
1154 ctxt.lastNode = node;
1155 ctxt.lastIndex = (
i & ~INDEX_MASK);
1158 value_type value = node->cell[
i & INDEX_MASK].value;
1159 if (value == value_type{}) {
1164 return iterator(node, std::make_pair(
i, value));
1171 iterator lowerBound(index_type
i)
const {
1173 return lowerBound(
i, ctxt);
1180 iterator lowerBound(index_type
i, op_context&)
const {
1182 if (!unsynced.root)
return end();
1185 if (!inBoundaries(
i)) {
1187 if (
i < unsynced.offset) {
1188 const auto& value = unsynced.first->cell[0].value;
1189 auto res =
iterator(unsynced.first, std::make_pair(unsynced.offset, value));
1200 Node* node = unsynced.root;
1201 unsigned level = unsynced.levels;
1207 Node* next = node->cell[x].ptr;
1211 if (x == NUM_CELLS - 1) {
1213 node =
const_cast<Node*
>(node->parent);
1214 if (!node)
return end();
1218 i =
i & getLevelMask(level);
1221 i += 1ull << (BITS * level);
1226 return iterator(node, std::make_pair(
i, node->cell[x].value));
1242 iterator upperBound(index_type
i)
const {
1244 return upperBound(
i, ctxt);
1251 iterator upperBound(index_type
i, op_context& ctxt)
const {
1252 if (
i == std::numeric_limits<index_type>::max()) {
1255 return lowerBound(
i + 1, ctxt);
1263 void dump(
bool detailed, std::ostream& out,
const Node& node,
int level,
index_type offset,
1264 int indent = 0)
const {
1265 auto x = getIndex(offset, level + 1);
1266 out <<
times(
"\t", indent) << x <<
": Node " << &node <<
" on level " << level
1267 <<
" parent: " << node.parent <<
" -- range: " << offset <<
" - "
1268 << (offset + ~getLevelMask(level + 1)) <<
"\n";
1271 for (
int i = 0;
i < NUM_CELLS;
i++) {
1272 if (detailed || node.cell[
i].value !=
value_type()) {
1273 out <<
times(
"\t", indent + 1) <<
i <<
": [" << (offset +
i) <<
"] " << node.cell[
i].value
1278 for (
int i = 0;
i < NUM_CELLS;
i++) {
1279 if (node.cell[
i].ptr) {
1280 dump(detailed, out, *node.cell[
i].ptr, level - 1,
1281 offset + (
i * (
index_type(1) << (level * BIT_PER_STEP))), indent + 1);
1282 }
else if (detailed) {
1283 auto low = offset + (
i * (1 << (level * BIT_PER_STEP)));
1284 auto hig =
low + ~getLevelMask(level);
1285 out <<
times(
"\t", indent + 1) <<
i <<
": empty range " <<
low <<
" - " << hig <<
"\n";
1296 void dump(
bool detail =
false, std::ostream& out = std::cout)
const {
1297 if (!unsynced.root) {
1298 out <<
" - empty - \n";
1301 out <<
"root: " << unsynced.root <<
"\n";
1302 out <<
"offset: " << unsynced.offset <<
"\n";
1303 out <<
"first: " << unsynced.first <<
"\n";
1304 out <<
"fist offset: " << unsynced.firstOffset <<
"\n";
1305 dump(detail, out, *unsynced.root, unsynced.levels, unsynced.offset);
1316 static Node* newNode() {
1323 static void freeNodes(Node* node,
int level) {
1326 for (
int i = 0;
i < NUM_CELLS;
i++) {
1327 freeNodes(node->cell[
i].ptr, level - 1);
1337 freeNodes(unsynced.root, unsynced.levels);
1338 unsynced.root =
nullptr;
1339 unsynced.levels = 0;
1345 static Node*
clone(
const Node* node,
int level) {
1347 if (node ==
nullptr) {
1352 auto* res =
new Node();
1357 for (
int i = 0;
i < NUM_CELLS;
i++) {
1358 res->cell[
i].value =
copy(node->cell[
i].value);
1364 for (
int i = 0;
i < NUM_CELLS;
i++) {
1365 auto cur =
clone(node->cell[
i].ptr, level - 1);
1366 if (cur !=
nullptr) {
1369 res->cell[
i].ptr = cur;
1380 static Node* findFirst(Node* node,
int level) {
1383 for (
int i = 0;
i < NUM_CELLS;
i++) {
1384 Node* cur = node->cell[
i].ptr;
1392 assert(found &&
"No first node!");
1404 assert(unsynced.levels < (
sizeof(index_type) * 8 / BITS) + 1);
1407 Node* node = newNode();
1408 node->parent =
nullptr;
1412 node->cell[x].ptr = unsynced.root;
1415 unsynced.root->parent = node;
1418 unsynced.root = node;
1422 unsynced.offset &= getLevelMask(unsynced.levels + 1);
1429 void raiseLevel(RootInfoSnapshot& info) {
1431 assert(info.levels < (
sizeof(index_type) * 8 / BITS) + 1);
1434 Node* newRoot = newNode();
1435 newRoot->parent =
nullptr;
1439 newRoot->cell[x].ptr = info.root;
1442 auto oldRoot = info.root;
1443 info.root = newRoot;
1449 info.offset &= getLevelMask(info.levels + 1);
1452 if (tryUpdateRootInfo(info)) {
1454 oldRoot->parent = info.root;
1465 bool inBoundaries(index_type a)
const {
1466 return inBoundaries(a, unsynced.levels, unsynced.offset);
1473 static bool inBoundaries(index_type a, uint32_t levels, index_type offset) {
1474 auto mask = getLevelMask(levels + 1);
1475 return (a & mask) == offset;
1483 return (a & (INDEX_MASK << (level * BIT_PER_STEP))) >> (level * BIT_PER_STEP);
1490 static index_type getLevelMask(
unsigned level) {
1491 if (level > (
sizeof(
index_type) * 8 / BITS))
return 0;
1492 return (~(
index_type(0)) << (level * BIT_PER_STEP));
1496 namespace detail::brie {
1501 template <
typename SparseBitMap>
1506 using nested_iterator =
typename data_store_t::iterator;
1509 nested_iterator iter;
1523 : iter(iter), mask(
SparseBitMap::toMask(iter->second)),
1529 : iter(iter), mask(
m), value(value) {}
1534 return iter == other.
iter && mask == other.
mask;
1539 return !(*
this == other);
1543 const value_type& operator*()
const {
1555 if (moveToNextInMask())
return *
this;
1561 if (!iter.isEnd()) {
1577 bool isEnd()
const {
1578 return iter.
isEnd();
1581 void print(std::ostream& out)
const {
1582 out <<
"SparseBitMapIter(" << iter <<
" -> " << std::bitset<64>(mask) <<
" @ " << value <<
")";
1586 friend std::ostream&
operator<<(std::ostream& out,
const SparseBitMapIter& iter) {
1592 bool moveToNextInMask() {
1594 if (mask == 0)
return false;
1597 auto pos = __builtin_ctzll(mask);
1600 mask &= ~(1llu << pos);
1620 template <
unsigned BITS = 4>
1622 template <
typename A>
1628 using value_t = uint64_t;
1632 value_t operator()(value_t a, value_t
b)
const {
1642 static constexpr
size_t BITS_PER_ENTRY =
sizeof(
value_t) * CHAR_BIT;
1643 static constexpr
size_t LEAF_INDEX_WIDTH = __builtin_ctz(BITS_PER_ENTRY);
1644 static constexpr uint64_t LEAF_INDEX_MASK = BITS_PER_ENTRY - 1;
1646 static uint64_t toMask(
const value_t& value) {
1647 static_assert(
sizeof(
value_t) ==
sizeof(uint64_t),
"Fixed for 64-bit compiler.");
1648 return reinterpret_cast<const uint64_t&
>(value);
1676 bool empty()
const {
1677 return store.
empty();
1681 using op_context =
typename data_store_t::op_context;
1686 bool set(index_type
i) {
1688 return set(
i, ctxt);
1706 auto order = std::memory_order::memory_order_relaxed;
1709 value_t old = val.load(order);
1712 if (old & bit)
return false;
1715 if (!val.compare_exchange_strong(old, old | bit, order, order))
continue;
1724 value_t old = val.fetch_or(bit, std::memory_order::memory_order_relaxed);
1725 return (old & bit) == 0u;
1731 bool test(index_type
i)
const {
1733 return test(
i, ctxt);
1740 bool test(index_type
i, op_context& ctxt)
const {
1741 value_t bit = (1ull << (
i & LEAF_INDEX_MASK));
1742 return store.
lookup(
i >> LEAF_INDEX_WIDTH, ctxt) & bit;
1762 std::size_t
size()
const {
1764 std::size_t res = 0;
1765 for (
const auto& cur : store) {
1766 res += __builtin_popcountll(cur.second);
1774 std::size_t getMemoryUsage()
const {
1784 if (
this == &other)
return;
1801 auto it = store.
begin();
1802 if (it.isEnd())
return end();
1809 iterator end()
const {
1819 return find(
i, ctxt);
1829 auto it = store.
find(
i >> LEAF_INDEX_WIDTH, ctxt);
1830 if (it.isEnd())
return end();
1833 uint64_t mask = toMask(it->second);
1834 if (!(mask & (1llu << (
i & LEAF_INDEX_MASK))))
return end();
1837 mask &= ((1ull << (
i & LEAF_INDEX_MASK)) - 1);
1846 auto it = store.
lowerBound(
i >> LEAF_INDEX_WIDTH);
1847 if (it.isEnd())
return end();
1850 uint64_t mask = toMask(it->second);
1853 if (!(mask & ((~uint64_t(0)) << (
i & LEAF_INDEX_MASK)))) {
1854 index_type next = ((
i >> LEAF_INDEX_WIDTH) + 1) << LEAF_INDEX_WIDTH;
1855 if (next <
i)
return end();
1856 return lower_bound(next);
1860 if (it->first ==
i >> LEAF_INDEX_WIDTH) {
1861 mask &= ((~uint64_t(0)) << (
i & LEAF_INDEX_MASK));
1865 index_type pos = __builtin_ctzll(mask);
1868 mask = mask & ~(1ull << pos);
1871 index_type val = (it->first << LEAF_INDEX_WIDTH) | pos;
1872 return iterator(it, mask, val);
1879 iterator upper_bound(index_type
i)
const {
1880 if (
i == std::numeric_limits<index_type>::max()) {
1883 return lower_bound(
i + 1);
1890 void dump(
bool detail =
false, std::ostream& out = std::cout)
const {
1891 store.
dump(detail, out);
1907 namespace detail::brie {
1916 template <
typename Value,
typename IterCore>
1918 template <
unsigned Len,
unsigned Pos,
unsigned Dimensions>
1921 template <
unsigned Dimensions>
1924 template <
unsigned Dimensions>
1927 template <
unsigned Pos,
unsigned Dimensions>
1930 template <
unsigned Dimensions>
1933 template <
typename A,
typename B>
1944 auto getNestedView() {
1945 auto& nested_iter_ref = iter_core.getNested();
1946 auto nested_val =
tail(value);
1948 std::move(nested_val), nested_iter_ref);
1952 explicit TrieIterator(Value value, IterCore iter_core) : value(
std::move(value)), iter_core(iter_core) {}
1971 return !(*
this == other);
1974 const Value& operator*()
const {
1978 const Value* operator->()
const {
1983 iter_core.inc(value);
1995 out <<
"iter(" << iter_core <<
" -> " << value <<
")";
2004 template <
unsigned Dim>
2014 template <
unsigned Dim,
typename Derived>
2017 return static_cast<Derived&
>(*this);
2020 const Derived& impl()
const {
2021 return static_cast<const Derived&
>(*this);
2026 using store_type =
typename types::store_type;
2045 void insertAll(
const TrieBase& other) {
2046 store.addAll(other.
store);
2059 bool empty()
const {
2060 return store.empty();
2066 iterator begin()
const {
2067 return empty() ? end() : iterator(store.begin());
2074 iterator end()
const {
2078 iterator find(const_entry_span_type entry, op_context& ctxt)
const {
2079 auto range = impl().template getBoundaries<Dim>(entry, ctxt);
2093 template <
unsigned levels>
2096 return impl().template getBoundaries<levels>(entry, ctxt);
2099 template <
unsigned levels>
2100 range<iterator> getBoundaries(
const entry_type& entry, op_context& ctxt)
const {
2101 return impl().template getBoundaries<levels>(const_entry_span_type(entry), ctxt);
2104 template <
unsigned levels>
2106 return impl().template getBoundaries<levels>(const_entry_span_type(entry));
2109 template <
unsigned levels,
typename... Values,
typename = std::enable_if_t<(isRamType<Values> && ...)>>
2115 #define BRIE_OVERLOAD_INIT_LIST(fn, constness) \
2116 auto fn(const_entry_span_type entry) constness { \
2118 return impl().fn(entry, ctxt); \
2120 auto fn(const entry_type& entry, op_context& ctxt) constness { \
2121 return impl().fn(const_entry_span_type(entry), ctxt); \
2123 auto fn(const entry_type& entry) constness { \
2124 return impl().fn(const_entry_span_type(entry)); \
2133 #undef BRIE_OVERLOAD_INIT_LIST
2138 struct hint_statistics {
2140 CacheAccessCounter inserts;
2146 CacheAccessCounter get_boundaries;
2151 mutable hint_statistics hint_stats;
2154 void printStats(std::ostream& out)
const {
2155 out <<
"---------------------------------\n";
2156 out <<
" insert-hint (hits/misses/total): " << hint_stats.inserts.getHits() <<
"/"
2157 << hint_stats.inserts.getMisses() <<
"/" << hint_stats.inserts.getAccesses() <<
"\n";
2158 out <<
" contains-hint (hits/misses/total):" << hint_stats.contains.getHits() <<
"/"
2159 << hint_stats.contains.getMisses() <<
"/" << hint_stats.contains.getAccesses() <<
"\n";
2160 out <<
" get-boundaries-hint (hits/misses/total):" << hint_stats.get_boundaries.getHits() <<
"/"
2161 << hint_stats.get_boundaries.getMisses() <<
"/" << hint_stats.get_boundaries.getAccesses()
2163 out <<
"---------------------------------\n";
2167 template <
unsigned Dim>
2175 template <
unsigned Level>
2177 template <
typename IterCore>
2185 template <
typename IterCore>
2186 IterCore& operator()(IterCore& core) {
2196 template <
unsigned Pos,
unsigned Dim>
2198 template <
unsigned bits,
typename iterator>
2201 auto first = store.
begin();
2203 iter.value[Pos] = *first;
2206 template <
typename Store,
typename iterator>
2207 void operator()(
const Store& store, iterator& iter)
const {
2209 auto first = store.begin();
2211 iter.value[Pos] = first->first;
2217 template <
unsigned Dim>
2219 template <
typename Store,
typename iterator>
2220 void operator()(
const Store&, iterator&)
const {
2225 template <
unsigned Dim>
2227 template <
unsigned bits,
typename iterator>
2230 auto first = store.
begin();
2231 iter.value[0] = *first;
2232 iter.iter_core.setIterator(std::move(first));
2235 template <
typename Store,
typename iterator>
2238 auto first = store.begin();
2239 iter.value[0] = first->first;
2240 iter.iter_core.setIterator(std::move(first));
2251 template <
unsigned Len,
unsigned Pos,
unsigned Dim>
2253 template <
unsigned bits,
typename iterator,
typename entry_type>
2255 const SparseBitMap<bits>& store, iterator& begin, iterator& end,
const entry_type& entry)
const {
2257 auto cur = store.
find(entry[Pos]);
2260 if (cur == store.
end())
return false;
2268 begin.value[Pos] = entry[Pos];
2274 template <
typename Store,
typename iterator,
typename entry_type>
2275 bool operator()(
const Store& store, iterator& begin, iterator& end,
const entry_type& entry)
const {
2277 auto cur = store.find(entry[Pos]);
2280 if (cur == store.end())
return false;
2286 begin.value[Pos] = entry[Pos];
2289 auto res =
fix_binding<Len - 1, Pos + 1, Dim>()(cur->second->getStore(), begin, end, entry);
2294 if (cur != store.end()) {
2305 template <
unsigned Pos,
unsigned Dim>
2307 template <
unsigned bits,
typename iterator,
typename entry_type>
2309 const entry_type& )
const {
2311 auto a = store.
begin();
2313 begin.value[Pos] = *a;
2318 template <
typename Store,
typename iterator,
typename entry_type>
2319 bool operator()(
const Store& store, iterator& begin, iterator& end,
const entry_type& entry)
const {
2321 auto a = store.begin();
2323 begin.value[Pos] = a->first;
2331 template <
unsigned Dim>
2333 template <
typename Store,
typename iterator,
typename entry_type>
2334 bool operator()(
const Store& , iterator& , iterator& ,
2335 const entry_type& )
const {
2345 template <
unsigned Dim>
2348 using const_entry_span_type =
typename types::const_entry_span_type;
2350 template <
unsigned bits,
typename iterator>
2351 bool operator()(
const SparseBitMap<bits>& store, iterator&& iter, const_entry_span_type entry)
const {
2353 if (cur == store.
end())
return false;
2356 iter.iter_core.setIterator(cur);
2357 iter.value[0] = *cur;
2361 template <
typename Store,
typename iterator>
2363 auto cur = store.lowerBound(entry[0]);
2364 if (cur == store.end())
return false;
2369 iter.iter_core.setIterator(cur);
2370 iter.value[0] = cur->first;
2371 fix_first_nested<Dim - 1>()(cur->second->getStore(), iter.getNestedView());
2380 for (
size_t i = 1;
i < Dim; ++
i)
2383 return (*
this)(store, iter,
sub);
2386 iter.iter_core.setIterator(cur);
2387 iter.value[0] = cur->first;
2396 template <
unsigned Dim>
2399 using const_entry_span_type =
typename types::const_entry_span_type;
2401 template <
unsigned bits,
typename iterator>
2402 bool operator()(
const SparseBitMap<bits>& store, iterator&& iter, const_entry_span_type entry)
const {
2404 if (cur == store.
end())
return false;
2407 iter.iter_core.setIterator(cur);
2408 iter.value[0] = *cur;
2412 template <
typename Store,
typename iterator>
2414 auto cur = store.lowerBound(entry[0]);
2415 if (cur == store.end())
return false;
2420 iter.iter_core.setIterator(cur);
2421 iter.value[0] = cur->first;
2422 fix_first_nested<Dim - 1>()(cur->second->getStore(), iter.getNestedView());
2431 for (
size_t i = 1;
i < Dim; ++
i)
2434 return (*
this)(store, iter,
sub);
2437 iter.iter_core.setIterator(cur);
2438 iter.value[0] = cur->first;
2443 template <
unsigned Dim>
2445 using entry_type = std::array<brie_element_type, Dim>;
2450 using nested_trie_type =
Trie<Dim - 1>;
2453 struct nested_trie_merger {
2454 nested_trie_type* operator()(nested_trie_type* a,
const nested_trie_type*
b)
const {
2456 if (!a)
return new nested_trie_type(*
b);
2482 nested_core_iter nested;
2488 entry[0] = iter->first;
2489 nested = {iter->second->getStore().begin(),
tail(entry)};
2496 store_iter& getIterator() {
2500 nested_core_iter& getNested() {
2506 auto nested_entry =
tail(entry);
2507 if (nested.inc(nested_entry))
return true;
2513 if (iter.isEnd())
return false;
2516 entry[0] = iter->first;
2519 nested = {iter->second->getStore().begin(), nested_entry};
2524 return nested == other.
nested && iter == other.
iter;
2527 bool operator!=(
const iterator_core& other)
const {
2528 return !(*
this == other);
2532 void print(std::ostream& out)
const {
2533 out << iter <<
" | " << nested;
2536 friend std::ostream&
operator<<(std::ostream& out,
const iterator_core& iter) {
2553 nested_ctxt nestedCtxt{};
2556 unsigned lastBoundaryLevels{Dim + 1};
2557 entry_type lastBoundaryRequest{};
2564 using entry_type = std::array<brie_element_type, 1>;
2583 iterator_core() =
default;
2591 void setIterator(store_iter store_iter) {
2595 store_iter& getIterator() {
2604 if (iter.isEnd())
return false;
2611 bool operator==(
const iterator_core& other)
const {
2612 return iter == other.iter;
2615 bool operator!=(
const iterator_core& other)
const {
2616 return !(*
this == other);
2620 void print(std::ostream& out)
const {
2624 friend std::ostream&
operator<<(std::ostream& out,
const iterator_core& iter) {
2637 template <
unsigned Dim>
2639 template <
unsigned N>
2645 using nested_trie_type =
typename types::nested_trie_type;
2653 using entry_type =
typename types::entry_type;
2654 using iterator =
typename types::iterator;
2655 using iterator_core =
typename types::iterator_core;
2666 using base::getBoundaries;
2668 using base::lower_bound;
2669 using base::upper_bound;
2678 std::size_t
size()
const {
2680 std::size_t res = 0;
2681 for (
auto&& [_, v] : store)
2690 std::size_t getMemoryUsage()
const {
2692 auto res =
sizeof(*this) -
sizeof(store) + store.getMemoryUsage();
2693 for (
auto&& [_, v] : store)
2694 res += v->getMemoryUsage();
2705 for (
auto& cur : store)
2721 using value_t =
typename store_type::value_type;
2722 using atomic_value_t =
typename store_type::atomic_value_type;
2725 if (ctxt.lastNested && ctxt.lastQuery ==
tuple[0]) {
2726 base::hint_stats.inserts.addHit();
2727 return ctxt.lastNested->insert(
tail(
tuple), ctxt.nestedCtxt);
2730 base::hint_stats.inserts.addMiss();
2733 atomic_value_t& next = store.getAtomic(
tuple[0], ctxt.local);
2736 value_t nextPtr = next;
2741 auto newNested = std::make_unique<nested_trie_type>();
2742 if (next.compare_exchange_weak(nextPtr, newNested.get())) {
2743 nextPtr = newNested.release();
2752 if (nextPtr != ctxt.lastNested) {
2753 ctxt.lastQuery =
tuple[0];
2754 ctxt.lastNested = nextPtr;
2755 ctxt.nestedCtxt = {};
2759 return nextPtr->insert(
tail(tuple), ctxt.nestedCtxt);
2762 bool contains(const_entry_span_type tuple, op_context& ctxt)
const {
2764 if (ctxt.lastNested && ctxt.lastQuery == tuple[0]) {
2765 base::hint_stats.contains.addHit();
2766 return ctxt.lastNested->contains(
tail(tuple), ctxt.nestedCtxt);
2769 base::hint_stats.contains.addMiss();
2772 auto next = store.lookup(tuple[0], ctxt.local);
2775 if (next != ctxt.lastNested) {
2776 ctxt.lastQuery = tuple[0];
2777 ctxt.lastNested = next;
2778 ctxt.nestedCtxt = {};
2782 return next && next->contains(
tail(tuple), ctxt.nestedCtxt);
2795 template <
unsigned levels>
2796 range<iterator> getBoundaries(const_entry_span_type entry, op_context& ctxt)
const {
2798 if constexpr (levels == 0) return
make_range(begin(), end());
2801 if (ctxt.lastBoundaryLevels == levels) {
2803 for (
unsigned i = 0;
i < levels; ++
i) {
2804 fit = fit && (entry[
i] == ctxt.lastBoundaryRequest[
i]);
2809 base::hint_stats.get_boundaries.addHit();
2810 return ctxt.lastBoundaries;
2815 base::hint_stats.get_boundaries.addMiss();
2822 auto found = fix_binding<levels, 0, Dim>()(store, begin, end, entry);
2823 if (!found)
return make_range(iterator(), iterator());
2826 static_assert(std::tuple_size_v<decltype(ctxt.lastBoundaryRequest)> == Dim);
2827 static_assert(std::tuple_size_v<decltype(entry)> == Dim);
2828 ctxt.lastBoundaryLevels = levels;
2829 std::copy_n(entry.begin(), Dim, ctxt.lastBoundaryRequest.begin());
2830 ctxt.lastBoundaries =
make_range(begin, end);
2833 return ctxt.lastBoundaries;
2843 iterator lower_bound(const_entry_span_type entry, op_context& )
const {
2848 bool found = fix_lower_bound<Dim>()(store, res, entry);
2851 return found ? res : end();
2870 return found ? res : end();
2881 std::vector<range<iterator>> partition(
unsigned chunks = 500)
const {
2882 std::vector<range<iterator>> res;
2885 if (this->empty())
return res;
2888 int step = std::max(store.size() / chunks,
size_t(1));
2891 auto priv = begin();
2892 for (
auto it = store.begin(); it != store.end(); ++it, c++) {
2893 if (c % step != 0 || c == 1) {
2913 class Trie<1u> :
public TrieBase<1u, Trie<1u>> {
2914 using base = TrieBase<1u, Trie<1u>>;
2915 using types = TrieTypes<1u>;
2916 using store_type =
typename types::store_type;
2921 using const_entry_span_type =
typename types::const_entry_span_type;
2922 using entry_span_type =
typename types::entry_span_type;
2923 using entry_type =
typename types::entry_type;
2924 using iterator =
typename types::iterator;
2925 using iterator_core =
typename types::iterator_core;
2926 using op_context =
typename types::op_context;
2928 using operation_hints = op_context;
2936 using base::getBoundaries;
2938 using base::lower_bound;
2939 using base::upper_bound;
2945 return store.size();
2951 std::size_t getMemoryUsage()
const {
2953 return sizeof(*this) -
sizeof(store) + store.getMemoryUsage();
2972 return store.set(
tuple[0], ctxt);
2984 return store.test(
tuple[0], ctxt);
2996 std::vector<range<iterator>> partition(
unsigned chunks = 500)
const {
2997 std::vector<range<iterator>> res;
3000 if (this->empty())
return res;
3003 int step =
static_cast<int>(std::max(store.size() / chunks,
size_t(1)));
3006 auto priv = begin();
3007 for (
auto it = store.begin(); it != store.end(); ++it, c++) {
3008 if (c % step != 0 || c == 1) {
3011 auto cur = iterator(it);
3030 template <
unsigned levels>
3031 range<iterator> getBoundaries(const_entry_span_type entry, op_context& ctxt)
const {
3033 if (levels == 0)
return make_range(begin(), end());
3035 auto pos = store.find(entry[0], ctxt);
3036 if (pos == store.end())
return make_range(end(), end());
3039 return make_range(iterator(pos), iterator(next));
3042 iterator lower_bound(const_entry_span_type entry, op_context&)
const {
3043 return iterator(store.lower_bound(entry[0]));
3046 iterator upper_bound(const_entry_span_type entry, op_context&)
const {
3057 template <
typename A>
3061 template <
typename A>
3065 template <
typename A,
typename IterCore>
3071 #undef __sync_synchronize
3072 #undef __sync_bool_compare_and_swap