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