home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / i18n / sortkey.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-22  |  8.7 KB  |  374 lines

  1. /*
  2. *****************************************************************************************
  3. *                                                                                       *
  4. * COPYRIGHT:                                                                            *
  5. *   (C) Copyright Taligent, Inc.,  1996                                                 *
  6. *   (C) Copyright International Business Machines Corporation,  1996-1998               *
  7. *   Licensed Material - Program-Property of IBM - All Rights Reserved.                  *
  8. *   US Government Users Restricted Rights - Use, duplication, or disclosure             *
  9. *   restricted by GSA ADP Schedule Contract with IBM Corp.                              *
  10. *                                                                                       *
  11. *****************************************************************************************
  12. */
  13. //===============================================================================
  14. //
  15. // File sortkey.cpp
  16. //
  17. // 
  18. //
  19. // Created by: Helena Shih
  20. //
  21. // Modification History:
  22. //
  23. //  Date         Name          Description
  24. //
  25. //  6/20/97      helena        Java class name change.
  26. //  6/23/97      helena        Added comments to make code more readable.
  27. //  6/26/98      erm           Canged to use byte arrays instead of UnicodeString
  28. //  7/31/98      erm           hashCode: minimum inc should be 2 not 1,
  29. //                             Cleaned up operator=
  30. // 07/12/99      helena        HPUX 11 CC port.
  31. //===============================================================================
  32.  
  33. #ifndef _SORTKEY
  34. #include "sortkey.h"
  35. #endif
  36.  
  37. #ifndef _CMEMORY
  38. #include "cmemory.h"
  39. #endif
  40.  
  41. // A hash code of kInvalidHashCode indicates that the has code needs
  42. // to be computed. A hash code of kEmptyHashCode is used for empty keys
  43. // and for any key whose computed hash code is kInvalidHashCode.
  44. const int32_t CollationKey::kInvalidHashCode = 0;
  45. const int32_t CollationKey::kEmptyHashCode = 1;
  46.  
  47. CollationKey::CollationKey()
  48.     : fCount(0), fCapacity(0), fBogus(FALSE),
  49.       fHashCode(kEmptyHashCode), fBytes(NULL)
  50. {
  51. }
  52.  
  53. // Create a collation key from a bit array.
  54. CollationKey::CollationKey(const uint8_t* newValues, int32_t count)
  55.     : fCount(count), fCapacity(count), fBogus(FALSE),
  56.       fHashCode(kInvalidHashCode)
  57. {
  58.     fBytes = new uint8_t[count];
  59.  
  60.     if (fBytes == NULL)
  61.     {
  62.         setToBogus();
  63.         return;
  64.     }
  65.  
  66.     icu_memcpy(fBytes, newValues, fCount);
  67. }
  68.  
  69. CollationKey::CollationKey(const UnicodeString& value)
  70. {
  71.     copyUnicodeString(value);
  72. }
  73.  
  74. CollationKey::CollationKey(const CollationKey& other)
  75.     : fCount(other.fCount), fCapacity(other.fCapacity), fBogus(FALSE),
  76.       fHashCode(other.fHashCode), fBytes(NULL)
  77. {
  78.     if (other.fBogus)
  79.     {
  80.         setToBogus();
  81.         return;
  82.     }
  83.  
  84.     fBytes = new uint8_t[fCapacity];
  85.  
  86.     if (fBytes == NULL)
  87.     {
  88.         setToBogus();
  89.         return;
  90.     }
  91.  
  92.     icu_memcpy(fBytes, other.fBytes, other.fCount);
  93.     if(fCapacity>fCount) {
  94.         icu_memset(fBytes+fCount, 0, fCapacity-fCount);
  95.     }
  96. }
  97.  
  98. CollationKey::~CollationKey()
  99. {
  100.     delete[] fBytes;
  101. }
  102.  
  103. // set the key to an empty state
  104. CollationKey&
  105. CollationKey::reset()
  106. {
  107.     fCount = 0;
  108.     fBogus = FALSE;
  109.     fHashCode = kEmptyHashCode;
  110.  
  111.     return *this;
  112. }
  113.  
  114. // set the key to a "bogus" or invalid state
  115. CollationKey&
  116. CollationKey::setToBogus()
  117. {
  118.     delete[] fBytes;
  119.     fBytes = NULL;
  120.  
  121.     fCapacity = 0;
  122.     fCount = 0;
  123.     fHashCode = kInvalidHashCode;
  124.  
  125.     return *this;
  126. }
  127.  
  128. bool_t
  129. CollationKey::operator==(const CollationKey& source) const
  130. {
  131.     return (this->fCount == source.fCount &&
  132.             (this->fBytes == source.fBytes ||
  133.              icu_memcmp(this->fBytes, source.fBytes, this->fCount) == 0));
  134. }
  135.  
  136. const CollationKey&
  137. CollationKey::operator=(const CollationKey& other)
  138. {
  139.     if (this != &other)
  140.     {
  141.         if (other.isBogus())
  142.         {
  143.             return setToBogus();
  144.         }
  145.  
  146.         if (other.fBytes != NULL)
  147.         {
  148.             ensureCapacity(other.fCount);
  149.  
  150.             if (isBogus())
  151.             {
  152.                 return *this;
  153.             }
  154.  
  155.             fHashCode = other.fHashCode;
  156.             icu_memcpy(fBytes, other.fBytes, fCount);
  157.         }
  158.         else
  159.         {
  160.             reset();
  161.         }
  162.     }
  163.  
  164.     return *this;
  165. }
  166.  
  167. // Bitwise comparison for the collation keys.
  168. // NOTE: this is somewhat messy 'cause we can't count
  169. // on memcmp returning the exact values which match
  170. // Collator::EComparisonResult
  171. Collator::EComparisonResult
  172. CollationKey::compareTo(const CollationKey& target) const
  173. {
  174.     int count = (this->fCount < target.fCount) ? this->fCount : target.fCount;
  175.  
  176.     if (count == 0)
  177.     {
  178.         // If count is 0, at least one of the keys is empty.
  179.         // An empty key is always LESS than a non-empty one
  180.         // and EQUAL to another empty
  181.         if (this->fCount < target.fCount)
  182.         {
  183.             return Collator::LESS;
  184.         }
  185.  
  186.         if (this->fCount > target.fCount)
  187.         {
  188.             return Collator::GREATER;
  189.         }
  190.  
  191.         return Collator::EQUAL;
  192.     }
  193.  
  194.     int result = icu_memcmp(this->fBytes, target.fBytes, count);
  195.  
  196.     if (result < 0)
  197.     {
  198.         return Collator::LESS;
  199.     }
  200.  
  201.     if (result > 0)
  202.     {
  203.         return Collator::GREATER;
  204.     }
  205.  
  206.     return Collator::EQUAL;
  207. }
  208.  
  209. CollationKey&
  210. CollationKey::ensureCapacity(int32_t newSize)
  211. {
  212.     if (fCapacity < newSize)
  213.     {
  214.         delete[] fBytes;
  215.  
  216.         fBytes = new uint8_t[newSize];
  217.  
  218.         if (fBytes == NULL)
  219.         {
  220.             return setToBogus();
  221.         }
  222.  
  223.         icu_memset(fBytes, 0, fCapacity);
  224.         fCapacity = newSize;
  225.     }
  226.  
  227.     fBogus = FALSE;
  228.     fCount = newSize;
  229.     fHashCode = kInvalidHashCode;
  230.  
  231.     return *this;
  232. }
  233.  
  234. int32_t
  235. CollationKey::storeUnicodeString(int32_t cursor, const UnicodeString &value)
  236. {
  237.     UTextOffset input = 0;
  238.     int32_t charCount = value.size();
  239.  
  240.     while (input < charCount)
  241.     {
  242.         cursor = storeBytes(cursor, value[input++]);
  243.     }
  244.  
  245.     return storeBytes(cursor, 0);
  246. }
  247.  
  248. CollationKey&
  249. CollationKey::copyUnicodeString(const UnicodeString &value)
  250. {
  251.     int32_t charCount = value.size();
  252.  
  253.     // We allocate enough space for two null bytes at the end.
  254.     ensureCapacity((charCount * 2) + 2);
  255.  
  256.     if (isBogus())
  257.     {
  258.         return *this;
  259.     }
  260.  
  261.     storeUnicodeString(0, value);
  262.  
  263.     return *this;
  264. }
  265.  
  266. void
  267. CollationKey::reverseBytes(UTextOffset from, UTextOffset to)
  268. {
  269.     uint8_t *left  = &fBytes[from];
  270.     uint8_t *right = &fBytes[to - 2];
  271.  
  272.     while (left < right)
  273.     {
  274.         uint8_t swap[2];
  275.  
  276.         swap[0] = right[0];
  277.         swap[1] = right[1]; 
  278.  
  279.         right[0] = left[0];
  280.         right[1] = left[1];
  281.  
  282.         left[0]  = swap[0];
  283.         left[1]  = swap[1];
  284.         
  285.         left += 2;
  286.         right -= 2;
  287.     }
  288. }
  289.         
  290. // Create a copy of the byte array.
  291. uint8_t*
  292. CollationKey::toByteArray(int32_t& count) const
  293. {
  294.     uint8_t *result = new uint8_t[fCount];
  295.     
  296.     if (result == NULL)
  297.     {
  298.         count = 0;
  299.     }
  300.     else
  301.     {
  302.         count = fCount;
  303.         icu_memcpy(result, fBytes, fCount);
  304.     }
  305.  
  306.     return result;  
  307. }
  308.  
  309. uint16_t*
  310. CollationKey::copyValues(int32_t &size) const
  311. {
  312.     uint16_t *result;
  313.     uint8_t *input = fBytes;
  314.     UTextOffset output = 0;
  315.  
  316.     size = fCount / 2;
  317.     result = new uint16_t[size];
  318.  
  319.     if (result == NULL)
  320.     {
  321.         size = 0;
  322.     }
  323.     else
  324.     {
  325.         while (output < size)
  326.         {
  327.             result[output] = (input[0] << 8) | input[1];
  328.             output += 1;
  329.             input += 2;
  330.         }
  331.     }
  332.  
  333.     return result;
  334. }
  335.  
  336. int32_t
  337. CollationKey::hashCode() const
  338. {
  339.     // (Cribbed from UnicodeString)
  340.     // We cache the hashCode; when it becomes invalid, due to any change to the
  341.     // string, we note this by setting it to kInvalidHashCode. [LIU]
  342.  
  343.     // Note: This method is semantically const, but physically non-const.
  344.  
  345.     if (fHashCode == kInvalidHashCode)
  346.     {
  347.         // We compute the hash by iterating sparsely over 64 (at most) characters
  348.         // spaced evenly through the string.  For each character, we multiply the
  349.         // previous hash value by a prime number and add the new character in,
  350.         // in the manner of a additive linear congruential random number generator,
  351.         // thus producing a pseudorandom deterministic value which should be well
  352.         // distributed over the output range. [LIU]
  353.         const uint8_t   *p = fBytes, *limit = fBytes + fCount;
  354.         int32_t         inc = (fCount >= 256) ? fCount/128 : 2; // inc = max(fSize/64, 1);
  355.         int32_t         hash = 0;
  356.  
  357.         while (p < limit)
  358.         {
  359.             hash = ( hash * 37 ) + ((p[0] << 8) + p[1]); 
  360.             p += inc;
  361.         }
  362.  
  363.         // If we happened to get kInvalidHashCode, replace it with kEmptyHashCode
  364.         if (hash == kInvalidHashCode)
  365.         {
  366.             hash = kEmptyHashCode;
  367.         }
  368.  
  369.         ((CollationKey *)this)->fHashCode = hash; // cast away const
  370.     }
  371.  
  372.     return fHashCode;
  373. }
  374.