number_padding.cpp (3490B)
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 13 using namespace icu; 14 using namespace icu::number; 15 using namespace icu::number::impl; 16 17 namespace { 18 19 int32_t 20 addPaddingHelper(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, kUndefinedField, status); 25 } 26 return U16_LENGTH(paddingCp) * requiredPadding; 27 } 28 29 } 30 31 Padder::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 37 Padder::Padder(int32_t width) : fWidth(width) {} 38 39 Padder Padder::none() { 40 return {-1}; 41 } 42 43 Padder 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 52 Padder 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 62 int32_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 */