1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5* Copyright (C) 2014-2016, International Business Machines
6* Corporation and others.  All Rights Reserved.
7******************************************************************************
8* simpleformatter.h
9*/
10
11#ifndef __SIMPLEFORMATTER_H__
12#define __SIMPLEFORMATTER_H__
13
14/**
15 * \file
16 * \brief C++ API: Simple formatter, minimal subset of MessageFormat.
17 */
18
19#include "unicode/utypes.h"
20#include "unicode/unistr.h"
21
22U_NAMESPACE_BEGIN
23
24// Forward declaration:
25namespace number {
26namespace impl {
27class SimpleModifier;
28}
29}
30
31/**
32 * Formats simple patterns like "{1} was born in {0}".
33 * Minimal subset of MessageFormat; fast, simple, minimal dependencies.
34 * Supports only numbered arguments with no type nor style parameters,
35 * and formats only string values.
36 * Quoting via ASCII apostrophe compatible with ICU MessageFormat default behavior.
37 *
38 * Factory methods set error codes for syntax errors
39 * and for too few or too many arguments/placeholders.
40 *
41 * SimpleFormatter objects are thread-safe except for assignment and applying new patterns.
42 *
43 * Example:
44 * <pre>
45 * UErrorCode errorCode = U_ZERO_ERROR;
46 * SimpleFormatter fmt("{1} '{born}' in {0}", errorCode);
47 * UnicodeString result;
48 *
49 * // Output: "paul {born} in england"
50 * fmt.format("england", "paul", result, errorCode);
51 * </pre>
52 *
53 * This class is not intended for public subclassing.
54 *
55 * @see MessageFormat
56 * @see UMessagePatternApostropheMode
57 * @stable ICU 57
58 */
59class U_COMMON_API SimpleFormatter U_FINAL : public UMemory {
60public:
61    /**
62     * Default constructor.
63     * @stable ICU 57
64     */
65    SimpleFormatter() : compiledPattern((char16_t)0) {}
66
67    /**
68     * Constructs a formatter from the pattern string.
69     *
70     * @param pattern The pattern string.
71     * @param errorCode ICU error code in/out parameter.
72     *                  Must fulfill U_SUCCESS before the function call.
73     *                  Set to U_ILLEGAL_ARGUMENT_ERROR for bad argument syntax.
74     * @stable ICU 57
75     */
76    SimpleFormatter(const UnicodeString& pattern, UErrorCode &errorCode) {
77        applyPattern(pattern, errorCode);
78    }
79
80    /**
81     * Constructs a formatter from the pattern string.
82     * The number of arguments checked against the given limits is the
83     * highest argument number plus one, not the number of occurrences of arguments.
84     *
85     * @param pattern The pattern string.
86     * @param min The pattern must have at least this many arguments.
87     * @param max The pattern must have at most this many arguments.
88     * @param errorCode ICU error code in/out parameter.
89     *                  Must fulfill U_SUCCESS before the function call.
90     *                  Set to U_ILLEGAL_ARGUMENT_ERROR for bad argument syntax and
91     *                  too few or too many arguments.
92     * @stable ICU 57
93     */
94    SimpleFormatter(const UnicodeString& pattern, int32_t min, int32_t max,
95                    UErrorCode &errorCode) {
96        applyPatternMinMaxArguments(pattern, min, max, errorCode);
97    }
98
99    /**
100     * Copy constructor.
101     * @stable ICU 57
102     */
103    SimpleFormatter(const SimpleFormatter& other)
104            : compiledPattern(other.compiledPattern) {}
105
106    /**
107     * Assignment operator.
108     * @stable ICU 57
109     */
110    SimpleFormatter &operator=(const SimpleFormatter& other);
111
112    /**
113     * Destructor.
114     * @stable ICU 57
115     */
116    ~SimpleFormatter();
117
118    /**
119     * Changes this object according to the new pattern.
120     *
121     * @param pattern The pattern string.
122     * @param errorCode ICU error code in/out parameter.
123     *                  Must fulfill U_SUCCESS before the function call.
124     *                  Set to U_ILLEGAL_ARGUMENT_ERROR for bad argument syntax.
125     * @return TRUE if U_SUCCESS(errorCode).
126     * @stable ICU 57
127     */
128    UBool applyPattern(const UnicodeString &pattern, UErrorCode &errorCode) {
129        return applyPatternMinMaxArguments(pattern, 0, INT32_MAX, errorCode);
130    }
131
132    /**
133     * Changes this object according to the new pattern.
134     * The number of arguments checked against the given limits is the
135     * highest argument number plus one, not the number of occurrences of arguments.
136     *
137     * @param pattern The pattern string.
138     * @param min The pattern must have at least this many arguments.
139     * @param max The pattern must have at most this many arguments.
140     * @param errorCode ICU error code in/out parameter.
141     *                  Must fulfill U_SUCCESS before the function call.
142     *                  Set to U_ILLEGAL_ARGUMENT_ERROR for bad argument syntax and
143     *                  too few or too many arguments.
144     * @return TRUE if U_SUCCESS(errorCode).
145     * @stable ICU 57
146     */
147    UBool applyPatternMinMaxArguments(const UnicodeString &pattern,
148                                      int32_t min, int32_t max, UErrorCode &errorCode);
149
150    /**
151     * @return The max argument number + 1.
152     * @stable ICU 57
153     */
154    int32_t getArgumentLimit() const {
155        return getArgumentLimit(compiledPattern.getBuffer(), compiledPattern.length());
156    }
157
158    /**
159     * Formats the given value, appending to the appendTo builder.
160     * The argument value must not be the same object as appendTo.
161     * getArgumentLimit() must be at most 1.
162     *
163     * @param value0 Value for argument {0}.
164     * @param appendTo Gets the formatted pattern and value appended.
165     * @param errorCode ICU error code in/out parameter.
166     *                  Must fulfill U_SUCCESS before the function call.
167     * @return appendTo
168     * @stable ICU 57
169     */
170    UnicodeString &format(
171            const UnicodeString &value0,
172            UnicodeString &appendTo, UErrorCode &errorCode) const;
173
174    /**
175     * Formats the given values, appending to the appendTo builder.
176     * An argument value must not be the same object as appendTo.
177     * getArgumentLimit() must be at most 2.
178     *
179     * @param value0 Value for argument {0}.
180     * @param value1 Value for argument {1}.
181     * @param appendTo Gets the formatted pattern and values appended.
182     * @param errorCode ICU error code in/out parameter.
183     *                  Must fulfill U_SUCCESS before the function call.
184     * @return appendTo
185     * @stable ICU 57
186     */
187    UnicodeString &format(
188            const UnicodeString &value0,
189            const UnicodeString &value1,
190            UnicodeString &appendTo, UErrorCode &errorCode) const;
191
192    /**
193     * Formats the given values, appending to the appendTo builder.
194     * An argument value must not be the same object as appendTo.
195     * getArgumentLimit() must be at most 3.
196     *
197     * @param value0 Value for argument {0}.
198     * @param value1 Value for argument {1}.
199     * @param value2 Value for argument {2}.
200     * @param appendTo Gets the formatted pattern and values appended.
201     * @param errorCode ICU error code in/out parameter.
202     *                  Must fulfill U_SUCCESS before the function call.
203     * @return appendTo
204     * @stable ICU 57
205     */
206    UnicodeString &format(
207            const UnicodeString &value0,
208            const UnicodeString &value1,
209            const UnicodeString &value2,
210            UnicodeString &appendTo, UErrorCode &errorCode) const;
211
212    /**
213     * Formats the given values, appending to the appendTo string.
214     *
215     * @param values The argument values.
216     *               An argument value must not be the same object as appendTo.
217     *               Can be NULL if valuesLength==getArgumentLimit()==0.
218     * @param valuesLength The length of the values array.
219     *                     Must be at least getArgumentLimit().
220     * @param appendTo Gets the formatted pattern and values appended.
221     * @param offsets offsets[i] receives the offset of where
222     *                values[i] replaced pattern argument {i}.
223     *                Can be shorter or longer than values. Can be NULL if offsetsLength==0.
224     *                If there is no {i} in the pattern, then offsets[i] is set to -1.
225     * @param offsetsLength The length of the offsets array.
226     * @param errorCode ICU error code in/out parameter.
227     *                  Must fulfill U_SUCCESS before the function call.
228     * @return appendTo
229     * @stable ICU 57
230     */
231    UnicodeString &formatAndAppend(
232            const UnicodeString *const *values, int32_t valuesLength,
233            UnicodeString &appendTo,
234            int32_t *offsets, int32_t offsetsLength, UErrorCode &errorCode) const;
235
236    /**
237     * Formats the given values, replacing the contents of the result string.
238     * May optimize by actually appending to the result if it is the same object
239     * as the value corresponding to the initial argument in the pattern.
240     *
241     * @param values The argument values.
242     *               An argument value may be the same object as result.
243     *               Can be NULL if valuesLength==getArgumentLimit()==0.
244     * @param valuesLength The length of the values array.
245     *                     Must be at least getArgumentLimit().
246     * @param result Gets its contents replaced by the formatted pattern and values.
247     * @param offsets offsets[i] receives the offset of where
248     *                values[i] replaced pattern argument {i}.
249     *                Can be shorter or longer than values. Can be NULL if offsetsLength==0.
250     *                If there is no {i} in the pattern, then offsets[i] is set to -1.
251     * @param offsetsLength The length of the offsets array.
252     * @param errorCode ICU error code in/out parameter.
253     *                  Must fulfill U_SUCCESS before the function call.
254     * @return result
255     * @stable ICU 57
256     */
257    UnicodeString &formatAndReplace(
258            const UnicodeString *const *values, int32_t valuesLength,
259            UnicodeString &result,
260            int32_t *offsets, int32_t offsetsLength, UErrorCode &errorCode) const;
261
262    /**
263     * Returns the pattern text with none of the arguments.
264     * Like formatting with all-empty string values.
265     * @stable ICU 57
266     */
267    UnicodeString getTextWithNoArguments() const {
268        return getTextWithNoArguments(compiledPattern.getBuffer(), compiledPattern.length());
269    }
270
271private:
272    /**
273     * Binary representation of the compiled pattern.
274     * Index 0: One more than the highest argument number.
275     * Followed by zero or more arguments or literal-text segments.
276     *
277     * An argument is stored as its number, less than ARG_NUM_LIMIT.
278     * A literal-text segment is stored as its length (at least 1) offset by ARG_NUM_LIMIT,
279     * followed by that many chars.
280     */
281    UnicodeString compiledPattern;
282
283    static inline int32_t getArgumentLimit(const char16_t *compiledPattern,
284                                              int32_t compiledPatternLength) {
285        return compiledPatternLength == 0 ? 0 : compiledPattern[0];
286    }
287
288    static UnicodeString getTextWithNoArguments(const char16_t *compiledPattern, int32_t compiledPatternLength);
289
290    static UnicodeString &format(
291            const char16_t *compiledPattern, int32_t compiledPatternLength,
292            const UnicodeString *const *values,
293            UnicodeString &result, const UnicodeString *resultCopy, UBool forbidResultAsValue,
294            int32_t *offsets, int32_t offsetsLength,
295            UErrorCode &errorCode);
296
297    // Give access to internals to SimpleModifier for number formatting
298    friend class number::impl::SimpleModifier;
299};
300
301U_NAMESPACE_END
302
303#endif  // __SIMPLEFORMATTER_H__
304