LCOV - code coverage report
Current view: top level - asmjit - zonetree.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 13 66 19.7 %
Date: 2026-11-05 10:19:06 Functions: 2 13 15.4 %

          Line data    Source code
       1             : #ifdef __PLUMED_HAS_ASMJIT
       2             : // This file is part of AsmJit project <https://asmjit.com>
       3             : //
       4             : // See asmjit.h or LICENSE.md for license and copyright information
       5             : // SPDX-License-Identifier: Zlib
       6             : 
       7             : #ifndef ASMJIT_CORE_ZONETREE_H_INCLUDED
       8             : #define ASMJIT_CORE_ZONETREE_H_INCLUDED
       9             : 
      10             : #include "support.h"
      11             : 
      12             : ASMJIT_BEGIN_NAMESPACE
      13             : 
      14             : //! \addtogroup asmjit_zone
      15             : //! \{
      16             : 
      17             : //! RB-Tree node.
      18             : //!
      19             : //! The color is stored in a least significant bit of the `left` node.
      20             : //!
      21             : //! WARNING: Always use accessors to access left and right children.
      22             : class ZoneTreeNode {
      23             : public:
      24             :   ASMJIT_NONCOPYABLE(ZoneTreeNode)
      25             : 
      26             :   //! \name Constants
      27             :   //! \{
      28             : 
      29             :   enum : uintptr_t {
      30             :     kRedMask = 0x1,
      31             :     kPtrMask = ~kRedMask
      32             :   };
      33             : 
      34             :   //! \}
      35             : 
      36             :   //! \name Members
      37             :   //! \{
      38             : 
      39             :   uintptr_t _rbNodeData[2];
      40             : 
      41             :   //! \}
      42             : 
      43             :   //! \name Construction & Destruction
      44             :   //! \{
      45             : 
      46             :   inline ZoneTreeNode() noexcept
      47       27392 :     : _rbNodeData { 0, 0 } {}
      48             : 
      49             :   //! \}
      50             : 
      51             :   //! \name Accessors
      52             :   //! \{
      53             : 
      54           0 :   inline bool isRed() const noexcept { return static_cast<bool>(_rbNodeData[0] & kRedMask); }
      55             : 
      56           0 :   inline bool hasChild(size_t i) const noexcept { return _rbNodeData[i] > kRedMask; }
      57             :   inline bool hasLeft() const noexcept { return _rbNodeData[0] > kRedMask; }
      58             :   inline bool hasRight() const noexcept { return _rbNodeData[1] != 0; }
      59             : 
      60             :   template<typename T = ZoneTreeNode>
      61             :   inline T* child(size_t i) const noexcept { return static_cast<T*>(_getChild(i)); }
      62             :   template<typename T = ZoneTreeNode>
      63             :   inline T* left() const noexcept { return static_cast<T*>(_getLeft()); }
      64             :   template<typename T = ZoneTreeNode>
      65             :   inline T* right() const noexcept { return static_cast<T*>(_getRight()); }
      66             : 
      67             :   //! \}
      68             : 
      69             :   //! \cond INTERNAL
      70             :   //! \name Internal
      71             :   //! \{
      72             : 
      73           0 :   inline ZoneTreeNode* _getChild(size_t i) const noexcept { return (ZoneTreeNode*)(_rbNodeData[i] & kPtrMask); }
      74           0 :   inline ZoneTreeNode* _getLeft() const noexcept { return (ZoneTreeNode*)(_rbNodeData[0] & kPtrMask); }
      75           0 :   inline ZoneTreeNode* _getRight() const noexcept { return (ZoneTreeNode*)(_rbNodeData[1]); }
      76             : 
      77           0 :   inline void _setChild(size_t i, ZoneTreeNode* node) noexcept { _rbNodeData[i] = (_rbNodeData[i] & kRedMask) | (uintptr_t)node; }
      78             :   inline void _setLeft(ZoneTreeNode* node) noexcept { _rbNodeData[0] = (_rbNodeData[0] & kRedMask) | (uintptr_t)node; }
      79           0 :   inline void _setRight(ZoneTreeNode* node) noexcept { _rbNodeData[1] = (uintptr_t)node; }
      80             : 
      81           0 :   inline void _makeRed() noexcept { _rbNodeData[0] |= kRedMask; }
      82           0 :   inline void _makeBlack() noexcept { _rbNodeData[0] &= kPtrMask; }
      83             : 
      84             :   //! Tests whether the node is RED (RED node must be non-null and must have RED flag set).
      85           0 :   static inline bool _isValidRed(ZoneTreeNode* node) noexcept { return node && node->isRed(); }
      86             : 
      87             :   //! \}
      88             :   //! \endcond
      89             : };
      90             : 
      91             : //! RB-Tree node casted to `NodeT`.
      92             : template<typename NodeT>
      93             : class ZoneTreeNodeT : public ZoneTreeNode {
      94             : public:
      95             :   ASMJIT_NONCOPYABLE(ZoneTreeNodeT)
      96             : 
      97             :   //! \name Construction & Destruction
      98             :   //! \{
      99             : 
     100             :   inline ZoneTreeNodeT() noexcept
     101             :     : ZoneTreeNode() {}
     102             : 
     103             :   //! \}
     104             : 
     105             :   //! \name Accessors
     106             :   //! \{
     107             : 
     108             :   inline NodeT* child(size_t i) const noexcept { return static_cast<NodeT*>(_getChild(i)); }
     109             :   inline NodeT* left() const noexcept { return static_cast<NodeT*>(_getLeft()); }
     110             :   inline NodeT* right() const noexcept { return static_cast<NodeT*>(_getRight()); }
     111             : 
     112             :   //! \}
     113             : };
     114             : 
     115             : //! RB-Tree.
     116             : template<typename NodeT>
     117             : class ZoneTree {
     118             : public:
     119             :   ASMJIT_NONCOPYABLE(ZoneTree)
     120             : 
     121             :   typedef NodeT Node;
     122             :   NodeT* _root;
     123             : 
     124             :   //! \name Construction & Destruction
     125             :   //! \{
     126             : 
     127       54914 :   inline ZoneTree() noexcept
     128       54914 :     : _root(nullptr) {}
     129             : 
     130             :   inline ZoneTree(ZoneTree&& other) noexcept
     131             :     : _root(other._root) {}
     132             : 
     133       54914 :   inline void reset() noexcept { _root = nullptr; }
     134             : 
     135             :   //! \}
     136             : 
     137             :   //! \name Accessors
     138             :   //! \{
     139             : 
     140             :   inline bool empty() const noexcept { return _root == nullptr; }
     141           0 :   inline NodeT* root() const noexcept { return static_cast<NodeT*>(_root); }
     142             : 
     143             :   //! \}
     144             : 
     145             :   //! \name Utilities
     146             :   //! \{
     147             : 
     148             :   inline void swap(ZoneTree& other) noexcept {
     149             :     std::swap(_root, other._root);
     150             :   }
     151             : 
     152             :   template<typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
     153       27392 :   void insert(NodeT* ASMJIT_NONNULL(node), const CompareT& cmp = CompareT()) noexcept {
     154             :     // Node to insert must not contain garbage.
     155             :     ASMJIT_ASSERT(!node->hasLeft());
     156             :     ASMJIT_ASSERT(!node->hasRight());
     157             :     ASMJIT_ASSERT(!node->isRed());
     158             : 
     159       27392 :     if (!_root) {
     160       27392 :       _root = node;
     161       27392 :       return;
     162             :     }
     163             : 
     164             :     ZoneTreeNode head;           // False root node,
     165             :     head._setRight(_root);       // having root on the right.
     166             : 
     167             :     ZoneTreeNode* g = nullptr;   // Grandparent.
     168             :     ZoneTreeNode* p = nullptr;   // Parent.
     169             :     ZoneTreeNode* t = &head;     // Iterator.
     170             :     ZoneTreeNode* q = _root;     // Query.
     171             : 
     172             :     size_t dir = 0;              // Direction for accessing child nodes.
     173             :     size_t last = 0;             // Not needed to initialize, but makes some tools happy.
     174             : 
     175             :     node->_makeRed();            // New nodes are always red and violations fixed appropriately.
     176             : 
     177             :     // Search down the tree.
     178             :     for (;;) {
     179           0 :       if (!q) {
     180             :         // Insert new node at the bottom.
     181             :         q = node;
     182             :         p->_setChild(dir, node);
     183             :       }
     184             :       else if (_isValidRed(q->_getLeft()) && _isValidRed(q->_getRight())) {
     185             :         // Color flip.
     186             :         q->_makeRed();
     187             :         q->_getLeft()->_makeBlack();
     188             :         q->_getRight()->_makeBlack();
     189             :       }
     190             : 
     191             :       // Fix red violation.
     192             :       if (_isValidRed(q) && _isValidRed(p)) {
     193           0 :         ASMJIT_ASSUME(g != nullptr);
     194             :         ASMJIT_ASSUME(p != nullptr);
     195           0 :         t->_setChild(t->_getRight() == g,
     196           0 :                      q == p->_getChild(last) ? _singleRotate(g, !last) : _doubleRotate(g, !last));
     197             :       }
     198             : 
     199             :       // Stop if found.
     200           0 :       if (q == node)
     201             :         break;
     202             : 
     203             :       last = dir;
     204           0 :       dir = cmp(*static_cast<NodeT*>(q), *static_cast<NodeT*>(node)) < 0;
     205             : 
     206             :       // Update helpers.
     207           0 :       if (g) t = g;
     208             : 
     209             :       g = p;
     210             :       p = q;
     211             :       q = q->_getChild(dir);
     212             :     }
     213             : 
     214             :     // Update root and make it black.
     215           0 :     _root = static_cast<NodeT*>(head._getRight());
     216             :     _root->_makeBlack();
     217             :   }
     218             : 
     219             :   //! Remove node from RBTree.
     220             :   template<typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
     221           0 :   void remove(ZoneTreeNode* ASMJIT_NONNULL(node), const CompareT& cmp = CompareT()) noexcept {
     222             :     ZoneTreeNode head;           // False root node,
     223           0 :     head._setRight(_root);       // having root on the right.
     224             : 
     225             :     ZoneTreeNode* g = nullptr;   // Grandparent.
     226             :     ZoneTreeNode* p = nullptr;   // Parent.
     227             :     ZoneTreeNode* q = &head;     // Query.
     228             : 
     229             :     ZoneTreeNode* f  = nullptr;  // Found item.
     230             :     ZoneTreeNode* gf = nullptr;  // Found grandparent.
     231             :     size_t dir = 1;              // Direction (0 or 1).
     232             : 
     233             :     // Search and push a red down.
     234           0 :     while (q->hasChild(dir)) {
     235             :       size_t last = dir;
     236             : 
     237             :       // Update helpers.
     238             :       g = p;
     239             :       p = q;
     240             :       q = q->_getChild(dir);
     241           0 :       dir = cmp(*static_cast<NodeT*>(q), *static_cast<NodeT*>(node)) < 0;
     242             : 
     243             :       // Save found node.
     244           0 :       if (q == node) {
     245             :         f = q;
     246             :         gf = g;
     247             :       }
     248             : 
     249             :       // Push the red node down.
     250             :       if (!_isValidRed(q) && !_isValidRed(q->_getChild(dir))) {
     251           0 :         if (_isValidRed(q->_getChild(!dir))) {
     252           0 :           ZoneTreeNode* child = _singleRotate(q, dir);
     253             :           p->_setChild(last, child);
     254             :           p = child;
     255             :         }
     256           0 :         else if (!_isValidRed(q->_getChild(!dir)) && p->_getChild(!last)) {
     257             :           ZoneTreeNode* s = p->_getChild(!last);
     258             :           if (!_isValidRed(s->_getChild(!last)) && !_isValidRed(s->_getChild(last))) {
     259             :             // Color flip.
     260             :             p->_makeBlack();
     261             :             s->_makeRed();
     262             :             q->_makeRed();
     263             :           }
     264             :           else {
     265           0 :             ASMJIT_ASSUME(g != nullptr);
     266             :             ASMJIT_ASSUME(s != nullptr);
     267             : 
     268           0 :             size_t dir2 = g->_getRight() == p;
     269             :             ZoneTreeNode* child = g->_getChild(dir2);
     270             : 
     271             :             if (_isValidRed(s->_getChild(last))) {
     272           0 :               child = _doubleRotate(p, last);
     273             :               g->_setChild(dir2, child);
     274             :             }
     275             :             else if (_isValidRed(s->_getChild(!last))) {
     276           0 :               child = _singleRotate(p, last);
     277             :               g->_setChild(dir2, child);
     278             :             }
     279             : 
     280             :             // Ensure correct coloring.
     281             :             q->_makeRed();
     282             :             child->_makeRed();
     283             :             child->_getLeft()->_makeBlack();
     284             :             child->_getRight()->_makeBlack();
     285             :           }
     286             :         }
     287             :       }
     288             :     }
     289             : 
     290             :     // Replace and remove.
     291             :     ASMJIT_ASSERT(f != nullptr);
     292             :     ASMJIT_ASSERT(f != &head);
     293             :     ASMJIT_ASSERT(q != &head);
     294             : 
     295           0 :     p->_setChild(p->_getRight() == q,
     296             :                  q->_getChild(q->_getLeft() == nullptr));
     297             : 
     298             :     // NOTE: The original algorithm used a trick to just copy 'key/value' to `f` and mark `q` for deletion. But this
     299             :     // is unacceptable here as we really want to destroy the passed `node`. So, we have to make sure that we have
     300             :     // really removed `f` and not `q`.
     301           0 :     if (f != q) {
     302             :       ASMJIT_ASSERT(f != &head);
     303             :       ASMJIT_ASSERT(f != gf);
     304             : 
     305           0 :       ZoneTreeNode* n = gf ? gf : &head;
     306           0 :       dir = (n == &head) ? 1  : cmp(*static_cast<NodeT*>(n), *static_cast<NodeT*>(node)) < 0;
     307             : 
     308             :       for (;;) {
     309           0 :         if (n->_getChild(dir) == f) {
     310             :           n->_setChild(dir, q);
     311             :           // RAW copy, including the color.
     312           0 :           q->_rbNodeData[0] = f->_rbNodeData[0];
     313           0 :           q->_rbNodeData[1] = f->_rbNodeData[1];
     314             :           break;
     315             :         }
     316             : 
     317             :         n = n->_getChild(dir);
     318             : 
     319             :         // Cannot be true as we know that it must reach `f` in few iterations.
     320             :         ASMJIT_ASSERT(n != nullptr);
     321           0 :         dir = cmp(*static_cast<NodeT*>(n), *static_cast<NodeT*>(node)) < 0;
     322             :       }
     323             :     }
     324             : 
     325             :     // Update root and make it black.
     326           0 :     _root = static_cast<NodeT*>(head._getRight());
     327           0 :     if (_root) _root->_makeBlack();
     328           0 :   }
     329             : 
     330             :   template<typename KeyT, typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
     331         100 :   inline NodeT* get(const KeyT& key, const CompareT& cmp = CompareT()) const noexcept {
     332         100 :     ZoneTreeNode* node = _root;
     333         100 :     while (node) {
     334           0 :       auto result = cmp(*static_cast<const NodeT*>(node), key);
     335         100 :       if (result == 0) break;
     336             : 
     337             :       // Go left or right depending on the `result`.
     338           0 :       node = node->_getChild(result < 0);
     339             :     }
     340         100 :     return static_cast<NodeT*>(node);
     341             :   }
     342             : 
     343             :   //! \}
     344             : 
     345             :   //! \cond INTERNAL
     346             :   //! \name Internal
     347             :   //! \{
     348             : 
     349             :   static inline bool _isValidRed(ZoneTreeNode* node) noexcept { return ZoneTreeNode::_isValidRed(node); }
     350             : 
     351             :   //! Single rotation.
     352           0 :   static inline ZoneTreeNode* _singleRotate(ZoneTreeNode* ASMJIT_NONNULL(root), size_t dir) noexcept {
     353           0 :     ZoneTreeNode* save = root->_getChild(!dir);
     354           0 :     ASMJIT_ASSUME(save != nullptr);
     355             : 
     356             :     ZoneTreeNode* saveChild = save->_getChild(dir);
     357             :     root->_setChild(!dir, saveChild);
     358             :     save->_setChild( dir, root);
     359             :     root->_makeRed();
     360             :     save->_makeBlack();
     361           0 :     return save;
     362             :   }
     363             : 
     364             :   //! Double rotation.
     365           0 :   static inline ZoneTreeNode* _doubleRotate(ZoneTreeNode* ASMJIT_NONNULL(root), size_t dir) noexcept {
     366           0 :     ZoneTreeNode* child = root->_getChild(!dir);
     367           0 :     ASMJIT_ASSUME(child != nullptr);
     368             : 
     369           0 :     root->_setChild(!dir, _singleRotate(child, !dir));
     370           0 :     return _singleRotate(root, dir);
     371             :   }
     372             : 
     373             :   //! \}
     374             :   //! \endcond
     375             : };
     376             : 
     377             : //! \}
     378             : 
     379             : ASMJIT_END_NAMESPACE
     380             : 
     381             : #endif // ASMJIT_CORE_ZONETREE_H_INCLUDED
     382             : 
     383             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16