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