diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /intl/icu/source/i18n/ucoleitr.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'intl/icu/source/i18n/ucoleitr.cpp')
-rw-r--r-- | intl/icu/source/i18n/ucoleitr.cpp | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/ucoleitr.cpp b/intl/icu/source/i18n/ucoleitr.cpp new file mode 100644 index 000000000..9c73afda1 --- /dev/null +++ b/intl/icu/source/i18n/ucoleitr.cpp @@ -0,0 +1,531 @@ +// Copyright (C) 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/* +****************************************************************************** +* Copyright (C) 2001-2016, International Business Machines +* Corporation and others. All Rights Reserved. +****************************************************************************** +* +* File ucoleitr.cpp +* +* Modification History: +* +* Date Name Description +* 02/15/2001 synwee Modified all methods to process its own function +* instead of calling the equivalent c++ api (coleitr.h) +* 2012-2014 markus Rewritten in C++ again. +******************************************************************************/ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_COLLATION + +#include "unicode/coleitr.h" +#include "unicode/tblcoll.h" +#include "unicode/ucoleitr.h" +#include "unicode/ustring.h" +#include "unicode/sortkey.h" +#include "unicode/uobject.h" +#include "cmemory.h" +#include "usrchimp.h" + +U_NAMESPACE_USE + +#define BUFFER_LENGTH 100 + +#define DEFAULT_BUFFER_SIZE 16 +#define BUFFER_GROW 8 + +#define ARRAY_COPY(dst, src, count) uprv_memcpy((void *) (dst), (void *) (src), (size_t)(count) * sizeof (src)[0]) + +#define NEW_ARRAY(type, count) (type *) uprv_malloc((size_t)(count) * sizeof(type)) + +#define DELETE_ARRAY(array) uprv_free((void *) (array)) + +struct RCEI +{ + uint32_t ce; + int32_t low; + int32_t high; +}; + +U_NAMESPACE_BEGIN + +struct RCEBuffer +{ + RCEI defaultBuffer[DEFAULT_BUFFER_SIZE]; + RCEI *buffer; + int32_t bufferIndex; + int32_t bufferSize; + + RCEBuffer(); + ~RCEBuffer(); + + UBool isEmpty() const; + void put(uint32_t ce, int32_t ixLow, int32_t ixHigh, UErrorCode &errorCode); + const RCEI *get(); +}; + +RCEBuffer::RCEBuffer() +{ + buffer = defaultBuffer; + bufferIndex = 0; + bufferSize = UPRV_LENGTHOF(defaultBuffer); +} + +RCEBuffer::~RCEBuffer() +{ + if (buffer != defaultBuffer) { + DELETE_ARRAY(buffer); + } +} + +UBool RCEBuffer::isEmpty() const +{ + return bufferIndex <= 0; +} + +void RCEBuffer::put(uint32_t ce, int32_t ixLow, int32_t ixHigh, UErrorCode &errorCode) +{ + if (U_FAILURE(errorCode)) { + return; + } + if (bufferIndex >= bufferSize) { + RCEI *newBuffer = NEW_ARRAY(RCEI, bufferSize + BUFFER_GROW); + if (newBuffer == NULL) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + return; + } + + ARRAY_COPY(newBuffer, buffer, bufferSize); + + if (buffer != defaultBuffer) { + DELETE_ARRAY(buffer); + } + + buffer = newBuffer; + bufferSize += BUFFER_GROW; + } + + buffer[bufferIndex].ce = ce; + buffer[bufferIndex].low = ixLow; + buffer[bufferIndex].high = ixHigh; + + bufferIndex += 1; +} + +const RCEI *RCEBuffer::get() +{ + if (bufferIndex > 0) { + return &buffer[--bufferIndex]; + } + + return NULL; +} + +PCEBuffer::PCEBuffer() +{ + buffer = defaultBuffer; + bufferIndex = 0; + bufferSize = UPRV_LENGTHOF(defaultBuffer); +} + +PCEBuffer::~PCEBuffer() +{ + if (buffer != defaultBuffer) { + DELETE_ARRAY(buffer); + } +} + +void PCEBuffer::reset() +{ + bufferIndex = 0; +} + +UBool PCEBuffer::isEmpty() const +{ + return bufferIndex <= 0; +} + +void PCEBuffer::put(uint64_t ce, int32_t ixLow, int32_t ixHigh, UErrorCode &errorCode) +{ + if (U_FAILURE(errorCode)) { + return; + } + if (bufferIndex >= bufferSize) { + PCEI *newBuffer = NEW_ARRAY(PCEI, bufferSize + BUFFER_GROW); + if (newBuffer == NULL) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + return; + } + + ARRAY_COPY(newBuffer, buffer, bufferSize); + + if (buffer != defaultBuffer) { + DELETE_ARRAY(buffer); + } + + buffer = newBuffer; + bufferSize += BUFFER_GROW; + } + + buffer[bufferIndex].ce = ce; + buffer[bufferIndex].low = ixLow; + buffer[bufferIndex].high = ixHigh; + + bufferIndex += 1; +} + +const PCEI *PCEBuffer::get() +{ + if (bufferIndex > 0) { + return &buffer[--bufferIndex]; + } + + return NULL; +} + +UCollationPCE::UCollationPCE(UCollationElements *elems) { init(elems); } + +UCollationPCE::UCollationPCE(CollationElementIterator *iter) { init(iter); } + +void UCollationPCE::init(UCollationElements *elems) { + init(CollationElementIterator::fromUCollationElements(elems)); +} + +void UCollationPCE::init(CollationElementIterator *iter) +{ + cei = iter; + init(*iter->rbc_); +} + +void UCollationPCE::init(const Collator &coll) +{ + UErrorCode status = U_ZERO_ERROR; + + strength = coll.getAttribute(UCOL_STRENGTH, status); + toShift = coll.getAttribute(UCOL_ALTERNATE_HANDLING, status) == UCOL_SHIFTED; + isShifted = FALSE; + variableTop = coll.getVariableTop(status); +} + +UCollationPCE::~UCollationPCE() +{ + // nothing to do +} + +uint64_t UCollationPCE::processCE(uint32_t ce) +{ + uint64_t primary = 0, secondary = 0, tertiary = 0, quaternary = 0; + + // This is clean, but somewhat slow... + // We could apply the mask to ce and then + // just get all three orders... + switch(strength) { + default: + tertiary = ucol_tertiaryOrder(ce); + U_FALLTHROUGH; + + case UCOL_SECONDARY: + secondary = ucol_secondaryOrder(ce); + U_FALLTHROUGH; + + case UCOL_PRIMARY: + primary = ucol_primaryOrder(ce); + } + + // **** This should probably handle continuations too. **** + // **** That means that we need 24 bits for the primary **** + // **** instead of the 16 that we're currently using. **** + // **** So we can lay out the 64 bits as: 24.12.12.16. **** + // **** Another complication with continuations is that **** + // **** the *second* CE is marked as a continuation, so **** + // **** we always have to peek ahead to know how long **** + // **** the primary is... **** + if ((toShift && variableTop > ce && primary != 0) + || (isShifted && primary == 0)) { + + if (primary == 0) { + return UCOL_IGNORABLE; + } + + if (strength >= UCOL_QUATERNARY) { + quaternary = primary; + } + + primary = secondary = tertiary = 0; + isShifted = TRUE; + } else { + if (strength >= UCOL_QUATERNARY) { + quaternary = 0xFFFF; + } + + isShifted = FALSE; + } + + return primary << 48 | secondary << 32 | tertiary << 16 | quaternary; +} + +U_NAMESPACE_END + +/* public methods ---------------------------------------------------- */ + +U_CAPI UCollationElements* U_EXPORT2 +ucol_openElements(const UCollator *coll, + const UChar *text, + int32_t textLength, + UErrorCode *status) +{ + if (U_FAILURE(*status)) { + return NULL; + } + if (coll == NULL || (text == NULL && textLength != 0)) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return NULL; + } + const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll); + if (rbc == NULL) { + *status = U_UNSUPPORTED_ERROR; // coll is a Collator but not a RuleBasedCollator + return NULL; + } + + UnicodeString s((UBool)(textLength < 0), text, textLength); + CollationElementIterator *cei = rbc->createCollationElementIterator(s); + if (cei == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + + return cei->toUCollationElements(); +} + + +U_CAPI void U_EXPORT2 +ucol_closeElements(UCollationElements *elems) +{ + delete CollationElementIterator::fromUCollationElements(elems); +} + +U_CAPI void U_EXPORT2 +ucol_reset(UCollationElements *elems) +{ + CollationElementIterator::fromUCollationElements(elems)->reset(); +} + +U_CAPI int32_t U_EXPORT2 +ucol_next(UCollationElements *elems, + UErrorCode *status) +{ + if (U_FAILURE(*status)) { + return UCOL_NULLORDER; + } + + return CollationElementIterator::fromUCollationElements(elems)->next(*status); +} + +U_NAMESPACE_BEGIN + +int64_t +UCollationPCE::nextProcessed( + int32_t *ixLow, + int32_t *ixHigh, + UErrorCode *status) +{ + int64_t result = UCOL_IGNORABLE; + uint32_t low = 0, high = 0; + + if (U_FAILURE(*status)) { + return UCOL_PROCESSED_NULLORDER; + } + + pceBuffer.reset(); + + do { + low = cei->getOffset(); + int32_t ce = cei->next(*status); + high = cei->getOffset(); + + if (ce == UCOL_NULLORDER) { + result = UCOL_PROCESSED_NULLORDER; + break; + } + + result = processCE((uint32_t)ce); + } while (result == UCOL_IGNORABLE); + + if (ixLow != NULL) { + *ixLow = low; + } + + if (ixHigh != NULL) { + *ixHigh = high; + } + + return result; +} + +U_NAMESPACE_END + +U_CAPI int32_t U_EXPORT2 +ucol_previous(UCollationElements *elems, + UErrorCode *status) +{ + if(U_FAILURE(*status)) { + return UCOL_NULLORDER; + } + return CollationElementIterator::fromUCollationElements(elems)->previous(*status); +} + +U_NAMESPACE_BEGIN + +int64_t +UCollationPCE::previousProcessed( + int32_t *ixLow, + int32_t *ixHigh, + UErrorCode *status) +{ + int64_t result = UCOL_IGNORABLE; + int32_t low = 0, high = 0; + + if (U_FAILURE(*status)) { + return UCOL_PROCESSED_NULLORDER; + } + + // pceBuffer.reset(); + + while (pceBuffer.isEmpty()) { + // buffer raw CEs up to non-ignorable primary + RCEBuffer rceb; + int32_t ce; + + // **** do we need to reset rceb, or will it always be empty at this point **** + do { + high = cei->getOffset(); + ce = cei->previous(*status); + low = cei->getOffset(); + + if (ce == UCOL_NULLORDER) { + if (!rceb.isEmpty()) { + break; + } + + goto finish; + } + + rceb.put((uint32_t)ce, low, high, *status); + } while (U_SUCCESS(*status) && ((ce & UCOL_PRIMARYORDERMASK) == 0 || isContinuation(ce))); + + // process the raw CEs + while (U_SUCCESS(*status) && !rceb.isEmpty()) { + const RCEI *rcei = rceb.get(); + + result = processCE(rcei->ce); + + if (result != UCOL_IGNORABLE) { + pceBuffer.put(result, rcei->low, rcei->high, *status); + } + } + if (U_FAILURE(*status)) { + return UCOL_PROCESSED_NULLORDER; + } + } + +finish: + if (pceBuffer.isEmpty()) { + // **** Is -1 the right value for ixLow, ixHigh? **** + if (ixLow != NULL) { + *ixLow = -1; + } + + if (ixHigh != NULL) { + *ixHigh = -1 + ; + } + return UCOL_PROCESSED_NULLORDER; + } + + const PCEI *pcei = pceBuffer.get(); + + if (ixLow != NULL) { + *ixLow = pcei->low; + } + + if (ixHigh != NULL) { + *ixHigh = pcei->high; + } + + return pcei->ce; +} + +U_NAMESPACE_END + +U_CAPI int32_t U_EXPORT2 +ucol_getMaxExpansion(const UCollationElements *elems, + int32_t order) +{ + return CollationElementIterator::fromUCollationElements(elems)->getMaxExpansion(order); + + // TODO: The old code masked the order according to strength and then did a binary search. + // However this was probably at least partially broken because of the following comment. + // Still, it might have found a match when this version may not. + + // FIXME: with a masked search, there might be more than one hit, + // so we need to look forward and backward from the match to find all + // of the hits... +} + +U_CAPI void U_EXPORT2 +ucol_setText( UCollationElements *elems, + const UChar *text, + int32_t textLength, + UErrorCode *status) +{ + if (U_FAILURE(*status)) { + return; + } + + if ((text == NULL && textLength != 0)) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + UnicodeString s((UBool)(textLength < 0), text, textLength); + return CollationElementIterator::fromUCollationElements(elems)->setText(s, *status); +} + +U_CAPI int32_t U_EXPORT2 +ucol_getOffset(const UCollationElements *elems) +{ + return CollationElementIterator::fromUCollationElements(elems)->getOffset(); +} + +U_CAPI void U_EXPORT2 +ucol_setOffset(UCollationElements *elems, + int32_t offset, + UErrorCode *status) +{ + if (U_FAILURE(*status)) { + return; + } + + CollationElementIterator::fromUCollationElements(elems)->setOffset(offset, *status); +} + +U_CAPI int32_t U_EXPORT2 +ucol_primaryOrder (int32_t order) +{ + return (order >> 16) & 0xffff; +} + +U_CAPI int32_t U_EXPORT2 +ucol_secondaryOrder (int32_t order) +{ + return (order >> 8) & 0xff; +} + +U_CAPI int32_t U_EXPORT2 +ucol_tertiaryOrder (int32_t order) +{ + return order & 0xff; +} + +#endif /* #if !UCONFIG_NO_COLLATION */ |