1 /* 2 * Copyright © 2017,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_VECTOR_HH 28 #define HB_VECTOR_HH 29 30 #include "hb.hh" 31 #include "hb-array.hh" 32 #include "hb-meta.hh" 33 #include "hb-null.hh" 34 35 36 template <typename Type, 37 bool sorted=false> 38 struct hb_vector_t 39 { 40 typedef Type item_t; 41 static constexpr unsigned item_size = hb_static_size (Type); 42 using array_t = typename std::conditional<sorted, hb_sorted_array_t<Type>, hb_array_t<Type>>::type; 43 using c_array_t = typename std::conditional<sorted, hb_sorted_array_t<const Type>, hb_array_t<const Type>>::type; 44 45 hb_vector_t () = default; hb_vector_thb_vector_t46 hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t () 47 { 48 alloc (lst.size (), true); 49 for (auto&& item : lst) 50 push (item); 51 } 52 template <typename Iterable, 53 hb_requires (hb_is_iterable (Iterable))> hb_vector_thb_vector_t54 hb_vector_t (const Iterable &o) : hb_vector_t () 55 { 56 auto iter = hb_iter (o); 57 if (iter.is_random_access_iterator || iter.has_fast_len) 58 alloc (hb_len (iter), true); 59 hb_copy (iter, *this); 60 } hb_vector_thb_vector_t61 hb_vector_t (const hb_vector_t &o) : hb_vector_t () 62 { 63 alloc (o.length, true); 64 if (unlikely (in_error ())) return; 65 copy_array (o.as_array ()); 66 } hb_vector_thb_vector_t67 hb_vector_t (array_t o) : hb_vector_t () 68 { 69 alloc (o.length, true); 70 if (unlikely (in_error ())) return; 71 copy_array (o); 72 } hb_vector_thb_vector_t73 hb_vector_t (c_array_t o) : hb_vector_t () 74 { 75 alloc (o.length, true); 76 if (unlikely (in_error ())) return; 77 copy_array (o); 78 } hb_vector_thb_vector_t79 hb_vector_t (hb_vector_t &&o) 80 { 81 allocated = o.allocated; 82 length = o.length; 83 arrayZ = o.arrayZ; 84 o.init (); 85 } ~hb_vector_thb_vector_t86 ~hb_vector_t () { fini (); } 87 88 public: 89 int allocated = 0; /* < 0 means allocation failed. */ 90 unsigned int length = 0; 91 public: 92 Type *arrayZ = nullptr; 93 inithb_vector_t94 void init () 95 { 96 allocated = length = 0; 97 arrayZ = nullptr; 98 } init0hb_vector_t99 void init0 () 100 { 101 } 102 finihb_vector_t103 void fini () 104 { 105 /* We allow a hack to make the vector point to a foreign array 106 * by the user. In that case length/arrayZ are non-zero but 107 * allocated is zero. Don't free anything. */ 108 if (allocated) 109 { 110 shrink_vector (0); 111 hb_free (arrayZ); 112 } 113 init (); 114 } 115 resethb_vector_t116 void reset () 117 { 118 if (unlikely (in_error ())) 119 reset_error (); 120 resize (0); 121 } 122 swap(hb_vector_t & a,hb_vector_t & b)123 friend void swap (hb_vector_t& a, hb_vector_t& b) 124 { 125 hb_swap (a.allocated, b.allocated); 126 hb_swap (a.length, b.length); 127 hb_swap (a.arrayZ, b.arrayZ); 128 } 129 operator =hb_vector_t130 hb_vector_t& operator = (const hb_vector_t &o) 131 { 132 reset (); 133 alloc (o.length, true); 134 if (unlikely (in_error ())) return *this; 135 136 copy_array (o.as_array ()); 137 138 return *this; 139 } operator =hb_vector_t140 hb_vector_t& operator = (hb_vector_t &&o) 141 { 142 hb_swap (*this, o); 143 return *this; 144 } 145 as_byteshb_vector_t146 hb_bytes_t as_bytes () const 147 { return hb_bytes_t ((const char *) arrayZ, get_size ()); } 148 operator ==hb_vector_t149 bool operator == (const hb_vector_t &o) const { return as_array () == o.as_array (); } operator !=hb_vector_t150 bool operator != (const hb_vector_t &o) const { return !(*this == o); } hashhb_vector_t151 uint32_t hash () const { return as_array ().hash (); } 152 operator []hb_vector_t153 Type& operator [] (int i_) 154 { 155 unsigned int i = (unsigned int) i_; 156 if (unlikely (i >= length)) 157 return Crap (Type); 158 return arrayZ[i]; 159 } operator []hb_vector_t160 const Type& operator [] (int i_) const 161 { 162 unsigned int i = (unsigned int) i_; 163 if (unlikely (i >= length)) 164 return Null (Type); 165 return arrayZ[i]; 166 } 167 tailhb_vector_t168 Type& tail () { return (*this)[length - 1]; } tailhb_vector_t169 const Type& tail () const { return (*this)[length - 1]; } 170 operator boolhb_vector_t171 explicit operator bool () const { return length; } get_sizehb_vector_t172 unsigned get_size () const { return length * item_size; } 173 174 /* Sink interface. */ 175 template <typename T> operator <<hb_vector_t176 hb_vector_t& operator << (T&& v) { push (std::forward<T> (v)); return *this; } 177 as_arrayhb_vector_t178 array_t as_array () { return hb_array (arrayZ, length); } as_arrayhb_vector_t179 c_array_t as_array () const { return hb_array (arrayZ, length); } 180 181 /* Iterator. */ 182 typedef c_array_t iter_t; 183 typedef array_t writer_t; iterhb_vector_t184 iter_t iter () const { return as_array (); } writerhb_vector_t185 writer_t writer () { return as_array (); } operator iter_thb_vector_t186 operator iter_t () const { return iter (); } operator writer_thb_vector_t187 operator writer_t () { return writer (); } 188 189 /* Faster range-based for loop. */ beginhb_vector_t190 Type *begin () const { return arrayZ; } endhb_vector_t191 Type *end () const { return arrayZ + length; } 192 193 as_sorted_arrayhb_vector_t194 hb_sorted_array_t<Type> as_sorted_array () 195 { return hb_sorted_array (arrayZ, length); } as_sorted_arrayhb_vector_t196 hb_sorted_array_t<const Type> as_sorted_array () const 197 { return hb_sorted_array (arrayZ, length); } 198 operator T*hb_vector_t199 template <typename T> explicit operator T * () { return arrayZ; } operator const T*hb_vector_t200 template <typename T> explicit operator const T * () const { return arrayZ; } 201 operator +hb_vector_t202 Type * operator + (unsigned int i) { return arrayZ + i; } operator +hb_vector_t203 const Type * operator + (unsigned int i) const { return arrayZ + i; } 204 pushhb_vector_t205 Type *push () 206 { 207 if (unlikely (!resize (length + 1))) 208 return std::addressof (Crap (Type)); 209 return std::addressof (arrayZ[length - 1]); 210 } pushhb_vector_t211 template <typename... Args> Type *push (Args&&... args) 212 { 213 if (unlikely ((int) length >= allocated && !alloc (length + 1))) 214 // If push failed to allocate then don't copy v, since this may cause 215 // the created copy to leak memory since we won't have stored a 216 // reference to it. 217 return std::addressof (Crap (Type)); 218 219 /* Emplace. */ 220 Type *p = std::addressof (arrayZ[length++]); 221 return new (p) Type (std::forward<Args> (args)...); 222 } 223 in_errorhb_vector_t224 bool in_error () const { return allocated < 0; } set_errorhb_vector_t225 void set_error () 226 { 227 assert (allocated >= 0); 228 allocated = -allocated - 1; 229 } reset_errorhb_vector_t230 void reset_error () 231 { 232 assert (allocated < 0); 233 allocated = -(allocated + 1); 234 } 235 236 template <typename T = Type, 237 hb_enable_if (hb_is_trivially_copy_assignable(T))> 238 Type * realloc_vectorhb_vector_t239 realloc_vector (unsigned new_allocated, hb_priority<0>) 240 { 241 if (!new_allocated) 242 { 243 hb_free (arrayZ); 244 return nullptr; 245 } 246 return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); 247 } 248 template <typename T = Type, 249 hb_enable_if (!hb_is_trivially_copy_assignable(T))> 250 Type * realloc_vectorhb_vector_t251 realloc_vector (unsigned new_allocated, hb_priority<0>) 252 { 253 if (!new_allocated) 254 { 255 hb_free (arrayZ); 256 return nullptr; 257 } 258 Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type)); 259 if (likely (new_array)) 260 { 261 for (unsigned i = 0; i < length; i++) 262 { 263 new (std::addressof (new_array[i])) Type (); 264 new_array[i] = std::move (arrayZ[i]); 265 arrayZ[i].~Type (); 266 } 267 hb_free (arrayZ); 268 } 269 return new_array; 270 } 271 /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */ 272 template <typename T = Type, 273 hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) || 274 hb_is_same (T, hb_array_t <typename T::item_t>))> 275 Type * realloc_vectorhb_vector_t276 realloc_vector (unsigned new_allocated, hb_priority<1>) 277 { 278 if (!new_allocated) 279 { 280 hb_free (arrayZ); 281 return nullptr; 282 } 283 return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); 284 } 285 286 template <typename T = Type, 287 hb_enable_if (hb_is_trivially_constructible(T))> 288 void grow_vectorhb_vector_t289 grow_vector (unsigned size, hb_priority<0>) 290 { 291 hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); 292 length = size; 293 } 294 template <typename T = Type, 295 hb_enable_if (!hb_is_trivially_constructible(T))> 296 void grow_vectorhb_vector_t297 grow_vector (unsigned size, hb_priority<0>) 298 { 299 for (; length < size; length++) 300 new (std::addressof (arrayZ[length])) Type (); 301 } 302 /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */ 303 template <typename T = Type, 304 hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) || 305 hb_is_same (T, hb_array_t <typename T::item_t>))> 306 void grow_vectorhb_vector_t307 grow_vector (unsigned size, hb_priority<1>) 308 { 309 hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); 310 length = size; 311 } 312 313 template <typename T = Type, 314 hb_enable_if (hb_is_trivially_copyable (T))> 315 void copy_arrayhb_vector_t316 copy_array (hb_array_t<const Type> other) 317 { 318 length = other.length; 319 if (!HB_OPTIMIZE_SIZE_VAL && sizeof (T) >= sizeof (long long)) 320 /* This runs faster because of alignment. */ 321 for (unsigned i = 0; i < length; i++) 322 arrayZ[i] = other.arrayZ[i]; 323 else 324 hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size); 325 } 326 template <typename T = Type, 327 hb_enable_if (!hb_is_trivially_copyable (T) && 328 std::is_copy_constructible<T>::value)> 329 void copy_arrayhb_vector_t330 copy_array (hb_array_t<const Type> other) 331 { 332 length = 0; 333 while (length < other.length) 334 { 335 length++; 336 new (std::addressof (arrayZ[length - 1])) Type (other.arrayZ[length - 1]); 337 } 338 } 339 template <typename T = Type, 340 hb_enable_if (!hb_is_trivially_copyable (T) && 341 !std::is_copy_constructible<T>::value && 342 std::is_default_constructible<T>::value && 343 std::is_copy_assignable<T>::value)> 344 void copy_arrayhb_vector_t345 copy_array (hb_array_t<const Type> other) 346 { 347 length = 0; 348 while (length < other.length) 349 { 350 length++; 351 new (std::addressof (arrayZ[length - 1])) Type (); 352 arrayZ[length - 1] = other.arrayZ[length - 1]; 353 } 354 } 355 356 void shrink_vectorhb_vector_t357 shrink_vector (unsigned size) 358 { 359 assert (size <= length); 360 if (!std::is_trivially_destructible<Type>::value) 361 { 362 unsigned count = length - size; 363 Type *p = arrayZ + length - 1; 364 while (count--) 365 p--->~Type (); 366 } 367 length = size; 368 } 369 370 void shift_down_vectorhb_vector_t371 shift_down_vector (unsigned i) 372 { 373 for (; i < length; i++) 374 arrayZ[i - 1] = std::move (arrayZ[i]); 375 } 376 377 /* Allocate for size but don't adjust length. */ allochb_vector_t378 bool alloc (unsigned int size, bool exact=false) 379 { 380 if (unlikely (in_error ())) 381 return false; 382 383 unsigned int new_allocated; 384 if (exact) 385 { 386 /* If exact was specified, we allow shrinking the storage. */ 387 size = hb_max (size, length); 388 if (size <= (unsigned) allocated && 389 size >= (unsigned) allocated >> 2) 390 return true; 391 392 new_allocated = size; 393 } 394 else 395 { 396 if (likely (size <= (unsigned) allocated)) 397 return true; 398 399 new_allocated = allocated; 400 while (size > new_allocated) 401 new_allocated += (new_allocated >> 1) + 8; 402 } 403 404 405 /* Reallocate */ 406 407 bool overflows = 408 (int) in_error () || 409 (new_allocated < size) || 410 hb_unsigned_mul_overflows (new_allocated, sizeof (Type)); 411 412 if (unlikely (overflows)) 413 { 414 set_error (); 415 return false; 416 } 417 418 Type *new_array = realloc_vector (new_allocated, hb_prioritize); 419 420 if (unlikely (new_allocated && !new_array)) 421 { 422 if (new_allocated <= (unsigned) allocated) 423 return true; // shrinking failed; it's okay; happens in our fuzzer 424 425 set_error (); 426 return false; 427 } 428 429 arrayZ = new_array; 430 allocated = new_allocated; 431 432 return true; 433 } 434 resizehb_vector_t435 bool resize (int size_, bool initialize = true, bool exact = false) 436 { 437 unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; 438 if (!alloc (size, exact)) 439 return false; 440 441 if (size > length) 442 { 443 if (initialize) 444 grow_vector (size, hb_prioritize); 445 } 446 else if (size < length) 447 { 448 if (initialize) 449 shrink_vector (size); 450 } 451 452 length = size; 453 return true; 454 } resize_exacthb_vector_t455 bool resize_exact (int size_, bool initialize = true) 456 { 457 return resize (size_, initialize, true); 458 } 459 pophb_vector_t460 Type pop () 461 { 462 if (!length) return Null (Type); 463 Type v (std::move (arrayZ[length - 1])); 464 arrayZ[length - 1].~Type (); 465 length--; 466 return v; 467 } 468 remove_orderedhb_vector_t469 void remove_ordered (unsigned int i) 470 { 471 if (unlikely (i >= length)) 472 return; 473 shift_down_vector (i + 1); 474 arrayZ[length - 1].~Type (); 475 length--; 476 } 477 478 template <bool Sorted = sorted, 479 hb_enable_if (!Sorted)> remove_unorderedhb_vector_t480 void remove_unordered (unsigned int i) 481 { 482 if (unlikely (i >= length)) 483 return; 484 if (i != length - 1) 485 arrayZ[i] = std::move (arrayZ[length - 1]); 486 arrayZ[length - 1].~Type (); 487 length--; 488 } 489 shrinkhb_vector_t490 void shrink (int size_, bool shrink_memory = true) 491 { 492 unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; 493 if (size >= length) 494 return; 495 496 shrink_vector (size); 497 498 if (shrink_memory) 499 alloc (size, true); /* To force shrinking memory if needed. */ 500 } 501 502 503 /* Sorting API. */ qsorthb_vector_t504 void qsort (int (*cmp)(const void*, const void*) = Type::cmp) 505 { as_array ().qsort (cmp); } 506 507 /* Unsorted search API. */ 508 template <typename T> lsearchhb_vector_t509 Type *lsearch (const T &x, Type *not_found = nullptr) 510 { return as_array ().lsearch (x, not_found); } 511 template <typename T> lsearchhb_vector_t512 const Type *lsearch (const T &x, const Type *not_found = nullptr) const 513 { return as_array ().lsearch (x, not_found); } 514 template <typename T> lfindhb_vector_t515 bool lfind (const T &x, unsigned *pos = nullptr) const 516 { return as_array ().lfind (x, pos); } 517 518 /* Sorted search API. */ 519 template <typename T, 520 bool Sorted=sorted, hb_enable_if (Sorted)> bsearchhb_vector_t521 Type *bsearch (const T &x, Type *not_found = nullptr) 522 { return as_array ().bsearch (x, not_found); } 523 template <typename T, 524 bool Sorted=sorted, hb_enable_if (Sorted)> bsearchhb_vector_t525 const Type *bsearch (const T &x, const Type *not_found = nullptr) const 526 { return as_array ().bsearch (x, not_found); } 527 template <typename T, 528 bool Sorted=sorted, hb_enable_if (Sorted)> bfindhb_vector_t529 bool bfind (const T &x, unsigned int *i = nullptr, 530 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 531 unsigned int to_store = (unsigned int) -1) const 532 { return as_array ().bfind (x, i, not_found, to_store); } 533 }; 534 535 template <typename Type> 536 using hb_sorted_vector_t = hb_vector_t<Type, true>; 537 538 #endif /* HB_VECTOR_HH */ 539