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