1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
7 #ifndef __NUMBER_STRINGBUILDER_H__
8 #define __NUMBER_STRINGBUILDER_H__
12 #include "unicode/unum.h" // for UNUM_FIELD_COUNT
19 class FormattedValueStringBuilderImpl
;
22 * A StringBuilder optimized for formatting. It implements the following key
23 * features beyond a UnicodeString:
26 * <li>Efficient prepend as well as append.
27 * <li>Keeps tracks of Fields in an efficient manner.
30 * See also FormattedValueStringBuilderImpl.
32 * @author sffc (Shane Carr)
34 class U_I18N_API FormattedStringBuilder
: public UMemory
{
36 static const int32_t DEFAULT_CAPACITY
= 40;
39 union ValueOrHeapArray
{
40 T value
[DEFAULT_CAPACITY
];
48 FormattedStringBuilder();
50 ~FormattedStringBuilder();
52 FormattedStringBuilder(const FormattedStringBuilder
&other
);
54 // Convention: bottom 4 bits for field, top 4 bits for field category.
55 // Field category 0 implies the number category so that the number field
56 // literals can be directly passed as a Field type.
57 // See the helper functions in "StringBuilderFieldUtils" below.
58 typedef uint8_t Field
;
60 FormattedStringBuilder
&operator=(const FormattedStringBuilder
&other
);
62 int32_t length() const;
64 int32_t codePointCount() const;
66 inline char16_t charAt(int32_t index
) const {
68 U_ASSERT(index
< fLength
);
69 return getCharPtr()[fZero
+ index
];
72 inline Field
fieldAt(int32_t index
) const {
74 U_ASSERT(index
< fLength
);
75 return getFieldPtr()[fZero
+ index
];
78 UChar32
getFirstCodePoint() const;
80 UChar32
getLastCodePoint() const;
82 UChar32
codePointAt(int32_t index
) const;
84 UChar32
codePointBefore(int32_t index
) const;
86 FormattedStringBuilder
&clear();
88 /** Appends a UTF-16 code unit. */
89 inline int32_t appendChar16(char16_t codeUnit
, Field field
, UErrorCode
& status
) {
90 // appendCodePoint handles both code units and code points.
91 return insertCodePoint(fLength
, codeUnit
, field
, status
);
94 /** Inserts a UTF-16 code unit. Note: insert at index 0 is very efficient. */
95 inline int32_t insertChar16(int32_t index
, char16_t codeUnit
, Field field
, UErrorCode
& status
) {
96 // insertCodePoint handles both code units and code points.
97 return insertCodePoint(index
, codeUnit
, field
, status
);
100 /** Appends a Unicode code point. */
101 inline int32_t appendCodePoint(UChar32 codePoint
, Field field
, UErrorCode
&status
) {
102 return insertCodePoint(fLength
, codePoint
, field
, status
);
105 /** Inserts a Unicode code point. Note: insert at index 0 is very efficient. */
106 int32_t insertCodePoint(int32_t index
, UChar32 codePoint
, Field field
, UErrorCode
&status
);
108 /** Appends a string. */
109 inline int32_t append(const UnicodeString
&unistr
, Field field
, UErrorCode
&status
) {
110 return insert(fLength
, unistr
, field
, status
);
113 /** Inserts a string. Note: insert at index 0 is very efficient. */
114 int32_t insert(int32_t index
, const UnicodeString
&unistr
, Field field
, UErrorCode
&status
);
116 /** Inserts a substring. Note: insert at index 0 is very efficient.
118 * @param start Start index of the substring of unistr to be inserted.
119 * @param end End index of the substring of unistr to be inserted (exclusive).
121 int32_t insert(int32_t index
, const UnicodeString
&unistr
, int32_t start
, int32_t end
, Field field
,
124 /** Deletes a substring and then inserts a string at that same position.
125 * Similar to JavaScript Array.prototype.splice().
127 * @param startThis Start of the span to delete.
128 * @param endThis End of the span to delete (exclusive).
129 * @param unistr The string to insert at the deletion position.
130 * @param startOther Start index of the substring of unistr to be inserted.
131 * @param endOther End index of the substring of unistr to be inserted (exclusive).
133 int32_t splice(int32_t startThis
, int32_t endThis
, const UnicodeString
&unistr
,
134 int32_t startOther
, int32_t endOther
, Field field
, UErrorCode
& status
);
136 /** Appends a formatted string. */
137 int32_t append(const FormattedStringBuilder
&other
, UErrorCode
&status
);
139 /** Inserts a formatted string. Note: insert at index 0 is very efficient. */
140 int32_t insert(int32_t index
, const FormattedStringBuilder
&other
, UErrorCode
&status
);
143 * Ensures that the string buffer contains a NUL terminator. The NUL terminator does
144 * not count toward the string length. Any further changes to the string (insert or
145 * append) may invalidate the NUL terminator.
147 * You should call this method after the formatted string is completely built if you
148 * plan to return a pointer to the string from a C API.
150 void writeTerminator(UErrorCode
& status
);
153 * Gets a "safe" UnicodeString that can be used even after the FormattedStringBuilder is destructed.
155 UnicodeString
toUnicodeString() const;
158 * Gets an "unsafe" UnicodeString that is valid only as long as the FormattedStringBuilder is alive and
159 * unchanged. Slightly faster than toUnicodeString().
161 const UnicodeString
toTempUnicodeString() const;
163 UnicodeString
toDebugString() const;
165 const char16_t *chars() const;
167 bool contentEquals(const FormattedStringBuilder
&other
) const;
169 bool containsField(Field field
) const;
172 bool fUsingHeap
= false;
173 ValueOrHeapArray
<char16_t> fChars
;
174 ValueOrHeapArray
<Field
> fFields
;
175 int32_t fZero
= DEFAULT_CAPACITY
/ 2;
178 inline char16_t *getCharPtr() {
179 return fUsingHeap
? fChars
.heap
.ptr
: fChars
.value
;
182 inline const char16_t *getCharPtr() const {
183 return fUsingHeap
? fChars
.heap
.ptr
: fChars
.value
;
186 inline Field
*getFieldPtr() {
187 return fUsingHeap
? fFields
.heap
.ptr
: fFields
.value
;
190 inline const Field
*getFieldPtr() const {
191 return fUsingHeap
? fFields
.heap
.ptr
: fFields
.value
;
194 inline int32_t getCapacity() const {
195 return fUsingHeap
? fChars
.heap
.capacity
: DEFAULT_CAPACITY
;
198 int32_t prepareForInsert(int32_t index
, int32_t count
, UErrorCode
&status
);
200 int32_t prepareForInsertHelper(int32_t index
, int32_t count
, UErrorCode
&status
);
202 int32_t remove(int32_t index
, int32_t count
);
204 friend class FormattedValueStringBuilderImpl
;
208 * Helper functions for dealing with the Field typedef, which stores fields
209 * in a compressed format.
211 class StringBuilderFieldUtils
{
213 struct CategoryFieldPair
{
218 /** Compile-time function to construct a Field from a category and a field */
219 template <int32_t category
, int32_t field
>
220 static constexpr FormattedStringBuilder::Field
compress() {
221 static_assert(category
!= 0, "cannot use Undefined category in FieldUtils");
222 static_assert(category
<= 0xf, "only 4 bits for category");
223 static_assert(field
<= 0xf, "only 4 bits for field");
224 return static_cast<int8_t>((category
<< 4) | field
);
227 /** Runtime inline function to unpack the category and field from the Field */
228 static inline CategoryFieldPair
expand(FormattedStringBuilder::Field field
) {
229 if (field
== UNUM_FIELD_COUNT
) {
230 return {UFIELD_CATEGORY_UNDEFINED
, 0};
232 CategoryFieldPair ret
= {
236 if (ret
.category
== 0) {
237 ret
.category
= UFIELD_CATEGORY_NUMBER
;
242 static inline bool isNumericField(FormattedStringBuilder::Field field
) {
243 int8_t category
= field
>> 4;
244 return category
== 0 || category
== UFIELD_CATEGORY_NUMBER
;
251 #endif //__NUMBER_STRINGBUILDER_H__
253 #endif /* #if !UCONFIG_NO_FORMATTING */