#include "unicode/utypes.h"
#if !UCONFIG_NO_COLLATION
#include "unicode/sortkey.h"
#include "cmemory.h"
#include "uelement.h"
#include "ustr_imp.h"
U_NAMESPACE_BEGIN
#define kInvalidHashCode ((int32_t)0)
#define kEmptyHashCode ((int32_t)1)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationKey)
CollationKey::CollationKey()
: UObject(), fBogus(FALSE), fCount(0), fCapacity(0),
fHashCode(kEmptyHashCode), fBytes(NULL)
{
}
CollationKey::CollationKey(const uint8_t* newValues, int32_t count)
: UObject(), fBogus(FALSE), fCount(count), fCapacity(count),
fHashCode(kInvalidHashCode)
{
fBytes = (uint8_t *)uprv_malloc(count);
if (fBytes == NULL)
{
setToBogus();
return;
}
uprv_memcpy(fBytes, newValues, fCount);
}
CollationKey::CollationKey(const CollationKey& other)
: UObject(other), fBogus(FALSE), fCount(other.fCount), fCapacity(other.fCapacity),
fHashCode(other.fHashCode), fBytes(NULL)
{
if (other.fBogus)
{
setToBogus();
return;
}
fBytes = (uint8_t *)uprv_malloc(fCapacity);
if (fBytes == NULL)
{
setToBogus();
return;
}
uprv_memcpy(fBytes, other.fBytes, other.fCount);
if(fCapacity>fCount) {
uprv_memset(fBytes+fCount, 0, fCapacity-fCount);
}
}
CollationKey::~CollationKey()
{
uprv_free(fBytes);
}
void CollationKey::adopt(uint8_t *values, int32_t capacity, int32_t count) {
if(fBytes != NULL) {
uprv_free(fBytes);
}
fBytes = values;
fCapacity = capacity;
setLength(count);
}
void CollationKey::setLength(int32_t newLength) {
fBogus = FALSE;
fCount = newLength;
fHashCode = kInvalidHashCode;
}
CollationKey&
CollationKey::reset()
{
fCount = 0;
fBogus = FALSE;
fHashCode = kEmptyHashCode;
return *this;
}
CollationKey&
CollationKey::setToBogus()
{
uprv_free(fBytes);
fBytes = NULL;
fCapacity = 0;
fCount = 0;
fHashCode = kInvalidHashCode;
return *this;
}
UBool
CollationKey::operator==(const CollationKey& source) const
{
return (this->fCount == source.fCount &&
(this->fBytes == source.fBytes ||
uprv_memcmp(this->fBytes, source.fBytes, this->fCount) == 0));
}
const CollationKey&
CollationKey::operator=(const CollationKey& other)
{
if (this != &other)
{
if (other.isBogus())
{
return setToBogus();
}
if (other.fBytes != NULL)
{
ensureCapacity(other.fCount);
if (isBogus())
{
return *this;
}
fHashCode = other.fHashCode;
uprv_memcpy(fBytes, other.fBytes, fCount);
}
else
{
fCount = 0;
fBogus = FALSE;
fHashCode = kEmptyHashCode;
}
}
return *this;
}
Collator::EComparisonResult
CollationKey::compareTo(const CollationKey& target) const
{
uint8_t *src = this->fBytes;
uint8_t *tgt = target.fBytes;
if (src == tgt)
return Collator::EQUAL;
int minLength;
Collator::EComparisonResult result;
if (this->fCount != target.fCount) {
if (this->fCount < target.fCount) {
minLength = this->fCount;
result = Collator::LESS;
}
else {
minLength = target.fCount;
result = Collator::GREATER;
}
}
else {
minLength = target.fCount;
result = Collator::EQUAL;
}
if (minLength > 0) {
int diff = uprv_memcmp(src, tgt, minLength);
if (diff > 0) {
return Collator::GREATER;
}
else
if (diff < 0) {
return Collator::LESS;
}
}
return result;
}
UCollationResult
CollationKey::compareTo(const CollationKey& target, UErrorCode &status) const
{
if(U_SUCCESS(status)) {
uint8_t *src = this->fBytes;
uint8_t *tgt = target.fBytes;
if (src == tgt)
return UCOL_EQUAL;
int minLength;
UCollationResult result;
if (this->fCount != target.fCount) {
if (this->fCount < target.fCount) {
minLength = this->fCount;
result = UCOL_LESS;
}
else {
minLength = target.fCount;
result = UCOL_GREATER;
}
}
else {
minLength = target.fCount;
result = UCOL_EQUAL;
}
if (minLength > 0) {
int diff = uprv_memcmp(src, tgt, minLength);
if (diff > 0) {
return UCOL_GREATER;
}
else
if (diff < 0) {
return UCOL_LESS;
}
}
return result;
} else {
return UCOL_EQUAL;
}
}
CollationKey&
CollationKey::ensureCapacity(int32_t newSize)
{
if (fCapacity < newSize)
{
uprv_free(fBytes);
fBytes = (uint8_t *)uprv_malloc(newSize);
if (fBytes == NULL)
{
return setToBogus();
}
uprv_memset(fBytes, 0, fCapacity);
fCapacity = newSize;
}
fBogus = FALSE;
fCount = newSize;
fHashCode = kInvalidHashCode;
return *this;
}
#ifdef U_USE_COLLATION_KEY_DEPRECATES
uint8_t*
CollationKey::toByteArray(int32_t& count) const
{
uint8_t *result = (uint8_t*) uprv_malloc( sizeof(uint8_t) * fCount );
if (result == NULL)
{
count = 0;
}
else
{
count = fCount;
uprv_memcpy(result, fBytes, fCount);
}
return result;
}
#endif
int32_t
CollationKey::hashCode() const
{
if (fHashCode == kInvalidHashCode)
{
const char *s = reinterpret_cast<const char *>(fBytes);
((CollationKey *)this)->fHashCode = s == NULL ? 0 : ustr_hashCharsN(s, fCount);
#if 0
const uint8_t *p = fBytes, *limit = fBytes + fCount;
int32_t inc = (fCount >= 256) ? fCount/128 : 2; int32_t hash = 0;
while (p < limit)
{
hash = ( hash * 37 ) + ((p[0] << 8) + p[1]);
p += inc;
}
if (hash == kInvalidHashCode)
{
hash = kEmptyHashCode;
}
((CollationKey *)this)->fHashCode = hash; #endif
}
return fHashCode;
}
U_NAMESPACE_END
U_CAPI int32_t U_EXPORT2
ucol_keyHashCode(const uint8_t *key,
int32_t length)
{
icu::CollationKey newKey(key, length);
return newKey.hashCode();
}
#endif