| // © 2017 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| |
| #include "unicode/utypes.h" |
| |
| #if !UCONFIG_NO_FORMATTING |
| |
| #include "unicode/numberformatter.h" |
| #include "number_types.h" |
| #include "formatted_string_builder.h" |
| #include "number_decimfmtprops.h" |
| |
| using namespace icu; |
| using namespace icu::number; |
| using namespace icu::number::impl; |
| |
| namespace { |
| |
| int32_t |
| addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, FormattedStringBuilder &string, int32_t index, |
| UErrorCode &status) { |
| for (int32_t i = 0; i < requiredPadding; i++) { |
| // TODO: If appending to the end, this will cause actual insertion operations. Improve. |
| string.insertCodePoint(index, paddingCp, kUndefinedField, status); |
| } |
| return U16_LENGTH(paddingCp) * requiredPadding; |
| } |
| |
| } |
| |
| Padder::Padder(UChar32 cp, int32_t width, UNumberFormatPadPosition position) : fWidth(width) { |
| // TODO(13034): Consider making this a string instead of code point. |
| fUnion.padding.fCp = cp; |
| fUnion.padding.fPosition = position; |
| } |
| |
| Padder::Padder(int32_t width) : fWidth(width) {} |
| |
| Padder Padder::none() { |
| return {-1}; |
| } |
| |
| Padder Padder::codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosition position) { |
| // TODO: Validate the code point? |
| if (targetWidth >= 0) { |
| return {cp, targetWidth, position}; |
| } else { |
| return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR}; |
| } |
| } |
| |
| Padder Padder::forProperties(const DecimalFormatProperties& properties) { |
| UChar32 padCp; |
| if (properties.padString.length() > 0) { |
| padCp = properties.padString.char32At(0); |
| } else { |
| padCp = kFallbackPaddingString[0]; |
| } |
| return {padCp, properties.formatWidth, properties.padPosition.getOrDefault(UNUM_PAD_BEFORE_PREFIX)}; |
| } |
| |
| int32_t Padder::padAndApply(const Modifier &mod1, const Modifier &mod2, |
| FormattedStringBuilder &string, int32_t leftIndex, int32_t rightIndex, |
| UErrorCode &status) const { |
| int32_t modLength = mod1.getCodePointCount() + mod2.getCodePointCount(); |
| int32_t requiredPadding = fWidth - modLength - string.codePointCount(); |
| U_ASSERT(leftIndex == 0 && |
| rightIndex == string.length()); // fix the previous line to remove this assertion |
| |
| int length = 0; |
| if (requiredPadding <= 0) { |
| // Padding is not required. |
| length += mod1.apply(string, leftIndex, rightIndex, status); |
| length += mod2.apply(string, leftIndex, rightIndex + length, status); |
| return length; |
| } |
| |
| PadPosition position = fUnion.padding.fPosition; |
| UChar32 paddingCp = fUnion.padding.fCp; |
| if (position == UNUM_PAD_AFTER_PREFIX) { |
| length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status); |
| } else if (position == UNUM_PAD_BEFORE_SUFFIX) { |
| length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status); |
| } |
| length += mod1.apply(string, leftIndex, rightIndex + length, status); |
| length += mod2.apply(string, leftIndex, rightIndex + length, status); |
| if (position == UNUM_PAD_BEFORE_PREFIX) { |
| length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status); |
| } else if (position == UNUM_PAD_AFTER_SUFFIX) { |
| length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status); |
| } |
| |
| return length; |
| } |
| |
| #endif /* #if !UCONFIG_NO_FORMATTING */ |