2017-01-20 00:20:31 +00:00
|
|
|
// © 2016 and later: Unicode, Inc. and others.
|
2016-06-15 18:58:17 +00:00
|
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
1999-10-27 16:34:57 +00:00
|
|
|
/*
|
2003-06-02 22:21:58 +00:00
|
|
|
***************************************************************************
|
2016-05-31 21:45:07 +00:00
|
|
|
* Copyright (C) 1999-2016 International Business Machines Corporation
|
2010-05-19 17:29:33 +00:00
|
|
|
* and others. All rights reserved.
|
2003-06-02 22:21:58 +00:00
|
|
|
***************************************************************************
|
1999-10-27 16:34:57 +00:00
|
|
|
*/
|
2003-08-27 01:01:42 +00:00
|
|
|
//
|
2017-09-19 18:17:22 +00:00
|
|
|
// file: rbbi.cpp Contains the implementation of the rule based break iterator
|
2003-08-27 01:01:42 +00:00
|
|
|
// runtime engine and the API implementation for
|
|
|
|
// class RuleBasedBreakIterator
|
|
|
|
//
|
1999-10-27 16:34:57 +00:00
|
|
|
|
2012-06-28 23:28:00 +00:00
|
|
|
#include "utypeinfo.h" // for 'typeid' to work
|
2010-05-19 17:29:33 +00:00
|
|
|
|
2002-09-20 01:54:48 +00:00
|
|
|
#include "unicode/utypes.h"
|
|
|
|
|
|
|
|
#if !UCONFIG_NO_BREAK_ITERATION
|
2002-06-27 21:14:47 +00:00
|
|
|
|
2018-08-24 17:52:15 +00:00
|
|
|
#include <cinttypes>
|
|
|
|
|
2000-01-10 21:10:21 +00:00
|
|
|
#include "unicode/rbbi.h"
|
|
|
|
#include "unicode/schriter.h"
|
2006-05-08 16:08:53 +00:00
|
|
|
#include "unicode/uchriter.h"
|
2003-08-22 23:26:53 +00:00
|
|
|
#include "unicode/uclean.h"
|
2017-04-23 19:35:52 +00:00
|
|
|
#include "unicode/udata.h"
|
2017-09-19 18:17:22 +00:00
|
|
|
|
2017-04-23 19:35:52 +00:00
|
|
|
#include "brkeng.h"
|
2017-09-19 18:17:22 +00:00
|
|
|
#include "ucln_cmn.h"
|
2001-02-22 01:03:05 +00:00
|
|
|
#include "cmemory.h"
|
2002-08-08 00:39:13 +00:00
|
|
|
#include "cstring.h"
|
2019-04-09 00:06:44 +00:00
|
|
|
#include "localsvc.h"
|
2017-04-23 19:35:52 +00:00
|
|
|
#include "rbbidata.h"
|
2017-09-19 18:17:22 +00:00
|
|
|
#include "rbbi_cache.h"
|
2017-04-23 19:35:52 +00:00
|
|
|
#include "rbbirb.h"
|
2002-07-22 23:24:55 +00:00
|
|
|
#include "uassert.h"
|
2017-04-23 19:35:52 +00:00
|
|
|
#include "umutex.h"
|
2017-09-19 18:17:22 +00:00
|
|
|
#include "uvectr32.h"
|
2002-06-25 17:23:07 +00:00
|
|
|
|
2006-07-14 00:47:15 +00:00
|
|
|
#ifdef RBBI_DEBUG
|
2017-09-19 18:17:22 +00:00
|
|
|
static UBool gTrace = FALSE;
|
2006-07-14 00:47:15 +00:00
|
|
|
#endif
|
|
|
|
|
2001-10-08 23:26:58 +00:00
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
|
2008-03-14 06:41:45 +00:00
|
|
|
// The state number of the starting state
|
2017-09-19 18:17:22 +00:00
|
|
|
constexpr int32_t START_STATE = 1;
|
1999-10-27 16:34:57 +00:00
|
|
|
|
2008-03-14 06:41:45 +00:00
|
|
|
// The state-transition value indicating "stop"
|
2017-09-19 18:17:22 +00:00
|
|
|
constexpr int32_t STOP_STATE = 0;
|
2000-01-08 02:05:05 +00:00
|
|
|
|
2003-08-27 01:01:42 +00:00
|
|
|
|
|
|
|
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedBreakIterator)
|
1999-10-27 16:34:57 +00:00
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
|
1999-10-27 16:34:57 +00:00
|
|
|
//=======================================================================
|
|
|
|
// constructors
|
|
|
|
//=======================================================================
|
|
|
|
|
|
|
|
/**
|
2000-01-08 02:05:05 +00:00
|
|
|
* Constructs a RuleBasedBreakIterator that uses the already-created
|
|
|
|
* tables object that is passed in as a parameter.
|
1999-10-27 16:34:57 +00:00
|
|
|
*/
|
2018-01-19 22:30:56 +00:00
|
|
|
RuleBasedBreakIterator::RuleBasedBreakIterator(RBBIDataHeader* data, UErrorCode &status)
|
2018-03-01 19:33:46 +00:00
|
|
|
: fSCharIter(UnicodeString())
|
2018-01-19 22:30:56 +00:00
|
|
|
{
|
2017-09-19 18:17:22 +00:00
|
|
|
init(status);
|
2003-09-09 23:51:17 +00:00
|
|
|
fData = new RBBIDataWrapper(data, status); // status checked in constructor
|
2002-11-30 04:41:53 +00:00
|
|
|
if (U_FAILURE(status)) {return;}
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
if(fData == nullptr) {
|
2002-06-29 09:31:05 +00:00
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
if (fData->fForwardTable->fLookAheadResultsSize > 0) {
|
|
|
|
fLookAheadMatches = static_cast<int32_t *>(
|
|
|
|
uprv_malloc(fData->fForwardTable->fLookAheadResultsSize * sizeof(int32_t)));
|
|
|
|
if (fLookAheadMatches == nullptr) {
|
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
|
|
|
|
2011-04-29 17:49:01 +00:00
|
|
|
//
|
|
|
|
// Construct from precompiled binary rules (tables). This constructor is public API,
|
|
|
|
// taking the rules as a (const uint8_t *) to match the type produced by getBinaryRules().
|
|
|
|
//
|
|
|
|
RuleBasedBreakIterator::RuleBasedBreakIterator(const uint8_t *compiledRules,
|
|
|
|
uint32_t ruleLength,
|
2018-01-19 22:30:56 +00:00
|
|
|
UErrorCode &status)
|
2018-03-01 19:33:46 +00:00
|
|
|
: fSCharIter(UnicodeString())
|
2018-01-19 22:30:56 +00:00
|
|
|
{
|
2017-09-19 18:17:22 +00:00
|
|
|
init(status);
|
2011-04-29 17:49:01 +00:00
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return;
|
|
|
|
}
|
2011-05-09 02:56:05 +00:00
|
|
|
if (compiledRules == NULL || ruleLength < sizeof(RBBIDataHeader)) {
|
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
2011-04-29 17:49:01 +00:00
|
|
|
const RBBIDataHeader *data = (const RBBIDataHeader *)compiledRules;
|
2011-05-09 02:56:05 +00:00
|
|
|
if (data->fLength > ruleLength) {
|
2011-04-29 17:49:01 +00:00
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
fData = new RBBIDataWrapper(data, RBBIDataWrapper::kDontAdopt, status);
|
2011-04-29 17:49:01 +00:00
|
|
|
if (U_FAILURE(status)) {return;}
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
if(fData == nullptr) {
|
2011-04-29 17:49:01 +00:00
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
if (fData->fForwardTable->fLookAheadResultsSize > 0) {
|
|
|
|
fLookAheadMatches = static_cast<int32_t *>(
|
|
|
|
uprv_malloc(fData->fForwardTable->fLookAheadResultsSize * sizeof(int32_t)));
|
|
|
|
if (fLookAheadMatches == nullptr) {
|
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
}
|
2011-04-29 17:49:01 +00:00
|
|
|
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Constructor from a UDataMemory handle to precompiled break rules
|
|
|
|
// stored in an ICU data file.
|
|
|
|
//
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
RuleBasedBreakIterator::RuleBasedBreakIterator(UDataMemory* udm, UErrorCode &status)
|
2018-03-01 19:33:46 +00:00
|
|
|
: fSCharIter(UnicodeString())
|
2000-01-08 02:05:05 +00:00
|
|
|
{
|
2017-09-19 18:17:22 +00:00
|
|
|
init(status);
|
2003-09-09 23:51:17 +00:00
|
|
|
fData = new RBBIDataWrapper(udm, status); // status checked in constructor
|
2002-11-30 04:41:53 +00:00
|
|
|
if (U_FAILURE(status)) {return;}
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
if(fData == nullptr) {
|
2002-06-29 09:31:05 +00:00
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
if (fData->fForwardTable->fLookAheadResultsSize > 0) {
|
|
|
|
fLookAheadMatches = static_cast<int32_t *>(
|
|
|
|
uprv_malloc(fData->fForwardTable->fLookAheadResultsSize * sizeof(int32_t)));
|
|
|
|
if (fLookAheadMatches == nullptr) {
|
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Constructor from a set of rules supplied as a string.
|
|
|
|
//
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
RuleBasedBreakIterator::RuleBasedBreakIterator( const UnicodeString &rules,
|
|
|
|
UParseError &parseError,
|
|
|
|
UErrorCode &status)
|
2018-03-01 19:33:46 +00:00
|
|
|
: fSCharIter(UnicodeString())
|
2002-06-25 17:23:07 +00:00
|
|
|
{
|
2017-09-19 18:17:22 +00:00
|
|
|
init(status);
|
2002-11-30 04:41:53 +00:00
|
|
|
if (U_FAILURE(status)) {return;}
|
2002-06-25 17:23:07 +00:00
|
|
|
RuleBasedBreakIterator *bi = (RuleBasedBreakIterator *)
|
2008-02-17 19:13:10 +00:00
|
|
|
RBBIRuleBuilder::createRuleBasedBreakIterator(rules, &parseError, status);
|
2002-08-08 00:39:13 +00:00
|
|
|
// Note: This is a bit awkward. The RBBI ruleBuilder has a factory method that
|
|
|
|
// creates and returns a complete RBBI. From here, in a constructor, we
|
|
|
|
// can't just return the object created by the builder factory, hence
|
|
|
|
// the assignment of the factory created object to "this".
|
2002-06-25 17:23:07 +00:00
|
|
|
if (U_SUCCESS(status)) {
|
|
|
|
*this = *bi;
|
|
|
|
delete bi;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Default Constructor. Create an empty shell that can be set up later.
|
|
|
|
// Used when creating a RuleBasedBreakIterator from a set
|
|
|
|
// of rules.
|
|
|
|
//-------------------------------------------------------------------------------
|
2018-01-19 22:30:56 +00:00
|
|
|
RuleBasedBreakIterator::RuleBasedBreakIterator()
|
2018-03-01 19:33:46 +00:00
|
|
|
: fSCharIter(UnicodeString())
|
2018-01-19 22:30:56 +00:00
|
|
|
{
|
2017-09-19 18:17:22 +00:00
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
init(status);
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copy constructor. Will produce a break iterator with the same behavior,
|
|
|
|
// and which iterates over the same text, as the one passed in.
|
|
|
|
//
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
RuleBasedBreakIterator::RuleBasedBreakIterator(const RuleBasedBreakIterator& other)
|
2018-01-19 22:30:56 +00:00
|
|
|
: BreakIterator(other),
|
2018-03-01 19:33:46 +00:00
|
|
|
fSCharIter(UnicodeString())
|
2000-01-08 02:05:05 +00:00
|
|
|
{
|
2017-09-19 18:17:22 +00:00
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
this->init(status);
|
2002-06-25 17:23:07 +00:00
|
|
|
*this = other;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
|
1999-10-27 16:34:57 +00:00
|
|
|
/**
|
2000-01-08 02:05:05 +00:00
|
|
|
* Destructor
|
1999-10-27 16:34:57 +00:00
|
|
|
*/
|
2000-01-08 02:05:05 +00:00
|
|
|
RuleBasedBreakIterator::~RuleBasedBreakIterator() {
|
2018-01-19 22:30:56 +00:00
|
|
|
if (fCharIter != &fSCharIter) {
|
2006-05-08 16:08:53 +00:00
|
|
|
// fCharIter was adopted from the outside.
|
|
|
|
delete fCharIter;
|
|
|
|
}
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fCharIter = nullptr;
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_close(&fText);
|
2006-04-22 05:29:27 +00:00
|
|
|
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
if (fData != nullptr) {
|
2002-06-25 17:23:07 +00:00
|
|
|
fData->removeReference();
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fData = nullptr;
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
2017-09-19 18:17:22 +00:00
|
|
|
delete fBreakCache;
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fBreakCache = nullptr;
|
2017-09-19 18:17:22 +00:00
|
|
|
|
|
|
|
delete fDictionaryCache;
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fDictionaryCache = nullptr;
|
2017-09-19 18:17:22 +00:00
|
|
|
|
|
|
|
delete fLanguageBreakEngines;
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fLanguageBreakEngines = nullptr;
|
2017-09-19 18:17:22 +00:00
|
|
|
|
|
|
|
delete fUnhandledBreakEngine;
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fUnhandledBreakEngine = nullptr;
|
|
|
|
|
|
|
|
uprv_free(fLookAheadMatches);
|
|
|
|
fLookAheadMatches = nullptr;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2000-01-08 02:05:05 +00:00
|
|
|
* Assignment operator. Sets this iterator to have the same behavior,
|
|
|
|
* and iterate over the same text, as the one passed in.
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
* TODO: needs better handling of memory allocation errors.
|
1999-10-27 16:34:57 +00:00
|
|
|
*/
|
2000-01-08 02:05:05 +00:00
|
|
|
RuleBasedBreakIterator&
|
|
|
|
RuleBasedBreakIterator::operator=(const RuleBasedBreakIterator& that) {
|
2002-06-25 17:23:07 +00:00
|
|
|
if (this == &that) {
|
|
|
|
return *this;
|
|
|
|
}
|
2017-07-31 20:20:37 +00:00
|
|
|
BreakIterator::operator=(that);
|
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
if (fLanguageBreakEngines != NULL) {
|
|
|
|
delete fLanguageBreakEngines;
|
|
|
|
fLanguageBreakEngines = NULL; // Just rebuild for now
|
|
|
|
}
|
|
|
|
// TODO: clone fLanguageBreakEngines from "that"
|
2006-04-22 05:29:27 +00:00
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_clone(&fText, &that.fText, FALSE, TRUE, &status);
|
2006-05-08 16:08:53 +00:00
|
|
|
|
2018-01-19 22:30:56 +00:00
|
|
|
if (fCharIter != &fSCharIter) {
|
2006-05-08 16:08:53 +00:00
|
|
|
delete fCharIter;
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
2018-01-27 01:07:26 +00:00
|
|
|
fCharIter = &fSCharIter;
|
2000-01-08 02:05:05 +00:00
|
|
|
|
2018-01-19 22:30:56 +00:00
|
|
|
if (that.fCharIter != NULL && that.fCharIter != &that.fSCharIter) {
|
2006-05-08 16:08:53 +00:00
|
|
|
// This is a little bit tricky - it will intially appear that
|
|
|
|
// this->fCharIter is adopted, even if that->fCharIter was
|
|
|
|
// not adopted. That's ok.
|
|
|
|
fCharIter = that.fCharIter->clone();
|
|
|
|
}
|
2018-01-19 22:30:56 +00:00
|
|
|
fSCharIter = that.fSCharIter;
|
|
|
|
if (fCharIter == NULL) {
|
|
|
|
fCharIter = &fSCharIter;
|
|
|
|
}
|
2006-04-22 05:29:27 +00:00
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
if (fData != NULL) {
|
|
|
|
fData->removeReference();
|
|
|
|
fData = NULL;
|
|
|
|
}
|
|
|
|
if (that.fData != NULL) {
|
|
|
|
fData = that.fData->addReference();
|
|
|
|
}
|
2000-01-08 02:05:05 +00:00
|
|
|
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
uprv_free(fLookAheadMatches);
|
|
|
|
fLookAheadMatches = nullptr;
|
|
|
|
if (fData && fData->fForwardTable->fLookAheadResultsSize > 0) {
|
|
|
|
fLookAheadMatches = static_cast<int32_t *>(
|
|
|
|
uprv_malloc(fData->fForwardTable->fLookAheadResultsSize * sizeof(int32_t)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
fPosition = that.fPosition;
|
|
|
|
fRuleStatusIndex = that.fRuleStatusIndex;
|
|
|
|
fDone = that.fDone;
|
|
|
|
|
|
|
|
// TODO: both the dictionary and the main cache need to be copied.
|
|
|
|
// Current position could be within a dictionary range. Trying to continue
|
|
|
|
// the iteration without the caches present would go to the rules, with
|
|
|
|
// the assumption that the current position is on a rule boundary.
|
|
|
|
fBreakCache->reset(fPosition, fRuleStatusIndex);
|
|
|
|
fDictionaryCache->reset();
|
|
|
|
|
2000-01-08 02:05:05 +00:00
|
|
|
return *this;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2002-08-01 21:07:56 +00:00
|
|
|
//
|
2002-06-25 17:23:07 +00:00
|
|
|
// init() Shared initialization routine. Used by all the constructors.
|
2002-08-08 00:39:13 +00:00
|
|
|
// Initializes all fields, leaving the object in a consistent state.
|
2002-06-25 17:23:07 +00:00
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
2017-09-19 18:17:22 +00:00
|
|
|
void RuleBasedBreakIterator::init(UErrorCode &status) {
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fCharIter = nullptr;
|
|
|
|
fData = nullptr;
|
2017-09-19 18:17:22 +00:00
|
|
|
fPosition = 0;
|
|
|
|
fRuleStatusIndex = 0;
|
|
|
|
fDone = false;
|
2004-03-05 05:04:10 +00:00
|
|
|
fDictionaryCharCount = 0;
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fLanguageBreakEngines = nullptr;
|
|
|
|
fUnhandledBreakEngine = nullptr;
|
|
|
|
fBreakCache = nullptr;
|
|
|
|
fDictionaryCache = nullptr;
|
|
|
|
fLookAheadMatches = nullptr;
|
2017-09-19 18:17:22 +00:00
|
|
|
|
2018-03-01 21:00:46 +00:00
|
|
|
// Note: IBM xlC is unable to assign or initialize member fText from UTEXT_INITIALIZER.
|
|
|
|
// fText = UTEXT_INITIALIZER;
|
|
|
|
static const UText initializedUText = UTEXT_INITIALIZER;
|
|
|
|
uprv_memcpy(&fText, &initializedUText, sizeof(UText));
|
|
|
|
|
|
|
|
if (U_FAILURE(status)) {
|
2017-09-19 18:17:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_openUChars(&fText, NULL, 0, &status);
|
2017-09-19 18:17:22 +00:00
|
|
|
fDictionaryCache = new DictionaryCache(this, status);
|
|
|
|
fBreakCache = new BreakCache(this, status);
|
2018-01-27 01:07:26 +00:00
|
|
|
if (U_SUCCESS(status) && (fDictionaryCache == NULL || fBreakCache == NULL)) {
|
2017-09-19 18:17:22 +00:00
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
}
|
2002-06-25 17:23:07 +00:00
|
|
|
|
2002-08-01 16:17:41 +00:00
|
|
|
#ifdef RBBI_DEBUG
|
2003-05-16 20:11:01 +00:00
|
|
|
static UBool debugInitDone = FALSE;
|
|
|
|
if (debugInitDone == FALSE) {
|
2002-06-25 17:23:07 +00:00
|
|
|
char *debugEnv = getenv("U_RBBIDEBUG");
|
2002-08-08 00:39:13 +00:00
|
|
|
if (debugEnv && uprv_strstr(debugEnv, "trace")) {
|
2017-09-19 18:17:22 +00:00
|
|
|
gTrace = TRUE;
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
|
|
|
debugInitDone = TRUE;
|
|
|
|
}
|
2003-05-16 20:11:01 +00:00
|
|
|
#endif
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// clone - Returns a newly-constructed RuleBasedBreakIterator with the same
|
|
|
|
// behavior, and iterating over the same text, as this one.
|
|
|
|
// Virtual function: does the right thing with subclasses.
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
2019-08-22 00:13:18 +00:00
|
|
|
RuleBasedBreakIterator*
|
|
|
|
RuleBasedBreakIterator::clone() const {
|
2000-01-08 02:05:05 +00:00
|
|
|
return new RuleBasedBreakIterator(*this);
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2000-01-08 02:05:05 +00:00
|
|
|
* Equality operator. Returns TRUE if both BreakIterators are of the
|
|
|
|
* same class, have the same behavior, and iterate over the same text.
|
|
|
|
*/
|
2000-05-18 22:08:39 +00:00
|
|
|
UBool
|
2000-01-08 02:05:05 +00:00
|
|
|
RuleBasedBreakIterator::operator==(const BreakIterator& that) const {
|
2010-05-19 17:29:33 +00:00
|
|
|
if (typeid(*this) != typeid(that)) {
|
2006-04-22 05:29:27 +00:00
|
|
|
return FALSE;
|
2002-09-05 18:51:50 +00:00
|
|
|
}
|
2017-09-19 18:17:22 +00:00
|
|
|
if (this == &that) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
2002-06-27 21:14:47 +00:00
|
|
|
|
2017-07-31 20:20:37 +00:00
|
|
|
// The base class BreakIterator carries no state that participates in equality,
|
|
|
|
// and does not implement an equality function that would otherwise be
|
|
|
|
// checked at this point.
|
|
|
|
|
2002-09-05 18:51:50 +00:00
|
|
|
const RuleBasedBreakIterator& that2 = (const RuleBasedBreakIterator&) that;
|
2006-04-22 05:29:27 +00:00
|
|
|
|
2018-01-27 01:07:26 +00:00
|
|
|
if (!utext_equals(&fText, &that2.fText)) {
|
2006-04-22 05:29:27 +00:00
|
|
|
// The two break iterators are operating on different text,
|
2017-07-31 20:20:37 +00:00
|
|
|
// or have a different iteration position.
|
|
|
|
// Note that fText's position is always the same as the break iterator's position.
|
2006-04-22 05:29:27 +00:00
|
|
|
return FALSE;
|
2019-08-13 20:00:43 +00:00
|
|
|
}
|
2006-04-22 05:29:27 +00:00
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
if (!(fPosition == that2.fPosition &&
|
|
|
|
fRuleStatusIndex == that2.fRuleStatusIndex &&
|
|
|
|
fDone == that2.fDone)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2006-04-22 05:29:27 +00:00
|
|
|
if (that2.fData == fData ||
|
|
|
|
(fData != NULL && that2.fData != NULL && *that2.fData == *fData)) {
|
|
|
|
// The two break iterators are using the same rules.
|
|
|
|
return TRUE;
|
2002-09-05 18:51:50 +00:00
|
|
|
}
|
2006-04-22 05:29:27 +00:00
|
|
|
return FALSE;
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compute a hash code for this BreakIterator
|
1999-10-27 16:34:57 +00:00
|
|
|
* @return A hash code
|
|
|
|
*/
|
2000-01-08 02:05:05 +00:00
|
|
|
int32_t
|
|
|
|
RuleBasedBreakIterator::hashCode(void) const {
|
2002-08-09 21:39:02 +00:00
|
|
|
int32_t hash = 0;
|
|
|
|
if (fData != NULL) {
|
|
|
|
hash = fData->hashCode();
|
|
|
|
}
|
|
|
|
return hash;
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
|
|
|
|
2006-04-22 05:29:27 +00:00
|
|
|
|
|
|
|
void RuleBasedBreakIterator::setText(UText *ut, UErrorCode &status) {
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return;
|
|
|
|
}
|
2017-09-19 18:17:22 +00:00
|
|
|
fBreakCache->reset();
|
|
|
|
fDictionaryCache->reset();
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_clone(&fText, ut, FALSE, TRUE, &status);
|
2006-05-08 16:08:53 +00:00
|
|
|
|
|
|
|
// Set up a dummy CharacterIterator to be returned if anyone
|
|
|
|
// calls getText(). With input from UText, there is no reasonable
|
|
|
|
// way to return a characterIterator over the actual input text.
|
|
|
|
// Return one over an empty string instead - this is the closest
|
|
|
|
// we can come to signaling a failure.
|
|
|
|
// (GetText() is obsolete, this failure is sort of OK)
|
2018-01-19 22:30:56 +00:00
|
|
|
fSCharIter.setText(UnicodeString());
|
2006-05-08 16:08:53 +00:00
|
|
|
|
2018-01-19 22:30:56 +00:00
|
|
|
if (fCharIter != &fSCharIter) {
|
2006-05-08 16:08:53 +00:00
|
|
|
// existing fCharIter was adopted from the outside. Delete it now.
|
|
|
|
delete fCharIter;
|
|
|
|
}
|
2018-01-19 22:30:56 +00:00
|
|
|
fCharIter = &fSCharIter;
|
2006-05-08 16:08:53 +00:00
|
|
|
|
2006-04-22 05:29:27 +00:00
|
|
|
this->first();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UText *RuleBasedBreakIterator::getUText(UText *fillIn, UErrorCode &status) const {
|
2018-01-27 01:07:26 +00:00
|
|
|
UText *result = utext_clone(fillIn, &fText, FALSE, TRUE, &status);
|
2006-04-22 05:29:27 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-10-27 16:34:57 +00:00
|
|
|
//=======================================================================
|
|
|
|
// BreakIterator overrides
|
|
|
|
//=======================================================================
|
2000-01-08 02:05:05 +00:00
|
|
|
|
|
|
|
/**
|
2017-04-23 19:35:52 +00:00
|
|
|
* Return a CharacterIterator over the text being analyzed.
|
2000-01-08 02:05:05 +00:00
|
|
|
*/
|
2006-04-22 05:29:27 +00:00
|
|
|
CharacterIterator&
|
2000-01-08 02:05:05 +00:00
|
|
|
RuleBasedBreakIterator::getText() const {
|
2006-05-08 16:08:53 +00:00
|
|
|
return *fCharIter;
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the iterator to analyze a new piece of text. This function resets
|
|
|
|
* the current iteration position to the beginning of the text.
|
|
|
|
* @param newText An iterator over the text to analyze.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
RuleBasedBreakIterator::adoptText(CharacterIterator* newText) {
|
2017-04-23 19:35:52 +00:00
|
|
|
// If we are holding a CharacterIterator adopted from a
|
2006-05-08 16:08:53 +00:00
|
|
|
// previous call to this function, delete it now.
|
2018-01-19 22:30:56 +00:00
|
|
|
if (fCharIter != &fSCharIter) {
|
2006-05-08 16:08:53 +00:00
|
|
|
delete fCharIter;
|
|
|
|
}
|
|
|
|
|
2006-04-22 05:29:27 +00:00
|
|
|
fCharIter = newText;
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
2017-09-19 18:17:22 +00:00
|
|
|
fBreakCache->reset();
|
|
|
|
fDictionaryCache->reset();
|
2017-04-23 19:35:52 +00:00
|
|
|
if (newText==NULL || newText->startIndex() != 0) {
|
2006-04-22 05:29:27 +00:00
|
|
|
// startIndex !=0 wants to be an error, but there's no way to report it.
|
|
|
|
// Make the iterator text be an empty string.
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_openUChars(&fText, NULL, 0, &status);
|
2006-04-22 05:29:27 +00:00
|
|
|
} else {
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_openCharacterIterator(&fText, newText, &status);
|
2006-04-22 05:29:27 +00:00
|
|
|
}
|
2002-08-08 00:39:13 +00:00
|
|
|
this->first();
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2002-06-27 21:14:47 +00:00
|
|
|
* Set the iterator to analyze a new piece of text. This function resets
|
2000-01-08 02:05:05 +00:00
|
|
|
* the current iteration position to the beginning of the text.
|
|
|
|
* @param newText An iterator over the text to analyze.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
RuleBasedBreakIterator::setText(const UnicodeString& newText) {
|
2006-04-22 05:29:27 +00:00
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
2017-09-19 18:17:22 +00:00
|
|
|
fBreakCache->reset();
|
|
|
|
fDictionaryCache->reset();
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_openConstUnicodeString(&fText, &newText, &status);
|
2006-05-08 16:08:53 +00:00
|
|
|
|
2017-04-23 19:35:52 +00:00
|
|
|
// Set up a character iterator on the string.
|
2006-05-08 16:08:53 +00:00
|
|
|
// Needed in case someone calls getText().
|
|
|
|
// Can not, unfortunately, do this lazily on the (probably never)
|
|
|
|
// call to getText(), because getText is const.
|
2018-01-19 22:30:56 +00:00
|
|
|
fSCharIter.setText(newText);
|
2006-05-08 16:08:53 +00:00
|
|
|
|
2018-01-19 22:30:56 +00:00
|
|
|
if (fCharIter != &fSCharIter) {
|
2006-05-08 16:08:53 +00:00
|
|
|
// old fCharIter was adopted from the outside. Delete it.
|
|
|
|
delete fCharIter;
|
|
|
|
}
|
2018-01-19 22:30:56 +00:00
|
|
|
fCharIter = &fSCharIter;
|
2006-05-08 16:08:53 +00:00
|
|
|
|
2002-08-08 00:39:13 +00:00
|
|
|
this->first();
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
|
|
|
|
2001-03-07 22:42:46 +00:00
|
|
|
|
2011-06-09 22:49:40 +00:00
|
|
|
/**
|
|
|
|
* Provide a new UText for the input text. Must reference text with contents identical
|
|
|
|
* to the original.
|
|
|
|
* Intended for use with text data originating in Java (garbage collected) environments
|
|
|
|
* where the data may be moved in memory at arbitrary times.
|
|
|
|
*/
|
|
|
|
RuleBasedBreakIterator &RuleBasedBreakIterator::refreshInputText(UText *input, UErrorCode &status) {
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
if (input == NULL) {
|
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
return *this;
|
|
|
|
}
|
2018-01-27 01:07:26 +00:00
|
|
|
int64_t pos = utext_getNativeIndex(&fText);
|
2011-06-09 22:49:40 +00:00
|
|
|
// Shallow read-only clone of the new UText into the existing input UText
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_clone(&fText, input, FALSE, TRUE, &status);
|
2011-06-09 22:49:40 +00:00
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return *this;
|
|
|
|
}
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_setNativeIndex(&fText, pos);
|
|
|
|
if (utext_getNativeIndex(&fText) != pos) {
|
2011-06-09 22:49:40 +00:00
|
|
|
// Sanity check. The new input utext is supposed to have the exact same
|
|
|
|
// contents as the old. If we can't set to the same position, it doesn't.
|
|
|
|
// The contents underlying the old utext might be invalid at this point,
|
|
|
|
// so it's not safe to check directly.
|
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2000-01-08 02:05:05 +00:00
|
|
|
|
1999-10-27 16:34:57 +00:00
|
|
|
/**
|
2014-09-08 17:36:46 +00:00
|
|
|
* Sets the current iteration position to the beginning of the text, position zero.
|
|
|
|
* @return The new iterator position, which is zero.
|
1999-10-27 16:34:57 +00:00
|
|
|
*/
|
1999-12-22 22:57:04 +00:00
|
|
|
int32_t RuleBasedBreakIterator::first(void) {
|
2017-09-19 18:17:22 +00:00
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
if (!fBreakCache->seek(0)) {
|
|
|
|
fBreakCache->populateNear(0, status);
|
|
|
|
}
|
|
|
|
fBreakCache->current();
|
|
|
|
U_ASSERT(fPosition == 0);
|
2006-04-22 05:29:27 +00:00
|
|
|
return 0;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the current iteration position to the end of the text.
|
|
|
|
* @return The text's past-the-end offset.
|
|
|
|
*/
|
1999-12-22 22:57:04 +00:00
|
|
|
int32_t RuleBasedBreakIterator::last(void) {
|
2018-01-27 01:07:26 +00:00
|
|
|
int32_t endPos = (int32_t)utext_nativeLength(&fText);
|
2017-09-19 18:17:22 +00:00
|
|
|
UBool endShouldBeBoundary = isBoundary(endPos); // Has side effect of setting iterator position.
|
|
|
|
(void)endShouldBeBoundary;
|
|
|
|
U_ASSERT(endShouldBeBoundary);
|
|
|
|
U_ASSERT(fPosition == endPos);
|
|
|
|
return endPos;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Advances the iterator either forward or backward the specified number of steps.
|
|
|
|
* Negative values move backward, and positive values move forward. This is
|
|
|
|
* equivalent to repeatedly calling next() or previous().
|
|
|
|
* @param n The number of steps to move. The sign indicates the direction
|
|
|
|
* (negative is backwards, and positive is forwards).
|
|
|
|
* @return The character offset of the boundary position n boundaries away from
|
|
|
|
* the current one.
|
|
|
|
*/
|
|
|
|
int32_t RuleBasedBreakIterator::next(int32_t n) {
|
2017-09-19 18:17:22 +00:00
|
|
|
int32_t result = 0;
|
|
|
|
if (n > 0) {
|
|
|
|
for (; n > 0 && result != UBRK_DONE; --n) {
|
|
|
|
result = next();
|
|
|
|
}
|
|
|
|
} else if (n < 0) {
|
|
|
|
for (; n < 0 && result != UBRK_DONE; ++n) {
|
|
|
|
result = previous();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result = current();
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Advances the iterator to the next boundary position.
|
|
|
|
* @return The position of the first boundary after this one.
|
|
|
|
*/
|
1999-12-22 22:57:04 +00:00
|
|
|
int32_t RuleBasedBreakIterator::next(void) {
|
2017-09-19 18:17:22 +00:00
|
|
|
fBreakCache->next();
|
|
|
|
return fDone ? UBRK_DONE : fPosition;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-09-19 18:17:22 +00:00
|
|
|
* Move the iterator backwards, to the boundary preceding the current one.
|
|
|
|
*
|
|
|
|
* Starts from the current position within fText.
|
|
|
|
* Starting position need not be on a boundary.
|
|
|
|
*
|
|
|
|
* @return The position of the boundary position immediately preceding the starting position.
|
1999-10-27 16:34:57 +00:00
|
|
|
*/
|
1999-12-22 22:57:04 +00:00
|
|
|
int32_t RuleBasedBreakIterator::previous(void) {
|
2017-09-19 18:17:22 +00:00
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
fBreakCache->previous(status);
|
|
|
|
return fDone ? UBRK_DONE : fPosition;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the iterator to refer to the first boundary position following
|
|
|
|
* the specified position.
|
2017-09-19 18:17:22 +00:00
|
|
|
* @param startPos The position from which to begin searching for a break position.
|
1999-10-27 16:34:57 +00:00
|
|
|
* @return The position of the first break after the current position.
|
|
|
|
*/
|
2017-09-19 18:17:22 +00:00
|
|
|
int32_t RuleBasedBreakIterator::following(int32_t startPos) {
|
|
|
|
// if the supplied position is before the beginning, return the
|
2014-05-17 00:44:39 +00:00
|
|
|
// text's starting offset
|
2017-09-19 18:17:22 +00:00
|
|
|
if (startPos < 0) {
|
2014-05-17 00:44:39 +00:00
|
|
|
return first();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move requested offset to a code point start. It might be on a trail surrogate,
|
2017-09-19 18:17:22 +00:00
|
|
|
// or on a trail byte if the input is UTF-8. Or it may be beyond the end of the text.
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_setNativeIndex(&fText, startPos);
|
|
|
|
startPos = (int32_t)utext_getNativeIndex(&fText);
|
2006-03-23 00:54:12 +00:00
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
fBreakCache->following(startPos, status);
|
|
|
|
return fDone ? UBRK_DONE : fPosition;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the iterator to refer to the last boundary position before the
|
|
|
|
* specified position.
|
2017-09-19 18:17:22 +00:00
|
|
|
* @param offset The position to begin searching for a break from.
|
1999-10-27 16:34:57 +00:00
|
|
|
* @return The position of the last boundary before the starting position.
|
|
|
|
*/
|
|
|
|
int32_t RuleBasedBreakIterator::preceding(int32_t offset) {
|
2018-01-27 01:07:26 +00:00
|
|
|
if (offset > utext_nativeLength(&fText)) {
|
2014-05-17 00:44:39 +00:00
|
|
|
return last();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move requested offset to a code point start. It might be on a trail surrogate,
|
|
|
|
// or on a trail byte if the input is UTF-8.
|
2005-07-08 01:57:58 +00:00
|
|
|
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_setNativeIndex(&fText, offset);
|
2018-08-11 01:05:58 +00:00
|
|
|
int32_t adjustedOffset = static_cast<int32_t>(utext_getNativeIndex(&fText));
|
2017-09-19 18:17:22 +00:00
|
|
|
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
fBreakCache->preceding(adjustedOffset, status);
|
|
|
|
return fDone ? UBRK_DONE : fPosition;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if the specfied position is a boundary position. As a side
|
|
|
|
* effect, leaves the iterator pointing to the first boundary position at
|
|
|
|
* or after "offset".
|
2017-09-19 18:17:22 +00:00
|
|
|
*
|
1999-10-27 16:34:57 +00:00
|
|
|
* @param offset the offset to check.
|
|
|
|
* @return True if "offset" is a boundary position.
|
|
|
|
*/
|
2000-05-18 22:08:39 +00:00
|
|
|
UBool RuleBasedBreakIterator::isBoundary(int32_t offset) {
|
2000-01-08 02:05:05 +00:00
|
|
|
// out-of-range indexes are never boundary positions
|
2006-04-22 05:29:27 +00:00
|
|
|
if (offset < 0) {
|
2002-08-08 00:39:13 +00:00
|
|
|
first(); // For side effects on current position, tag values.
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
// Adjust offset to be on a code point boundary and not beyond the end of the text.
|
2018-03-26 23:01:16 +00:00
|
|
|
// Note that isBoundary() is always false for offsets that are not on code point boundaries.
|
2017-09-19 18:17:22 +00:00
|
|
|
// But we still need the side effect of leaving iteration at the following boundary.
|
|
|
|
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_setNativeIndex(&fText, offset);
|
2018-08-11 01:05:58 +00:00
|
|
|
int32_t adjustedOffset = static_cast<int32_t>(utext_getNativeIndex(&fText));
|
2017-09-19 18:17:22 +00:00
|
|
|
|
|
|
|
bool result = false;
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
if (fBreakCache->seek(adjustedOffset) || fBreakCache->populateNear(adjustedOffset, status)) {
|
|
|
|
result = (fBreakCache->current() == offset);
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
2002-06-27 21:14:47 +00:00
|
|
|
|
2018-01-27 01:07:26 +00:00
|
|
|
if (result && adjustedOffset < offset && utext_char32At(&fText, offset) == U_SENTINEL) {
|
2017-09-19 18:17:22 +00:00
|
|
|
// Original offset is beyond the end of the text. Return FALSE, it's not a boundary,
|
|
|
|
// but the iteration position remains set to the end of the text, which is a boundary.
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (!result) {
|
|
|
|
// Not on a boundary. isBoundary() must leave iterator on the following boundary.
|
|
|
|
// Cache->seek(), above, left us on the preceding boundary, so advance one.
|
|
|
|
next();
|
|
|
|
}
|
2005-09-27 00:03:32 +00:00
|
|
|
return result;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
|
1999-10-27 16:34:57 +00:00
|
|
|
/**
|
|
|
|
* Returns the current iteration position.
|
|
|
|
* @return The current iteration position.
|
|
|
|
*/
|
2000-01-08 02:05:05 +00:00
|
|
|
int32_t RuleBasedBreakIterator::current(void) const {
|
2017-09-19 18:17:22 +00:00
|
|
|
return fPosition;
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
|
1999-10-27 16:34:57 +00:00
|
|
|
//=======================================================================
|
2002-06-27 21:14:47 +00:00
|
|
|
// implementation
|
1999-10-27 16:34:57 +00:00
|
|
|
//=======================================================================
|
2000-01-08 02:05:05 +00:00
|
|
|
|
2005-09-29 04:20:36 +00:00
|
|
|
//
|
|
|
|
// RBBIRunMode - the state machine runs an extra iteration at the beginning and end
|
|
|
|
// of user text. A variable with this enum type keeps track of where we
|
|
|
|
// are. The state machine only fetches user input while in the RUN mode.
|
|
|
|
//
|
|
|
|
enum RBBIRunMode {
|
|
|
|
RBBI_START, // state machine processing is before first char of input
|
|
|
|
RBBI_RUN, // state machine processing is in the user text
|
|
|
|
RBBI_END // state machine processing is after end of user text.
|
|
|
|
};
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
|
2020-05-19 20:44:14 +00:00
|
|
|
// Wrapper functions to select the appropriate handleNext() or handleSafePrevious()
|
|
|
|
// instantiation, based on whether an 8 or 16 bit table is required.
|
|
|
|
//
|
|
|
|
// These Trie access functions will be inlined within the handleNext()/Previous() instantions.
|
|
|
|
static inline uint16_t TrieFunc8(const UCPTrie *trie, UChar32 c) {
|
|
|
|
return UCPTRIE_FAST_GET(trie, UCPTRIE_8, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t TrieFunc16(const UCPTrie *trie, UChar32 c) {
|
|
|
|
return UCPTRIE_FAST_GET(trie, UCPTRIE_16, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t RuleBasedBreakIterator::handleNext() {
|
|
|
|
const RBBIStateTable *statetable = fData->fForwardTable;
|
|
|
|
bool use8BitsTrie = ucptrie_getValueWidth(fData->fTrie) == UCPTRIE_VALUE_BITS_8;
|
|
|
|
if (statetable->fFlags & RBBI_8BITS_ROWS) {
|
|
|
|
if (use8BitsTrie) {
|
2020-06-09 20:19:17 +00:00
|
|
|
return handleNext<RBBIStateTableRow8, TrieFunc8>();
|
2020-05-19 20:44:14 +00:00
|
|
|
} else {
|
2020-06-09 20:19:17 +00:00
|
|
|
return handleNext<RBBIStateTableRow8, TrieFunc16>();
|
2020-05-19 20:44:14 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (use8BitsTrie) {
|
2020-06-09 20:19:17 +00:00
|
|
|
return handleNext<RBBIStateTableRow16, TrieFunc8>();
|
2020-05-19 20:44:14 +00:00
|
|
|
} else {
|
2020-06-09 20:19:17 +00:00
|
|
|
return handleNext<RBBIStateTableRow16, TrieFunc16>();
|
2020-05-19 20:44:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t RuleBasedBreakIterator::handleSafePrevious(int32_t fromPosition) {
|
|
|
|
const RBBIStateTable *statetable = fData->fReverseTable;
|
|
|
|
bool use8BitsTrie = ucptrie_getValueWidth(fData->fTrie) == UCPTRIE_VALUE_BITS_8;
|
|
|
|
if (statetable->fFlags & RBBI_8BITS_ROWS) {
|
|
|
|
if (use8BitsTrie) {
|
2020-06-09 20:19:17 +00:00
|
|
|
return handleSafePrevious<RBBIStateTableRow8, TrieFunc8>(fromPosition);
|
2020-05-19 20:44:14 +00:00
|
|
|
} else {
|
2020-06-09 20:19:17 +00:00
|
|
|
return handleSafePrevious<RBBIStateTableRow8, TrieFunc16>(fromPosition);
|
2020-05-19 20:44:14 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (use8BitsTrie) {
|
2020-06-09 20:19:17 +00:00
|
|
|
return handleSafePrevious<RBBIStateTableRow16, TrieFunc8>(fromPosition);
|
2020-05-19 20:44:14 +00:00
|
|
|
} else {
|
2020-06-09 20:19:17 +00:00
|
|
|
return handleSafePrevious<RBBIStateTableRow16, TrieFunc16>(fromPosition);
|
2020-05-19 20:44:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-29 04:20:36 +00:00
|
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
//
|
2017-09-19 18:17:22 +00:00
|
|
|
// handleNext()
|
|
|
|
// Run the state machine to find a boundary
|
2005-09-29 04:20:36 +00:00
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------------
|
2020-06-09 20:19:17 +00:00
|
|
|
template <typename RowType, RuleBasedBreakIterator::PTrieFunc trieFunc>
|
2017-09-19 18:17:22 +00:00
|
|
|
int32_t RuleBasedBreakIterator::handleNext() {
|
2005-09-27 00:03:32 +00:00
|
|
|
int32_t state;
|
2012-02-06 19:57:08 +00:00
|
|
|
uint16_t category = 0;
|
2005-09-29 04:20:36 +00:00
|
|
|
RBBIRunMode mode;
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2020-05-19 20:44:14 +00:00
|
|
|
RowType *row;
|
2005-09-29 04:20:36 +00:00
|
|
|
UChar32 c;
|
2016-02-26 21:58:26 +00:00
|
|
|
int32_t result = 0;
|
|
|
|
int32_t initialPosition = 0;
|
2017-09-19 18:17:22 +00:00
|
|
|
const RBBIStateTable *statetable = fData->fForwardTable;
|
2016-02-26 21:58:26 +00:00
|
|
|
const char *tableData = statetable->fTableData;
|
|
|
|
uint32_t tableRowLen = statetable->fRowLen;
|
2020-06-09 20:19:17 +00:00
|
|
|
uint32_t dictStart = statetable->fDictCategoriesStart;
|
2006-07-14 00:47:15 +00:00
|
|
|
#ifdef RBBI_DEBUG
|
2017-09-19 18:17:22 +00:00
|
|
|
if (gTrace) {
|
2006-07-14 00:47:15 +00:00
|
|
|
RBBIDebugPuts("Handle Next pos char state category");
|
|
|
|
}
|
|
|
|
#endif
|
2002-07-22 22:02:08 +00:00
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
// handleNext alway sets the break tag value.
|
|
|
|
// Set the default for it.
|
|
|
|
fRuleStatusIndex = 0;
|
|
|
|
|
|
|
|
fDictionaryCharCount = 0;
|
2002-07-22 22:02:08 +00:00
|
|
|
|
1999-10-27 16:34:57 +00:00
|
|
|
// if we're already at the end of the text, return DONE.
|
2017-09-19 18:17:22 +00:00
|
|
|
initialPosition = fPosition;
|
2018-01-27 01:07:26 +00:00
|
|
|
UTEXT_SETNATIVEINDEX(&fText, initialPosition);
|
2006-07-14 06:09:40 +00:00
|
|
|
result = initialPosition;
|
2018-01-27 01:07:26 +00:00
|
|
|
c = UTEXT_NEXT32(&fText);
|
2017-09-20 22:58:39 +00:00
|
|
|
if (c==U_SENTINEL) {
|
2017-09-19 18:17:22 +00:00
|
|
|
fDone = TRUE;
|
|
|
|
return UBRK_DONE;
|
2002-07-22 22:02:08 +00:00
|
|
|
}
|
1999-10-27 16:34:57 +00:00
|
|
|
|
2005-09-27 00:03:32 +00:00
|
|
|
// Set the initial state for the state machine
|
|
|
|
state = START_STATE;
|
2020-05-19 20:44:14 +00:00
|
|
|
row = (RowType *)
|
2006-08-01 00:06:20 +00:00
|
|
|
//(statetable->fTableData + (statetable->fRowLen * state));
|
|
|
|
(tableData + tableRowLen * state);
|
2017-04-23 19:35:52 +00:00
|
|
|
|
|
|
|
|
2005-09-29 04:20:36 +00:00
|
|
|
mode = RBBI_RUN;
|
|
|
|
if (statetable->fFlags & RBBI_BOF_REQUIRED) {
|
|
|
|
category = 2;
|
|
|
|
mode = RBBI_START;
|
|
|
|
}
|
2002-06-25 17:23:07 +00:00
|
|
|
|
2002-06-27 21:14:47 +00:00
|
|
|
|
2002-08-08 00:39:13 +00:00
|
|
|
// loop until we reach the end of the text or transition to state 0
|
2005-09-27 00:03:32 +00:00
|
|
|
//
|
2002-08-08 00:39:13 +00:00
|
|
|
for (;;) {
|
2006-07-14 06:09:40 +00:00
|
|
|
if (c == U_SENTINEL) {
|
2003-10-21 21:47:16 +00:00
|
|
|
// Reached end of input string.
|
2005-09-29 04:20:36 +00:00
|
|
|
if (mode == RBBI_END) {
|
2017-04-23 19:35:52 +00:00
|
|
|
// We have already run the loop one last time with the
|
2005-09-27 00:03:32 +00:00
|
|
|
// character set to the psueudo {eof} value. Now it is time
|
|
|
|
// to unconditionally bail out.
|
|
|
|
break;
|
2003-10-21 21:47:16 +00:00
|
|
|
}
|
2005-09-27 00:03:32 +00:00
|
|
|
// Run the loop one last time with the fake end-of-input character category.
|
2005-09-29 04:20:36 +00:00
|
|
|
mode = RBBI_END;
|
2005-09-27 00:03:32 +00:00
|
|
|
category = 1;
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2005-09-27 00:03:32 +00:00
|
|
|
// Get the char category. An incoming category of 1 or 2 means that
|
|
|
|
// we are preset for doing the beginning or end of input, and
|
|
|
|
// that we shouldn't get a category from an actual text input character.
|
|
|
|
//
|
2005-09-29 04:20:36 +00:00
|
|
|
if (mode == RBBI_RUN) {
|
2005-09-27 00:03:32 +00:00
|
|
|
// look up the current character's character category, which tells us
|
|
|
|
// which column in the state table to look at.
|
2020-05-19 20:44:14 +00:00
|
|
|
category = trieFunc(fData->fTrie, c);
|
2020-06-09 20:19:17 +00:00
|
|
|
fDictionaryCharCount += (category >= dictStart);
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
1999-10-27 16:34:57 +00:00
|
|
|
|
2011-11-14 19:32:51 +00:00
|
|
|
#ifdef RBBI_DEBUG
|
2017-09-19 18:17:22 +00:00
|
|
|
if (gTrace) {
|
2018-08-24 17:52:15 +00:00
|
|
|
RBBIDebugPrintf(" %4" PRId64 " ", utext_getNativeIndex(&fText));
|
2004-09-15 17:11:47 +00:00
|
|
|
if (0x20<=c && c<0x7f) {
|
|
|
|
RBBIDebugPrintf("\"%c\" ", c);
|
|
|
|
} else {
|
|
|
|
RBBIDebugPrintf("%5x ", c);
|
|
|
|
}
|
|
|
|
RBBIDebugPrintf("%3d %3d\n", state, category);
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
2004-09-15 17:11:47 +00:00
|
|
|
#endif
|
1999-10-27 16:34:57 +00:00
|
|
|
|
2005-09-27 00:03:32 +00:00
|
|
|
// State Transition - move machine to its next state
|
|
|
|
//
|
2011-11-14 19:32:51 +00:00
|
|
|
|
2017-12-14 21:25:46 +00:00
|
|
|
// fNextState is a variable-length array.
|
2011-11-14 19:32:51 +00:00
|
|
|
U_ASSERT(category<fData->fHeader->fCatCount);
|
|
|
|
state = row->fNextState[category]; /*Not accessing beyond memory*/
|
2020-05-19 20:44:14 +00:00
|
|
|
row = (RowType *)
|
2006-08-01 00:06:20 +00:00
|
|
|
// (statetable->fTableData + (statetable->fRowLen * state));
|
|
|
|
(tableData + tableRowLen * state);
|
2002-06-27 21:14:47 +00:00
|
|
|
|
|
|
|
|
2020-05-27 23:36:22 +00:00
|
|
|
uint16_t accepting = row->fAccepting;
|
|
|
|
if (accepting == ACCEPTING_UNCONDITIONAL) {
|
2005-09-27 00:03:32 +00:00
|
|
|
// Match found, common case.
|
2006-07-14 06:09:40 +00:00
|
|
|
if (mode != RBBI_START) {
|
2018-01-27 01:07:26 +00:00
|
|
|
result = (int32_t)UTEXT_GETNATIVEINDEX(&fText);
|
2006-07-14 06:09:40 +00:00
|
|
|
}
|
2020-05-27 23:36:22 +00:00
|
|
|
fRuleStatusIndex = row->fTagsIdx; // Remember the break status (tag) values.
|
|
|
|
} else if (accepting > ACCEPTING_UNCONDITIONAL) {
|
2017-04-23 19:35:52 +00:00
|
|
|
// Lookahead match is completed.
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
U_ASSERT(accepting < fData->fForwardTable->fLookAheadResultsSize);
|
|
|
|
int32_t lookaheadResult = fLookAheadMatches[accepting];
|
2016-02-26 21:58:26 +00:00
|
|
|
if (lookaheadResult >= 0) {
|
2020-05-27 23:36:22 +00:00
|
|
|
fRuleStatusIndex = row->fTagsIdx;
|
2017-09-19 18:17:22 +00:00
|
|
|
fPosition = lookaheadResult;
|
2016-02-26 21:58:26 +00:00
|
|
|
return lookaheadResult;
|
2003-11-05 23:50:39 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-23 00:48:36 +00:00
|
|
|
|
|
|
|
// If we are at the position of the '/' in a look-ahead (hard break) rule;
|
|
|
|
// record the current position, to be returned later, if the full rule matches.
|
|
|
|
// TODO: Move this check before the previous check of fAccepting.
|
|
|
|
// This would enable hard-break rules with no following context.
|
|
|
|
// But there are line break test failures when trying this. Investigate.
|
|
|
|
// Issue ICU-20837
|
2020-05-27 23:36:22 +00:00
|
|
|
uint16_t rule = row->fLookAhead;
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
U_ASSERT(rule == 0 || rule > ACCEPTING_UNCONDITIONAL);
|
|
|
|
U_ASSERT(rule == 0 || rule < fData->fForwardTable->fLookAheadResultsSize);
|
|
|
|
if (rule > ACCEPTING_UNCONDITIONAL) {
|
2018-01-27 01:07:26 +00:00
|
|
|
int32_t pos = (int32_t)UTEXT_GETNATIVEINDEX(&fText);
|
ICU-13590 RBBI, improve handling of concurrent look-ahead rules.
Change the mapping from rule number to boundary position to use a simple array
instead of a linear search lookup map.
Look-ahead rules have a preceding context, a boundary position, and following context.
In the implementation, when the preceding context matches, the potential boundary
position is saved. Then, if the following context proves to match, the saved boundary is
returned as an actual boundary.
Look-ahead rules are numbered, and the implementation maintains a map from
rule number to the tentative saved boundary position.
In an earlier improvement to the rule builder, the rule numbering was changed to be a
contiguous sequence, from the original sparse numbering. In anticipation of
changing the mapping from number to position to use a simple array.
2020-06-27 00:52:40 +00:00
|
|
|
fLookAheadMatches[rule] = pos;
|
2000-01-08 02:05:05 +00:00
|
|
|
}
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
if (state == STOP_STATE) {
|
2003-10-21 21:47:16 +00:00
|
|
|
// This is the normal exit from the lookup state machine.
|
|
|
|
// We have advanced through the string until it is certain that no
|
|
|
|
// longer match is possible, no matter what characters follow.
|
2002-06-25 17:23:07 +00:00
|
|
|
break;
|
2004-04-16 01:15:04 +00:00
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
|
|
|
|
// Advance to the next character.
|
2006-07-14 06:09:40 +00:00
|
|
|
// If this is a beginning-of-input loop iteration, don't advance
|
|
|
|
// the input position. The next iteration will be processing the
|
|
|
|
// first real input character.
|
|
|
|
if (mode == RBBI_RUN) {
|
2018-01-27 01:07:26 +00:00
|
|
|
c = UTEXT_NEXT32(&fText);
|
2006-07-14 06:09:40 +00:00
|
|
|
} else {
|
|
|
|
if (mode == RBBI_START) {
|
|
|
|
mode = RBBI_RUN;
|
|
|
|
}
|
|
|
|
}
|
1999-10-27 16:34:57 +00:00
|
|
|
}
|
2000-01-08 02:05:05 +00:00
|
|
|
|
2003-10-21 21:47:16 +00:00
|
|
|
// The state machine is done. Check whether it found a match...
|
2002-06-27 21:14:47 +00:00
|
|
|
|
2003-10-21 21:47:16 +00:00
|
|
|
// If the iterator failed to advance in the match engine, force it ahead by one.
|
|
|
|
// (This really indicates a defect in the break rules. They should always match
|
|
|
|
// at least one character.)
|
|
|
|
if (result == initialPosition) {
|
2018-01-27 01:07:26 +00:00
|
|
|
utext_setNativeIndex(&fText, initialPosition);
|
|
|
|
utext_next32(&fText);
|
|
|
|
result = (int32_t)utext_getNativeIndex(&fText);
|
2017-09-19 18:17:22 +00:00
|
|
|
fRuleStatusIndex = 0;
|
2003-10-21 21:47:16 +00:00
|
|
|
}
|
2000-01-08 02:05:05 +00:00
|
|
|
|
2003-10-21 21:47:16 +00:00
|
|
|
// Leave the iterator at our result position.
|
2017-09-19 18:17:22 +00:00
|
|
|
fPosition = result;
|
2004-12-22 00:23:15 +00:00
|
|
|
#ifdef RBBI_DEBUG
|
2017-09-19 18:17:22 +00:00
|
|
|
if (gTrace) {
|
2004-12-22 00:23:15 +00:00
|
|
|
RBBIDebugPrintf("result = %d\n\n", result);
|
|
|
|
}
|
|
|
|
#endif
|
1999-10-27 16:34:57 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2004-04-16 01:15:04 +00:00
|
|
|
|
2018-03-17 00:34:48 +00:00
|
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// handleSafePrevious()
|
|
|
|
//
|
|
|
|
// Iterate backwards using the safe reverse rules.
|
|
|
|
// The logic of this function is similar to handleNext(), but simpler
|
|
|
|
// because the safe table does not require as many options.
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------------
|
2020-06-09 20:19:17 +00:00
|
|
|
template <typename RowType, RuleBasedBreakIterator::PTrieFunc trieFunc>
|
2018-03-17 00:34:48 +00:00
|
|
|
int32_t RuleBasedBreakIterator::handleSafePrevious(int32_t fromPosition) {
|
2020-05-19 20:44:14 +00:00
|
|
|
|
2018-03-17 00:34:48 +00:00
|
|
|
int32_t state;
|
|
|
|
uint16_t category = 0;
|
2020-05-19 20:44:14 +00:00
|
|
|
RowType *row;
|
2018-03-17 00:34:48 +00:00
|
|
|
UChar32 c;
|
|
|
|
int32_t result = 0;
|
|
|
|
|
2018-03-26 23:01:16 +00:00
|
|
|
const RBBIStateTable *stateTable = fData->fReverseTable;
|
2018-03-17 00:34:48 +00:00
|
|
|
UTEXT_SETNATIVEINDEX(&fText, fromPosition);
|
|
|
|
#ifdef RBBI_DEBUG
|
|
|
|
if (gTrace) {
|
|
|
|
RBBIDebugPuts("Handle Previous pos char state category");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// if we're already at the start of the text, return DONE.
|
|
|
|
if (fData == NULL || UTEXT_GETNATIVEINDEX(&fText)==0) {
|
|
|
|
return BreakIterator::DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the initial state for the state machine
|
|
|
|
c = UTEXT_PREVIOUS32(&fText);
|
|
|
|
state = START_STATE;
|
2020-05-19 20:44:14 +00:00
|
|
|
row = (RowType *)
|
2018-03-17 00:34:48 +00:00
|
|
|
(stateTable->fTableData + (stateTable->fRowLen * state));
|
|
|
|
|
|
|
|
// loop until we reach the start of the text or transition to state 0
|
|
|
|
//
|
|
|
|
for (; c != U_SENTINEL; c = UTEXT_PREVIOUS32(&fText)) {
|
|
|
|
|
|
|
|
// look up the current character's character category, which tells us
|
|
|
|
// which column in the state table to look at.
|
|
|
|
//
|
2020-05-19 20:44:14 +00:00
|
|
|
// Off the dictionary flag bit. For reverse iteration it is not used.
|
|
|
|
category = trieFunc(fData->fTrie, c);
|
2018-03-17 00:34:48 +00:00
|
|
|
|
|
|
|
#ifdef RBBI_DEBUG
|
|
|
|
if (gTrace) {
|
|
|
|
RBBIDebugPrintf(" %4d ", (int32_t)utext_getNativeIndex(&fText));
|
|
|
|
if (0x20<=c && c<0x7f) {
|
|
|
|
RBBIDebugPrintf("\"%c\" ", c);
|
|
|
|
} else {
|
|
|
|
RBBIDebugPrintf("%5x ", c);
|
|
|
|
}
|
|
|
|
RBBIDebugPrintf("%3d %3d\n", state, category);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// State Transition - move machine to its next state
|
|
|
|
//
|
|
|
|
// fNextState is a variable-length array.
|
|
|
|
U_ASSERT(category<fData->fHeader->fCatCount);
|
|
|
|
state = row->fNextState[category]; /*Not accessing beyond memory*/
|
2020-05-19 20:44:14 +00:00
|
|
|
row = (RowType *)
|
2018-03-17 00:34:48 +00:00
|
|
|
(stateTable->fTableData + (stateTable->fRowLen * state));
|
|
|
|
|
|
|
|
if (state == STOP_STATE) {
|
|
|
|
// This is the normal exit from the lookup state machine.
|
|
|
|
// Transistion to state zero means we have found a safe point.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The state machine is done. Check whether it found a match...
|
|
|
|
result = (int32_t)UTEXT_GETNATIVEINDEX(&fText);
|
|
|
|
#ifdef RBBI_DEBUG
|
|
|
|
if (gTrace) {
|
|
|
|
RBBIDebugPrintf("result = %d\n\n", result);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-05-19 20:44:14 +00:00
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
//
|
2002-08-08 00:39:13 +00:00
|
|
|
// getRuleStatus() Return the break rule tag associated with the current
|
|
|
|
// iterator position. If the iterator arrived at its current
|
|
|
|
// position by iterating forwards, the value will have been
|
|
|
|
// cached by the handleNext() function.
|
|
|
|
//
|
2002-06-25 17:23:07 +00:00
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
2004-03-05 05:04:10 +00:00
|
|
|
int32_t RuleBasedBreakIterator::getRuleStatus() const {
|
|
|
|
|
|
|
|
// fLastRuleStatusIndex indexes to the start of the appropriate status record
|
|
|
|
// (the number of status values.)
|
|
|
|
// This function returns the last (largest) of the array of status values.
|
2017-09-19 18:17:22 +00:00
|
|
|
int32_t idx = fRuleStatusIndex + fData->fRuleStatusTable[fRuleStatusIndex];
|
2004-03-05 05:04:10 +00:00
|
|
|
int32_t tagVal = fData->fRuleStatusTable[idx];
|
|
|
|
|
|
|
|
return tagVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int32_t RuleBasedBreakIterator::getRuleStatusVec(
|
2017-09-19 18:17:22 +00:00
|
|
|
int32_t *fillInVec, int32_t capacity, UErrorCode &status) {
|
2004-03-05 05:04:10 +00:00
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
int32_t numVals = fData->fRuleStatusTable[fRuleStatusIndex];
|
2004-03-05 05:04:10 +00:00
|
|
|
int32_t numValsToCopy = numVals;
|
|
|
|
if (numVals > capacity) {
|
2004-04-16 01:15:04 +00:00
|
|
|
status = U_BUFFER_OVERFLOW_ERROR;
|
2004-03-05 05:04:10 +00:00
|
|
|
numValsToCopy = capacity;
|
|
|
|
}
|
|
|
|
int i;
|
|
|
|
for (i=0; i<numValsToCopy; i++) {
|
2017-09-19 18:17:22 +00:00
|
|
|
fillInVec[i] = fData->fRuleStatusTable[fRuleStatusIndex + i + 1];
|
2004-03-05 05:04:10 +00:00
|
|
|
}
|
|
|
|
return numVals;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
//
|
2002-08-08 00:39:13 +00:00
|
|
|
// getBinaryRules Access to the compiled form of the rules,
|
2002-06-25 17:23:07 +00:00
|
|
|
// for use by build system tools that save the data
|
|
|
|
// for standard iterator types.
|
|
|
|
//
|
|
|
|
//-------------------------------------------------------------------------------
|
2002-06-27 01:50:22 +00:00
|
|
|
const uint8_t *RuleBasedBreakIterator::getBinaryRules(uint32_t &length) {
|
2002-06-25 17:23:07 +00:00
|
|
|
const uint8_t *retPtr = NULL;
|
2002-06-27 01:50:22 +00:00
|
|
|
length = 0;
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
if (fData != NULL) {
|
|
|
|
retPtr = (const uint8_t *)fData->fHeader;
|
2002-08-08 00:39:13 +00:00
|
|
|
length = fData->fHeader->fLength;
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
|
|
|
return retPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-22 00:13:18 +00:00
|
|
|
RuleBasedBreakIterator *RuleBasedBreakIterator::createBufferClone(
|
|
|
|
void * /*stackBuffer*/, int32_t &bufferSize, UErrorCode &status) {
|
2001-02-21 23:40:41 +00:00
|
|
|
if (U_FAILURE(status)){
|
2002-06-25 17:23:07 +00:00
|
|
|
return NULL;
|
2001-02-21 23:40:41 +00:00
|
|
|
}
|
2001-09-26 21:09:18 +00:00
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
if (bufferSize == 0) {
|
2013-09-17 19:48:50 +00:00
|
|
|
bufferSize = 1; // preflighting for deprecated functionality
|
2002-06-25 17:23:07 +00:00
|
|
|
return NULL;
|
2001-02-21 23:40:41 +00:00
|
|
|
}
|
2001-09-26 21:09:18 +00:00
|
|
|
|
2013-09-17 19:48:50 +00:00
|
|
|
BreakIterator *clonedBI = clone();
|
|
|
|
if (clonedBI == NULL) {
|
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
} else {
|
|
|
|
status = U_SAFECLONE_ALLOCATED_WARNING;
|
2001-02-21 23:40:41 +00:00
|
|
|
}
|
2013-09-17 19:48:50 +00:00
|
|
|
return (RuleBasedBreakIterator *)clonedBI;
|
2001-02-21 23:40:41 +00:00
|
|
|
}
|
2001-10-08 23:26:58 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
U_NAMESPACE_END
|
|
|
|
|
|
|
|
|
2017-04-23 19:35:52 +00:00
|
|
|
static icu::UStack *gLanguageBreakFactories = nullptr;
|
|
|
|
static const icu::UnicodeString *gEmptyString = nullptr;
|
2013-09-10 00:34:12 +00:00
|
|
|
static icu::UInitOnce gLanguageBreakFactoriesInitOnce = U_INITONCE_INITIALIZER;
|
2017-04-23 19:35:52 +00:00
|
|
|
static icu::UInitOnce gRBBIInitOnce = U_INITONCE_INITIALIZER;
|
2006-09-03 17:08:23 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
/**
|
2017-04-23 19:35:52 +00:00
|
|
|
* Release all static memory held by breakiterator.
|
2006-03-23 00:54:12 +00:00
|
|
|
*/
|
|
|
|
U_CDECL_BEGIN
|
2020-03-06 19:17:02 +00:00
|
|
|
UBool U_CALLCONV rbbi_cleanup(void) {
|
2017-04-23 19:35:52 +00:00
|
|
|
delete gLanguageBreakFactories;
|
|
|
|
gLanguageBreakFactories = nullptr;
|
|
|
|
delete gEmptyString;
|
|
|
|
gEmptyString = nullptr;
|
2013-06-01 03:37:16 +00:00
|
|
|
gLanguageBreakFactoriesInitOnce.reset();
|
2017-04-23 19:35:52 +00:00
|
|
|
gRBBIInitOnce.reset();
|
2006-03-23 00:54:12 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
U_CDECL_END
|
|
|
|
|
|
|
|
U_CDECL_BEGIN
|
|
|
|
static void U_CALLCONV _deleteFactory(void *obj) {
|
2011-07-06 04:03:35 +00:00
|
|
|
delete (icu::LanguageBreakFactory *) obj;
|
2006-03-23 00:54:12 +00:00
|
|
|
}
|
|
|
|
U_CDECL_END
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
|
2017-04-23 19:35:52 +00:00
|
|
|
static void U_CALLCONV rbbiInit() {
|
|
|
|
gEmptyString = new UnicodeString();
|
|
|
|
ucln_common_registerCleanup(UCLN_COMMON_RBBI, rbbi_cleanup);
|
|
|
|
}
|
|
|
|
|
2013-06-01 03:37:16 +00:00
|
|
|
static void U_CALLCONV initLanguageFactories() {
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
U_ASSERT(gLanguageBreakFactories == NULL);
|
|
|
|
gLanguageBreakFactories = new UStack(_deleteFactory, NULL, status);
|
|
|
|
if (gLanguageBreakFactories != NULL && U_SUCCESS(status)) {
|
|
|
|
ICULanguageBreakFactory *builtIn = new ICULanguageBreakFactory(status);
|
|
|
|
gLanguageBreakFactories->push(builtIn, status);
|
2006-03-23 00:54:12 +00:00
|
|
|
#ifdef U_LOCAL_SERVICE_HOOK
|
2013-06-01 03:37:16 +00:00
|
|
|
LanguageBreakFactory *extra = (LanguageBreakFactory *)uprv_svc_hook("languageBreakFactory", &status);
|
|
|
|
if (extra != NULL) {
|
|
|
|
gLanguageBreakFactories->push(extra, status);
|
2006-03-23 00:54:12 +00:00
|
|
|
}
|
2013-06-01 03:37:16 +00:00
|
|
|
#endif
|
2006-03-23 00:54:12 +00:00
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
ucln_common_registerCleanup(UCLN_COMMON_RBBI, rbbi_cleanup);
|
2013-06-01 03:37:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const LanguageBreakEngine*
|
2017-12-04 02:14:32 +00:00
|
|
|
getLanguageBreakEngineFromFactory(UChar32 c)
|
2013-06-01 03:37:16 +00:00
|
|
|
{
|
|
|
|
umtx_initOnce(gLanguageBreakFactoriesInitOnce, &initLanguageFactories);
|
2006-03-23 00:54:12 +00:00
|
|
|
if (gLanguageBreakFactories == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
int32_t i = gLanguageBreakFactories->size();
|
|
|
|
const LanguageBreakEngine *lbe = NULL;
|
|
|
|
while (--i >= 0) {
|
|
|
|
LanguageBreakFactory *factory = (LanguageBreakFactory *)(gLanguageBreakFactories->elementAt(i));
|
2017-12-04 02:14:32 +00:00
|
|
|
lbe = factory->getEngineFor(c);
|
2006-03-23 00:54:12 +00:00
|
|
|
if (lbe != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lbe;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// getLanguageBreakEngine Find an appropriate LanguageBreakEngine for the
|
2012-08-16 23:01:49 +00:00
|
|
|
// the character c.
|
2006-03-23 00:54:12 +00:00
|
|
|
//
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
const LanguageBreakEngine *
|
|
|
|
RuleBasedBreakIterator::getLanguageBreakEngine(UChar32 c) {
|
|
|
|
const LanguageBreakEngine *lbe = NULL;
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
if (fLanguageBreakEngines == NULL) {
|
|
|
|
fLanguageBreakEngines = new UStack(status);
|
2008-01-14 18:52:26 +00:00
|
|
|
if (fLanguageBreakEngines == NULL || U_FAILURE(status)) {
|
2006-03-23 00:54:12 +00:00
|
|
|
delete fLanguageBreakEngines;
|
|
|
|
fLanguageBreakEngines = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
int32_t i = fLanguageBreakEngines->size();
|
|
|
|
while (--i >= 0) {
|
|
|
|
lbe = (const LanguageBreakEngine *)(fLanguageBreakEngines->elementAt(i));
|
2017-12-03 00:36:54 +00:00
|
|
|
if (lbe->handles(c)) {
|
2006-03-23 00:54:12 +00:00
|
|
|
return lbe;
|
|
|
|
}
|
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
// No existing dictionary took the character. See if a factory wants to
|
|
|
|
// give us a new LanguageBreakEngine for this character.
|
2017-12-03 00:36:54 +00:00
|
|
|
lbe = getLanguageBreakEngineFromFactory(c);
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
// If we got one, use it and push it on our stack.
|
|
|
|
if (lbe != NULL) {
|
|
|
|
fLanguageBreakEngines->push((void *)lbe, status);
|
|
|
|
// Even if we can't remember it, we can keep looking it up, so
|
|
|
|
// return it even if the push fails.
|
|
|
|
return lbe;
|
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
// No engine is forthcoming for this character. Add it to the
|
|
|
|
// reject set. Create the reject break engine if needed.
|
|
|
|
if (fUnhandledBreakEngine == NULL) {
|
|
|
|
fUnhandledBreakEngine = new UnhandledEngine(status);
|
|
|
|
if (U_SUCCESS(status) && fUnhandledBreakEngine == NULL) {
|
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
2018-02-16 22:32:05 +00:00
|
|
|
return nullptr;
|
2006-03-23 00:54:12 +00:00
|
|
|
}
|
|
|
|
// Put it last so that scripts for which we have an engine get tried
|
|
|
|
// first.
|
|
|
|
fLanguageBreakEngines->insertElementAt(fUnhandledBreakEngine, 0, status);
|
|
|
|
// If we can't insert it, or creation failed, get rid of it
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
delete fUnhandledBreakEngine;
|
|
|
|
fUnhandledBreakEngine = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
// Tell the reject engine about the character; at its discretion, it may
|
|
|
|
// add more than just the one character.
|
2017-12-03 00:36:54 +00:00
|
|
|
fUnhandledBreakEngine->handleCharacter(c);
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2006-03-23 00:54:12 +00:00
|
|
|
return fUnhandledBreakEngine;
|
|
|
|
}
|
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
void RuleBasedBreakIterator::dumpCache() {
|
|
|
|
fBreakCache->dumpCache();
|
|
|
|
}
|
2017-04-23 19:35:52 +00:00
|
|
|
|
2018-02-08 01:42:04 +00:00
|
|
|
void RuleBasedBreakIterator::dumpTables() {
|
|
|
|
fData->printData();
|
|
|
|
}
|
|
|
|
|
2017-04-23 19:35:52 +00:00
|
|
|
/**
|
|
|
|
* Returns the description used to create this iterator
|
|
|
|
*/
|
|
|
|
|
|
|
|
const UnicodeString&
|
|
|
|
RuleBasedBreakIterator::getRules() const {
|
|
|
|
if (fData != NULL) {
|
|
|
|
return fData->getRuleSourceString();
|
|
|
|
} else {
|
|
|
|
umtx_initOnce(gRBBIInitOnce, &rbbiInit);
|
|
|
|
return *gEmptyString;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-08 23:26:58 +00:00
|
|
|
U_NAMESPACE_END
|
|
|
|
|
2002-09-20 01:54:48 +00:00
|
|
|
#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
|