Coverage Report

Created: 2025-06-24 06:43

/src/icu/source/i18n/formattedval_impl.h
Line
Count
Source (jump to first uncovered line)
1
// © 2018 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
4
#ifndef __FORMVAL_IMPL_H__
5
#define __FORMVAL_IMPL_H__
6
7
#include "unicode/utypes.h"
8
#if !UCONFIG_NO_FORMATTING
9
10
// This file contains compliant implementations of FormattedValue which can be
11
// leveraged by ICU formatters.
12
//
13
// Each implementation is defined in its own cpp file in order to split
14
// dependencies more modularly.
15
16
#include "unicode/formattedvalue.h"
17
#include "capi_helper.h"
18
#include "fphdlimp.h"
19
#include "util.h"
20
#include "uvectr32.h"
21
#include "formatted_string_builder.h"
22
23
24
/**
25
 * Represents the type of constraint for ConstrainedFieldPosition.
26
 *
27
 * Constraints are used to control the behavior of iteration in FormattedValue.
28
 *
29
 * @internal
30
 */
31
typedef enum UCFPosConstraintType {
32
    /**
33
     * Represents the lack of a constraint.
34
     *
35
     * This is the value of fConstraint if no "constrain" methods were called.
36
     *
37
     * @internal
38
     */
39
    UCFPOS_CONSTRAINT_NONE = 0,
40
41
    /**
42
     * Represents that the field category is constrained.
43
     *
44
     * This is the value of fConstraint if constraintCategory was called.
45
     *
46
     * FormattedValue implementations should not change the field category
47
     * while this constraint is active.
48
     *
49
     * @internal
50
     */
51
    UCFPOS_CONSTRAINT_CATEGORY,
52
53
    /**
54
     * Represents that the field and field category are constrained.
55
     *
56
     * This is the value of fConstraint if constraintField was called.
57
     *
58
     * FormattedValue implementations should not change the field or field category
59
     * while this constraint is active.
60
     *
61
     * @internal
62
     */
63
    UCFPOS_CONSTRAINT_FIELD
64
} UCFPosConstraintType;
65
66
67
U_NAMESPACE_BEGIN
68
69
70
/**
71
 * Implementation of FormattedValue using FieldPositionHandler to accept fields.
72
 *
73
 * TODO(ICU-20897): This class is unused. If it is not needed when fixing ICU-20897,
74
 * it should be deleted.
75
 */
76
class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue {
77
public:
78
79
    /** @param initialFieldCapacity Initially allocate space for this many fields. */
80
    FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status);
81
82
    virtual ~FormattedValueFieldPositionIteratorImpl();
83
84
    // Implementation of FormattedValue (const):
85
86
    UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
87
    UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
88
    Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
89
    UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
90
91
    // Additional methods used during construction phase only (non-const):
92
93
    FieldPositionIteratorHandler getHandler(UErrorCode& status);
94
    void appendString(UnicodeString string, UErrorCode& status);
95
96
    /**
97
     * Computes the spans for duplicated values.
98
     * For example, if the string has fields:
99
     * 
100
     *     ...aa..[b.cc]..d.[bb.e.c]..a..
101
     *
102
     * then the spans will be the bracketed regions.
103
     *
104
     * Assumes that the currently known fields are sorted
105
     * and all in the same category.
106
     */
107
    void addOverlapSpans(UFieldCategory spanCategory, int8_t firstIndex, UErrorCode& status);
108
109
    /**
110
     * Sorts the fields: start index first, length second.
111
     */
112
    void sort();
113
114
private:
115
    UnicodeString fString;
116
    UVector32 fFields;
117
};
118
119
120
// Internal struct that must be exported for MSVC
121
struct U_I18N_API SpanInfo {
122
    UFieldCategory category;
123
    int32_t spanValue;
124
    int32_t start;
125
    int32_t length;
126
};
127
128
// Export an explicit template instantiation of the MaybeStackArray that
129
//    is used as a data member of CEBuffer.
130
//
131
//    When building DLLs for Windows this is required even though
132
//    no direct access to the MaybeStackArray leaks out of the i18n library.
133
//
134
// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
135
//
136
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
137
template class U_I18N_API MaybeStackArray<SpanInfo, 8>;
138
#endif
139
140
/**
141
 * Implementation of FormattedValue based on FormattedStringBuilder.
142
 *
143
 * The implementation currently revolves around numbers and number fields.
144
 * However, it can be generalized in the future when there is a need.
145
 *
146
 * @author sffc (Shane Carr)
147
 */
148
// Exported as U_I18N_API for tests
149
class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue {
150
public:
151
152
    FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField);
153
154
    virtual ~FormattedValueStringBuilderImpl();
155
156
    // Implementation of FormattedValue (const):
157
158
    UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
159
    UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
160
    Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
161
    UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
162
163
    // Additional helper functions:
164
    UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
165
    void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
166
0
    inline FormattedStringBuilder& getStringRef() {
167
0
        return fString;
168
0
    }
169
0
    inline const FormattedStringBuilder& getStringRef() const {
170
0
        return fString;
171
0
    }
172
173
    /**
174
     * Adds additional metadata used for span fields.
175
     *
176
     * category: the category to use for the span field.
177
     * spanValue: the value of the span field: index of the list item, for example.
178
     * start: the start position within the string of the span. -1 if unknown.
179
     * length: the length of the span, used to split adjacent fields.
180
     */
181
    void appendSpanInfo(UFieldCategory category, int32_t spanValue, int32_t start, int32_t length, UErrorCode& status);
182
    void prependSpanInfo(UFieldCategory category, int32_t spanValue, int32_t start, int32_t length, UErrorCode& status);
183
184
private:
185
    FormattedStringBuilder fString;
186
    FormattedStringBuilder::Field fNumericField;
187
    MaybeStackArray<SpanInfo, 8> spanIndices;
188
    int32_t spanIndicesCount = 0;
189
190
    bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const;
191
    static bool isIntOrGroup(FormattedStringBuilder::Field field);
192
    static bool isTrimmable(FormattedStringBuilder::Field field);
193
    int32_t trimBack(int32_t limit) const;
194
    int32_t trimFront(int32_t start) const;
195
};
196
197
198
// C API Helpers for FormattedValue
199
// Magic number as ASCII == "UFV"
200
struct UFormattedValueImpl;
201
typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper;
202
struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
203
    // This pointer should be set by the child class.
204
    FormattedValue* fFormattedValue = nullptr;
205
};
206
207
208
/** Boilerplate to check for valid status before dereferencing the fData pointer. */
209
#define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \
210
0
    if (U_FAILURE(status)) { \
211
0
        return returnExpression; \
212
0
    } \
213
0
    if (fData == nullptr) { \
214
0
        status = fErrorCode; \
215
0
        return returnExpression; \
216
0
    } \
217
218
219
/** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */
220
#define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \
221
    Name::Name(Name&& src) U_NOEXCEPT \
222
0
            : fData(src.fData), fErrorCode(src.fErrorCode) { \
223
0
        src.fData = nullptr; \
224
0
        src.fErrorCode = U_INVALID_STATE_ERROR; \
225
0
    } \
Unexecuted instantiation: icu_70::number::FormattedNumber::FormattedNumber(icu_70::number::FormattedNumber&&)
Unexecuted instantiation: icu_70::number::FormattedNumberRange::FormattedNumberRange(icu_70::number::FormattedNumberRange&&)
Unexecuted instantiation: icu_70::FormattedList::FormattedList(icu_70::FormattedList&&)
226
0
    Name::~Name() { \
227
0
        delete fData; \
228
0
        fData = nullptr; \
229
0
    } \
Unexecuted instantiation: icu_70::number::FormattedNumber::~FormattedNumber()
Unexecuted instantiation: icu_70::number::FormattedNumberRange::~FormattedNumberRange()
Unexecuted instantiation: icu_70::FormattedList::~FormattedList()
230
0
    Name& Name::operator=(Name&& src) U_NOEXCEPT { \
231
0
        delete fData; \
232
0
        fData = src.fData; \
233
0
        src.fData = nullptr; \
234
0
        fErrorCode = src.fErrorCode; \
235
0
        src.fErrorCode = U_INVALID_STATE_ERROR; \
236
0
        return *this; \
237
0
    } \
Unexecuted instantiation: icu_70::number::FormattedNumber::operator=(icu_70::number::FormattedNumber&&)
Unexecuted instantiation: icu_70::number::FormattedNumberRange::operator=(icu_70::number::FormattedNumberRange&&)
Unexecuted instantiation: icu_70::FormattedList::operator=(icu_70::FormattedList&&)
238
0
    UnicodeString Name::toString(UErrorCode& status) const { \
239
0
        UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
240
0
        return fData->toString(status); \
241
0
    } \
Unexecuted instantiation: icu_70::number::FormattedNumber::toString(UErrorCode&) const
Unexecuted instantiation: icu_70::number::FormattedNumberRange::toString(UErrorCode&) const
Unexecuted instantiation: icu_70::FormattedList::toString(UErrorCode&) const
242
0
    UnicodeString Name::toTempString(UErrorCode& status) const { \
243
0
        UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
244
0
        return fData->toTempString(status); \
245
0
    } \
Unexecuted instantiation: icu_70::number::FormattedNumber::toTempString(UErrorCode&) const
Unexecuted instantiation: icu_70::number::FormattedNumberRange::toTempString(UErrorCode&) const
Unexecuted instantiation: icu_70::FormattedList::toTempString(UErrorCode&) const
246
0
    Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \
247
0
        UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \
248
0
        return fData->appendTo(appendable, status); \
249
0
    } \
Unexecuted instantiation: icu_70::number::FormattedNumber::appendTo(icu_70::Appendable&, UErrorCode&) const
Unexecuted instantiation: icu_70::number::FormattedNumberRange::appendTo(icu_70::Appendable&, UErrorCode&) const
Unexecuted instantiation: icu_70::FormattedList::appendTo(icu_70::Appendable&, UErrorCode&) const
250
0
    UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \
251
0
        UPRV_FORMATTED_VALUE_METHOD_GUARD(false) \
252
0
        return fData->nextPosition(cfpos, status); \
253
0
    }
Unexecuted instantiation: icu_70::number::FormattedNumber::nextPosition(icu_70::ConstrainedFieldPosition&, UErrorCode&) const
Unexecuted instantiation: icu_70::number::FormattedNumberRange::nextPosition(icu_70::ConstrainedFieldPosition&, UErrorCode&) const
Unexecuted instantiation: icu_70::FormattedList::nextPosition(icu_70::ConstrainedFieldPosition&, UErrorCode&) const
254
255
256
/** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */
257
#define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \
258
    U_CAPI CType* U_EXPORT2 \
259
    Prefix ## _openResult (UErrorCode* ec) { \
260
        if (U_FAILURE(*ec)) { \
261
            return nullptr; \
262
        } \
263
        ImplType* impl = new ImplType(); \
264
        if (impl == nullptr) { \
265
            *ec = U_MEMORY_ALLOCATION_ERROR; \
266
            return nullptr; \
267
        } \
268
        return static_cast<HelperType*>(impl)->exportForC(); \
269
    } \
270
    U_CAPI const UFormattedValue* U_EXPORT2 \
271
    Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
272
        const ImplType* result = HelperType::validate(uresult, *ec); \
273
        if (U_FAILURE(*ec)) { return nullptr; } \
274
        return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
275
    } \
276
    U_CAPI void U_EXPORT2 \
277
    Prefix ## _closeResult (CType* uresult) { \
278
        UErrorCode localStatus = U_ZERO_ERROR; \
279
        const ImplType* impl = HelperType::validate(uresult, localStatus); \
280
        delete impl; \
281
    }
282
283
284
/**
285
 * Implementation of the standard methods for a UFormattedValue "subclass" C API.
286
 * @param CPPType The public C++ type, like FormattedList
287
 * @param CType The public C type, like UFormattedList
288
 * @param ImplType A name to use for the implementation class
289
 * @param HelperType A name to use for the "mixin" typedef for C API conversion
290
 * @param Prefix The C API prefix, like ulistfmt
291
 * @param MagicNumber A unique 32-bit number to use to identify this type
292
 */
293
#define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \
294
    U_NAMESPACE_BEGIN \
295
    class ImplType; \
296
    typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \
297
    class ImplType : public UFormattedValueImpl, public HelperType { \
298
    public: \
299
        ImplType(); \
300
        ~ImplType(); \
301
        CPPType fImpl; \
302
    }; \
303
    ImplType::ImplType() { \
304
        fFormattedValue = &fImpl; \
305
    } \
306
    ImplType::~ImplType() {} \
307
    U_NAMESPACE_END \
308
    UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
309
310
311
U_NAMESPACE_END
312
313
#endif /* #if !UCONFIG_NO_FORMATTING */
314
#endif // __FORMVAL_IMPL_H__