1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4**********************************************************************
5* Copyright (C) 2001-2012, International Business Machines
6* Corporation and others. All Rights Reserved.
7**********************************************************************
8* Date Name Description
9* 07/26/01 aliu Creation.
10**********************************************************************
11*/
12
13#include "unicode/utypes.h"
14
15#if !UCONFIG_NO_TRANSLITERATION
16
17#include "quant.h"
18#include "unicode/unistr.h"
19#include "util.h"
20
21U_NAMESPACE_BEGIN
22
23UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Quantifier)
24
25Quantifier::Quantifier(UnicodeFunctor *adoptedMatcher,
26 uint32_t _minCount, uint32_t _maxCount) {
27 // assert(adopted != 0);
28 // assert(minCount <= maxCount);
29 matcher = adoptedMatcher;
30 this->minCount = _minCount;
31 this->maxCount = _maxCount;
32}
33
34Quantifier::Quantifier(const Quantifier& o) :
35 UnicodeFunctor(o),
36 UnicodeMatcher(o),
37 matcher(o.matcher->clone()),
38 minCount(o.minCount),
39 maxCount(o.maxCount)
40{
41}
42
43Quantifier::~Quantifier() {
44 delete matcher;
45}
46
47/**
48 * Implement UnicodeFunctor
49 */
50Quantifier* Quantifier::clone() const {
51 return new Quantifier(*this);
52}
53
54/**
55 * UnicodeFunctor API. Cast 'this' to a UnicodeMatcher* pointer
56 * and return the pointer.
57 */
58UnicodeMatcher* Quantifier::toMatcher() const {
59 Quantifier *nonconst_this = const_cast<Quantifier *>(this);
60 UnicodeMatcher *nonconst_base = static_cast<UnicodeMatcher *>(nonconst_this);
61
62 return nonconst_base;
63}
64
65UMatchDegree Quantifier::matches(const Replaceable& text,
66 int32_t& offset,
67 int32_t limit,
68 UBool incremental) {
69 int32_t start = offset;
70 uint32_t count = 0;
71 while (count < maxCount) {
72 int32_t pos = offset;
73 UMatchDegree m = matcher->toMatcher()->matches(text, offset, limit, incremental);
74 if (m == U_MATCH) {
75 ++count;
76 if (pos == offset) {
77 // If offset has not moved we have a zero-width match.
78 // Don't keep matching it infinitely.
79 break;
80 }
81 } else if (incremental && m == U_PARTIAL_MATCH) {
82 return U_PARTIAL_MATCH;
83 } else {
84 break;
85 }
86 }
87 if (incremental && offset == limit) {
88 return U_PARTIAL_MATCH;
89 }
90 if (count >= minCount) {
91 return U_MATCH;
92 }
93 offset = start;
94 return U_MISMATCH;
95}
96
97/**
98 * Implement UnicodeMatcher
99 */
100UnicodeString& Quantifier::toPattern(UnicodeString& result,
101 UBool escapeUnprintable) const {
102 result.truncate(0);
103 matcher->toMatcher()->toPattern(result, escapeUnprintable);
104 if (minCount == 0) {
105 if (maxCount == 1) {
106 return result.append((UChar)63); /*?*/
107 } else if (maxCount == MAX) {
108 return result.append((UChar)42); /***/
109 }
110 // else fall through
111 } else if (minCount == 1 && maxCount == MAX) {
112 return result.append((UChar)43); /*+*/
113 }
114 result.append((UChar)123); /*{*/
115 ICU_Utility::appendNumber(result, minCount);
116 result.append((UChar)44); /*,*/
117 if (maxCount != MAX) {
118 ICU_Utility::appendNumber(result, maxCount);
119 }
120 result.append((UChar)125); /*}*/
121 return result;
122}
123
124/**
125 * Implement UnicodeMatcher
126 */
127UBool Quantifier::matchesIndexValue(uint8_t v) const {
128 return (minCount == 0) || matcher->toMatcher()->matchesIndexValue(v);
129}
130
131/**
132 * Implement UnicodeMatcher
133 */
134void Quantifier::addMatchSetTo(UnicodeSet& toUnionTo) const {
135 if (maxCount > 0) {
136 matcher->toMatcher()->addMatchSetTo(toUnionTo);
137 }
138}
139
140/**
141 * Implement UnicodeFunctor
142 */
143void Quantifier::setData(const TransliterationRuleData* d) {
144 matcher->setData(d);
145}
146
147U_NAMESPACE_END
148
149#endif /* #if !UCONFIG_NO_TRANSLITERATION */
150
151//eof
152