intrusive_heap.h 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_CONTAINERS_INTRUSIVE_HEAP_H_
  5. #define BASE_CONTAINERS_INTRUSIVE_HEAP_H_
  6. // Implements a standard max-heap, but with arbitrary element removal. To
  7. // facilitate this, each element has associated with it a HeapHandle (an opaque
  8. // wrapper around the index at which the element is stored), which is maintained
  9. // by the heap as elements move within it.
  10. //
  11. // An IntrusiveHeap is implemented as a standard max-heap over a std::vector<T>,
  12. // like std::make_heap. Insertion, removal and updating are amortized O(lg size)
  13. // (occasional O(size) cost if a new vector allocation is required). Retrieving
  14. // an element by handle is O(1). Looking up the top element is O(1). Insertions,
  15. // removals and updates invalidate all iterators, but handles remain valid.
  16. // Similar to a std::set, all iterators are read-only so as to disallow changing
  17. // elements and violating the heap property. That being said, if the type you
  18. // are storing is able to have its sort key be changed externally you can
  19. // repair the heap by resorting the modified element via a call to "Update".
  20. //
  21. // Example usage:
  22. //
  23. // // Create a heap, wrapping integer elements with WithHeapHandle in order to
  24. // // endow them with heap handles.
  25. // IntrusiveHeap<WithHeapHandle<int>> heap;
  26. //
  27. // // WithHeapHandle<T> is for simple or opaque types. In cases where you
  28. // // control the type declaration you can also provide HeapHandle storage by
  29. // // deriving from InternalHeapHandleStorage.
  30. // class Foo : public InternalHeapHandleStorage {
  31. // public:
  32. // explicit Foo(int);
  33. // ...
  34. // };
  35. // IntrusiveHeap<Foo> heap2;
  36. //
  37. // // Insert some elements. Like most containers, "insert" returns an iterator
  38. // // to the element in the container.
  39. // heap.insert(3);
  40. // heap.insert(1);
  41. // auto it = heap.insert(4);
  42. //
  43. // // By default this is a max heap, so the top element should be 4 at this
  44. // // point.
  45. // EXPECT_EQ(4, heap.top().value());
  46. //
  47. // // Iterators are invalidated by further heap operations, but handles are
  48. // // not. Grab a handle to the current top element so we can track it across
  49. // // changes.
  50. // HeapHandle* handle = it->handle();
  51. //
  52. // // Insert a new max element. 4 should no longer be the top.
  53. // heap.insert(5);
  54. // EXPECT_EQ(5, heap.top().value());
  55. //
  56. // // We can lookup and erase element 4 by its handle, even though it has
  57. // // moved. Note that erasing the element invalidates the handle to it.
  58. // EXPECT_EQ(4, heap.at(*handle).value());
  59. // heap.erase(*handle);
  60. // handle = nullptr;
  61. //
  62. // // Popping the current max (5), makes 3 the new max, as we already erased
  63. // // element 4.
  64. // heap.pop();
  65. // EXPECT_EQ(3, heap.top().value());
  66. //
  67. // Under the hood the HeapHandle is managed by an object implementing the
  68. // HeapHandleAccess interface, which is passed as a parameter to the
  69. // IntrusiveHeap template:
  70. //
  71. // // Gets the heap handle associated with the element. This should return the
  72. // // most recently set handle value, or HeapHandle::Invalid(). This is only
  73. // // called in DCHECK builds.
  74. // HeapHandle GetHeapHandle(const T*);
  75. //
  76. // // Changes the result of GetHeapHandle. GetHeapHandle() must return the
  77. // // most recent value provided to SetHeapHandle() or HeapHandle::Invalid().
  78. // // In some implementations, where GetHeapHandle() can independently
  79. // // reproduce the correct value, it is possible that SetHeapHandle() does
  80. // // nothing.
  81. // void SetHeapHandle(T*, HeapHandle);
  82. //
  83. // // Clears the heap handle associated with the given element. After calling
  84. // // this GetHeapHandle() must return HeapHandle::Invalid().
  85. // void ClearHeapHandle(T*);
  86. //
  87. // The default implementation of HeapHandleAccess assumes that your type
  88. // provides HeapHandle storage and will simply forward these calls to equivalent
  89. // member functions on the type T:
  90. //
  91. // void T::SetHeapHandle(HeapHandle)
  92. // void T::ClearHeapHandle()
  93. // HeapHandle T::GetHeapHandle() const
  94. //
  95. // The WithHeapHandle and InternalHeapHandleStorage classes in turn provide
  96. // implementations of that contract.
  97. //
  98. // In summary, to provide heap handle support for your type, you can do one of
  99. // the following (from most manual / least magical, to least manual / most
  100. // magical):
  101. //
  102. // 0. use a custom HeapHandleAccessor, and implement storage however you want;
  103. // 1. use the default HeapHandleAccessor, and manually provide storage on your
  104. // your element type and implement the IntrusiveHeap contract;
  105. // 2. use the default HeapHandleAccessor, and endow your type with handle
  106. // storage by deriving from a helper class (see InternalHeapHandleStorage);
  107. // or,
  108. // 3. use the default HeapHandleAccessor, and wrap your type in a container that
  109. // provides handle storage (see WithHeapHandle<T>).
  110. //
  111. // Approach 0 is suitable for custom types that already implement something akin
  112. // to heap handles, via back pointers or any other mechanism, but where the
  113. // storage is external to the objects in the heap. If you already have the
  114. // ability to determine where in a container an object lives despite it
  115. // being moved, then you don't need the overhead of storing an actual HeapHandle
  116. // whose value can be inferred.
  117. //
  118. // Approach 1 is is suitable in cases like the above, but where the data
  119. // allowing you to determine the index of an element in a container is stored
  120. // directly in the object itself.
  121. //
  122. // Approach 2 is suitable for types whose declarations you control, where you
  123. // are able to use inheritance.
  124. //
  125. // Finally, approach 3 is suitable when you are storing PODs, or a type whose
  126. // declaration you can not change.
  127. //
  128. // Most users should be using approach 2 or 3.
  129. #include <algorithm>
  130. #include <functional>
  131. #include <limits>
  132. #include <type_traits>
  133. #include <utility>
  134. #include <vector>
  135. #include "base/base_export.h"
  136. #include "base/check_op.h"
  137. #include "base/macros.h"
  138. #include "base/memory/ptr_util.h"
  139. namespace base {
  140. // Intended as a wrapper around an |index_| in the vector storage backing an
  141. // IntrusiveHeap. A HeapHandle is associated with each element in an
  142. // IntrusiveHeap, and is maintained by the heap as the object moves around
  143. // within it. It can be used to subsequently remove the element, or update it
  144. // in place.
  145. class BASE_EXPORT HeapHandle {
  146. public:
  147. enum : size_t { kInvalidIndex = std::numeric_limits<size_t>::max() };
  148. constexpr HeapHandle() = default;
  149. constexpr HeapHandle(const HeapHandle& other) = default;
  150. HeapHandle(HeapHandle&& other) noexcept
  151. : index_(std::exchange(other.index_, kInvalidIndex)) {}
  152. ~HeapHandle() = default;
  153. HeapHandle& operator=(const HeapHandle& other) = default;
  154. HeapHandle& operator=(HeapHandle&& other) noexcept {
  155. index_ = std::exchange(other.index_, kInvalidIndex);
  156. return *this;
  157. }
  158. static HeapHandle Invalid();
  159. // Resets this handle back to an invalid state.
  160. void reset() { index_ = kInvalidIndex; }
  161. // Accessors.
  162. size_t index() const { return index_; }
  163. bool IsValid() const { return index_ != kInvalidIndex; }
  164. // Comparison operators.
  165. friend bool operator==(const HeapHandle& lhs, const HeapHandle& rhs) {
  166. return lhs.index_ == rhs.index_;
  167. }
  168. friend bool operator!=(const HeapHandle& lhs, const HeapHandle& rhs) {
  169. return lhs.index_ != rhs.index_;
  170. }
  171. friend bool operator<(const HeapHandle& lhs, const HeapHandle& rhs) {
  172. return lhs.index_ < rhs.index_;
  173. }
  174. friend bool operator>(const HeapHandle& lhs, const HeapHandle& rhs) {
  175. return lhs.index_ > rhs.index_;
  176. }
  177. friend bool operator<=(const HeapHandle& lhs, const HeapHandle& rhs) {
  178. return lhs.index_ <= rhs.index_;
  179. }
  180. friend bool operator>=(const HeapHandle& lhs, const HeapHandle& rhs) {
  181. return lhs.index_ >= rhs.index_;
  182. }
  183. private:
  184. template <typename T, typename Compare, typename HeapHandleAccessor>
  185. friend class IntrusiveHeap;
  186. // Only IntrusiveHeaps can create valid HeapHandles.
  187. explicit HeapHandle(size_t index) : index_(index) {}
  188. size_t index_ = kInvalidIndex;
  189. };
  190. // The default HeapHandleAccessor, which simply forwards calls to the underlying
  191. // type.
  192. template <typename T>
  193. struct DefaultHeapHandleAccessor {
  194. void SetHeapHandle(T* element, HeapHandle handle) const {
  195. element->SetHeapHandle(handle);
  196. }
  197. void ClearHeapHandle(T* element) const { element->ClearHeapHandle(); }
  198. HeapHandle GetHeapHandle(const T* element) const {
  199. return element->GetHeapHandle();
  200. }
  201. };
  202. // Intrusive heap class. This is something like a std::vector (insertion and
  203. // removal are similar, objects don't have a fixed address in memory) crossed
  204. // with a std::set (elements are considered immutable once they're in the
  205. // container).
  206. template <typename T,
  207. typename Compare = std::less<T>,
  208. typename HeapHandleAccessor = DefaultHeapHandleAccessor<T>>
  209. class IntrusiveHeap {
  210. private:
  211. using UnderlyingType = std::vector<T>;
  212. public:
  213. //////////////////////////////////////////////////////////////////////////////
  214. // Types.
  215. using value_type = typename UnderlyingType::value_type;
  216. using size_type = typename UnderlyingType::size_type;
  217. using difference_type = typename UnderlyingType::difference_type;
  218. using value_compare = Compare;
  219. using heap_handle_accessor = HeapHandleAccessor;
  220. using reference = typename UnderlyingType::reference;
  221. using const_reference = typename UnderlyingType::const_reference;
  222. using pointer = typename UnderlyingType::pointer;
  223. using const_pointer = typename UnderlyingType::const_pointer;
  224. // Iterators are read-only.
  225. using iterator = typename UnderlyingType::const_iterator;
  226. using const_iterator = typename UnderlyingType::const_iterator;
  227. using reverse_iterator = typename UnderlyingType::const_reverse_iterator;
  228. using const_reverse_iterator =
  229. typename UnderlyingType::const_reverse_iterator;
  230. //////////////////////////////////////////////////////////////////////////////
  231. // Lifetime.
  232. IntrusiveHeap() = default;
  233. IntrusiveHeap(const value_compare& comp, const heap_handle_accessor& access)
  234. : impl_(comp, access) {}
  235. template <class InputIterator>
  236. IntrusiveHeap(InputIterator first,
  237. InputIterator last,
  238. const value_compare& comp = value_compare(),
  239. const heap_handle_accessor& access = heap_handle_accessor())
  240. : impl_(comp, access) {
  241. insert(first, last);
  242. }
  243. // Moves an intrusive heap. The outstanding handles remain valid and end up
  244. // pointing to the new heap.
  245. IntrusiveHeap(IntrusiveHeap&& other) = default;
  246. // Copy constructor for an intrusive heap.
  247. IntrusiveHeap(const IntrusiveHeap&);
  248. // Initializer list constructor.
  249. template <typename U>
  250. IntrusiveHeap(std::initializer_list<U> ilist,
  251. const value_compare& comp = value_compare(),
  252. const heap_handle_accessor& access = heap_handle_accessor())
  253. : impl_(comp, access) {
  254. insert(std::begin(ilist), std::end(ilist));
  255. }
  256. ~IntrusiveHeap();
  257. //////////////////////////////////////////////////////////////////////////////
  258. // Assignment.
  259. IntrusiveHeap& operator=(IntrusiveHeap&&) noexcept;
  260. IntrusiveHeap& operator=(const IntrusiveHeap&);
  261. IntrusiveHeap& operator=(std::initializer_list<value_type> ilist);
  262. //////////////////////////////////////////////////////////////////////////////
  263. // Element access.
  264. //
  265. // These provide O(1) const access to the elements in the heap. If you wish to
  266. // modify an element in the heap you should first remove it from the heap, and
  267. // then reinsert it into the heap, or use the "Replace*" helper functions. In
  268. // the rare case where you directly modify an element in the heap you can
  269. // subsequently repair the heap with "Update".
  270. const_reference at(size_type pos) const { return impl_.heap_.at(pos); }
  271. const_reference at(HeapHandle pos) const {
  272. return impl_.heap_.at(pos.index());
  273. }
  274. const_reference operator[](size_type pos) const { return impl_.heap_[pos]; }
  275. const_reference operator[](HeapHandle pos) const {
  276. return impl_.heap_[pos.index()];
  277. }
  278. const_reference front() const { return impl_.heap_.front(); }
  279. const_reference back() const { return impl_.heap_.back(); }
  280. const_reference top() const { return impl_.heap_.front(); }
  281. // May or may not return a null pointer if size() is zero.
  282. const_pointer data() const { return impl_.heap_.data(); }
  283. //////////////////////////////////////////////////////////////////////////////
  284. // Memory management.
  285. void reserve(size_type new_capacity) { impl_.heap_.reserve(new_capacity); }
  286. size_type capacity() const { return impl_.heap_.capacity(); }
  287. void shrink_to_fit() { impl_.heap_.shrink_to_fit(); }
  288. //////////////////////////////////////////////////////////////////////////////
  289. // Size management.
  290. void clear();
  291. size_type size() const { return impl_.heap_.size(); }
  292. size_type max_size() const { return impl_.heap_.max_size(); }
  293. bool empty() const { return impl_.heap_.empty(); }
  294. //////////////////////////////////////////////////////////////////////////////
  295. // Iterators.
  296. //
  297. // Only constant iterators are allowed.
  298. const_iterator begin() const { return impl_.heap_.cbegin(); }
  299. const_iterator cbegin() const { return impl_.heap_.cbegin(); }
  300. const_iterator end() const { return impl_.heap_.cend(); }
  301. const_iterator cend() const { return impl_.heap_.cend(); }
  302. const_reverse_iterator rbegin() const { return impl_.heap_.crbegin(); }
  303. const_reverse_iterator crbegin() const { return impl_.heap_.crbegin(); }
  304. const_reverse_iterator rend() const { return impl_.heap_.crend(); }
  305. const_reverse_iterator crend() const { return impl_.heap_.crend(); }
  306. //////////////////////////////////////////////////////////////////////////////
  307. // Insertion (these are std::multiset like, with no position hints).
  308. //
  309. // All insertion operations invalidate iterators, pointers and references.
  310. // Handles remain valid. Insertion of one element is amortized O(lg size)
  311. // (occasional O(size) cost if a new vector allocation is required).
  312. const_iterator insert(const value_type& value) { return InsertImpl(value); }
  313. const_iterator insert(value_type&& value) {
  314. return InsertImpl(std::move_if_noexcept(value));
  315. }
  316. template <class InputIterator>
  317. void insert(InputIterator first, InputIterator last);
  318. template <typename... Args>
  319. const_iterator emplace(Args&&... args);
  320. //////////////////////////////////////////////////////////////////////////////
  321. // Removing elements.
  322. //
  323. // Erasing invalidates all outstanding iterators, pointers and references.
  324. // Handles remain valid. Removing one element is amortized O(lg size)
  325. // (occasional O(size) cost if a new vector allocation is required).
  326. //
  327. // Note that it is safe for the element being removed to be in an invalid
  328. // state (modified such that it may currently violate the heap property)
  329. // when this called.
  330. // Takes the element from the heap at the given position, erasing that entry
  331. // from the heap. This can only be called if |value_type| is movable.
  332. value_type take(size_type pos);
  333. // Version of take that will accept iterators and handles. This can only be
  334. // called if |value_type| is movable.
  335. template <typename P>
  336. value_type take(P pos) {
  337. return take(ToIndex(pos));
  338. }
  339. // Takes the top element from the heap.
  340. value_type take_top() { return take(0u); }
  341. // Erases the element at the given position |pos|.
  342. void erase(size_type pos);
  343. // Version of erase that will accept iterators and handles.
  344. template <typename P>
  345. void erase(P pos) {
  346. erase(ToIndex(pos));
  347. }
  348. // Removes the element at the top of the heap (accessible via "top", or
  349. // "front" or "take").
  350. void pop() { erase(0u); }
  351. //////////////////////////////////////////////////////////////////////////////
  352. // Updating.
  353. //
  354. // Amortized cost of O(lg size).
  355. // Replaces the element corresponding to |handle| with a new |element|.
  356. const_iterator Replace(size_type pos, const T& element) {
  357. return ReplaceImpl(pos, element);
  358. }
  359. const_iterator Replace(size_type pos, T&& element) {
  360. return ReplaceImpl(pos, std::move_if_noexcept(element));
  361. }
  362. // Versions of Replace that will accept handles and iterators.
  363. template <typename P>
  364. const_iterator Replace(P pos, const T& element) {
  365. return ReplaceImpl(ToIndex(pos), element);
  366. }
  367. template <typename P>
  368. const_iterator Replace(P pos, T&& element) {
  369. return ReplaceImpl(ToIndex(pos), std::move_if_noexcept(element));
  370. }
  371. // Replaces the top element in the heap with the provided element.
  372. const_iterator ReplaceTop(const T& element) {
  373. return ReplaceTopImpl(element);
  374. }
  375. const_iterator ReplaceTop(T&& element) {
  376. return ReplaceTopImpl(std::move_if_noexcept(element));
  377. }
  378. // Causes the object at the given location to be resorted into an appropriate
  379. // position in the heap. To be used if the object in the heap was externally
  380. // modified, and the heap needs to be repaired. This only works if a single
  381. // heap element has been modified, otherwise the behaviour is undefined.
  382. const_iterator Update(size_type pos);
  383. template <typename P>
  384. const_iterator Update(P pos) {
  385. return Update(ToIndex(pos));
  386. }
  387. //////////////////////////////////////////////////////////////////////////////
  388. // Access to helper functors.
  389. const value_compare& value_comp() const { return impl_.get_value_compare(); }
  390. const heap_handle_accessor& heap_handle_access() const {
  391. return impl_.get_heap_handle_access();
  392. }
  393. //////////////////////////////////////////////////////////////////////////////
  394. // General operations.
  395. void swap(IntrusiveHeap& other) noexcept;
  396. friend void swap(IntrusiveHeap& lhs, IntrusiveHeap& rhs) { lhs.swap(rhs); }
  397. // Comparison operators. These check for exact equality. Two heaps that are
  398. // semantically equivalent (contain the same elements, but in different
  399. // orders) won't compare as equal using these operators.
  400. friend bool operator==(const IntrusiveHeap& lhs, const IntrusiveHeap& rhs) {
  401. return lhs.impl_.heap_ == rhs.impl_.heap_;
  402. }
  403. friend bool operator!=(const IntrusiveHeap& lhs, const IntrusiveHeap& rhs) {
  404. return lhs.impl_.heap_ != rhs.impl_.heap_;
  405. }
  406. //////////////////////////////////////////////////////////////////////////////
  407. // Utility functions.
  408. // Converts iterators and handles to indices. Helpers for templated versions
  409. // of insert/erase/Replace.
  410. size_type ToIndex(HeapHandle handle) { return handle.index(); }
  411. size_type ToIndex(const_iterator pos);
  412. size_type ToIndex(const_reverse_iterator pos);
  413. private:
  414. // Templated version of ToIndex that lets insert/erase/Replace work with all
  415. // integral types.
  416. template <typename I, typename = std::enable_if_t<std::is_integral<I>::value>>
  417. size_type ToIndex(I pos) {
  418. return static_cast<size_type>(pos);
  419. }
  420. // Returns the last valid index in |heap_|.
  421. size_type GetLastIndex() const { return impl_.heap_.size() - 1; }
  422. // Helper functions for setting heap handles.
  423. void SetHeapHandle(size_type i);
  424. void ClearHeapHandle(size_type i);
  425. HeapHandle GetHeapHandle(size_type i);
  426. // Helpers for doing comparisons between elements inside and outside of the
  427. // heap.
  428. bool Less(size_type i, size_type j);
  429. bool Less(const T& element, size_type i);
  430. bool Less(size_type i, const T& element);
  431. // The following function are all related to the basic heap algorithm
  432. // underpinning this data structure. They are templated so that they work with
  433. // both movable (U = T&&) and non-movable (U = const T&) types.
  434. // Primitive helpers for adding removing / elements to the heap. To minimize
  435. // moves, the heap is implemented by making a hole where an element used to
  436. // be (or where a new element will soon be), and moving the hole around,
  437. // before finally filling the hole or deleting the entry corresponding to the
  438. // hole.
  439. void MakeHole(size_type pos);
  440. template <typename U>
  441. void FillHole(size_type hole, U element);
  442. void MoveHole(size_type new_hole_pos, size_type old_hole_pos);
  443. // Moves a hold up the tree and fills it with the provided |element|. Returns
  444. // the final index of the element.
  445. template <typename U>
  446. size_type MoveHoleUpAndFill(size_type hole_pos, U element);
  447. // Moves a hole down the tree and fills it with the provided |element|. If
  448. // |kFillWithLeaf| is true it will deterministically move the hole all the
  449. // way down the tree, avoiding a second comparison per level, before
  450. // potentially moving it back up the tree.
  451. struct WithLeafElement {
  452. static constexpr bool kIsLeafElement = true;
  453. };
  454. struct WithElement {
  455. static constexpr bool kIsLeafElement = false;
  456. };
  457. template <typename FillElementType, typename U>
  458. size_type MoveHoleDownAndFill(size_type hole_pos, U element);
  459. // Implementation of Insert and Replace built on top of the MoveHole
  460. // primitives.
  461. template <typename U>
  462. const_iterator InsertImpl(U element);
  463. template <typename U>
  464. const_iterator ReplaceImpl(size_type pos, U element);
  465. template <typename U>
  466. const_iterator ReplaceTopImpl(U element);
  467. // To support comparators that may not be possible to default-construct, we
  468. // have to store an instance of value_compare. Using this to store all
  469. // internal state of IntrusiveHeap and using private inheritance to store
  470. // compare lets us take advantage of an empty base class optimization to avoid
  471. // extra space in the common case when Compare has no state.
  472. struct Impl : private value_compare, private heap_handle_accessor {
  473. Impl(const value_compare& value_comp,
  474. const heap_handle_accessor& heap_handle_access)
  475. : value_compare(value_comp), heap_handle_accessor(heap_handle_access) {}
  476. Impl() = default;
  477. Impl(Impl&&) = default;
  478. Impl(const Impl&) = default;
  479. Impl& operator=(Impl&& other) = default;
  480. Impl& operator=(const Impl& other) = default;
  481. const value_compare& get_value_compare() const { return *this; }
  482. value_compare& get_value_compare() { return *this; }
  483. const heap_handle_accessor& get_heap_handle_access() const { return *this; }
  484. heap_handle_accessor& get_heap_handle_access() { return *this; }
  485. // The items in the heap.
  486. UnderlyingType heap_;
  487. } impl_;
  488. };
  489. // Helper class to endow an object with internal HeapHandle storage. By deriving
  490. // from this type you endow your class with self-owned storage for a HeapHandle.
  491. // This is a move-only type so that the handle follows the element across moves
  492. // and resizes of the underlying vector.
  493. class BASE_EXPORT InternalHeapHandleStorage {
  494. public:
  495. InternalHeapHandleStorage();
  496. InternalHeapHandleStorage(const InternalHeapHandleStorage&) = delete;
  497. InternalHeapHandleStorage(InternalHeapHandleStorage&& other) noexcept;
  498. virtual ~InternalHeapHandleStorage();
  499. InternalHeapHandleStorage& operator=(const InternalHeapHandleStorage&) =
  500. delete;
  501. InternalHeapHandleStorage& operator=(
  502. InternalHeapHandleStorage&& other) noexcept;
  503. // Allows external clients to get a pointer to the heap handle. This allows
  504. // them to remove the element from the heap regardless of its location.
  505. HeapHandle* handle() const { return handle_.get(); }
  506. // Implementation of IntrusiveHeap contract. Inlined to keep heap code as fast
  507. // as possible.
  508. void SetHeapHandle(HeapHandle handle) {
  509. DCHECK(handle.IsValid());
  510. if (handle_)
  511. *handle_ = handle;
  512. }
  513. void ClearHeapHandle() {
  514. if (handle_)
  515. handle_->reset();
  516. }
  517. HeapHandle GetHeapHandle() const {
  518. if (handle_)
  519. return *handle_;
  520. return HeapHandle::Invalid();
  521. }
  522. // Utility functions.
  523. void swap(InternalHeapHandleStorage& other) noexcept;
  524. friend void swap(InternalHeapHandleStorage& lhs,
  525. InternalHeapHandleStorage& rhs) {
  526. lhs.swap(rhs);
  527. }
  528. private:
  529. std::unique_ptr<HeapHandle> handle_;
  530. };
  531. // Spiritually akin to a std::pair<T, std::unique_ptr<HeapHandle>>. Can be used
  532. // to wrap arbitrary types and provide them with a HeapHandle, making them
  533. // appropriate for use in an IntrusiveHeap. This is a move-only type.
  534. template <typename T>
  535. class WithHeapHandle : public InternalHeapHandleStorage {
  536. public:
  537. WithHeapHandle() = default;
  538. // Allow implicit conversion of any type that T supports for ease of use with
  539. // InstrusiveHeap constructors/insert/emplace.
  540. template <typename U>
  541. WithHeapHandle(U value) : value_(std::move_if_noexcept(value)) {}
  542. WithHeapHandle(T&& value) noexcept : value_(std::move(value)) {}
  543. // Constructor that forwards all arguments along to |value_|.
  544. template <class... Args>
  545. explicit WithHeapHandle(Args&&... args);
  546. WithHeapHandle(const WithHeapHandle&) = delete;
  547. WithHeapHandle(WithHeapHandle&& other) noexcept = default;
  548. ~WithHeapHandle() override = default;
  549. WithHeapHandle& operator=(const WithHeapHandle&) = delete;
  550. WithHeapHandle& operator=(WithHeapHandle&& other) = default;
  551. T& value() { return value_; }
  552. const T& value() const { return value_; }
  553. // Utility functions.
  554. void swap(WithHeapHandle& other) noexcept;
  555. friend void swap(WithHeapHandle& lhs, WithHeapHandle& rhs) { lhs.swap(rhs); }
  556. // Comparison operators, for compatibility with ordered STL containers.
  557. friend bool operator==(const WithHeapHandle& lhs, const WithHeapHandle& rhs) {
  558. return lhs.value_ == rhs.value_;
  559. }
  560. friend bool operator!=(const WithHeapHandle& lhs, const WithHeapHandle& rhs) {
  561. return lhs.value_ != rhs.value_;
  562. }
  563. friend bool operator<=(const WithHeapHandle& lhs, const WithHeapHandle& rhs) {
  564. return lhs.value_ <= rhs.value_;
  565. }
  566. friend bool operator<(const WithHeapHandle& lhs, const WithHeapHandle& rhs) {
  567. return lhs.value_ < rhs.value_;
  568. }
  569. friend bool operator>=(const WithHeapHandle& lhs, const WithHeapHandle& rhs) {
  570. return lhs.value_ >= rhs.value_;
  571. }
  572. friend bool operator>(const WithHeapHandle& lhs, const WithHeapHandle& rhs) {
  573. return lhs.value_ > rhs.value_;
  574. }
  575. private:
  576. T value_;
  577. };
  578. ////////////////////////////////////////////////////////////////////////////////
  579. // IMPLEMENTATION DETAILS
  580. namespace intrusive_heap {
  581. BASE_EXPORT inline size_t ParentIndex(size_t i) {
  582. DCHECK_NE(0u, i);
  583. return (i - 1) / 2;
  584. }
  585. BASE_EXPORT inline size_t LeftIndex(size_t i) {
  586. return 2 * i + 1;
  587. }
  588. template <typename HandleType>
  589. bool IsInvalid(const HandleType& handle) {
  590. return !handle || !handle->IsValid();
  591. }
  592. BASE_EXPORT inline void CheckInvalidOrEqualTo(HeapHandle handle, size_t index) {
  593. if (handle.IsValid())
  594. DCHECK_EQ(index, handle.index());
  595. }
  596. } // namespace intrusive_heap
  597. ////////////////////////////////////////////////////////////////////////////////
  598. // IntrusiveHeap
  599. template <typename T, typename Compare, typename HeapHandleAccessor>
  600. IntrusiveHeap<T, Compare, HeapHandleAccessor>::IntrusiveHeap(
  601. const IntrusiveHeap& other)
  602. : impl_(other.impl_) {
  603. for (size_t i = 0; i < size(); ++i) {
  604. SetHeapHandle(i);
  605. }
  606. }
  607. template <typename T, typename Compare, typename HeapHandleAccessor>
  608. IntrusiveHeap<T, Compare, HeapHandleAccessor>::~IntrusiveHeap() {
  609. clear();
  610. }
  611. template <typename T, typename Compare, typename HeapHandleAccessor>
  612. IntrusiveHeap<T, Compare, HeapHandleAccessor>&
  613. IntrusiveHeap<T, Compare, HeapHandleAccessor>::operator=(
  614. IntrusiveHeap&& other) noexcept {
  615. clear();
  616. impl_ = std::move(other.impl_);
  617. return *this;
  618. }
  619. template <typename T, typename Compare, typename HeapHandleAccessor>
  620. IntrusiveHeap<T, Compare, HeapHandleAccessor>&
  621. IntrusiveHeap<T, Compare, HeapHandleAccessor>::operator=(
  622. const IntrusiveHeap& other) {
  623. clear();
  624. impl_ = other.impl_;
  625. for (size_t i = 0; i < size(); ++i) {
  626. SetHeapHandle(i);
  627. }
  628. return *this;
  629. }
  630. template <typename T, typename Compare, typename HeapHandleAccessor>
  631. IntrusiveHeap<T, Compare, HeapHandleAccessor>&
  632. IntrusiveHeap<T, Compare, HeapHandleAccessor>::operator=(
  633. std::initializer_list<value_type> ilist) {
  634. clear();
  635. insert(std::begin(ilist), std::end(ilist));
  636. }
  637. template <typename T, typename Compare, typename HeapHandleAccessor>
  638. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::clear() {
  639. // Make all of the handles invalid before cleaning up the heap.
  640. for (size_type i = 0; i < size(); ++i) {
  641. ClearHeapHandle(i);
  642. }
  643. // Clear the heap.
  644. impl_.heap_.clear();
  645. }
  646. template <typename T, typename Compare, typename HeapHandleAccessor>
  647. template <class InputIterator>
  648. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::insert(InputIterator first,
  649. InputIterator last) {
  650. for (auto it = first; it != last; ++it) {
  651. insert(value_type(*it));
  652. }
  653. }
  654. template <typename T, typename Compare, typename HeapHandleAccessor>
  655. template <typename... Args>
  656. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::const_iterator
  657. IntrusiveHeap<T, Compare, HeapHandleAccessor>::emplace(Args&&... args) {
  658. value_type value(std::forward<Args>(args)...);
  659. return InsertImpl(std::move_if_noexcept(value));
  660. }
  661. template <typename T, typename Compare, typename HeapHandleAccessor>
  662. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::value_type
  663. IntrusiveHeap<T, Compare, HeapHandleAccessor>::take(size_type pos) {
  664. // Make a hole by taking the element out of the heap.
  665. MakeHole(pos);
  666. value_type val = std::move(impl_.heap_[pos]);
  667. // If the element being taken is already the last element then the heap
  668. // doesn't need to be repaired.
  669. if (pos != GetLastIndex()) {
  670. MakeHole(GetLastIndex());
  671. // Move the hole down the heap, filling it with the current leaf at the
  672. // very end of the heap.
  673. MoveHoleDownAndFill<WithLeafElement>(
  674. pos, std::move(impl_.heap_[GetLastIndex()]));
  675. }
  676. impl_.heap_.pop_back();
  677. return val;
  678. }
  679. // This is effectively identical to "take", but it avoids an unnecessary move.
  680. template <typename T, typename Compare, typename HeapHandleAccessor>
  681. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::erase(size_type pos) {
  682. DCHECK_LT(pos, size());
  683. // Make a hole by taking the element out of the heap.
  684. MakeHole(pos);
  685. // If the element being erased is already the last element then the heap
  686. // doesn't need to be repaired.
  687. if (pos != GetLastIndex()) {
  688. MakeHole(GetLastIndex());
  689. // Move the hole down the heap, filling it with the current leaf at the
  690. // very end of the heap.
  691. MoveHoleDownAndFill<WithLeafElement>(
  692. pos, std::move_if_noexcept(impl_.heap_[GetLastIndex()]));
  693. }
  694. impl_.heap_.pop_back();
  695. }
  696. template <typename T, typename Compare, typename HeapHandleAccessor>
  697. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::const_iterator
  698. IntrusiveHeap<T, Compare, HeapHandleAccessor>::Update(size_type pos) {
  699. DCHECK_LT(pos, size());
  700. MakeHole(pos);
  701. // Determine if we're >= parent, in which case we may need to go up.
  702. bool child_greater_eq_parent = false;
  703. size_type i = 0;
  704. if (pos > 0) {
  705. i = intrusive_heap::ParentIndex(pos);
  706. child_greater_eq_parent = !Less(pos, i);
  707. }
  708. if (child_greater_eq_parent) {
  709. i = MoveHoleUpAndFill(pos, std::move_if_noexcept(impl_.heap_[pos]));
  710. } else {
  711. i = MoveHoleDownAndFill<WithElement>(
  712. pos, std::move_if_noexcept(impl_.heap_[pos]));
  713. }
  714. return cbegin() + i;
  715. }
  716. template <typename T, typename Compare, typename HeapHandleAccessor>
  717. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::swap(
  718. IntrusiveHeap& other) noexcept {
  719. std::swap(impl_.get_value_compare(), other.impl_.get_value_compare());
  720. std::swap(impl_.get_heap_handle_access(),
  721. other.impl_.get_heap_handle_access());
  722. std::swap(impl_.heap_, other.impl_.heap_);
  723. }
  724. template <typename T, typename Compare, typename HeapHandleAccessor>
  725. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::size_type
  726. IntrusiveHeap<T, Compare, HeapHandleAccessor>::ToIndex(const_iterator pos) {
  727. DCHECK(cbegin() <= pos);
  728. DCHECK(pos <= cend());
  729. if (pos == cend())
  730. return HeapHandle::kInvalidIndex;
  731. return pos - cbegin();
  732. }
  733. template <typename T, typename Compare, typename HeapHandleAccessor>
  734. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::size_type
  735. IntrusiveHeap<T, Compare, HeapHandleAccessor>::ToIndex(
  736. const_reverse_iterator pos) {
  737. DCHECK(crbegin() <= pos);
  738. DCHECK(pos <= crend());
  739. if (pos == crend())
  740. return HeapHandle::kInvalidIndex;
  741. return (pos.base() - cbegin()) - 1;
  742. }
  743. template <typename T, typename Compare, typename HeapHandleAccessor>
  744. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::SetHeapHandle(size_type i) {
  745. impl_.get_heap_handle_access().SetHeapHandle(&impl_.heap_[i], HeapHandle(i));
  746. intrusive_heap::CheckInvalidOrEqualTo(GetHeapHandle(i), i);
  747. }
  748. template <typename T, typename Compare, typename HeapHandleAccessor>
  749. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::ClearHeapHandle(
  750. size_type i) {
  751. impl_.get_heap_handle_access().ClearHeapHandle(&impl_.heap_[i]);
  752. DCHECK(!GetHeapHandle(i).IsValid());
  753. }
  754. template <typename T, typename Compare, typename HeapHandleAccessor>
  755. HeapHandle IntrusiveHeap<T, Compare, HeapHandleAccessor>::GetHeapHandle(
  756. size_type i) {
  757. return impl_.get_heap_handle_access().GetHeapHandle(&impl_.heap_[i]);
  758. }
  759. template <typename T, typename Compare, typename HeapHandleAccessor>
  760. bool IntrusiveHeap<T, Compare, HeapHandleAccessor>::Less(size_type i,
  761. size_type j) {
  762. DCHECK_LT(i, size());
  763. DCHECK_LT(j, size());
  764. return impl_.get_value_compare()(impl_.heap_[i], impl_.heap_[j]);
  765. }
  766. template <typename T, typename Compare, typename HeapHandleAccessor>
  767. bool IntrusiveHeap<T, Compare, HeapHandleAccessor>::Less(const T& element,
  768. size_type i) {
  769. DCHECK_LT(i, size());
  770. return impl_.get_value_compare()(element, impl_.heap_[i]);
  771. }
  772. template <typename T, typename Compare, typename HeapHandleAccessor>
  773. bool IntrusiveHeap<T, Compare, HeapHandleAccessor>::Less(size_type i,
  774. const T& element) {
  775. DCHECK_LT(i, size());
  776. return impl_.get_value_compare()(impl_.heap_[i], element);
  777. }
  778. template <typename T, typename Compare, typename HeapHandleAccessor>
  779. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::MakeHole(size_type pos) {
  780. DCHECK_LT(pos, size());
  781. ClearHeapHandle(pos);
  782. }
  783. template <typename T, typename Compare, typename HeapHandleAccessor>
  784. template <typename U>
  785. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::FillHole(size_type hole_pos,
  786. U element) {
  787. // The hole that we're filling may not yet exist. This can occur when
  788. // inserting a new element into the heap.
  789. DCHECK_LE(hole_pos, size());
  790. if (hole_pos == size()) {
  791. impl_.heap_.push_back(std::move_if_noexcept(element));
  792. } else {
  793. impl_.heap_[hole_pos] = std::move_if_noexcept(element);
  794. }
  795. SetHeapHandle(hole_pos);
  796. }
  797. template <typename T, typename Compare, typename HeapHandleAccessor>
  798. void IntrusiveHeap<T, Compare, HeapHandleAccessor>::MoveHole(
  799. size_type new_hole_pos,
  800. size_type old_hole_pos) {
  801. // The old hole position may be one past the end. This occurs when a new
  802. // element is being added.
  803. DCHECK_NE(new_hole_pos, old_hole_pos);
  804. DCHECK_LT(new_hole_pos, size());
  805. DCHECK_LE(old_hole_pos, size());
  806. if (old_hole_pos == size()) {
  807. impl_.heap_.push_back(std::move_if_noexcept(impl_.heap_[new_hole_pos]));
  808. } else {
  809. impl_.heap_[old_hole_pos] =
  810. std::move_if_noexcept(impl_.heap_[new_hole_pos]);
  811. }
  812. SetHeapHandle(old_hole_pos);
  813. }
  814. template <typename T, typename Compare, typename HeapHandleAccessor>
  815. template <typename U>
  816. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::size_type
  817. IntrusiveHeap<T, Compare, HeapHandleAccessor>::MoveHoleUpAndFill(
  818. size_type hole_pos,
  819. U element) {
  820. // Moving 1 spot beyond the end is fine. This happens when we insert a new
  821. // element.
  822. DCHECK_LE(hole_pos, size());
  823. // Stop when the element is as far up as it can go.
  824. while (hole_pos != 0) {
  825. // If our parent is >= to us, we can stop.
  826. size_type parent = intrusive_heap::ParentIndex(hole_pos);
  827. if (!Less(parent, element))
  828. break;
  829. MoveHole(parent, hole_pos);
  830. hole_pos = parent;
  831. }
  832. FillHole(hole_pos, std::move_if_noexcept(element));
  833. return hole_pos;
  834. }
  835. template <typename T, typename Compare, typename HeapHandleAccessor>
  836. template <typename FillElementType, typename U>
  837. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::size_type
  838. IntrusiveHeap<T, Compare, HeapHandleAccessor>::MoveHoleDownAndFill(
  839. size_type hole_pos,
  840. U element) {
  841. DCHECK_LT(hole_pos, size());
  842. // If we're filling with a leaf, then that leaf element is about to be erased.
  843. // We pretend that the space doesn't exist in the heap.
  844. const size_type n = size() - (FillElementType::kIsLeafElement ? 1 : 0);
  845. DCHECK_LT(hole_pos, n);
  846. DCHECK(!GetHeapHandle(hole_pos).IsValid());
  847. while (true) {
  848. // If this spot has no children, then we've gone down as far as we can go.
  849. size_type left = intrusive_heap::LeftIndex(hole_pos);
  850. if (left >= n)
  851. break;
  852. size_type right = left + 1;
  853. // Get the larger of the potentially two child nodes.
  854. size_type largest = left;
  855. if (right < n && Less(left, right))
  856. largest = right;
  857. // If we're not deterministically moving the element all the way down to
  858. // become a leaf, then stop when it is >= the largest of the children.
  859. if (!FillElementType::kIsLeafElement && !Less(element, largest))
  860. break;
  861. MoveHole(largest, hole_pos);
  862. hole_pos = largest;
  863. }
  864. if (FillElementType::kIsLeafElement) {
  865. // If we're filling with a leaf node we may need to bubble the leaf back up
  866. // the tree a bit to repair the heap.
  867. hole_pos = MoveHoleUpAndFill(hole_pos, std::move_if_noexcept(element));
  868. } else {
  869. FillHole(hole_pos, std::move_if_noexcept(element));
  870. }
  871. return hole_pos;
  872. }
  873. template <typename T, typename Compare, typename HeapHandleAccessor>
  874. template <typename U>
  875. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::const_iterator
  876. IntrusiveHeap<T, Compare, HeapHandleAccessor>::InsertImpl(U element) {
  877. // MoveHoleUpAndFill can tolerate the initial hole being in a slot that
  878. // doesn't yet exist. It will be created by MoveHole by copy/move, thus
  879. // removing the need for a default constructor.
  880. size_t i = MoveHoleUpAndFill(size(), std::move_if_noexcept(element));
  881. return cbegin() + i;
  882. }
  883. template <typename T, typename Compare, typename HeapHandleAccessor>
  884. template <typename U>
  885. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::const_iterator
  886. IntrusiveHeap<T, Compare, HeapHandleAccessor>::ReplaceImpl(size_type pos,
  887. U element) {
  888. // If we're greater than our parent we need to go up, otherwise we may need
  889. // to go down.
  890. MakeHole(pos);
  891. size_type i = 0;
  892. if (!Less(element, pos)) {
  893. i = MoveHoleUpAndFill(pos, std::move_if_noexcept(element));
  894. } else {
  895. i = MoveHoleDownAndFill<WithElement>(pos, std::move_if_noexcept(element));
  896. }
  897. return cbegin() + i;
  898. }
  899. template <typename T, typename Compare, typename HeapHandleAccessor>
  900. template <typename U>
  901. typename IntrusiveHeap<T, Compare, HeapHandleAccessor>::const_iterator
  902. IntrusiveHeap<T, Compare, HeapHandleAccessor>::ReplaceTopImpl(U element) {
  903. MakeHole(0u);
  904. size_type i =
  905. MoveHoleDownAndFill<WithElement>(0u, std::move_if_noexcept(element));
  906. return cbegin() + i;
  907. }
  908. ////////////////////////////////////////////////////////////////////////////////
  909. // WithHeapHandle
  910. template <typename T>
  911. template <class... Args>
  912. WithHeapHandle<T>::WithHeapHandle(Args&&... args)
  913. : value_(std::forward<Args>(args)...) {}
  914. template <typename T>
  915. void WithHeapHandle<T>::swap(WithHeapHandle& other) noexcept {
  916. InternalHeapHandleStorage::swap(other);
  917. std::swap(value_, other.value_);
  918. }
  919. } // namespace base
  920. #endif // BASE_CONTAINERS_INTRUSIVE_HEAP_H_