| /* libs/graphics/sgl/SkTSearch.cpp |
| ** |
| ** Copyright 2006, The Android Open Source Project |
| ** |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| #include "SkTSearch.h" |
| #include <ctype.h> |
| |
| static inline const char* index_into_base(const char*const* base, int index, |
| size_t elemSize) |
| { |
| return *(const char*const*)((const char*)base + index * elemSize); |
| } |
| |
| int SkStrSearch(const char*const* base, int count, const char target[], |
| size_t target_len, size_t elemSize) |
| { |
| if (count <= 0) |
| return ~0; |
| |
| SkASSERT(base != NULL); |
| |
| int lo = 0; |
| int hi = count - 1; |
| |
| while (lo < hi) |
| { |
| int mid = (hi + lo) >> 1; |
| const char* elem = index_into_base(base, mid, elemSize); |
| |
| int cmp = strncmp(elem, target, target_len); |
| if (cmp < 0) |
| lo = mid + 1; |
| else if (cmp > 0 || strlen(elem) > target_len) |
| hi = mid; |
| else |
| return mid; |
| } |
| |
| const char* elem = index_into_base(base, hi, elemSize); |
| int cmp = strncmp(elem, target, target_len); |
| if (cmp || strlen(elem) > target_len) |
| { |
| if (cmp < 0) |
| hi += 1; |
| hi = ~hi; |
| } |
| return hi; |
| } |
| |
| int SkStrSearch(const char*const* base, int count, const char target[], |
| size_t elemSize) |
| { |
| return SkStrSearch(base, count, target, strlen(target), elemSize); |
| } |
| |
| int SkStrLCSearch(const char*const* base, int count, const char target[], |
| size_t len, size_t elemSize) |
| { |
| SkASSERT(target); |
| |
| SkAutoAsciiToLC tolc(target, len); |
| |
| return SkStrSearch(base, count, tolc.lc(), len, elemSize); |
| } |
| |
| int SkStrLCSearch(const char*const* base, int count, const char target[], |
| size_t elemSize) |
| { |
| return SkStrLCSearch(base, count, target, strlen(target), elemSize); |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| SkAutoAsciiToLC::SkAutoAsciiToLC(const char str[], size_t len) |
| { |
| // see if we need to compute the length |
| if ((long)len < 0) { |
| len = strlen(str); |
| } |
| fLength = len; |
| |
| // assign lc to our preallocated storage if len is small enough, or allocate |
| // it on the heap |
| char* lc; |
| if (len <= STORAGE) { |
| lc = fStorage; |
| } else { |
| lc = (char*)sk_malloc_throw(len + 1); |
| } |
| fLC = lc; |
| |
| // convert any asii to lower-case. we let non-ascii (utf8) chars pass |
| // through unchanged |
| for (int i = (int)(len - 1); i >= 0; --i) { |
| int c = str[i]; |
| if ((c & 0x80) == 0) { // is just ascii |
| c = tolower(c); |
| } |
| lc[i] = c; |
| } |
| lc[len] = 0; |
| } |
| |
| SkAutoAsciiToLC::~SkAutoAsciiToLC() |
| { |
| if (fLC != fStorage) { |
| sk_free(fLC); |
| } |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| #define SK_QSortTempSize 16 |
| |
| static inline void sk_qsort_swap(char a[], char b[], size_t elemSize) |
| { |
| char tmp[SK_QSortTempSize]; |
| |
| while (elemSize > 0) |
| { |
| size_t size = elemSize; |
| if (size > SK_QSortTempSize) |
| size = SK_QSortTempSize; |
| elemSize -= size; |
| |
| memcpy(tmp, a, size); |
| memcpy(a, b, size); |
| memcpy(b, tmp, size); |
| a += size; |
| b += size; |
| } |
| } |
| |
| static void SkQSort_Partition(char* first, char* last, size_t elemSize, SkQSortCompareProc compare) |
| { |
| char* left = first; |
| char* rite = last; |
| char* pivot = left; |
| |
| while (left <= rite) |
| { |
| while (left < last && compare(left, pivot) < 0) |
| left += elemSize; |
| while (first < rite && compare(rite, pivot) > 0) |
| rite -= elemSize; |
| if (left <= rite) |
| { |
| if (left < rite) |
| { |
| SkASSERT(compare(left, rite) >= 0); |
| sk_qsort_swap(left, rite, elemSize); |
| } |
| left += elemSize; |
| rite -= elemSize; |
| } |
| } |
| if (first < rite) |
| SkQSort_Partition(first, rite, elemSize, compare); |
| if (left < last) |
| SkQSort_Partition(left, last, elemSize, compare); |
| } |
| |
| void SkQSort(void* base, size_t count, size_t elemSize, SkQSortCompareProc compare) |
| { |
| SkASSERT(base); |
| SkASSERT(compare); |
| SkASSERT(elemSize > 0); |
| |
| if (count <= 1) |
| return; |
| |
| SkQSort_Partition((char*)base, (char*)base + (count - 1) * elemSize, elemSize, compare); |
| } |
| |
| #ifdef SK_DEBUG |
| |
| #include "SkRandom.h" |
| |
| #ifdef SK_SUPPORT_UNITTEST |
| extern "C" { |
| int compare_int(const void* a, const void* b) |
| { |
| return *(const int*)a - *(const int*)b; |
| } |
| } |
| #endif |
| |
| void SkQSort_UnitTest() |
| { |
| #ifdef SK_SUPPORT_UNITTEST |
| int array[100]; |
| SkRandom rand; |
| |
| for (int i = 0; i < 1000; i++) |
| { |
| int j, count = rand.nextRangeU(1, SK_ARRAY_COUNT(array)); |
| for (j = 0; j < count; j++) |
| array[j] = rand.nextS() & 0xFF; |
| SkQSort(array, count, sizeof(int), compare_int); |
| for (j = 1; j < count; j++) |
| SkASSERT(array[j-1] <= array[j]); |
| } |
| #endif |
| } |
| |
| #endif |