1 package com.sharkysoft.printf.engine;
2
3 import java.math.BigDecimal;
4 import java.math.BigInteger;
5
6 import com.sharkysoft.string.StringToolbox;
7
8 /***
9 * Formats integers.
10 *
11 * <p>An <code>IntegerFormatter</code> formats integers. See
12 * {@link NumberFormatter} for a generalized discussion relating to this
13 * class.</p>
14 *
15 * <blockquote class="example">
16 *
17 * <p><b>Example:</b> Output the contents of integer array <var>vals</var>,
18 * one integer per line, right-<wbr>justified in a 25-<wbr>character-<wbr>wide
19 * field. Round each integer to 3 significant digits.</p>
20 *
21 *<blockquote><pre>
22 *int[] vals = {2000, 34, 32768};
23 *IntegerFormatter formatter = new IntegerFormatter();
24 *formatter.setFieldWidth(25);
25 *formatter.setPadChar(':'); // non-space chosen for emphasis
26 *formatter.setAlignment(AlignmentMode.gpRight);
27 *formatter.setSigDigits(3);
28 *for (int i = 0; i < vals.length; ++ i)
29 * System.out.println(formatter.format(vals[i]));
30 *</pre></blockquote>
31 *
32 * <p>This produces the following output:</p>
33 *
34 *<blockquote><pre>
35 *:::::::::::::::::::::2000
36 *:::::::::::::::::::::::34
37 *::::::::::::::::::::32800
38 *</pre></blockquote>
39 *
40 * </blockquote>
41 *
42 * <p>The formatting properties for a given instance of this class can be
43 * updated at any time, and doing so changes the way that subsequent data is
44 * formatted. For a detailed description of all formatting properties, review
45 * the documentation below and in the superclass.</p>
46 *
47 * @author Sharky
48 */
49 public class IntegerFormatter extends NumberFormatter
50 {
51
52
53
54
55
56
57
58 /***
59 * Pad digit.
60 *
61 * <p>Details:</b> Property <code>PadDigit</code> is the pad digit to use when
62 * extra digits are required because of the <code>MinDigits</code> property.
63 * <b>Default value:</b> '0'.</p>
64 *
65 * @see #getPadDigit()
66 * @see #setPadDigit(char)
67 */
68 protected char mcPadDigit = '0';
69
70 /***
71 * Retrieves PadDigit property.
72 *
73 * @return current value
74 *
75 * @see #mcPadDigit
76 */
77 public char getPadDigit()
78 {
79 return mcPadDigit;
80 }
81
82 /***
83 * Updates PadDigit property.
84 *
85 * @param icPadDigit new value
86 *
87 * @see #mcPadDigit
88 */
89 public void setPadDigit(final char icPadDigit)
90 {
91 mcPadDigit = icPadDigit;
92 }
93
94
95
96
97
98
99
100 /***
101 * Minimum digits.
102 *
103 * <p><b>Details:</b> Property <code>MinDigits</code> is the minimum number of
104 * digits to display in the formatted output. If the number isn't large
105 * enough to fill all the digits, the padding digit will be used to fill out
106 * the rest. If this property is 0, digits will only be displayed if the
107 * value being rendered is non-zero. <b>Default value:</b> 1.</p>
108 *
109 * @see #getMinDigits()
110 * @see #setMinDigits(int)
111 */
112 protected int mnMinDigits = 1;
113
114 /***
115 * Retrieves MinDigits property.
116 *
117 * @return current value
118 *
119 * @see #mnMinDigits
120 */
121 public int getMinDigits()
122 {
123 return mnMinDigits;
124 }
125
126 /***
127 * Updates MinDigits property.
128 *
129 * @param inMinDigits new value
130 *
131 * @see #mnMinDigits
132 */
133 public void setMinDigits(final int inMinDigits)
134 {
135 if (inMinDigits < 0)
136 throw new IllegalArgumentException("inMinDigits=" + inMinDigits);
137 mnMinDigits = inMinDigits;
138 }
139
140 /***
141 * Default constructor.
142 */
143 public IntegerFormatter() {}
144
145 /***
146 * Renders value.
147 *
148 * <p><b>Details:</b> <code>format</code> renders the given integer value into
149 * a numeric string, formatted according to the criteria set forth in the
150 * properties.</p>
151 *
152 * @param ipValue value to render
153 * @return rendered value
154 */
155 public String format(BigInteger ipValue)
156 {
157 if (mnSigDigits > 0)
158 ipValue = setSignificantDigits(new BigDecimal(ipValue), mnSigDigits).toBigInteger();
159 final String vsPrefix;
160 final String vsSuffix;
161 String vsDigits;
162 switch (ipValue.signum())
163 {
164 case +1:
165 vsPrefix = msPosPrefix;
166 vsSuffix = msPosSuffix;
167 vsDigits = ipValue.toString(mnRadix);
168 break;
169 case 0:
170 vsPrefix = msZeroPrefix;
171 vsSuffix = msZeroSuffix;
172 vsDigits = mnMinDigits > 0 ? "0" : "";
173 break;
174 case -1:
175 vsPrefix = msNegPrefix;
176 vsSuffix = msNegSuffix;
177 vsDigits = ipValue.negate().toString(mnRadix);
178 break;
179 default:
180 throw new RuntimeException ("unreachable code");
181 }
182 if (mzUpperCase)
183 vsDigits = vsDigits.toUpperCase();
184
185 final String vsExtender;
186 final int vsExtra = mnMinDigits - vsDigits.length();
187 if (vsExtra > 0)
188 {
189 if (mcPadDigit != 0)
190 vsExtender = StringToolbox.repeat(mcPadDigit, vsExtra);
191 else
192 vsExtender = StringToolbox.repeat(' ', vsExtra);
193 }
194 else
195 vsExtender = "";
196 StringBuffer vsLeftSide = new StringBuffer();
197 StringBuffer vsRightSide = new StringBuffer();
198
199 if (mnAlignment == AlignmentMode.FULL)
200 {
201 vsLeftSide.append(vsPrefix);
202 vsRightSide.append(vsExtender);
203 }
204 else
205 {
206 if (mcPadDigit != 0)
207 {
208 vsRightSide.append(vsPrefix);
209 vsRightSide.append(vsExtender);
210 }
211 else
212 {
213 vsRightSide.append(vsExtender);
214 vsRightSide.append(vsPrefix);
215 }
216 }
217
218 vsRightSide.append(vsDigits);
219
220 return format(vsLeftSide.toString(), vsRightSide.toString());
221 }
222
223 /***
224 * Renders value.
225 *
226 * <p><b>Details:</b> <code>format</code> renders the given integer value into
227 * a numeric string, formatted according to the criteria set forth in the
228 * properties.</p>
229 *
230 * @param ilValue value to render
231 * @return rendered value
232 */
233 public final String format(final long ilValue)
234 {
235 return format(BigInteger.valueOf(ilValue));
236 }
237
238 /***
239 * Renders value.
240 *
241 * <p><b>Details:</b> <code>format</code> renders the given integer value into
242 * a numeric string, formatted according to the criteria set forth in the
243 * properties.</p>
244 *
245 * @param inValue value to render
246 * @return rendered value
247 */
248 public final String format(final int inValue)
249 {
250 return format(BigInteger.valueOf(inValue));
251 }
252
253
254
255
256
257
258
259 /***
260 * Long MSB manipulation constant.
261 *
262 * <p><b>Details:</b> This constant is used by <code>formatUnsigned</code> to
263 * manipulate the sign bit of a long value into the value's most significant
264 * bit. Refer to the source for <code>formatUnsigned(long)</code> for more
265 * details.</p>
266 */
267 private static final BigInteger LONG_NEG_ADJUSTMENT = new BigInteger("ffffffffffffffff", 16).not();
268
269 /***
270 * Renders unsigned value.
271 *
272 * <p><b>Details:</b> <code>formatUnsigned</code> renders the given integer
273 * value as a numeric string, formatted according to the criteria set forth in
274 * the properties. The integer value is interpreted as an unsigned value.</p>
275 *
276 * @param ilValue value to render
277 * @return rendered value
278 */
279 public final String formatUnsigned(final long ilValue)
280 {
281 BigInteger vpBig = BigInteger.valueOf(ilValue);
282 if (ilValue < 0)
283 vpBig = vpBig.xor(LONG_NEG_ADJUSTMENT);
284 return format(vpBig);
285 }
286
287 /***
288 * Renders unsigned value.
289 *
290 * <p><b>Details:</b> <code>formatUnsigned</code> renders the given integer
291 * value as a numeric string, formatted according to the criteria set forth in
292 * the properties. The integer value is interpreted as an unsigned value.</p>
293 *
294 * @param inValue value to render
295 * @return rendered value
296 */
297 public final String formatUnsigned(final int inValue)
298 {
299 return format(BigInteger.valueOf(inValue & 0xffffffffL));
300 }
301
302 /***
303 * Renders unsigned value.
304 *
305 * <p><b>Details:</b> <code>formatUnsigned</code> renders the given integer
306 * value as a numeric string, formatted according to the criteria set forth in
307 * the properties. The integer value is interpreted as an unsigned value.</p>
308 *
309 * @param iwValue value to render
310 * @return rendered value
311 */
312 public final String formatUnsigned(final short iwValue)
313 {
314 return format(BigInteger.valueOf(iwValue & 0xffffL));
315 }
316
317 /***
318 * Renders unsigned value.
319 *
320 * <p><b>Details:</b> <code>formatUnsigned</code> renders the given integer
321 * value as a numeric string, formatted according to the criteria set forth in
322 * the properties. The integer value is interpreted as an unsigned value.</p>
323 *
324 * @param ibValue value to render
325 * @return rendered value
326 */
327 public final String formatUnsigned(byte ibValue)
328 {
329 return format(BigInteger.valueOf(ibValue & 0xffL));
330 }
331
332 }
333