/src/harfbuzz/src/hb-priority-queue.hh
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2020 Google, Inc. |
3 | | * |
4 | | * This is part of HarfBuzz, a text shaping library. |
5 | | * |
6 | | * Permission is hereby granted, without written agreement and without |
7 | | * license or royalty fees, to use, copy, modify, and distribute this |
8 | | * software and its documentation for any purpose, provided that the |
9 | | * above copyright notice and the following two paragraphs appear in |
10 | | * all copies of this software. |
11 | | * |
12 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | | * DAMAGE. |
17 | | * |
18 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | | * |
24 | | * Google Author(s): Garret Rieger |
25 | | */ |
26 | | |
27 | | #ifndef HB_PRIORITY_QUEUE_HH |
28 | | #define HB_PRIORITY_QUEUE_HH |
29 | | |
30 | | #include "hb.hh" |
31 | | #include "hb-vector.hh" |
32 | | |
33 | | /* |
34 | | * hb_priority_queue_t |
35 | | * |
36 | | * Priority queue implemented as a binary heap. Supports extract minimum |
37 | | * and insert operations. |
38 | | * |
39 | | * The priority queue is implemented as a binary heap, which is a complete |
40 | | * binary tree. The root of the tree is the minimum element. The heap |
41 | | * property is that the priority of a node is less than or equal to the |
42 | | * priority of its children. The heap is stored in an array, with the |
43 | | * children of node i stored at indices 2i + 1 and 2i + 2. |
44 | | */ |
45 | | template <typename K> |
46 | | struct hb_priority_queue_t |
47 | | { |
48 | | private: |
49 | | typedef hb_pair_t<K, unsigned> item_t; |
50 | | hb_vector_t<item_t> heap; |
51 | | |
52 | | public: |
53 | | |
54 | | void reset () { heap.resize (0); } |
55 | | |
56 | | bool in_error () const { return heap.in_error (); } |
57 | | |
58 | | bool alloc (unsigned size) |
59 | | { return heap.alloc (size); } |
60 | | |
61 | | #ifndef HB_OPTIMIZE_SIZE |
62 | | HB_ALWAYS_INLINE |
63 | | #endif |
64 | | void insert (K priority, unsigned value) |
65 | 0 | { |
66 | 0 | heap.push (item_t (priority, value)); |
67 | 0 | if (unlikely (heap.in_error ())) return; |
68 | 0 | bubble_up (heap.length - 1); |
69 | 0 | } |
70 | | |
71 | | #ifndef HB_OPTIMIZE_SIZE |
72 | | HB_ALWAYS_INLINE |
73 | | #endif |
74 | | item_t pop_minimum () |
75 | 0 | { |
76 | 0 | assert (!is_empty ()); |
77 | 0 |
|
78 | 0 | item_t result = heap.arrayZ[0]; |
79 | 0 |
|
80 | 0 | heap.arrayZ[0] = heap.arrayZ[heap.length - 1]; |
81 | 0 | heap.resize (heap.length - 1); |
82 | 0 |
|
83 | 0 | if (!is_empty ()) |
84 | 0 | bubble_down (0); |
85 | 0 |
|
86 | 0 | return result; |
87 | 0 | } |
88 | | |
89 | | const item_t& minimum () |
90 | | { |
91 | | return heap[0]; |
92 | | } |
93 | | |
94 | 0 | bool is_empty () const { return heap.length == 0; } |
95 | 0 | explicit operator bool () const { return !is_empty (); } |
96 | | unsigned int get_population () const { return heap.length; } |
97 | | |
98 | | /* Sink interface. */ |
99 | | hb_priority_queue_t& operator << (item_t item) |
100 | | { insert (item.first, item.second); return *this; } |
101 | | |
102 | | private: |
103 | | |
104 | | static constexpr unsigned parent (unsigned index) |
105 | 0 | { |
106 | 0 | return (index - 1) / 2; |
107 | 0 | } |
108 | | |
109 | | static constexpr unsigned left_child (unsigned index) |
110 | 0 | { |
111 | 0 | return 2 * index + 1; |
112 | 0 | } |
113 | | |
114 | | static constexpr unsigned right_child (unsigned index) |
115 | 0 | { |
116 | 0 | return 2 * index + 2; |
117 | 0 | } |
118 | | |
119 | | HB_ALWAYS_INLINE |
120 | | void bubble_down (unsigned index) |
121 | 0 | { |
122 | 0 | repeat: |
123 | 0 | assert (index < heap.length); |
124 | 0 |
|
125 | 0 | unsigned left = left_child (index); |
126 | 0 | unsigned right = right_child (index); |
127 | 0 |
|
128 | 0 | bool has_left = left < heap.length; |
129 | 0 | if (!has_left) |
130 | 0 | // If there's no left, then there's also no right. |
131 | 0 | return; |
132 | 0 |
|
133 | 0 | bool has_right = right < heap.length; |
134 | 0 | if (heap.arrayZ[index].first <= heap.arrayZ[left].first |
135 | 0 | && (!has_right || heap.arrayZ[index].first <= heap.arrayZ[right].first)) |
136 | 0 | return; |
137 | 0 |
|
138 | 0 | unsigned child; |
139 | 0 | if (!has_right || heap.arrayZ[left].first < heap.arrayZ[right].first) |
140 | 0 | child = left; |
141 | 0 | else |
142 | 0 | child = right; |
143 | 0 |
|
144 | 0 | swap (index, child); |
145 | 0 | index = child; |
146 | 0 | goto repeat; |
147 | 0 | } |
148 | | |
149 | | HB_ALWAYS_INLINE |
150 | | void bubble_up (unsigned index) |
151 | 0 | { |
152 | 0 | repeat: |
153 | 0 | assert (index < heap.length); |
154 | 0 |
|
155 | 0 | if (index == 0) return; |
156 | 0 |
|
157 | 0 | unsigned parent_index = parent (index); |
158 | 0 | if (heap.arrayZ[parent_index].first <= heap.arrayZ[index].first) |
159 | 0 | return; |
160 | 0 |
|
161 | 0 | swap (index, parent_index); |
162 | 0 | index = parent_index; |
163 | 0 | goto repeat; |
164 | 0 | } |
165 | | |
166 | | void swap (unsigned a, unsigned b) noexcept |
167 | 0 | { |
168 | 0 | assert (a < heap.length); |
169 | 0 | assert (b < heap.length); |
170 | 0 | hb_swap (heap.arrayZ[a], heap.arrayZ[b]); |
171 | 0 | } |
172 | | }; |
173 | | |
174 | | #endif /* HB_PRIORITY_QUEUE_HH */ |