Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/hb-map.hh @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * Copyright © 2018 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): Behdad Esfahbod | |
| 25 */ | |
| 26 | |
| 27 #ifndef HB_MAP_HH | |
| 28 #define HB_MAP_HH | |
| 29 | |
| 30 #include "hb.hh" | |
| 31 | |
| 32 | |
| 33 /* | |
| 34 * hb_hashmap_t | |
| 35 */ | |
| 36 | |
| 37 extern HB_INTERNAL const hb_codepoint_t minus_1; | |
| 38 | |
| 39 template <typename K, typename V, | |
| 40 bool minus_one = false> | |
| 41 struct hb_hashmap_t | |
| 42 { | |
| 43 hb_hashmap_t () { init (); } | |
| 44 ~hb_hashmap_t () { fini (); } | |
| 45 | |
| 46 hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (o.population); hb_copy (o, *this); } | |
| 47 hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); } | |
| 48 hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); resize (o.population); hb_copy (o, *this); return *this; } | |
| 49 hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; } | |
| 50 | |
| 51 hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t () | |
| 52 { | |
| 53 for (auto&& item : lst) | |
| 54 set (item.first, item.second); | |
| 55 } | |
| 56 template <typename Iterable, | |
| 57 hb_requires (hb_is_iterable (Iterable))> | |
| 58 hb_hashmap_t (const Iterable &o) : hb_hashmap_t () | |
| 59 { | |
| 60 auto iter = hb_iter (o); | |
| 61 if (iter.is_random_access_iterator) | |
| 62 resize (hb_len (iter)); | |
| 63 hb_copy (iter, *this); | |
| 64 } | |
| 65 | |
| 66 struct item_t | |
| 67 { | |
| 68 K key; | |
| 69 uint32_t hash : 30; | |
| 70 uint32_t is_used_ : 1; | |
| 71 uint32_t is_tombstone_ : 1; | |
| 72 V value; | |
| 73 | |
| 74 item_t () : key (), | |
| 75 hash (0), | |
| 76 is_used_ (false), is_tombstone_ (false), | |
| 77 value () {} | |
| 78 | |
| 79 bool is_used () const { return is_used_; } | |
| 80 void set_used (bool is_used) { is_used_ = is_used; } | |
| 81 bool is_tombstone () const { return is_tombstone_; } | |
| 82 void set_tombstone (bool is_tombstone) { is_tombstone_ = is_tombstone; } | |
| 83 bool is_real () const { return is_used_ && !is_tombstone_; } | |
| 84 | |
| 85 template <bool v = minus_one, | |
| 86 hb_enable_if (v == false)> | |
| 87 static inline const V& default_value () { return Null(V); }; | |
| 88 template <bool v = minus_one, | |
| 89 hb_enable_if (v == true)> | |
| 90 static inline const V& default_value () | |
| 91 { | |
| 92 static_assert (hb_is_same (V, hb_codepoint_t), ""); | |
| 93 return minus_1; | |
| 94 }; | |
| 95 | |
| 96 bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); } | |
| 97 bool operator == (const item_t &o) const { return *this == o.key; } | |
| 98 hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); } | |
| 99 hb_pair_t<const K &, const V &> get_pair_ref() const { return hb_pair_t<const K &, const V &> (key, value); } | |
| 100 | |
| 101 uint32_t total_hash () const | |
| 102 { return (hash * 31) + hb_hash (value); } | |
| 103 }; | |
| 104 | |
| 105 hb_object_header_t header; | |
| 106 unsigned int successful : 1; /* Allocations successful */ | |
| 107 unsigned int population : 31; /* Not including tombstones. */ | |
| 108 unsigned int occupancy; /* Including tombstones. */ | |
| 109 unsigned int mask; | |
| 110 unsigned int prime; | |
| 111 item_t *items; | |
| 112 | |
| 113 friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) | |
| 114 { | |
| 115 if (unlikely (!a.successful || !b.successful)) | |
| 116 return; | |
| 117 unsigned tmp = a.population; | |
| 118 a.population = b.population; | |
| 119 b.population = tmp; | |
| 120 //hb_swap (a.population, b.population); | |
| 121 hb_swap (a.occupancy, b.occupancy); | |
| 122 hb_swap (a.mask, b.mask); | |
| 123 hb_swap (a.prime, b.prime); | |
| 124 hb_swap (a.items, b.items); | |
| 125 } | |
| 126 void init () | |
| 127 { | |
| 128 hb_object_init (this); | |
| 129 | |
| 130 successful = true; | |
| 131 population = occupancy = 0; | |
| 132 mask = 0; | |
| 133 prime = 0; | |
| 134 items = nullptr; | |
| 135 } | |
| 136 void fini () | |
| 137 { | |
| 138 hb_object_fini (this); | |
| 139 | |
| 140 if (likely (items)) { | |
| 141 unsigned size = mask + 1; | |
| 142 for (unsigned i = 0; i < size; i++) | |
| 143 items[i].~item_t (); | |
| 144 hb_free (items); | |
| 145 items = nullptr; | |
| 146 } | |
| 147 population = occupancy = 0; | |
| 148 } | |
| 149 | |
| 150 void reset () | |
| 151 { | |
| 152 successful = true; | |
| 153 clear (); | |
| 154 } | |
| 155 | |
| 156 bool in_error () const { return !successful; } | |
| 157 | |
| 158 bool resize (unsigned new_population = 0) | |
| 159 { | |
| 160 if (unlikely (!successful)) return false; | |
| 161 | |
| 162 if (new_population != 0 && (new_population + new_population / 2) < mask) return true; | |
| 163 | |
| 164 unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8); | |
| 165 unsigned int new_size = 1u << power; | |
| 166 item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); | |
| 167 if (unlikely (!new_items)) | |
| 168 { | |
| 169 successful = false; | |
| 170 return false; | |
| 171 } | |
| 172 for (auto &_ : hb_iter (new_items, new_size)) | |
| 173 new (&_) item_t (); | |
| 174 | |
| 175 unsigned int old_size = size (); | |
| 176 item_t *old_items = items; | |
| 177 | |
| 178 /* Switch to new, empty, array. */ | |
| 179 population = occupancy = 0; | |
| 180 mask = new_size - 1; | |
| 181 prime = prime_for (power); | |
| 182 items = new_items; | |
| 183 | |
| 184 /* Insert back old items. */ | |
| 185 for (unsigned int i = 0; i < old_size; i++) | |
| 186 { | |
| 187 if (old_items[i].is_real ()) | |
| 188 { | |
| 189 set_with_hash (std::move (old_items[i].key), | |
| 190 old_items[i].hash, | |
| 191 std::move (old_items[i].value)); | |
| 192 } | |
| 193 old_items[i].~item_t (); | |
| 194 } | |
| 195 | |
| 196 hb_free (old_items); | |
| 197 | |
| 198 return true; | |
| 199 } | |
| 200 | |
| 201 template <typename KK, typename VV> | |
| 202 bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false) | |
| 203 { | |
| 204 if (unlikely (!successful)) return false; | |
| 205 if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; | |
| 206 item_t &item = item_for_hash (key, hash); | |
| 207 | |
| 208 if (is_delete && !(item == key)) | |
| 209 return true; /* Trying to delete non-existent key. */ | |
| 210 | |
| 211 if (item.is_used ()) | |
| 212 { | |
| 213 occupancy--; | |
| 214 if (!item.is_tombstone ()) | |
| 215 population--; | |
| 216 } | |
| 217 | |
| 218 item.key = std::forward<KK> (key); | |
| 219 item.value = std::forward<VV> (value); | |
| 220 item.hash = hash; | |
| 221 item.set_used (true); | |
| 222 item.set_tombstone (is_delete); | |
| 223 | |
| 224 occupancy++; | |
| 225 if (!is_delete) | |
| 226 population++; | |
| 227 | |
| 228 return true; | |
| 229 } | |
| 230 | |
| 231 template <typename VV> | |
| 232 bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); } | |
| 233 template <typename VV> | |
| 234 bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward<VV> (value)); } | |
| 235 | |
| 236 const V& get_with_hash (const K &key, uint32_t hash) const | |
| 237 { | |
| 238 if (unlikely (!items)) return item_t::default_value (); | |
| 239 auto &item = item_for_hash (key, hash); | |
| 240 return item.is_real () && item == key ? item.value : item_t::default_value (); | |
| 241 } | |
| 242 const V& get (const K &key) const | |
| 243 { | |
| 244 if (unlikely (!items)) return item_t::default_value (); | |
| 245 return get_with_hash (key, hb_hash (key)); | |
| 246 } | |
| 247 | |
| 248 void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); } | |
| 249 | |
| 250 /* Has interface. */ | |
| 251 const V& operator [] (K k) const { return get (k); } | |
| 252 template <typename VV=V> | |
| 253 bool has (K key, VV **vp = nullptr) const | |
| 254 { | |
| 255 if (unlikely (!items)) | |
| 256 return false; | |
| 257 auto &item = item_for_hash (key, hb_hash (key)); | |
| 258 if (item.is_real () && item == key) | |
| 259 { | |
| 260 if (vp) *vp = std::addressof (item.value); | |
| 261 return true; | |
| 262 } | |
| 263 else | |
| 264 return false; | |
| 265 } | |
| 266 /* Projection. */ | |
| 267 V operator () (K k) const { return get (k); } | |
| 268 | |
| 269 unsigned size () const { return mask ? mask + 1 : 0; } | |
| 270 | |
| 271 void clear () | |
| 272 { | |
| 273 if (unlikely (!successful)) return; | |
| 274 | |
| 275 for (auto &_ : hb_iter (items, size ())) | |
| 276 { | |
| 277 /* Reconstruct items. */ | |
| 278 _.~item_t (); | |
| 279 new (&_) item_t (); | |
| 280 } | |
| 281 | |
| 282 population = occupancy = 0; | |
| 283 } | |
| 284 | |
| 285 bool is_empty () const { return population == 0; } | |
| 286 explicit operator bool () const { return !is_empty (); } | |
| 287 | |
| 288 uint32_t hash () const | |
| 289 { | |
| 290 return | |
| 291 + iter_items () | |
| 292 | hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u) | |
| 293 ; | |
| 294 } | |
| 295 | |
| 296 bool is_equal (const hb_hashmap_t &other) const | |
| 297 { | |
| 298 if (population != other.population) return false; | |
| 299 | |
| 300 for (auto pair : iter ()) | |
| 301 if (other.get (pair.first) != pair.second) | |
| 302 return false; | |
| 303 | |
| 304 return true; | |
| 305 } | |
| 306 bool operator == (const hb_hashmap_t &other) const { return is_equal (other); } | |
| 307 bool operator != (const hb_hashmap_t &other) const { return !is_equal (other); } | |
| 308 | |
| 309 unsigned int get_population () const { return population; } | |
| 310 | |
| 311 /* | |
| 312 * Iterator | |
| 313 */ | |
| 314 | |
| 315 auto iter_items () const HB_AUTO_RETURN | |
| 316 ( | |
| 317 + hb_iter (items, size ()) | |
| 318 | hb_filter (&item_t::is_real) | |
| 319 ) | |
| 320 auto iter_ref () const HB_AUTO_RETURN | |
| 321 ( | |
| 322 + iter_items () | |
| 323 | hb_map (&item_t::get_pair_ref) | |
| 324 ) | |
| 325 auto iter () const HB_AUTO_RETURN | |
| 326 ( | |
| 327 + iter_items () | |
| 328 | hb_map (&item_t::get_pair) | |
| 329 ) | |
| 330 auto keys_ref () const HB_AUTO_RETURN | |
| 331 ( | |
| 332 + iter_items () | |
| 333 | hb_map (&item_t::key) | |
| 334 ) | |
| 335 auto keys () const HB_AUTO_RETURN | |
| 336 ( | |
| 337 + keys_ref () | |
| 338 | hb_map (hb_ridentity) | |
| 339 ) | |
| 340 auto values_ref () const HB_AUTO_RETURN | |
| 341 ( | |
| 342 + iter_items () | |
| 343 | hb_map (&item_t::value) | |
| 344 ) | |
| 345 auto values () const HB_AUTO_RETURN | |
| 346 ( | |
| 347 + values_ref () | |
| 348 | hb_map (hb_ridentity) | |
| 349 ) | |
| 350 | |
| 351 /* Sink interface. */ | |
| 352 hb_hashmap_t& operator << (const hb_pair_t<K, V>& v) | |
| 353 { set (v.first, v.second); return *this; } | |
| 354 hb_hashmap_t& operator << (const hb_pair_t<K, V&&>& v) | |
| 355 { set (v.first, std::move (v.second)); return *this; } | |
| 356 hb_hashmap_t& operator << (const hb_pair_t<K&&, V>& v) | |
| 357 { set (std::move (v.first), v.second); return *this; } | |
| 358 hb_hashmap_t& operator << (const hb_pair_t<K&&, V&&>& v) | |
| 359 { set (std::move (v.first), std::move (v.second)); return *this; } | |
| 360 | |
| 361 item_t& item_for_hash (const K &key, uint32_t hash) const | |
| 362 { | |
| 363 hash &= 0x3FFFFFFF; // We only store lower 30bit of hash | |
| 364 unsigned int i = hash % prime; | |
| 365 unsigned int step = 0; | |
| 366 unsigned int tombstone = (unsigned) -1; | |
| 367 while (items[i].is_used ()) | |
| 368 { | |
| 369 if (items[i].hash == hash && items[i] == key) | |
| 370 return items[i]; | |
| 371 if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) | |
| 372 tombstone = i; | |
| 373 i = (i + ++step) & mask; | |
| 374 } | |
| 375 return items[tombstone == (unsigned) -1 ? i : tombstone]; | |
| 376 } | |
| 377 | |
| 378 static unsigned int prime_for (unsigned int shift) | |
| 379 { | |
| 380 /* Following comment and table copied from glib. */ | |
| 381 /* Each table size has an associated prime modulo (the first prime | |
| 382 * lower than the table size) used to find the initial bucket. Probing | |
| 383 * then works modulo 2^n. The prime modulo is necessary to get a | |
| 384 * good distribution with poor hash functions. | |
| 385 */ | |
| 386 /* Not declaring static to make all kinds of compilers happy... */ | |
| 387 /*static*/ const unsigned int prime_mod [32] = | |
| 388 { | |
| 389 1, /* For 1 << 0 */ | |
| 390 2, | |
| 391 3, | |
| 392 7, | |
| 393 13, | |
| 394 31, | |
| 395 61, | |
| 396 127, | |
| 397 251, | |
| 398 509, | |
| 399 1021, | |
| 400 2039, | |
| 401 4093, | |
| 402 8191, | |
| 403 16381, | |
| 404 32749, | |
| 405 65521, /* For 1 << 16 */ | |
| 406 131071, | |
| 407 262139, | |
| 408 524287, | |
| 409 1048573, | |
| 410 2097143, | |
| 411 4194301, | |
| 412 8388593, | |
| 413 16777213, | |
| 414 33554393, | |
| 415 67108859, | |
| 416 134217689, | |
| 417 268435399, | |
| 418 536870909, | |
| 419 1073741789, | |
| 420 2147483647 /* For 1 << 31 */ | |
| 421 }; | |
| 422 | |
| 423 if (unlikely (shift >= ARRAY_LENGTH (prime_mod))) | |
| 424 return prime_mod[ARRAY_LENGTH (prime_mod) - 1]; | |
| 425 | |
| 426 return prime_mod[shift]; | |
| 427 } | |
| 428 }; | |
| 429 | |
| 430 /* | |
| 431 * hb_map_t | |
| 432 */ | |
| 433 | |
| 434 struct hb_map_t : hb_hashmap_t<hb_codepoint_t, | |
| 435 hb_codepoint_t, | |
| 436 true> | |
| 437 { | |
| 438 using hashmap = hb_hashmap_t<hb_codepoint_t, | |
| 439 hb_codepoint_t, | |
| 440 true>; | |
| 441 | |
| 442 ~hb_map_t () = default; | |
| 443 hb_map_t () : hashmap () {} | |
| 444 hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {} | |
| 445 hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {} | |
| 446 hb_map_t& operator= (const hb_map_t&) = default; | |
| 447 hb_map_t& operator= (hb_map_t&&) = default; | |
| 448 hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {} | |
| 449 template <typename Iterable, | |
| 450 hb_requires (hb_is_iterable (Iterable))> | |
| 451 hb_map_t (const Iterable &o) : hashmap (o) {} | |
| 452 }; | |
| 453 | |
| 454 template <typename K, typename V> | |
| 455 static inline | |
| 456 hb_hashmap_t<K, V>* hb_hashmap_create () | |
| 457 { | |
| 458 using hashmap = hb_hashmap_t<K, V>; | |
| 459 hashmap* map; | |
| 460 if (!(map = hb_object_create<hashmap> ())) | |
| 461 return nullptr; | |
| 462 | |
| 463 return map; | |
| 464 } | |
| 465 | |
| 466 template <typename K, typename V> | |
| 467 static inline | |
| 468 void hb_hashmap_destroy (hb_hashmap_t<K, V>* map) | |
| 469 { | |
| 470 if (!hb_object_destroy (map)) | |
| 471 return; | |
| 472 | |
| 473 hb_free (map); | |
| 474 } | |
| 475 | |
| 476 namespace hb { | |
| 477 | |
| 478 template <typename K, typename V> | |
| 479 struct vtable<hb_hashmap_t<K, V>> | |
| 480 { | |
| 481 static constexpr auto destroy = hb_hashmap_destroy<K,V>; | |
| 482 }; | |
| 483 | |
| 484 } | |
| 485 | |
| 486 | |
| 487 #endif /* HB_MAP_HH */ |
