• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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