CCF
Loading...
Searching...
No Matches
rb_map.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
6
7#include <cassert>
8#include <memory>
9#include <optional>
10#include <stdexcept>
11
12namespace rb
13{
14 template <class K, class V>
15 class Snapshot;
16
17 template <class K, class V>
18 class Map
19 {
20 private:
21 enum Color
22 {
23 R,
24 B
25 };
26
27 struct Node
28 {
29 Node(
30 Color c,
31 const std::shared_ptr<const Node>& lft,
32 const K& key,
33 const V& val,
34 const std::shared_ptr<const Node>& rgt) :
35 _c(c),
36 _lft(lft),
37 _key(key),
38 _val(val),
39 _rgt(rgt)
40 {
41 total_size = 1;
42 total_serialized_size = map::get_serialized_size_with_padding(key) +
43 map::get_serialized_size_with_padding(val);
44 if (lft)
45 {
46 total_size += lft->size();
47 total_serialized_size += lft->serialized_size();
48 }
49 if (rgt)
50 {
51 total_size += rgt->size();
52 total_serialized_size += rgt->serialized_size();
53 }
54 }
55
56 Color _c;
57 std::shared_ptr<const Node> _lft;
58 K _key;
59 V _val;
60 std::shared_ptr<const Node> _rgt;
61 size_t total_size = 0;
62 size_t total_serialized_size = 0;
63
64 size_t size() const
65 {
66 return total_size;
67 }
68
69 size_t serialized_size() const
70 {
71 return total_serialized_size;
72 }
73 };
74
75 explicit Map(std::shared_ptr<const Node> const& node) : _root(node) {}
76
77 Map(
78 Color c,
79 const Map& lft,
80 const K& key,
81 const V& val,
82 const Map& rgt,
83 std::optional<size_t> size = std::nullopt) :
84 _root(std::make_shared<const Node>(c, lft._root, key, val, rgt._root))
85 {
86 assert(lft.empty() || lft.rootKey() < key);
87 assert(rgt.empty() || key < rgt.rootKey());
88 }
89
90 public:
91 using KeyType = K;
92 using ValueType = V;
94
95 Map() {}
96
97 bool empty() const
98 {
99 return !_root;
100 }
101
102 size_t size() const
103 {
104 return empty() ? 0 : _root->size();
105 }
106
107 size_t get_serialized_size() const
108 {
109 return empty() ? 0 : _root->serialized_size();
110 }
111
112 std::optional<V> get(const K& key) const
113 {
114 auto v = getp(key);
115
116 if (v)
117 return *v;
118 else
119 return {};
120 }
121
122 const V* getp(const K& key) const
123 {
124 if (empty())
125 return nullptr;
126
127 auto& y = rootKey();
128
129 if (key < y)
130 return left().getp(key);
131 else if (y < key)
132 return right().getp(key);
133 else
134 return &rootValue();
135 }
136
137 Map put(const K& key, const V& value) const
138 {
139 Map t = insert(key, value);
140 return Map(B, t.left(), t.rootKey(), t.rootValue(), t.right(), t.size());
141 }
142
143 // Return a red-black tree without this key present.
144 //
145 // Based on the Introduction to Algorithms CLRS implementation.
146 Map remove(const K& key) const
147 {
148 auto res = _remove(key);
149 if (res.second && res.first.rootColor() == R)
150 {
151 auto r = res.first;
152 res.first = Map(B, r.left(), r.rootKey(), r.rootValue(), r.right());
153 }
154 return res.first;
155 }
156
157 template <class F>
158 bool foreach(F&& f) const
159 {
160 if (!empty())
161 {
162 if (!left().foreach(std::forward<F>(f)))
163 {
164 return false;
165 }
166 if (!f(rootKey(), rootValue()))
167 {
168 return false;
169 }
170 if (!right().foreach(std::forward<F>(f)))
171 {
172 return false;
173 }
174 }
175 return true;
176 }
177
178 std::unique_ptr<Snapshot> make_snapshot() const
179 {
180 return std::make_unique<Snapshot>(*this);
181 }
182
183 private:
184 std::shared_ptr<const Node> _root;
185
186 Color rootColor() const
187 {
188 if (empty())
189 {
190 // empty nodes are black
191 return B;
192 }
193 else
194 {
195 return _root->_c;
196 }
197 }
198
199 const K& rootKey() const
200 {
201 return _root->_key;
202 }
203
204 const V& rootValue() const
205 {
206 return _root->_val;
207 }
208
209 Map left() const
210 {
211 return Map(_root->_lft);
212 }
213
214 Map right() const
215 {
216 return Map(_root->_rgt);
217 }
218
219 // Insert a new key and value pair.
220 Map insert(const K& x, const V& v) const
221 {
222 if (empty())
223 return Map(R, Map(), x, v, Map());
224
225 const K& y = rootKey();
226 const V& yv = rootValue();
227 Color c = rootColor();
228
229 if (rootColor() == B)
230 {
231 if (x < y)
232 return balance(left().insert(x, v), y, yv, right());
233 else if (y < x)
234 return balance(left(), y, yv, right().insert(x, v));
235 else
236 return Map(c, left(), y, v, right());
237 }
238 else
239 {
240 if (x < y)
241 return Map(c, left().insert(x, v), y, yv, right());
242 else if (y < x)
243 return Map(c, left(), y, yv, right().insert(x, v));
244 else
245 return Map(c, left(), y, v, right());
246 }
247 }
248
249 // Called only when parent is black
250 static Map balance(const Map& lft, const K& x, const V& v, const Map& rgt)
251 {
252 if (lft.doubledLeft())
253 return Map(
254 R,
255 lft.left().paint(B),
256 lft.rootKey(),
257 lft.rootValue(),
258 Map(B, lft.right(), x, v, rgt));
259 else if (lft.doubledRight())
260 return Map(
261 R,
262 Map(
263 B, lft.left(), lft.rootKey(), lft.rootValue(), lft.right().left()),
264 lft.right().rootKey(),
265 lft.right().rootValue(),
266 Map(B, lft.right().right(), x, v, rgt));
267 else if (rgt.doubledLeft())
268 return Map(
269 R,
270 Map(B, lft, x, v, rgt.left().left()),
271 rgt.left().rootKey(),
272 rgt.left().rootValue(),
273 Map(
274 B,
275 rgt.left().right(),
276 rgt.rootKey(),
277 rgt.rootValue(),
278 rgt.right()));
279 else if (rgt.doubledRight())
280 return Map(
281 R,
282 Map(B, lft, x, v, rgt.left()),
283 rgt.rootKey(),
284 rgt.rootValue(),
285 rgt.right().paint(B));
286 else
287 return Map(B, lft, x, v, rgt);
288 }
289
290 bool doubledLeft() const
291 {
292 return !empty() && rootColor() == R && !left().empty() &&
293 left().rootColor() == R;
294 }
295
296 bool doubledRight() const
297 {
298 return !empty() && rootColor() == R && !right().empty() &&
299 right().rootColor() == R;
300 }
301
302 Map paint(Color c) const
303 {
304 return Map(c, left(), rootKey(), rootValue(), right());
305 }
306
307 Map rotateRight() const
308 {
309 auto x = left();
310 auto y = Map(rootColor(), x.right(), rootKey(), rootValue(), right());
311 return Map(x.rootColor(), x.left(), x.rootKey(), x.rootValue(), y);
312 }
313
314 Map rotateLeft() const
315 {
316 auto y = right();
317 auto x = Map(rootColor(), left(), rootKey(), rootValue(), y.left());
318 return Map(y.rootColor(), x, y.rootKey(), y.rootValue(), y.right());
319 }
320
321 // Fix a double black for this node, generated from removal.
322 // The double black node is the left node of this one.
323 // Return whether the double black needs to be propagated up.
324 std::pair<Map, bool> fixDoubleBlackLeft() const
325 {
326 auto sibling = right();
327
328 auto root = Map(*this);
329
330 if (sibling.rootColor() == R)
331 {
332 // recolor root and sibling
333 root = Map(
334 R, root.left(), root.rootKey(), root.rootValue(), sibling.paint(B));
335 // rotate root left to make the sibling the root
336 root = root.rotateLeft();
337 // We've moved the double black node during the rotation so now we need
338 // to fix it recursively
339 auto fixedLeft = root.left().fixDoubleBlackLeft();
340 root = Map(
341 root.rootColor(),
342 fixedLeft.first,
343 root.rootKey(),
344 root.rootValue(),
345 root.right());
346 if (!fixedLeft.second)
347 {
348 // nothing left to fix
349 return std::make_pair(root, false);
350 }
351 // in fixing that we may have moved the double black to a child of this
352 // root, so fix that now
353 sibling = root.right();
354 }
355
356 auto doubleBlack = false;
357 if (sibling.left().rootColor() == B && sibling.right().rootColor() == B)
358 {
359 // current node is being made black, siblings children are both black so
360 // we can safely convert the sibling to red and propagate the double
361 // black
362 sibling = sibling.paint(R);
363 // we might still have to propagate the double black up
364 doubleBlack = root.rootColor() == B;
365 root = Map(B, root.left(), root.rootKey(), root.rootValue(), sibling);
366 }
367 else
368 {
369 if (sibling.right().rootColor() == B)
370 {
371 // root, sibling and sibling's right are all black
372 // rotate the right with the sibling as the root
373 auto siblingLeft = sibling.left().paint(B);
374 sibling = Map(
375 R,
376 siblingLeft,
377 sibling.rootKey(),
378 sibling.rootValue(),
379 sibling.right());
380 sibling = sibling.rotateRight();
381 root = Map(
382 root.rootColor(),
383 root.left(),
384 root.rootKey(),
385 root.rootValue(),
386 sibling);
387 }
388
389 auto recoloredSibling = Map(
390 root.rootColor(),
391 sibling.left(),
392 sibling.rootKey(),
393 sibling.rootValue(),
394 sibling.right().paint(B));
395 root = Map(
396 B, root.left(), root.rootKey(), root.rootValue(), recoloredSibling);
397 root = root.rotateLeft();
398 doubleBlack = false;
399 }
400 return std::make_pair(root, doubleBlack);
401 }
402
403 std::pair<Map, bool> fixDoubleBlackRight() const
404 {
405 auto sibling = left();
406
407 auto root = Map(*this);
408
409 if (sibling.rootColor() == R)
410 {
411 // recolor root and sibling
412 root = Map(
413 R, sibling.paint(B), root.rootKey(), root.rootValue(), root.right());
414 // rotate root left to make the sibling the root
415 root = root.rotateRight();
416 // We've moved the double black node during the rotation so now we need
417 // to fix it recursively
418 auto fixedRight = root.right().fixDoubleBlackRight();
419 root = Map(
420 root.rootColor(),
421 root.left(),
422 root.rootKey(),
423 root.rootValue(),
424 fixedRight.first);
425 if (!fixedRight.second)
426 {
427 // nothing left to fix
428 return std::make_pair(root, false);
429 }
430 // in fixing that we may have moved the double black to a child of this
431 // root, so fix that now
432 sibling = root.left();
433 }
434
435 auto doubleBlack = false;
436 if (sibling.left().rootColor() == B && sibling.right().rootColor() == B)
437 {
438 // current node is being made black, siblings children are both black so
439 // we can safely convert the sibling to red and propagate the double
440 // black
441 sibling = sibling.paint(R);
442 // we might still have to propagate the double black up
443 doubleBlack = root.rootColor() == B;
444 root = Map(B, sibling, root.rootKey(), root.rootValue(), root.right());
445 }
446 else
447 {
448 if (sibling.left().rootColor() == B)
449 {
450 // root, sibling and sibling's left are all black
451 // rotate the right with the sibling as the root
452 auto siblingRight = sibling.right().paint(B);
453 sibling = Map(
454 R,
455 sibling.left(),
456 sibling.rootKey(),
457 sibling.rootValue(),
458 siblingRight);
459 sibling = sibling.rotateLeft();
460 root = Map(
461 root.rootColor(),
462 sibling,
463 root.rootKey(),
464 root.rootValue(),
465 root.right());
466 }
467
468 auto recoloredSibling = Map(
469 root.rootColor(),
470 sibling.left().paint(B),
471 sibling.rootKey(),
472 sibling.rootValue(),
473 sibling.right());
474 root = Map(
475 B, recoloredSibling, root.rootKey(), root.rootValue(), root.right());
476 root = root.rotateRight();
477 doubleBlack = false;
478 }
479 return std::make_pair(root, doubleBlack);
480 }
481
482 // Remove the node with the given key.
483 // returns a new map along with a bool indicating whether we need to handle
484 // a double black.
485 std::pair<Map, bool> _remove(const K& key) const
486 {
487 if (empty())
488 {
489 // key not present in the tree, can't remove it so just return an empty
490 // map.
491 return std::make_pair(Map(), false);
492 }
493
494 const K& rootk = rootKey();
495
496 if (key < rootk)
497 {
498 // remove key from the left subtree
499 auto left_without = left()._remove(key);
500 // copy the left into a new map to return
501 auto newMap =
502 Map(rootColor(), left_without.first, rootKey(), rootValue(), right());
503 if (left_without.second)
504 {
505 // there is a double black node in the left subtree so fix it up
506 return newMap.fixDoubleBlackLeft();
507 }
508 // no double blacks are present
509 return std::make_pair(newMap, false);
510 }
511 else if (rootk < key)
512 {
513 // mirror of the above case
514 auto right_without = right()._remove(key);
515 auto newMap =
516 Map(rootColor(), left(), rootKey(), rootValue(), right_without.first);
517 if (right_without.second)
518 {
519 return newMap.fixDoubleBlackRight();
520 }
521 return std::make_pair(newMap, false);
522 }
523 else if (key == rootk)
524 {
525 // delete key from this node
526 if (left().empty() && right().empty())
527 {
528 // leaf node, a simple case
529 auto doubleBlack = rootColor() == B;
530 return std::make_pair(Map(), doubleBlack);
531 }
532 else if (left().empty())
533 {
534 // nothing on the left so we can replace this node with the right
535 // child
536 auto r = right();
537 // Exactly one of the node being removed and the right node are black:
538 // - the left is empty so has a black height of 1
539 // - the right must also have a black height of 1 to maintain the
540 // height but it is not empty or we would have hit the above if
541 // statement
542 // - therefore the right node is red.
543 assert(r.left().empty());
544 assert(r.right().empty());
545 assert(r.rootColor() == R);
546 return std::make_pair(r.paint(B), false);
547 }
548 else if (right().empty())
549 {
550 // mirror of the above case
551 auto l = left();
552 assert(l.left().empty());
553 assert(l.right().empty());
554 assert(l.rootColor() == R);
555 return std::make_pair(l.paint(B), false);
556 }
557 else
558 {
559 // both children are non-empty, swap this node's key and value with
560 // the successor and then delete the successor
561 auto successor = right().minimum();
562 auto right_without = right()._remove(successor.first);
563 auto newMap = Map(
564 rootColor(),
565 left(),
566 successor.first,
567 successor.second,
568 right_without.first);
569 if (right_without.second)
570 {
571 return newMap.fixDoubleBlackRight();
572 }
573 return std::make_pair(newMap, false);
574 }
575 }
576 else
577 {
578 // key not found in the tree
579 return std::make_pair(Map(*this), false);
580 }
581 }
582
583 // Return the minimum key in this map along with its value.
584 std::pair<K, V> minimum() const
585 {
586 assert(!empty());
587
588 if (left().empty())
589 {
590 return std::make_pair(rootKey(), rootValue());
591 }
592 else
593 {
594 return left().minimum();
595 }
596 }
597
598#ifndef NDEBUG
599 // Check properties of the tree
600 void check() const
601 {
602 size_t totalBlackCount = 0;
603 _check(0, totalBlackCount);
604 }
605#endif
606
607#ifndef NDEBUG
608 // Print an s-expression style representation of the tree's colors
609 std::string to_str() const
610 {
611 auto ss = std::stringstream();
612 if (empty())
613 {
614 ss << "B";
615 return ss.str();
616 }
617 auto color = rootColor() == B ? "B" : "R";
618 ss << "(" << color << " " << left().to_str() << right().to_str() << ")";
619 return ss.str();
620 }
621#endif
622
623#ifndef NDEBUG
624 void _check(size_t blackCount, size_t& totalBlackCount) const
625 {
626 if (empty())
627 {
628 totalBlackCount = blackCount + 1;
629 return;
630 }
631
632 if (rootColor() == R)
633 {
634 if (!left().empty() && left().rootColor() == R)
635 {
636 throw std::logic_error("rb::Map::check(): Double red node found");
637 }
638 if (!right().empty() && right().rootColor() == R)
639 {
640 throw std::logic_error("rb::Map::check(): Double red node found");
641 }
642 }
643 size_t leftBlackCount = 0;
644 size_t rightBlackCount = 0;
645 left()._check(blackCount + (rootColor() == B ? 1 : 0), leftBlackCount);
646 right()._check(blackCount + (rootColor() == B ? 1 : 0), rightBlackCount);
647
648 if (leftBlackCount != rightBlackCount)
649 {
650 std::cout << to_str() << std::endl;
651 throw std::logic_error(fmt::format(
652 "rb::Map::check(): black counts didn't match between left and right "
653 "{} {}",
654 leftBlackCount,
655 rightBlackCount));
656 }
657
658 totalBlackCount = leftBlackCount + (rootColor() == B ? 1 : 0);
659 }
660#endif
661 };
662
663 template <class K, class V>
665 {
666 private:
667 const Map<K, V> map;
668
669 public:
670 Snapshot(const Map<K, V>& map_) : map(map_) {}
671
673 {
674 return map.get_serialized_size();
675 }
676
677 void serialize(uint8_t* data)
678 {
679 size_t size = map.get_serialized_size();
680
681 map.foreach([&data, &size](const K& k, const V& v) {
682 // Serialize the key
683 uint32_t key_size = map::serialize(k, data, size);
684 map::add_padding(key_size, data, size);
685
686 // Serialize the value
687 uint32_t value_size = map::serialize(v, data, size);
688 map::add_padding(value_size, data, size);
689 return true;
690 });
691
692 CCF_ASSERT_FMT(size == 0, "buffer not filled, remaining:{}", size);
693 }
694 };
695}
#define CCF_ASSERT_FMT(expr,...)
Definition ccf_assert.h:10
Definition rb_map.h:19
Map put(const K &key, const V &value) const
Definition rb_map.h:137
Map remove(const K &key) const
Definition rb_map.h:146
std::optional< V > get(const K &key) const
Definition rb_map.h:112
const V * getp(const K &key) const
Definition rb_map.h:122
size_t get_serialized_size() const
Definition rb_map.h:107
bool empty() const
Definition rb_map.h:97
size_t size() const
Definition rb_map.h:102
Snapshot< K, V > Snapshot
Definition rb_map.h:93
Map()
Definition rb_map.h:95
K KeyType
Definition rb_map.h:91
std::unique_ptr< Snapshot > make_snapshot() const
Definition rb_map.h:178
V ValueType
Definition rb_map.h:92
Definition rb_map.h:665
Snapshot(const Map< K, V > &map_)
Definition rb_map.h:670
void serialize(uint8_t *data)
Definition rb_map.h:677
size_t get_serialized_size()
Definition rb_map.h:672
SerialisedEntry K
Definition untyped_change_set.h:22
SerialisedEntry V
Definition untyped_change_set.h:23
Definition map_serializers.h:11
size_t serialize(const T &t, uint8_t *&data, size_t &size)
Definition map_serializers.h:48
Definition rb_map.h:13