1 // 2017 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 package com.ibm.icu.impl.number; 4 5 public class Padder { 6 public static final String FALLBACK_PADDING_STRING = "\u0020"; // i.e. a space 7 8 public enum PadPosition { 9 BEFORE_PREFIX, 10 AFTER_PREFIX, 11 BEFORE_SUFFIX, 12 AFTER_SUFFIX; 13 14 public static PadPosition fromOld(int old) { 15 switch (old) { 16 case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX: 17 return PadPosition.BEFORE_PREFIX; 18 case com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX: 19 return PadPosition.AFTER_PREFIX; 20 case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX: 21 return PadPosition.BEFORE_SUFFIX; 22 case com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX: 23 return PadPosition.AFTER_SUFFIX; 24 default: 25 throw new IllegalArgumentException("Don't know how to map " + old); 26 } 27 } 28 29 public int toOld() { 30 switch (this) { 31 case BEFORE_PREFIX: 32 return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX; 33 case AFTER_PREFIX: 34 return com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX; 35 case BEFORE_SUFFIX: 36 return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX; 37 case AFTER_SUFFIX: 38 return com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX; 39 default: 40 return -1; // silence compiler errors 41 } 42 } 43 } 44 45 /* like package-private */ public static final Padder NONE = new Padder(null, -1, null); 46 47 String paddingString; 48 int targetWidth; 49 PadPosition position; 50 51 public Padder(String paddingString, int targetWidth, PadPosition position) { 52 // TODO: Add a few default instances 53 this.paddingString = (paddingString == null) ? FALLBACK_PADDING_STRING : paddingString; 54 this.targetWidth = targetWidth; 55 this.position = (position == null) ? PadPosition.BEFORE_PREFIX : position; 56 } 57 58 public static Padder none() { 59 return NONE; 60 } 61 62 public static Padder codePoints(int cp, int targetWidth, PadPosition position) { 63 // TODO: Validate the code point 64 if (targetWidth >= 0) { 65 String paddingString = String.valueOf(Character.toChars(cp)); 66 return new Padder(paddingString, targetWidth, position); 67 } else { 68 throw new IllegalArgumentException("Padding width must not be negative"); 69 } 70 } 71 72 public boolean isValid() { 73 return targetWidth > 0; 74 } 75 76 public int padAndApply(Modifier mod1, Modifier mod2, NumberStringBuilder string, int leftIndex, int rightIndex) { 77 int modLength = mod1.getCodePointCount() + mod2.getCodePointCount(); 78 int requiredPadding = targetWidth - modLength - string.codePointCount(); 79 assert leftIndex == 0 && rightIndex == string.length(); // fix the previous line to remove this assertion 80 81 int length = 0; 82 if (requiredPadding <= 0) { 83 // Padding is not required. 84 length += mod1.apply(string, leftIndex, rightIndex); 85 length += mod2.apply(string, leftIndex, rightIndex + length); 86 return length; 87 } 88 89 if (position == PadPosition.AFTER_PREFIX) { 90 length += addPaddingHelper(paddingString, requiredPadding, string, leftIndex); 91 } else if (position == PadPosition.BEFORE_SUFFIX) { 92 length += addPaddingHelper(paddingString, requiredPadding, string, rightIndex + length); 93 } 94 length += mod1.apply(string, leftIndex, rightIndex + length); 95 length += mod2.apply(string, leftIndex, rightIndex + length); 96 if (position == PadPosition.BEFORE_PREFIX) { 97 length += addPaddingHelper(paddingString, requiredPadding, string, leftIndex); 98 } else if (position == PadPosition.AFTER_SUFFIX) { 99 length += addPaddingHelper(paddingString, requiredPadding, string, rightIndex + length); 100 } 101 102 return length; 103 } 104 105 private static int addPaddingHelper(String paddingString, int requiredPadding, NumberStringBuilder string, 106 int index) { 107 for (int i = 0; i < requiredPadding; i++) { 108 // TODO: If appending to the end, this will cause actual insertion operations. Improve. 109 string.insert(index, paddingString, null); 110 } 111 return paddingString.length() * requiredPadding; 112 } 113 }