Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #ifndef SkTSearch_DEFINED
     11 #define SkTSearch_DEFINED
     12 
     13 #include "SkTypes.h"
     14 
     15 /**
     16  *  All of the SkTSearch variants want to return the index (0...N-1) of the
     17  *  found element, or the bit-not of where to insert the element.
     18  *
     19  *  At a simple level, if the return value is negative, it was not found.
     20  *
     21  *  For clients that want to insert the new element if it was not found, use
     22  *  the following logic:
     23  *
     24  *  int index = SkTSearch(...);
     25  *  if (index >= 0) {
     26  *      // found at index
     27  *  } else {
     28  *      index = ~index; // now we are positive
     29  *      // insert at index
     30  *  }
     31  */
     32 
     33 template <typename T>
     34 int SkTSearch(const T* base, int count, const T& target, size_t elemSize)
     35 {
     36     SkASSERT(count >= 0);
     37     if (count <= 0)
     38         return ~0;
     39 
     40     SkASSERT(base != NULL); // base may be NULL if count is zero
     41 
     42     int lo = 0;
     43     int hi = count - 1;
     44 
     45     while (lo < hi)
     46     {
     47         int mid = (hi + lo) >> 1;
     48         const T* elem = (const T*)((const char*)base + mid * elemSize);
     49 
     50         if (*elem < target)
     51             lo = mid + 1;
     52         else
     53             hi = mid;
     54     }
     55 
     56     const T* elem = (const T*)((const char*)base + hi * elemSize);
     57     if (*elem != target)
     58     {
     59         if (*elem < target)
     60             hi += 1;
     61         hi = ~hi;
     62     }
     63     return hi;
     64 }
     65 
     66 template <typename T, int (COMPARE)(const T*, const T*)>
     67 int SkTSearch(const T* base, int count, const T& target, size_t elemSize)
     68 {
     69     SkASSERT(count >= 0);
     70     if (count <= 0) {
     71         return ~0;
     72     }
     73 
     74     SkASSERT(base != NULL); // base may be NULL if count is zero
     75 
     76     int lo = 0;
     77     int hi = count - 1;
     78 
     79     while (lo < hi) {
     80         int mid = (hi + lo) >> 1;
     81         const T* elem = (const T*)((const char*)base + mid * elemSize);
     82 
     83         if (COMPARE(elem, &target) < 0)
     84             lo = mid + 1;
     85         else
     86             hi = mid;
     87     }
     88 
     89     const T* elem = (const T*)((const char*)base + hi * elemSize);
     90     int pred = COMPARE(elem, &target);
     91     if (pred != 0) {
     92         if (pred < 0)
     93             hi += 1;
     94         hi = ~hi;
     95     }
     96     return hi;
     97 }
     98 
     99 template <typename T>
    100 int SkTSearch(const T* base, int count, const T& target, size_t elemSize,
    101               int (*compare)(const T*, const T*))
    102 {
    103     SkASSERT(count >= 0);
    104     if (count <= 0) {
    105         return ~0;
    106     }
    107 
    108     SkASSERT(base != NULL); // base may be NULL if count is zero
    109 
    110     int lo = 0;
    111     int hi = count - 1;
    112 
    113     while (lo < hi) {
    114         int mid = (hi + lo) >> 1;
    115         const T* elem = (const T*)((const char*)base + mid * elemSize);
    116 
    117         if ((*compare)(elem, &target) < 0)
    118             lo = mid + 1;
    119         else
    120             hi = mid;
    121     }
    122 
    123     const T* elem = (const T*)((const char*)base + hi * elemSize);
    124     int pred = (*compare)(elem, &target);
    125     if (pred != 0) {
    126         if (pred < 0)
    127             hi += 1;
    128         hi = ~hi;
    129     }
    130     return hi;
    131 }
    132 
    133 template <typename T>
    134 int SkTSearch(const T** base, int count, const T* target, size_t elemSize,
    135     int (*compare)(const T*, const T*))
    136 {
    137     SkASSERT(count >= 0);
    138     if (count <= 0)
    139         return ~0;
    140 
    141     SkASSERT(base != NULL); // base may be NULL if count is zero
    142 
    143     int lo = 0;
    144     int hi = count - 1;
    145 
    146     while (lo < hi)
    147     {
    148         int mid = (hi + lo) >> 1;
    149         const T* elem = *(const T**)((const char*)base + mid * elemSize);
    150 
    151         if ((*compare)(elem, target) < 0)
    152             lo = mid + 1;
    153         else
    154             hi = mid;
    155     }
    156 
    157     const T* elem = *(const T**)((const char*)base + hi * elemSize);
    158     int pred = (*compare)(elem, target);
    159     if (pred != 0)
    160     {
    161         if (pred < 0)
    162             hi += 1;
    163         hi = ~hi;
    164     }
    165     return hi;
    166 }
    167 
    168 template <typename T,  int (COMPARE)(const T*, const T*)>
    169 int SkTSearch(const T** base, int count, const T* target, size_t elemSize)
    170 {
    171     SkASSERT(count >= 0);
    172     if (count <= 0)
    173         return ~0;
    174 
    175     SkASSERT(base != NULL); // base may be NULL if count is zero
    176 
    177     int lo = 0;
    178     int hi = count - 1;
    179 
    180     while (lo < hi)
    181     {
    182         int mid = (hi + lo) >> 1;
    183         const T* elem = *(const T**)((const char*)base + mid * elemSize);
    184 
    185         if (COMPARE(elem, target) < 0)
    186             lo = mid + 1;
    187         else
    188             hi = mid;
    189     }
    190 
    191     const T* elem = *(const T**)((const char*)base + hi * elemSize);
    192     int pred = COMPARE(elem, target);
    193     if (pred != 0)
    194     {
    195         if (pred < 0)
    196             hi += 1;
    197         hi = ~hi;
    198     }
    199     return hi;
    200 }
    201 int SkStrSearch(const char*const* base, int count, const char target[],
    202                 size_t target_len, size_t elemSize);
    203 int SkStrSearch(const char*const* base, int count, const char target[],
    204                 size_t elemSize);
    205 
    206 /** Like SkStrSearch, but treats target as if it were all lower-case. Assumes that
    207     base points to a table of lower-case strings.
    208 */
    209 int SkStrLCSearch(const char*const* base, int count, const char target[],
    210                   size_t target_len, size_t elemSize);
    211 int SkStrLCSearch(const char*const* base, int count, const char target[],
    212                   size_t elemSize);
    213 
    214 /** Helper class to convert a string to lower-case, but only modifying the ascii
    215     characters. This makes the routine very fast and never changes the string
    216     length, but it is not suitable for linguistic purposes. Normally this is
    217     used for buiding and searching string tables.
    218 */
    219 class SkAutoAsciiToLC {
    220 public:
    221     SkAutoAsciiToLC(const char str[], size_t len = (size_t)-1);
    222     ~SkAutoAsciiToLC();
    223 
    224     const char* lc() const { return fLC; }
    225     size_t      length() const { return fLength; }
    226 
    227 private:
    228     char*   fLC;    // points to either the heap or fStorage
    229     size_t  fLength;
    230     enum {
    231         STORAGE = 64
    232     };
    233     char    fStorage[STORAGE+1];
    234 };
    235 
    236 // Helper when calling qsort with a compare proc that has typed its arguments
    237 #define SkCastForQSort(compare) reinterpret_cast<int (*)(const void*, const void*)>(compare)
    238 
    239 #endif
    240