3535// An intrusive red-black tree is constructed with two template parameters:
3636// K is the key type used.
3737// COMPARATOR must have a static function `cmp(K a, const IntrusiveRBNode* b)` which returns:
38- // - an int < 0 when a < b
39- // - an int == 0 when a == b
40- // - an int > 0 when a > b
41- // Additional static functions used for extra validation can optionally be provided:
42- // `cmp(K a, K b)` which returns:
43- // - an int < 0 when a < b
44- // - an int == 0 when a == b
45- // - an int > 0 when a > b
46- // `cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b)` which returns:
47- // - true if a < b
48- // - false otherwise
38+ // - RBTreeOrdering::less when a < b
39+ // - RBTreeOrdering::equal when a == b
40+ // - RBTreeOrdering::greater when a > b
41+ // A second static function `less(const IntrusiveRBNode* a, const IntrusiveRBNode* b)`
42+ // used for extra validation can optionally be provided. This should return:
43+ // - true if a < b
44+ // - false otherwise
4945// K needs to be of a type that is trivially destructible.
5046// K needs to be stored by the user and is not stored inside the tree.
5147// Nodes are address stable and will not change during its lifetime.
5450// K is the key type stored in the tree nodes.
5551// V is the value type stored in the tree nodes.
5652// COMPARATOR must have a static function `cmp(K a, K b)` which returns:
57- // - an int < 0 when a < b
58- // - an int == 0 when a == b
59- // - an int > 0 when a > b
60- // A second static function `cmp (const RBNode<K, V>* a, const RBNode<K, V>* b)`
53+ // - RBTreeOrdering::less when a < b
54+ // - RBTreeOrdering::equal when a == b
55+ // - RBTreeOrdering::greater when a > b
56+ // A second static function `less (const RBNode<K, V>* a, const RBNode<K, V>* b)`
6157// used for extra validation can optionally be provided. This should return:
6258// - true if a < b
6359// - false otherwise
6662// The tree will call a value's destructor when its node is removed.
6763// Nodes are address stable and will not change during its lifetime.
6864
65+ enum class RBTreeOrdering : int { less = -1 , equal = 0 , greater = 1 };
66+
6967template <typename K, typename NodeType, typename COMPARATOR>
7068class AbstractRBTree ;
7169
@@ -127,10 +125,11 @@ class IntrusiveRBNode {
127125 // Returns left child (now parent)
128126 IntrusiveRBNode* rotate_right ();
129127
130- template <typename NodeType, typename NodeVerifier>
128+ template <typename NodeType, typename NodeVerifier, typename USER_VERIFIER >
131129 void verify (size_t & num_nodes, size_t & black_nodes_until_leaf,
132130 size_t & shortest_leaf_path, size_t & longest_leaf_path,
133- size_t & tree_depth, bool expect_visited, NodeVerifier verifier) const ;
131+ size_t & tree_depth, bool expect_visited, NodeVerifier verifier,
132+ const USER_VERIFIER& extra_verifier) const ;
134133
135134};
136135
@@ -204,32 +203,37 @@ class AbstractRBTree {
204203 struct has_cmp_type <CMP, RET, ARG1, ARG2, decltype (static_cast <RET(*)(ARG1, ARG2)>(CMP::cmp), void ())> : std::true_type {};
205204
206205 template <typename CMP>
207- static constexpr bool HasKeyComparator = has_cmp_type<CMP, int , K, K>::value;
206+ static constexpr bool HasKeyComparator = has_cmp_type<CMP, RBTreeOrdering , K, K>::value;
208207
209208 template <typename CMP>
210- static constexpr bool HasNodeComparator = has_cmp_type<CMP, int , K, const NodeType*>::value;
209+ static constexpr bool HasNodeComparator = has_cmp_type<CMP, RBTreeOrdering, K, const NodeType*>::value;
210+
211+ template <typename CMP, typename RET, typename ARG1, typename ARG2, typename = void >
212+ struct has_less_type : std::false_type {};
213+ template <typename CMP, typename RET, typename ARG1, typename ARG2>
214+ struct has_less_type <CMP, RET, ARG1, ARG2, decltype (static_cast <RET(*)(ARG1, ARG2)>(CMP::less), void ())> : std::true_type {};
211215
212216 template <typename CMP>
213- static constexpr bool HasNodeVerifier = has_cmp_type <CMP, bool , const NodeType*, const NodeType*>::value;
217+ static constexpr bool HasNodeVerifier = has_less_type <CMP, bool , const NodeType*, const NodeType*>::value;
214218
215219 template <typename CMP = COMPARATOR, ENABLE_IF(HasKeyComparator<CMP> && !HasNodeComparator<CMP>)>
216- int cmp (const K& a, const NodeType* b) const {
220+ RBTreeOrdering cmp (const K& a, const NodeType* b) const {
217221 return COMPARATOR::cmp (a, b->key ());
218222 }
219223
220224 template <typename CMP = COMPARATOR, ENABLE_IF(HasNodeComparator<CMP>)>
221- int cmp (const K& a, const NodeType* b) const {
225+ RBTreeOrdering cmp (const K& a, const NodeType* b) const {
222226 return COMPARATOR::cmp (a, b);
223227 }
224228
225229 template <typename CMP = COMPARATOR, ENABLE_IF(!HasNodeVerifier<CMP>)>
226- bool cmp (const NodeType* a, const NodeType* b) const {
230+ bool less (const NodeType* a, const NodeType* b) const {
227231 return true ;
228232 }
229233
230234 template <typename CMP = COMPARATOR, ENABLE_IF(HasNodeVerifier<CMP>)>
231- bool cmp (const NodeType* a, const NodeType* b) const {
232- return COMPARATOR::cmp (a, b);
235+ bool less (const NodeType* a, const NodeType* b) const {
236+ return COMPARATOR::less (a, b);
233237 }
234238
235239 // Cannot assert if no key comparator exist.
@@ -238,7 +242,7 @@ class AbstractRBTree {
238242
239243 template <typename CMP = COMPARATOR, ENABLE_IF(HasKeyComparator<CMP>)>
240244 void assert_key_leq (K a, K b) const {
241- assert (COMPARATOR::cmp (a, b) <= 0 , " key a must be less or equal to key b" );
245+ assert (COMPARATOR::cmp (a, b) != RBTreeOrdering::greater , " key a must be less or equal to key b" );
242246 }
243247
244248 // True if node is black (nil nodes count as black)
@@ -257,10 +261,23 @@ class AbstractRBTree {
257261 // Assumption: node has at most one child. Two children is handled in `remove_at_cursor()`
258262 void remove_from_tree (IntrusiveRBNode* node);
259263
260- template <typename NodeVerifier>
261- void verify_self (NodeVerifier verifier) const ;
264+ struct empty_verifier {
265+ bool operator ()(const NodeType* n) const {
266+ return true ;
267+ }
268+ };
262269
263- void print_node_on (outputStream* st, int depth, const NodeType* n) const ;
270+ template <typename NodeVerifier, typename USER_VERIFIER>
271+ void verify_self (NodeVerifier verifier, const USER_VERIFIER& extra_verifier) const ;
272+
273+ struct default_printer {
274+ void operator ()(outputStream* st, const NodeType* n, int depth) const {
275+ n->print_on (st, depth);
276+ }
277+ };
278+
279+ template <typename PRINTER>
280+ void print_node_on (outputStream* st, int depth, const NodeType* n, const PRINTER& node_printer) const ;
264281
265282public:
266283 NONCOPYABLE (AbstractRBTree);
@@ -423,22 +440,30 @@ class AbstractRBTree {
423440 // Verifies that the tree is correct and holds rb-properties
424441 // If not using a key comparator (when using IntrusiveRBTree for example),
425442 // A second `cmp` must exist in COMPARATOR (see top of file).
426- template <typename CMP = COMPARATOR, ENABLE_IF(HasNodeVerifier<CMP>)>
427- void verify_self () const {
428- verify_self ([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp (a, b);});
443+ // Accepts an optional callable `bool extra_verifier(const Node* n)`.
444+ // This should return true if the node is valid.
445+ // If provided, each node is also verified through this callable.
446+ template <typename USER_VERIFIER = empty_verifier, typename CMP = COMPARATOR, ENABLE_IF(HasNodeVerifier<CMP>)>
447+ void verify_self (const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const {
448+ verify_self ([](const NodeType* a, const NodeType* b){ return COMPARATOR::less (a, b);}, extra_verifier);
429449 }
430450
431- template <typename CMP = COMPARATOR, ENABLE_IF(HasKeyComparator<CMP> && !HasNodeVerifier<CMP>)>
432- void verify_self () const {
433- verify_self ([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp (a->key (), b->key ()) < 0 ; });
451+ template <typename USER_VERIFIER = empty_verifier, typename CMP = COMPARATOR,
452+ ENABLE_IF (HasKeyComparator<CMP> && !HasNodeVerifier<CMP>)>
453+ void verify_self(const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const {
454+ verify_self ([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp (a->key (), b->key ()) == RBTreeOrdering::less; }, extra_verifier);
434455 }
435456
436- template <typename CMP = COMPARATOR, ENABLE_IF(HasNodeComparator<CMP> && !HasKeyComparator<CMP> && !HasNodeVerifier<CMP>)>
437- void verify_self () const {
438- verify_self ([](const NodeType*, const NodeType*){ return true ;});
457+ template <typename USER_VERIFIER = empty_verifier, typename CMP = COMPARATOR,
458+ ENABLE_IF (HasNodeComparator<CMP> && !HasKeyComparator<CMP> && !HasNodeVerifier<CMP>)>
459+ void verify_self(const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const {
460+ verify_self ([](const NodeType*, const NodeType*){ return true ;}, extra_verifier);
439461 }
440462
441- void print_on (outputStream* st) const ;
463+ // Accepts an optional printing callable `void node_printer(outputStream* st, const Node* n, int depth)`.
464+ // If provided, each node is printed through this callable rather than the default `print_on`.
465+ template <typename PRINTER = default_printer>
466+ void print_on (outputStream* st, const PRINTER& node_printer = PRINTER()) const ;
442467
443468};
444469
0 commit comments