694 lines
24 KiB
C++
694 lines
24 KiB
C++
// © 2016 and later: Unicode, Inc. and others.
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
|
//
|
|
// rbbisetb.cpp
|
|
//
|
|
/*
|
|
***************************************************************************
|
|
* Copyright (C) 2002-2008 International Business Machines Corporation *
|
|
* and others. All rights reserved. *
|
|
***************************************************************************
|
|
*/
|
|
//
|
|
// RBBISetBuilder Handles processing of Unicode Sets from RBBI rules
|
|
// (part of the rule building process.)
|
|
//
|
|
// Starting with the rules parse tree from the scanner,
|
|
//
|
|
// - Enumerate the set of UnicodeSets that are referenced
|
|
// by the RBBI rules.
|
|
// - compute a set of non-overlapping character ranges
|
|
// with all characters within a range belonging to the same
|
|
// set of input unicode sets.
|
|
// - Derive a set of non-overlapping UnicodeSet (like things)
|
|
// that will correspond to columns in the state table for
|
|
// the RBBI execution engine. All characters within one
|
|
// of these sets belong to the same set of the original
|
|
// UnicodeSets from the user's rules.
|
|
// - construct the trie table that maps input characters
|
|
// to the index of the matching non-overlapping set of set from
|
|
// the previous step.
|
|
//
|
|
|
|
#include "unicode/utypes.h"
|
|
|
|
#if !UCONFIG_NO_BREAK_ITERATION
|
|
|
|
#include "unicode/uniset.h"
|
|
#include "uvector.h"
|
|
#include "uassert.h"
|
|
#include "cmemory.h"
|
|
#include "cstring.h"
|
|
|
|
#include "rbbisetb.h"
|
|
#include "rbbinode.h"
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
const int32_t kMaxCharCategoriesFor8BitsTrie = 255;
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Constructor
|
|
//
|
|
//------------------------------------------------------------------------
|
|
RBBISetBuilder::RBBISetBuilder(RBBIRuleBuilder *rb)
|
|
{
|
|
fRB = rb;
|
|
fStatus = rb->fStatus;
|
|
fRangeList = nullptr;
|
|
fMutableTrie = nullptr;
|
|
fTrie = nullptr;
|
|
fTrieSize = 0;
|
|
fGroupCount = 0;
|
|
fSawBOF = false;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Destructor
|
|
//
|
|
//------------------------------------------------------------------------
|
|
RBBISetBuilder::~RBBISetBuilder()
|
|
{
|
|
RangeDescriptor *nextRangeDesc;
|
|
|
|
// Walk through & delete the linked list of RangeDescriptors
|
|
for (nextRangeDesc = fRangeList; nextRangeDesc!=NULL;) {
|
|
RangeDescriptor *r = nextRangeDesc;
|
|
nextRangeDesc = r->fNext;
|
|
delete r;
|
|
}
|
|
|
|
ucptrie_close(fTrie);
|
|
umutablecptrie_close(fMutableTrie);
|
|
}
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// build Build the list of non-overlapping character ranges
|
|
// from the Unicode Sets.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
void RBBISetBuilder::buildRanges() {
|
|
RBBINode *usetNode;
|
|
RangeDescriptor *rlRange;
|
|
|
|
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "usets")) {printSets();}
|
|
|
|
//
|
|
// Initialize the process by creating a single range encompassing all characters
|
|
// that is in no sets.
|
|
//
|
|
fRangeList = new RangeDescriptor(*fStatus); // will check for status here
|
|
if (fRangeList == NULL) {
|
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
|
return;
|
|
}
|
|
fRangeList->fStartChar = 0;
|
|
fRangeList->fEndChar = 0x10ffff;
|
|
|
|
if (U_FAILURE(*fStatus)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Find the set of non-overlapping ranges of characters
|
|
//
|
|
int ni;
|
|
for (ni=0; ; ni++) { // Loop over each of the UnicodeSets encountered in the input rules
|
|
usetNode = (RBBINode *)this->fRB->fUSetNodes->elementAt(ni);
|
|
if (usetNode==NULL) {
|
|
break;
|
|
}
|
|
|
|
UnicodeSet *inputSet = usetNode->fInputSet;
|
|
int32_t inputSetRangeCount = inputSet->getRangeCount();
|
|
int inputSetRangeIndex = 0;
|
|
rlRange = fRangeList;
|
|
|
|
for (;;) {
|
|
if (inputSetRangeIndex >= inputSetRangeCount) {
|
|
break;
|
|
}
|
|
UChar32 inputSetRangeBegin = inputSet->getRangeStart(inputSetRangeIndex);
|
|
UChar32 inputSetRangeEnd = inputSet->getRangeEnd(inputSetRangeIndex);
|
|
|
|
// skip over ranges from the range list that are completely
|
|
// below the current range from the input unicode set.
|
|
while (rlRange->fEndChar < inputSetRangeBegin) {
|
|
rlRange = rlRange->fNext;
|
|
}
|
|
|
|
// If the start of the range from the range list is before with
|
|
// the start of the range from the unicode set, split the range list range
|
|
// in two, with one part being before (wholly outside of) the unicode set
|
|
// and the other containing the rest.
|
|
// Then continue the loop; the post-split current range will then be skipped
|
|
// over
|
|
if (rlRange->fStartChar < inputSetRangeBegin) {
|
|
rlRange->split(inputSetRangeBegin, *fStatus);
|
|
if (U_FAILURE(*fStatus)) {
|
|
return;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Same thing at the end of the ranges...
|
|
// If the end of the range from the range list doesn't coincide with
|
|
// the end of the range from the unicode set, split the range list
|
|
// range in two. The first part of the split range will be
|
|
// wholly inside the Unicode set.
|
|
if (rlRange->fEndChar > inputSetRangeEnd) {
|
|
rlRange->split(inputSetRangeEnd+1, *fStatus);
|
|
if (U_FAILURE(*fStatus)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// The current rlRange is now entirely within the UnicodeSet range.
|
|
// Add this unicode set to the list of sets for this rlRange
|
|
if (rlRange->fIncludesSets->indexOf(usetNode) == -1) {
|
|
rlRange->fIncludesSets->addElement(usetNode, *fStatus);
|
|
if (U_FAILURE(*fStatus)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Advance over ranges that we are finished with.
|
|
if (inputSetRangeEnd == rlRange->fEndChar) {
|
|
inputSetRangeIndex++;
|
|
}
|
|
rlRange = rlRange->fNext;
|
|
}
|
|
}
|
|
|
|
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "range")) { printRanges();}
|
|
|
|
//
|
|
// Group the above ranges, with each group consisting of one or more
|
|
// ranges that are in exactly the same set of original UnicodeSets.
|
|
// The groups are numbered, and these group numbers are the set of
|
|
// input symbols recognized by the run-time state machine.
|
|
//
|
|
// Numbering: # 0 (state table column 0) is unused.
|
|
// # 1 is reserved - table column 1 is for end-of-input
|
|
// # 2 is reserved - table column 2 is for beginning-of-input
|
|
// # 3 is the first range list.
|
|
//
|
|
RangeDescriptor *rlSearchRange;
|
|
int32_t dictGroupCount = 0;
|
|
|
|
for (rlRange = fRangeList; rlRange!=nullptr; rlRange=rlRange->fNext) {
|
|
for (rlSearchRange=fRangeList; rlSearchRange != rlRange; rlSearchRange=rlSearchRange->fNext) {
|
|
if (rlRange->fIncludesSets->equals(*rlSearchRange->fIncludesSets)) {
|
|
rlRange->fNum = rlSearchRange->fNum;
|
|
rlRange->fIncludesDict = rlSearchRange->fIncludesDict;
|
|
break;
|
|
}
|
|
}
|
|
if (rlRange->fNum == 0) {
|
|
rlRange->fFirstInGroup = true;
|
|
if (rlRange->isDictionaryRange()) {
|
|
rlRange->fNum = ++dictGroupCount;
|
|
rlRange->fIncludesDict = true;
|
|
} else {
|
|
fGroupCount++;
|
|
rlRange->fNum = fGroupCount+2;
|
|
addValToSets(rlRange->fIncludesSets, rlRange->fNum);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Move the character category numbers for any dictionary ranges up, so that they
|
|
// immediately follow the non-dictionary ranges.
|
|
|
|
fDictCategoriesStart = fGroupCount + 3;
|
|
for (rlRange = fRangeList; rlRange!=nullptr; rlRange=rlRange->fNext) {
|
|
if (rlRange->fIncludesDict) {
|
|
rlRange->fNum += fDictCategoriesStart - 1;
|
|
if (rlRange->fFirstInGroup) {
|
|
addValToSets(rlRange->fIncludesSets, rlRange->fNum);
|
|
}
|
|
}
|
|
}
|
|
fGroupCount += dictGroupCount;
|
|
|
|
|
|
// Handle input sets that contain the special string {eof}.
|
|
// Column 1 of the state table is reserved for EOF on input.
|
|
// Column 2 is reserved for before-the-start-input.
|
|
// (This column can be optimized away later if there are no rule
|
|
// references to {bof}.)
|
|
// Add this column value (1 or 2) to the equivalent expression
|
|
// subtree for each UnicodeSet that contains the string {eof}
|
|
// Because {bof} and {eof} are not characters in the normal sense,
|
|
// they don't affect the computation of the ranges or TRIE.
|
|
|
|
UnicodeString eofString(u"eof");
|
|
UnicodeString bofString(u"bof");
|
|
for (ni=0; ; ni++) { // Loop over each of the UnicodeSets encountered in the input rules
|
|
usetNode = (RBBINode *)this->fRB->fUSetNodes->elementAt(ni);
|
|
if (usetNode==NULL) {
|
|
break;
|
|
}
|
|
UnicodeSet *inputSet = usetNode->fInputSet;
|
|
if (inputSet->contains(eofString)) {
|
|
addValToSet(usetNode, 1);
|
|
}
|
|
if (inputSet->contains(bofString)) {
|
|
addValToSet(usetNode, 2);
|
|
fSawBOF = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "rgroup")) {printRangeGroups();}
|
|
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "esets")) {printSets();}
|
|
}
|
|
|
|
|
|
//
|
|
// Build the Trie table for mapping UChar32 values to the corresponding
|
|
// range group number.
|
|
//
|
|
void RBBISetBuilder::buildTrie() {
|
|
fMutableTrie = umutablecptrie_open(
|
|
0, // Initial value for all code points.
|
|
0, // Error value for out-of-range input.
|
|
fStatus);
|
|
|
|
for (RangeDescriptor *range = fRangeList; range!=nullptr && U_SUCCESS(*fStatus); range=range->fNext) {
|
|
umutablecptrie_setRange(fMutableTrie,
|
|
range->fStartChar, // Range start
|
|
range->fEndChar, // Range end (inclusive)
|
|
range->fNum, // value for range
|
|
fStatus);
|
|
}
|
|
}
|
|
|
|
|
|
void RBBISetBuilder::mergeCategories(IntPair categories) {
|
|
U_ASSERT(categories.first >= 1);
|
|
U_ASSERT(categories.second > categories.first);
|
|
U_ASSERT((categories.first < fDictCategoriesStart && categories.second < fDictCategoriesStart) ||
|
|
(categories.first >= fDictCategoriesStart && categories.second >= fDictCategoriesStart));
|
|
|
|
for (RangeDescriptor *rd = fRangeList; rd != nullptr; rd = rd->fNext) {
|
|
int32_t rangeNum = rd->fNum;
|
|
if (rangeNum == categories.second) {
|
|
rd->fNum = categories.first;
|
|
} else if (rangeNum > categories.second) {
|
|
rd->fNum--;
|
|
}
|
|
}
|
|
--fGroupCount;
|
|
if (categories.second <= fDictCategoriesStart) {
|
|
--fDictCategoriesStart;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
//
|
|
// getTrieSize() Return the size that will be required to serialize the Trie.
|
|
//
|
|
//-----------------------------------------------------------------------------------
|
|
int32_t RBBISetBuilder::getTrieSize() {
|
|
if (U_FAILURE(*fStatus)) {
|
|
return 0;
|
|
}
|
|
if (fTrie == nullptr) {
|
|
bool use8Bits = getNumCharCategories() <= kMaxCharCategoriesFor8BitsTrie;
|
|
fTrie = umutablecptrie_buildImmutable(
|
|
fMutableTrie,
|
|
UCPTRIE_TYPE_FAST,
|
|
use8Bits ? UCPTRIE_VALUE_BITS_8 : UCPTRIE_VALUE_BITS_16,
|
|
fStatus);
|
|
fTrieSize = ucptrie_toBinary(fTrie, nullptr, 0, fStatus);
|
|
if (*fStatus == U_BUFFER_OVERFLOW_ERROR) {
|
|
*fStatus = U_ZERO_ERROR;
|
|
}
|
|
}
|
|
return fTrieSize;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
//
|
|
// serializeTrie() Put the serialized trie at the specified address.
|
|
// Trust the caller to have given us enough memory.
|
|
// getTrieSize() MUST be called first.
|
|
//
|
|
//-----------------------------------------------------------------------------------
|
|
void RBBISetBuilder::serializeTrie(uint8_t *where) {
|
|
ucptrie_toBinary(fTrie,
|
|
where, // Buffer
|
|
fTrieSize, // Capacity
|
|
fStatus);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// addValToSets Add a runtime-mapped input value to each uset from a
|
|
// list of uset nodes. (val corresponds to a state table column.)
|
|
// For each of the original Unicode sets - which correspond
|
|
// directly to uset nodes - a logically equivalent expression
|
|
// is constructed in terms of the remapped runtime input
|
|
// symbol set. This function adds one runtime input symbol to
|
|
// a list of sets.
|
|
//
|
|
// The "logically equivalent expression" is the tree for an
|
|
// or-ing together of all of the symbols that go into the set.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
void RBBISetBuilder::addValToSets(UVector *sets, uint32_t val) {
|
|
int32_t ix;
|
|
|
|
for (ix=0; ix<sets->size(); ix++) {
|
|
RBBINode *usetNode = (RBBINode *)sets->elementAt(ix);
|
|
addValToSet(usetNode, val);
|
|
}
|
|
}
|
|
|
|
void RBBISetBuilder::addValToSet(RBBINode *usetNode, uint32_t val) {
|
|
RBBINode *leafNode = new RBBINode(RBBINode::leafChar);
|
|
if (leafNode == NULL) {
|
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
|
return;
|
|
}
|
|
leafNode->fVal = (unsigned short)val;
|
|
if (usetNode->fLeftChild == NULL) {
|
|
usetNode->fLeftChild = leafNode;
|
|
leafNode->fParent = usetNode;
|
|
} else {
|
|
// There are already input symbols present for this set.
|
|
// Set up an OR node, with the previous stuff as the left child
|
|
// and the new value as the right child.
|
|
RBBINode *orNode = new RBBINode(RBBINode::opOr);
|
|
if (orNode == NULL) {
|
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
|
return;
|
|
}
|
|
orNode->fLeftChild = usetNode->fLeftChild;
|
|
orNode->fRightChild = leafNode;
|
|
orNode->fLeftChild->fParent = orNode;
|
|
orNode->fRightChild->fParent = orNode;
|
|
usetNode->fLeftChild = orNode;
|
|
orNode->fParent = usetNode;
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// getNumCharCategories
|
|
//
|
|
//------------------------------------------------------------------------
|
|
int32_t RBBISetBuilder::getNumCharCategories() const {
|
|
return fGroupCount + 3;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// getDictCategoriesStart
|
|
//
|
|
//------------------------------------------------------------------------
|
|
int32_t RBBISetBuilder::getDictCategoriesStart() const {
|
|
return fDictCategoriesStart;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// sawBOF
|
|
//
|
|
//------------------------------------------------------------------------
|
|
UBool RBBISetBuilder::sawBOF() const {
|
|
return fSawBOF;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// getFirstChar Given a runtime RBBI character category, find
|
|
// the first UChar32 that is in the set of chars
|
|
// in the category.
|
|
//------------------------------------------------------------------------
|
|
UChar32 RBBISetBuilder::getFirstChar(int32_t category) const {
|
|
RangeDescriptor *rlRange;
|
|
UChar32 retVal = (UChar32)-1;
|
|
for (rlRange = fRangeList; rlRange!=nullptr; rlRange=rlRange->fNext) {
|
|
if (rlRange->fNum == category) {
|
|
retVal = rlRange->fStartChar;
|
|
break;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// printRanges A debugging function.
|
|
// dump out all of the range definitions.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
#ifdef RBBI_DEBUG
|
|
void RBBISetBuilder::printRanges() {
|
|
RangeDescriptor *rlRange;
|
|
int i;
|
|
|
|
RBBIDebugPrintf("\n\n Nonoverlapping Ranges ...\n");
|
|
for (rlRange = fRangeList; rlRange!=nullptr; rlRange=rlRange->fNext) {
|
|
RBBIDebugPrintf("%4x-%4x ", rlRange->fStartChar, rlRange->fEndChar);
|
|
|
|
for (i=0; i<rlRange->fIncludesSets->size(); i++) {
|
|
RBBINode *usetNode = (RBBINode *)rlRange->fIncludesSets->elementAt(i);
|
|
UnicodeString setName {u"anon"};
|
|
RBBINode *setRef = usetNode->fParent;
|
|
if (setRef != nullptr) {
|
|
RBBINode *varRef = setRef->fParent;
|
|
if (varRef != nullptr && varRef->fType == RBBINode::varRef) {
|
|
setName = varRef->fText;
|
|
}
|
|
}
|
|
RBBI_DEBUG_printUnicodeString(setName); RBBIDebugPrintf(" ");
|
|
}
|
|
RBBIDebugPrintf("\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// printRangeGroups A debugging function.
|
|
// dump out all of the range groups.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
#ifdef RBBI_DEBUG
|
|
void RBBISetBuilder::printRangeGroups() {
|
|
int i;
|
|
|
|
RBBIDebugPrintf("\nRanges grouped by Unicode Set Membership...\n");
|
|
for (RangeDescriptor *rlRange = fRangeList; rlRange!=nullptr; rlRange=rlRange->fNext) {
|
|
if (rlRange->fFirstInGroup) {
|
|
int groupNum = rlRange->fNum;
|
|
RBBIDebugPrintf("%2i ", groupNum);
|
|
|
|
if (groupNum >= fDictCategoriesStart) { RBBIDebugPrintf(" <DICT> ");}
|
|
|
|
for (i=0; i<rlRange->fIncludesSets->size(); i++) {
|
|
RBBINode *usetNode = (RBBINode *)rlRange->fIncludesSets->elementAt(i);
|
|
UnicodeString setName = UNICODE_STRING("anon", 4);
|
|
RBBINode *setRef = usetNode->fParent;
|
|
if (setRef != NULL) {
|
|
RBBINode *varRef = setRef->fParent;
|
|
if (varRef != NULL && varRef->fType == RBBINode::varRef) {
|
|
setName = varRef->fText;
|
|
}
|
|
}
|
|
RBBI_DEBUG_printUnicodeString(setName); RBBIDebugPrintf(" ");
|
|
}
|
|
|
|
i = 0;
|
|
for (RangeDescriptor *tRange = rlRange; tRange != nullptr; tRange = tRange->fNext) {
|
|
if (tRange->fNum == rlRange->fNum) {
|
|
if (i++ % 5 == 0) {
|
|
RBBIDebugPrintf("\n ");
|
|
}
|
|
RBBIDebugPrintf(" %05x-%05x", tRange->fStartChar, tRange->fEndChar);
|
|
}
|
|
}
|
|
RBBIDebugPrintf("\n");
|
|
}
|
|
}
|
|
RBBIDebugPrintf("\n");
|
|
}
|
|
#endif
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// printSets A debugging function.
|
|
// dump out all of the set definitions.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
#ifdef RBBI_DEBUG
|
|
void RBBISetBuilder::printSets() {
|
|
int i;
|
|
|
|
RBBIDebugPrintf("\n\nUnicode Sets List\n------------------\n");
|
|
for (i=0; ; i++) {
|
|
RBBINode *usetNode;
|
|
RBBINode *setRef;
|
|
RBBINode *varRef;
|
|
UnicodeString setName;
|
|
|
|
usetNode = (RBBINode *)fRB->fUSetNodes->elementAt(i);
|
|
if (usetNode == NULL) {
|
|
break;
|
|
}
|
|
|
|
RBBIDebugPrintf("%3d ", i);
|
|
setName = UNICODE_STRING("anonymous", 9);
|
|
setRef = usetNode->fParent;
|
|
if (setRef != NULL) {
|
|
varRef = setRef->fParent;
|
|
if (varRef != NULL && varRef->fType == RBBINode::varRef) {
|
|
setName = varRef->fText;
|
|
}
|
|
}
|
|
RBBI_DEBUG_printUnicodeString(setName);
|
|
RBBIDebugPrintf(" ");
|
|
RBBI_DEBUG_printUnicodeString(usetNode->fText);
|
|
RBBIDebugPrintf("\n");
|
|
if (usetNode->fLeftChild != NULL) {
|
|
RBBINode::printTree(usetNode->fLeftChild, TRUE);
|
|
}
|
|
}
|
|
RBBIDebugPrintf("\n");
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
//
|
|
// RangeDescriptor copy constructor
|
|
//
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
RangeDescriptor::RangeDescriptor(const RangeDescriptor &other, UErrorCode &status) :
|
|
fStartChar(other.fStartChar), fEndChar {other.fEndChar}, fNum {other.fNum},
|
|
fIncludesDict{other.fIncludesDict}, fFirstInGroup{other.fFirstInGroup} {
|
|
|
|
if (U_FAILURE(status)) {
|
|
return;
|
|
}
|
|
fIncludesSets = new UVector(status);
|
|
if (this->fIncludesSets == nullptr) {
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
}
|
|
if (U_FAILURE(status)) {
|
|
return;
|
|
}
|
|
|
|
for (int32_t i=0; i<other.fIncludesSets->size(); i++) {
|
|
this->fIncludesSets->addElement(other.fIncludesSets->elementAt(i), status);
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
//
|
|
// RangeDesriptor default constructor
|
|
//
|
|
//-------------------------------------------------------------------------------------
|
|
RangeDescriptor::RangeDescriptor(UErrorCode &status) {
|
|
if (U_FAILURE(status)) {
|
|
return;
|
|
}
|
|
fIncludesSets = new UVector(status);
|
|
if (fIncludesSets == nullptr) {
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
//
|
|
// RangeDesriptor Destructor
|
|
//
|
|
//-------------------------------------------------------------------------------------
|
|
RangeDescriptor::~RangeDescriptor() {
|
|
delete fIncludesSets;
|
|
fIncludesSets = nullptr;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
//
|
|
// RangeDesriptor::split()
|
|
//
|
|
//-------------------------------------------------------------------------------------
|
|
void RangeDescriptor::split(UChar32 where, UErrorCode &status) {
|
|
U_ASSERT(where>fStartChar && where<=fEndChar);
|
|
RangeDescriptor *nr = new RangeDescriptor(*this, status);
|
|
if(nr == nullptr) {
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
return;
|
|
}
|
|
if (U_FAILURE(status)) {
|
|
delete nr;
|
|
return;
|
|
}
|
|
// RangeDescriptor copy constructor copies all fields.
|
|
// Only need to update those that are different after the split.
|
|
nr->fStartChar = where;
|
|
this->fEndChar = where-1;
|
|
nr->fNext = this->fNext;
|
|
this->fNext = nr;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
//
|
|
// RangeDescriptor::isDictionaryRange
|
|
//
|
|
// Test whether this range includes characters from
|
|
// the original Unicode Set named "dictionary".
|
|
//
|
|
// This function looks through the Unicode Sets that
|
|
// the range includes, checking for one named "dictionary"
|
|
//
|
|
// TODO: a faster way would be to find the set node for
|
|
// "dictionary" just once, rather than looking it
|
|
// up by name every time.
|
|
//
|
|
//-------------------------------------------------------------------------------------
|
|
bool RangeDescriptor::isDictionaryRange() {
|
|
static const char16_t *dictionary = u"dictionary";
|
|
for (int32_t i=0; i<fIncludesSets->size(); i++) {
|
|
RBBINode *usetNode = (RBBINode *)fIncludesSets->elementAt(i);
|
|
RBBINode *setRef = usetNode->fParent;
|
|
if (setRef != nullptr) {
|
|
RBBINode *varRef = setRef->fParent;
|
|
if (varRef && varRef->fType == RBBINode::varRef) {
|
|
const UnicodeString *setName = &varRef->fText;
|
|
if (setName->compare(dictionary, -1) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
U_NAMESPACE_END
|
|
|
|
#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
|