1 // Copyright (c) 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef LIBSPIRV_UTIL_MOVE_TO_FRONT_H_
16 #define LIBSPIRV_UTIL_MOVE_TO_FRONT_H_
17
18 #include <algorithm>
19 #include <cassert>
20 #include <cstdint>
21 #include <iomanip>
22 #include <iostream>
23 #include <ostream>
24 #include <sstream>
25 #include <unordered_map>
26 #include <unordered_set>
27 #include <vector>
28
29 namespace spvutils {
30
31 // Log(n) move-to-front implementation. Implements the following functions:
32 // Insert - pushes value to the front of the mtf sequence
33 // (only unique values allowed).
34 // Remove - remove value from the sequence.
35 // ValueFromRank - access value by its 1-indexed rank in the sequence.
36 // RankFromValue - get the rank of the given value in the sequence.
37 // Accessing a value with ValueFromRank or RankFromValue moves the value to the
38 // front of the sequence (rank of 1).
39 //
40 // The implementation is based on an AVL-based order statistic tree. The tree
41 // is ordered by timestamps issued when values are inserted or accessed (recent
42 // values go to the left side of the tree, old values are gradually rotated to
43 // the right side).
44 //
45 // Terminology
46 // rank: 1-indexed rank showing how recently the value was inserted or accessed.
47 // node: handle used internally to access node data.
48 // size: size of the subtree of a node (including the node).
49 // height: distance from a node to the farthest leaf.
50 template <typename Val>
51 class MoveToFront {
52 public:
53 explicit MoveToFront(size_t reserve_capacity = 128) {
54 nodes_.reserve(reserve_capacity);
55
56 // Create NIL node.
57 nodes_.emplace_back(Node());
58 }
59
~MoveToFront()60 virtual ~MoveToFront() {}
61
62 // Inserts value in the move-to-front sequence. Does nothing if the value is
63 // already in the sequence. Returns true if insertion was successful.
64 // The inserted value is placed at the front of the sequence (rank 1).
65 bool Insert(const Val& value);
66
67 // Removes value from move-to-front sequence. Returns false iff the value
68 // was not found.
69 bool Remove(const Val& value);
70
71 // Computes 1-indexed rank of value in the move-to-front sequence and moves
72 // the value to the front. Example:
73 // Before the call: 4 8 2 1 7
74 // RankFromValue(8) returns 1
75 // After the call: 8 4 2 1 7
76 // Returns true iff the value was found in the sequence.
77 bool RankFromValue(const Val& value, size_t* rank);
78
79 // Returns value corresponding to a 1-indexed rank in the move-to-front
80 // sequence and moves the value to the front. Example:
81 // Before the call: 4 8 2 1 7
82 // ValueFromRank(1) returns 8
83 // After the call: 8 4 2 1 7
84 // Returns true iff the rank is within bounds [1, GetSize()].
85 bool ValueFromRank(size_t rank, Val* value);
86
87 // Returns the number of elements in the move-to-front sequence.
GetSize()88 size_t GetSize() const {
89 return SizeOf(root_);
90 }
91
92 protected:
93 // Internal tree data structure uses handles instead of pointers. Leaves and
94 // root parent reference a singleton under handle 0. Although dereferencing
95 // a null pointer is not possible, inappropriate access to handle 0 would
96 // cause an assertion. Handles are not garbage collected if value was deprecated
97 // with DeprecateValue(). But handles are recycled when a node is repositioned.
98
99 // Internal tree data structure node.
100 struct Node {
101 // Timestamp from a logical clock which updates every time the element is
102 // accessed through ValueFromRank or RankFromValue.
103 uint32_t timestamp = 0;
104 // The size of the node's subtree, including the node.
105 // SizeOf(LeftOf(node)) + SizeOf(RightOf(node)) + 1.
106 uint32_t size = 0;
107 // Handles to connected nodes.
108 uint32_t left = 0;
109 uint32_t right = 0;
110 uint32_t parent = 0;
111 // Distance to the farthest leaf.
112 // Leaves have height 0, real nodes at least 1.
113 uint32_t height = 0;
114 // Stored value.
115 Val value = Val();
116 };
117
118 // Creates node and sets correct values. Non-NIL nodes should be created only
119 // through this function. If the node with this value has been created previously
120 // and since orphaned, reuses the old node instead of creating a new one.
CreateNode(uint32_t timestamp,const Val & value)121 uint32_t CreateNode(uint32_t timestamp, const Val& value) {
122 uint32_t handle = static_cast<uint32_t>(nodes_.size());
123 const auto result = value_to_node_.emplace(value, handle);
124 if (result.second) {
125 // Create new node.
126 nodes_.emplace_back(Node());
127 Node& node = nodes_.back();
128 node.timestamp = timestamp;
129 node.value = value;
130 node.size = 1;
131 // Non-NIL nodes start with height 1 because their NIL children are leaves.
132 node.height = 1;
133 } else {
134 // Reuse old node.
135 handle = result.first->second;
136 assert(!IsInTree(handle));
137 assert(ValueOf(handle) == value);
138 assert(SizeOf(handle) == 1);
139 assert(HeightOf(handle) == 1);
140 MutableTimestampOf(handle) = timestamp;
141 }
142
143 return handle;
144 }
145
146 // Node accessor methods. Naming is designed to be similar to natural
147 // language as these functions tend to be used in sequences, for example:
148 // ParentOf(LeftestDescendentOf(RightOf(node)))
149
150 // Returns value of the node referenced by |handle|.
ValueOf(uint32_t node)151 Val ValueOf(uint32_t node) const {
152 return nodes_.at(node).value;
153 }
154
155 // Returns left child of |node|.
LeftOf(uint32_t node)156 uint32_t LeftOf(uint32_t node) const {
157 return nodes_.at(node).left;
158 }
159
160 // Returns right child of |node|.
RightOf(uint32_t node)161 uint32_t RightOf(uint32_t node) const {
162 return nodes_.at(node).right;
163 }
164
165 // Returns parent of |node|.
ParentOf(uint32_t node)166 uint32_t ParentOf(uint32_t node) const {
167 return nodes_.at(node).parent;
168 }
169
170 // Returns timestamp of |node|.
TimestampOf(uint32_t node)171 uint32_t TimestampOf(uint32_t node) const {
172 assert(node);
173 return nodes_.at(node).timestamp;
174 }
175
176 // Returns size of |node|.
SizeOf(uint32_t node)177 uint32_t SizeOf(uint32_t node) const {
178 return nodes_.at(node).size;
179 }
180
181 // Returns height of |node|.
HeightOf(uint32_t node)182 uint32_t HeightOf(uint32_t node) const {
183 return nodes_.at(node).height;
184 }
185
186 // Returns mutable reference to value of |node|.
MutableValueOf(uint32_t node)187 Val& MutableValueOf(uint32_t node) {
188 assert(node);
189 return nodes_.at(node).value;
190 }
191
192 // Returns mutable reference to handle of left child of |node|.
MutableLeftOf(uint32_t node)193 uint32_t& MutableLeftOf(uint32_t node) {
194 assert(node);
195 return nodes_.at(node).left;
196 }
197
198 // Returns mutable reference to handle of right child of |node|.
MutableRightOf(uint32_t node)199 uint32_t& MutableRightOf(uint32_t node) {
200 assert(node);
201 return nodes_.at(node).right;
202 }
203
204 // Returns mutable reference to handle of parent of |node|.
MutableParentOf(uint32_t node)205 uint32_t& MutableParentOf(uint32_t node) {
206 assert(node);
207 return nodes_.at(node).parent;
208 }
209
210 // Returns mutable reference to timestamp of |node|.
MutableTimestampOf(uint32_t node)211 uint32_t& MutableTimestampOf(uint32_t node) {
212 assert(node);
213 return nodes_.at(node).timestamp;
214 }
215
216 // Returns mutable reference to size of |node|.
MutableSizeOf(uint32_t node)217 uint32_t& MutableSizeOf(uint32_t node) {
218 assert(node);
219 return nodes_.at(node).size;
220 }
221
222 // Returns mutable reference to height of |node|.
MutableHeightOf(uint32_t node)223 uint32_t& MutableHeightOf(uint32_t node) {
224 assert(node);
225 return nodes_.at(node).height;
226 }
227
228 // Returns true iff |node| is left child of its parent.
IsLeftChild(uint32_t node)229 bool IsLeftChild(uint32_t node) const {
230 assert(node);
231 return LeftOf(ParentOf(node)) == node;
232 }
233
234 // Returns true iff |node| is right child of its parent.
IsRightChild(uint32_t node)235 bool IsRightChild(uint32_t node) const {
236 assert(node);
237 return RightOf(ParentOf(node)) == node;
238 }
239
240 // Returns true iff |node| has no relatives.
IsOrphan(uint32_t node)241 bool IsOrphan(uint32_t node) const {
242 assert(node);
243 return !ParentOf(node) && !LeftOf(node) && !RightOf(node);
244 }
245
246 // Returns true iff |node| is in the tree.
IsInTree(uint32_t node)247 bool IsInTree(uint32_t node) const {
248 assert(node);
249 return node == root_ || !IsOrphan(node);
250 }
251
252 // Returns the height difference between right and left subtrees.
BalanceOf(uint32_t node)253 int BalanceOf(uint32_t node) const {
254 return int(HeightOf(RightOf(node))) - int(HeightOf(LeftOf(node)));
255 }
256
257 // Updates size and height of the node, assuming that the children have
258 // correct values.
259 void UpdateNode(uint32_t node);
260
261 // Returns the most LeftOf(LeftOf(... descendent which is not leaf.
LeftestDescendantOf(uint32_t node)262 uint32_t LeftestDescendantOf(uint32_t node) const {
263 uint32_t parent = 0;
264 while (node) {
265 parent = node;
266 node = LeftOf(node);
267 }
268 return parent;
269 }
270
271 // Returns the most RightOf(RightOf(... descendent which is not leaf.
RightestDescendantOf(uint32_t node)272 uint32_t RightestDescendantOf(uint32_t node) const {
273 uint32_t parent = 0;
274 while (node) {
275 parent = node;
276 node = RightOf(node);
277 }
278 return parent;
279 }
280
281 // Inserts node in the tree. The node must be an orphan.
282 void InsertNode(uint32_t node);
283
284 // Removes node from the tree. May change value_to_node_ if removal uses a
285 // scapegoat. Returns the removed (orphaned) handle for recycling. The
286 // returned handle may not be equal to |node| if scapegoat was used.
287 uint32_t RemoveNode(uint32_t node);
288
289 // Rotates |node| left, reassigns all connections and returns the node
290 // which takes place of the |node|.
291 uint32_t RotateLeft(const uint32_t node);
292
293 // Rotates |node| right, reassigns all connections and returns the node
294 // which takes place of the |node|.
295 uint32_t RotateRight(const uint32_t node);
296
297 // Root node handle. The tree is empty if root_ is 0.
298 uint32_t root_ = 0;
299
300 // Incremented counters for next timestamp and value.
301 uint32_t next_timestamp_ = 1;
302
303 // Holds all tree nodes. Indices of this vector are node handles.
304 std::vector<Node> nodes_;
305
306 // Maps ids to node handles.
307 std::unordered_map<Val, uint32_t> value_to_node_;
308 };
309
310 template <typename Val>
Insert(const Val & value)311 bool MoveToFront<Val>::Insert(const Val& value) {
312 auto it = value_to_node_.find(value);
313 if (it != value_to_node_.end() && IsInTree(it->second))
314 return false;
315
316 const size_t old_size = GetSize();
317 (void)old_size;
318
319 InsertNode(CreateNode(next_timestamp_++, value));
320
321 assert(value_to_node_.count(value));
322 assert(old_size + 1 == GetSize());
323 return true;
324 }
325
326 template <typename Val>
Remove(const Val & value)327 bool MoveToFront<Val>::Remove(const Val& value) {
328 auto it = value_to_node_.find(value);
329 if (it == value_to_node_.end())
330 return false;
331
332 if (!IsInTree(it->second))
333 return false;
334
335 const uint32_t orphan = RemoveNode(it->second);
336 (void)orphan;
337 // The node of |value| is still alive but it's orphaned now. Can still be
338 // reused later.
339 assert(!IsInTree(orphan));
340 assert(ValueOf(orphan) == value);
341 return true;
342 }
343
344 template <typename Val>
RankFromValue(const Val & value,size_t * rank)345 bool MoveToFront<Val>::RankFromValue(const Val& value, size_t* rank) {
346 const size_t old_size = GetSize();
347 (void)old_size;
348 const auto it = value_to_node_.find(value);
349 if (it == value_to_node_.end()) {
350 return false;
351 }
352
353 uint32_t target = it->second;
354
355 if (!IsInTree(target)) {
356 return false;
357 }
358
359 uint32_t node = target;
360 *rank = 1 + SizeOf(LeftOf(node));
361 while (node) {
362 if (IsRightChild(node))
363 *rank += 1 + SizeOf(LeftOf(ParentOf(node)));
364 node = ParentOf(node);
365 }
366
367 // Update timestamp and reposition the node.
368 target = RemoveNode(target);
369 assert(ValueOf(target) == value);
370 assert(old_size == GetSize() + 1);
371 MutableTimestampOf(target) = next_timestamp_++;
372 InsertNode(target);
373 assert(old_size == GetSize());
374 return true;
375 }
376
377 template <typename Val>
ValueFromRank(size_t rank,Val * value)378 bool MoveToFront<Val>::ValueFromRank(size_t rank, Val* value) {
379 const size_t old_size = GetSize();
380 if (rank <= 0 || rank > old_size) {
381 return false;
382 }
383
384 uint32_t node = root_;
385 while (node) {
386 const size_t left_subtree_num_nodes = SizeOf(LeftOf(node));
387 if (rank == left_subtree_num_nodes + 1) {
388 // This is the node we are looking for.
389 node = RemoveNode(node);
390 assert(old_size == GetSize() + 1);
391 MutableTimestampOf(node) = next_timestamp_++;
392 InsertNode(node);
393 assert(old_size == GetSize());
394 *value = ValueOf(node);
395 return true;
396 }
397
398 if (rank < left_subtree_num_nodes + 1) {
399 // Descend into the left subtree. The rank is still valid.
400 node = LeftOf(node);
401 } else {
402 // Descend into the right subtree. We leave behind the left subtree and
403 // the current node, adjust the |rank| accordingly.
404 rank -= left_subtree_num_nodes + 1;
405 node = RightOf(node);
406 }
407 }
408
409 assert(0);
410 return false;
411 }
412
413 template <typename Val>
InsertNode(uint32_t node)414 void MoveToFront<Val>::InsertNode(uint32_t node) {
415 assert(!IsInTree(node));
416 assert(SizeOf(node) == 1);
417 assert(HeightOf(node) == 1);
418 assert(TimestampOf(node));
419
420 if (!root_) {
421 root_ = node;
422 return;
423 }
424
425 uint32_t iter = root_;
426 uint32_t parent = 0;
427
428 // Will determine if |node| will become the right or left child after
429 // insertion (but before balancing).
430 bool right_child;
431
432 // Find the node which will become |node|'s parent after insertion
433 // (but before balancing).
434 while (iter) {
435 parent = iter;
436 assert(TimestampOf(iter) != TimestampOf(node));
437 right_child = TimestampOf(iter) > TimestampOf(node);
438 iter = right_child ? RightOf(iter) : LeftOf(iter);
439 }
440
441 assert(parent);
442
443 // Connect node and parent.
444 MutableParentOf(node) = parent;
445 if (right_child)
446 MutableRightOf(parent) = node;
447 else
448 MutableLeftOf(parent) = node;
449
450 // Insertion is finished. Start the balancing process.
451 bool needs_rebalancing = true;
452 parent = ParentOf(node);
453
454 while (parent) {
455 UpdateNode(parent);
456
457 if (needs_rebalancing) {
458 const int parent_balance = BalanceOf(parent);
459
460 if (RightOf(parent) == node) {
461 // Added node to the right subtree.
462 if (parent_balance > 1) {
463 // Parent is right heavy, rotate left.
464 if (BalanceOf(node) < 0)
465 RotateRight(node);
466 parent = RotateLeft(parent);
467 } else if (parent_balance == 0 || parent_balance == -1) {
468 // Parent is balanced or left heavy, no need to balance further.
469 needs_rebalancing = false;
470 }
471 } else {
472 // Added node to the left subtree.
473 if (parent_balance < -1) {
474 // Parent is left heavy, rotate right.
475 if (BalanceOf(node) > 0)
476 RotateLeft(node);
477 parent = RotateRight(parent);
478 } else if (parent_balance == 0 || parent_balance == 1) {
479 // Parent is balanced or right heavy, no need to balance further.
480 needs_rebalancing = false;
481 }
482 }
483 }
484
485 assert(BalanceOf(parent) >= -1 && (BalanceOf(parent) <= 1));
486
487 node = parent;
488 parent = ParentOf(parent);
489 }
490 }
491
492 template <typename Val>
RemoveNode(uint32_t node)493 uint32_t MoveToFront<Val>::RemoveNode(uint32_t node) {
494 if (LeftOf(node) && RightOf(node)) {
495 // If |node| has two children, then use another node as scapegoat and swap
496 // their contents. We pick the scapegoat on the side of the tree which has more nodes.
497 const uint32_t scapegoat = SizeOf(LeftOf(node)) >= SizeOf(RightOf(node)) ?
498 RightestDescendantOf(LeftOf(node)) : LeftestDescendantOf(RightOf(node));
499 assert(scapegoat);
500 std::swap(MutableValueOf(node), MutableValueOf(scapegoat));
501 std::swap(MutableTimestampOf(node), MutableTimestampOf(scapegoat));
502 value_to_node_[ValueOf(node)] = node;
503 value_to_node_[ValueOf(scapegoat)] = scapegoat;
504 node = scapegoat;
505 }
506
507 // |node| may have only one child at this point.
508 assert(!RightOf(node) || !LeftOf(node));
509
510 uint32_t parent = ParentOf(node);
511 uint32_t child = RightOf(node) ? RightOf(node) : LeftOf(node);
512
513 // Orphan |node| and reconnect parent and child.
514 if (child)
515 MutableParentOf(child) = parent;
516
517 if (parent) {
518 if (LeftOf(parent) == node)
519 MutableLeftOf(parent) = child;
520 else
521 MutableRightOf(parent) = child;
522 }
523
524 MutableParentOf(node) = 0;
525 MutableLeftOf(node) = 0;
526 MutableRightOf(node) = 0;
527 UpdateNode(node);
528 const uint32_t orphan = node;
529
530 if (root_ == node)
531 root_ = child;
532
533 // Removal is finished. Start the balancing process.
534 bool needs_rebalancing = true;
535 node = child;
536
537 while (parent) {
538 UpdateNode(parent);
539
540 if (needs_rebalancing) {
541 const int parent_balance = BalanceOf(parent);
542
543 if (parent_balance == 1 || parent_balance == -1) {
544 // The height of the subtree was not changed.
545 needs_rebalancing = false;
546 } else {
547 if (RightOf(parent) == node) {
548 // Removed node from the right subtree.
549 if (parent_balance < -1) {
550 // Parent is left heavy, rotate right.
551 const uint32_t sibling = LeftOf(parent);
552 if (BalanceOf(sibling) > 0)
553 RotateLeft(sibling);
554 parent = RotateRight(parent);
555 }
556 } else {
557 // Removed node from the left subtree.
558 if (parent_balance > 1) {
559 // Parent is right heavy, rotate left.
560 const uint32_t sibling = RightOf(parent);
561 if (BalanceOf(sibling) < 0)
562 RotateRight(sibling);
563 parent = RotateLeft(parent);
564 }
565 }
566 }
567 }
568
569 assert(BalanceOf(parent) >= -1 && (BalanceOf(parent) <= 1));
570
571 node = parent;
572 parent = ParentOf(parent);
573 }
574
575 return orphan;
576 }
577
578 template <typename Val>
RotateLeft(const uint32_t node)579 uint32_t MoveToFront<Val>::RotateLeft(const uint32_t node) {
580 const uint32_t pivot = RightOf(node);
581 assert(pivot);
582
583 // LeftOf(pivot) gets attached to node in place of pivot.
584 MutableRightOf(node) = LeftOf(pivot);
585 if (RightOf(node))
586 MutableParentOf(RightOf(node)) = node;
587
588 // Pivot gets attached to ParentOf(node) in place of node.
589 MutableParentOf(pivot) = ParentOf(node);
590 if (!ParentOf(node))
591 root_ = pivot;
592 else if (IsLeftChild(node))
593 MutableLeftOf(ParentOf(node)) = pivot;
594 else
595 MutableRightOf(ParentOf(node)) = pivot;
596
597 // Node is child of pivot.
598 MutableLeftOf(pivot) = node;
599 MutableParentOf(node) = pivot;
600
601 // Update both node and pivot. Pivot is the new parent of node, so node should
602 // be updated first.
603 UpdateNode(node);
604 UpdateNode(pivot);
605
606 return pivot;
607 }
608
609 template <typename Val>
RotateRight(const uint32_t node)610 uint32_t MoveToFront<Val>::RotateRight(const uint32_t node) {
611 const uint32_t pivot = LeftOf(node);
612 assert(pivot);
613
614 // RightOf(pivot) gets attached to node in place of pivot.
615 MutableLeftOf(node) = RightOf(pivot);
616 if (LeftOf(node))
617 MutableParentOf(LeftOf(node)) = node;
618
619 // Pivot gets attached to ParentOf(node) in place of node.
620 MutableParentOf(pivot) = ParentOf(node);
621 if (!ParentOf(node))
622 root_ = pivot;
623 else if (IsLeftChild(node))
624 MutableLeftOf(ParentOf(node)) = pivot;
625 else
626 MutableRightOf(ParentOf(node)) = pivot;
627
628 // Node is child of pivot.
629 MutableRightOf(pivot) = node;
630 MutableParentOf(node) = pivot;
631
632 // Update both node and pivot. Pivot is the new parent of node, so node should
633 // be updated first.
634 UpdateNode(node);
635 UpdateNode(pivot);
636
637 return pivot;
638 }
639
640 template <typename Val>
UpdateNode(uint32_t node)641 void MoveToFront<Val>::UpdateNode(uint32_t node) {
642 MutableSizeOf(node) = 1 + SizeOf(LeftOf(node)) + SizeOf(RightOf(node));
643 MutableHeightOf(node) =
644 1 + std::max(HeightOf(LeftOf(node)), HeightOf(RightOf(node)));
645 }
646
647 } // namespace spvutils
648
649 #endif // LIBSPIRV_UTIL_MOVE_TO_FRONT_H_
650