| /* | |
| * Copyright 2006 The Android Open Source Project | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SkTSearch_DEFINED | |
| #define SkTSearch_DEFINED | |
| #include "include/private/SkAssert.h" | |
| #include <cstddef> | |
| /** | |
| * All of the SkTSearch variants want to return the index (0...N-1) of the | |
| * found element, or the bit-not of where to insert the element. | |
| * | |
| * At a simple level, if the return value is negative, it was not found. | |
| * | |
| * For clients that want to insert the new element if it was not found, use | |
| * the following logic: | |
| * | |
| * int index = SkTSearch(...); | |
| * if (index >= 0) { | |
| * // found at index | |
| * } else { | |
| * index = ~index; // now we are positive | |
| * // insert at index | |
| * } | |
| */ | |
| // The most general form of SkTSearch takes an array of T and a key of type K. A functor, less, is | |
| // used to perform comparisons. It has two function operators: | |
| // bool operator() (const T& t, const K& k) | |
| // bool operator() (const K& t, const T& k) | |
| template <typename T, typename K, typename LESS> | |
| int SkTSearch(const T base[], int count, const K& key, size_t elemSize, const LESS& less) | |
| { | |
| SkASSERT(count >= 0); | |
| if (count <= 0) { | |
| return ~0; | |
| } | |
| SkASSERT(base != nullptr); // base may be nullptr if count is zero | |
| int lo = 0; | |
| int hi = count - 1; | |
| while (lo < hi) { | |
| int mid = lo + ((hi - lo) >> 1); | |
| const T* elem = (const T*)((const char*)base + mid * elemSize); | |
| if (less(*elem, key)) | |
| lo = mid + 1; | |
| else | |
| hi = mid; | |
| } | |
| const T* elem = (const T*)((const char*)base + hi * elemSize); | |
| if (less(*elem, key)) { | |
| hi += 1; | |
| hi = ~hi; | |
| } else if (less(key, *elem)) { | |
| hi = ~hi; | |
| } | |
| return hi; | |
| } | |
| // Specialization for case when T==K and the caller wants to use a function rather than functor. | |
| template <typename T, bool (LESS)(const T&, const T&)> | |
| int SkTSearch(const T base[], int count, const T& target, size_t elemSize) { | |
| return SkTSearch(base, count, target, elemSize, | |
| [](const T& a, const T& b) { return LESS(a, b); }); | |
| } | |
| // Specialization for T==K, compare using op <. | |
| template <typename T> | |
| int SkTSearch(const T base[], int count, const T& target, size_t elemSize) { | |
| return SkTSearch(base, count, target, elemSize, [](const T& a, const T& b) { return a < b; }); | |
| } | |
| // Specialization for case where domain is an array of T* and the key value is a T*, and you want | |
| // to compare the T objects, not the pointers. | |
| template <typename T, bool (LESS)(const T&, const T&)> | |
| int SkTSearch(T* base[], int count, T* target, size_t elemSize) { | |
| return SkTSearch(base, count, target, elemSize, | |
| [](const T* t, const T* k) { return LESS(*t, *k); }); | |
| } | |
| int SkStrSearch(const char*const* base, int count, const char target[], | |
| size_t target_len, size_t elemSize); | |
| int SkStrSearch(const char*const* base, int count, const char target[], | |
| size_t elemSize); | |
| /** Like SkStrSearch, but treats target as if it were all lower-case. Assumes that | |
| base points to a table of lower-case strings. | |
| */ | |
| int SkStrLCSearch(const char*const* base, int count, const char target[], | |
| size_t target_len, size_t elemSize); | |
| int SkStrLCSearch(const char*const* base, int count, const char target[], | |
| size_t elemSize); | |
| /** Helper class to convert a string to lower-case, but only modifying the ascii | |
| characters. This makes the routine very fast and never changes the string | |
| length, but it is not suitable for linguistic purposes. Normally this is | |
| used for buiding and searching string tables. | |
| */ | |
| class [[nodiscard]] SkAutoAsciiToLC { | |
| public: | |
| SkAutoAsciiToLC(const char str[], size_t len = (size_t)-1); | |
| ~SkAutoAsciiToLC(); | |
| const char* lc() const { return fLC; } | |
| size_t length() const { return fLength; } | |
| private: | |
| char* fLC; // points to either the heap or fStorage | |
| size_t fLength; | |
| enum { | |
| STORAGE = 64 | |
| }; | |
| char fStorage[STORAGE+1]; | |
| }; | |
| // Helper when calling qsort with a compare proc that has typed its arguments | |
| #define SkCastForQSort(compare) reinterpret_cast<int (*)(const void*, const void*)>(compare) | |
| #endif |