1// © 2017 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3
4#include "unicode/utypes.h"
5
6#if !UCONFIG_NO_FORMATTING
7
8#include "unicode/numberformatter.h"
9#include "number_types.h"
10#include "formatted_string_builder.h"
11#include "number_decimfmtprops.h"
12
13using namespace icu;
14using namespace icu::number;
15using namespace icu::number::impl;
16
17namespace {
18
19int32_t
20addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, FormattedStringBuilder &string, int32_t index,
21 UErrorCode &status) {
22 for (int32_t i = 0; i < requiredPadding; i++) {
23 // TODO: If appending to the end, this will cause actual insertion operations. Improve.
24 string.insertCodePoint(index, paddingCp, UNUM_FIELD_COUNT, status);
25 }
26 return U16_LENGTH(paddingCp) * requiredPadding;
27}
28
29}
30
31Padder::Padder(UChar32 cp, int32_t width, UNumberFormatPadPosition position) : fWidth(width) {
32 // TODO(13034): Consider making this a string instead of code point.
33 fUnion.padding.fCp = cp;
34 fUnion.padding.fPosition = position;
35}
36
37Padder::Padder(int32_t width) : fWidth(width) {}
38
39Padder Padder::none() {
40 return {-1};
41}
42
43Padder Padder::codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosition position) {
44 // TODO: Validate the code point?
45 if (targetWidth >= 0) {
46 return {cp, targetWidth, position};
47 } else {
48 return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
49 }
50}
51
52Padder Padder::forProperties(const DecimalFormatProperties& properties) {
53 UChar32 padCp;
54 if (properties.padString.length() > 0) {
55 padCp = properties.padString.char32At(0);
56 } else {
57 padCp = kFallbackPaddingString[0];
58 }
59 return {padCp, properties.formatWidth, properties.padPosition.getOrDefault(UNUM_PAD_BEFORE_PREFIX)};
60}
61
62int32_t Padder::padAndApply(const Modifier &mod1, const Modifier &mod2,
63 FormattedStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
64 UErrorCode &status) const {
65 int32_t modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
66 int32_t requiredPadding = fWidth - modLength - string.codePointCount();
67 U_ASSERT(leftIndex == 0 &&
68 rightIndex == string.length()); // fix the previous line to remove this assertion
69
70 int length = 0;
71 if (requiredPadding <= 0) {
72 // Padding is not required.
73 length += mod1.apply(string, leftIndex, rightIndex, status);
74 length += mod2.apply(string, leftIndex, rightIndex + length, status);
75 return length;
76 }
77
78 PadPosition position = fUnion.padding.fPosition;
79 UChar32 paddingCp = fUnion.padding.fCp;
80 if (position == UNUM_PAD_AFTER_PREFIX) {
81 length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status);
82 } else if (position == UNUM_PAD_BEFORE_SUFFIX) {
83 length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status);
84 }
85 length += mod1.apply(string, leftIndex, rightIndex + length, status);
86 length += mod2.apply(string, leftIndex, rightIndex + length, status);
87 if (position == UNUM_PAD_BEFORE_PREFIX) {
88 length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status);
89 } else if (position == UNUM_PAD_AFTER_SUFFIX) {
90 length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status);
91 }
92
93 return length;
94}
95
96#endif /* #if !UCONFIG_NO_FORMATTING */
97