Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(505)

Side by Side Diff: pkg/intl/number_format.dart

Issue 10952004: Change intl to use new pub layout (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/intl/message_lookup_local.dart ('k') | pkg/intl/number_symbols.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #library("number_format");
6
7 #import('dart:math');
8
9 #import("intl.dart");
10 #import("number_symbols.dart");
11 #import("number_symbols_data.dart");
12
13 class NumberFormat {
14 /** Variables to determine how number printing behaves. */
15 // TODO(alanknight): If these remain as variables and are set based on the
16 // pattern, can we make them final?
17 String _negativePrefix = '-';
18 String _positivePrefix = '';
19 String _negativeSuffix = '';
20 String _positiveSuffix = '';
21 /** How many numbers in a group when using punctuation to group digits in
22 * large numbers. e.g. in en_US: "1,000,000" has a grouping size of 3 digits
23 * between commas.
24 */
25 int _groupingSize = 3;
26 bool _decimalSeparatorAlwaysShown = false;
27 bool _useExponentialNotation = false;
28 int _maximumIntegerDigits = 40;
29 int _minimumIntegerDigits = 1;
30 int _maximumFractionDigits = 3; // invariant, >= minFractionDigits
31 int _minimumFractionDigits = 0;
32 int _minimumExponentDigits = 0;
33 bool _useSignForPositiveExponent = false;
34
35 /** The locale in which we print numbers. */
36 final String _locale;
37
38 /** Caches the symbols used for our locale. */
39 NumberSymbols _symbols;
40
41 /**
42 * Transient internal state in which to build up the result of the format
43 * operation. We can have this be just an instance variable because Dart is
44 * single-threaded and unless we do an asynchronous operation in the process
45 * of formatting then there will only ever be one number being formatted
46 * at a time. In languages with threads we'd need to pass this on the stack.
47 */
48 StringBuffer _buffer;
49
50 /**
51 * Create a number format that prints in [newPattern] as it applies in
52 * [locale].
53 */
54 NumberFormat([String newPattern, String locale]):
55 _locale = Intl.verifiedLocale(locale) {
56 // TODO(alanknight): There will need to be some kind of async setup
57 // operations so as not to bring along every locale in every program.
58 _symbols = numberFormatSymbols[_locale];
59 _setPattern(newPattern);
60 }
61
62 /**
63 * Return the locale code in which we operate, e.g. 'en_US' or 'pt'.
64 */
65 String get locale => _locale;
66
67 /**
68 * Return the symbols which are used in our locale. Cache them to avoid
69 * repeated lookup.
70 */
71 NumberSymbols get symbols {
72 return _symbols;
73 }
74
75 // TODO(alanknight): Actually use the pattern and locale.
76 _setPattern(String x) {}
77
78 /**
79 * Format [number] according to our pattern and return the formatted string.
80 */
81 String format(num number) {
82 // TODO(alanknight): Do we have to do anything for printing numbers bidi?
83 // Or are they always printed left to right?
84 if (number.isNaN()) return symbols.NAN;
85 if (number.isInfinite()) return "${_signPrefix(number)}${symbols.INFINITY}";
86
87 _newBuffer();
88 _add(_signPrefix(number));
89 _formatNumber(number.abs());
90 _add(_signSuffix(number));
91
92 var result = _buffer.toString();
93 _buffer = null;
94 return result;
95 }
96
97 /**
98 * Format the main part of the number in the form dictated by the pattern.
99 */
100 void _formatNumber(num number) {
101 if (_useExponentialNotation) {
102 _formatExponential(number);
103 } else {
104 _formatFixed(number);
105 }
106 }
107
108 /** Format the number in exponential notation. */
109 _formatExponential(num number) {
110 if (number == 0.0) {
111 _formatFixed(number);
112 _formatExponent(0);
113 return;
114 }
115
116 var exponent = (log(number) / log(10)).floor();
117 var mantissa = number / pow(10, exponent);
118
119 if (_minimumIntegerDigits < 1) {
120 exponent++;
121 mantissa /= 10;
122 } else {
123 exponent -= _minimumIntegerDigits - 1;
124 mantissa *= pow(10, _minimumIntegerDigits - 1);
125 }
126 _formatFixed(number);
127 _formatExponent(exponent);
128 }
129
130 /**
131 * Format the exponent portion, e.g. in "1.3e-5" the "e-5".
132 */
133 void _formatExponent(num exponent) {
134 _add(symbols.EXP_SYMBOL);
135 if (exponent < 0) {
136 exponent = -exponent;
137 _add(symbols.MINUS_SIGN);
138 } else if (_useSignForPositiveExponent) {
139 _add(symbols.PLUS_SIGN);
140 }
141 _pad(_minimumExponentDigits, exponent.toString());
142 }
143
144 /**
145 * Format the basic number portion, inluding the fractional digits.
146 */
147 void _formatFixed(num number) {
148 // Round the number.
149 var power = pow(10, _maximumFractionDigits);
150 var intValue = number.truncate().toInt();
151 var multiplied = (number * power).round();
152 var fracValue = (multiplied - intValue * power).floor().toInt();
153 var fractionPresent = _minimumFractionDigits > 0 || fracValue > 0;
154
155 // On dartj2s the integer part may be large enough to be a floating
156 // point value, in which case we reduce it until it is small enough
157 // to be printed as an integer and pad the remainder with zeros.
158 var paddingDigits = new StringBuffer();
159 while ((intValue & 0x7fffffff) != intValue) {
160 paddingDigits.add(symbols.ZERO_DIGIT);
161 intValue = (intValue / 10).toInt();
162 }
163 var integerDigits = "${intValue}${paddingDigits}".charCodes();
164 var digitLength = integerDigits.length;
165
166 if (_hasPrintableIntegerPart(intValue)) {
167 _pad(_minimumIntegerDigits - digitLength);
168 for (var i = 0; i < digitLength; i++) {
169 _addDigit(integerDigits[i]);
170 _group(digitLength, i);
171 }
172 } else if (!fractionPresent) {
173 // If neither fraction nor integer part exists, just print zero.
174 _addZero();
175 }
176
177 _decimalSeparator(fractionPresent);
178 _formatFractionPart((fracValue + power).toString());
179 }
180
181 /**
182 * Format the part after the decimal place in a fixed point number.
183 */
184 void _formatFractionPart(String fractionPart) {
185 var fractionCodes = fractionPart.charCodes();
186 var fractionLength = fractionPart.length;
187 while (fractionPart[fractionLength - 1] == '0' &&
188 fractionLength > _minimumFractionDigits + 1) {
189 fractionLength--;
190 }
191 for (var i = 1; i < fractionLength; i++) {
192 _addDigit(fractionCodes[i]);
193 }
194 }
195
196 /** Print the decimal separator if appropriate. */
197 void _decimalSeparator(bool fractionPresent) {
198 if (_decimalSeparatorAlwaysShown || fractionPresent) {
199 _add(symbols.DECIMAL_SEP);
200 }
201 }
202
203 /**
204 * Return true if we have a main integer part which is printable, either
205 * because we have digits left of the decimal point, or because there are
206 * a minimum number of printable digits greater than 1.
207 */
208 bool _hasPrintableIntegerPart(int intValue) {
209 return intValue > 0 || _minimumIntegerDigits > 0;
210 }
211
212 /**
213 * Create a new empty buffer. See comment on [_buffer] variable for why
214 * we have it as an instance variable rather than passing it on the stack.
215 */
216 void _newBuffer() { _buffer = new StringBuffer(); }
217
218 /** A group of methods that provide support for writing digits and other
219 * required characters into [_buffer] easily.
220 */
221 void _add(String x) { _buffer.add(x);}
222 void _addCharCode(int x) { _buffer.addCharCode(x); }
223 void _addZero() { _buffer.add(symbols.ZERO_DIGIT); }
224 void _addDigit(int x) { _buffer.addCharCode(_localeZero + x - _zero); }
225
226 /** Print padding up to [numberOfDigits] above what's included in [basic]. */
227 void _pad(int numberOfDigits, [String basic = '']) {
228 for (var i = 0; i < numberOfDigits - basic.length; i++) {
229 _add(symbols.ZERO_DIGIT);
230 }
231 for (var x in basic.charCodes()) {
232 _addDigit(x);
233 }
234 }
235
236 /**
237 * We are printing the digits of the number from left to right. We may need
238 * to print a thousands separator or other grouping character as appropriate
239 * to the locale. So we find how many places we are from the end of the number
240 * by subtracting our current [position] from the [totalLength] and print
241 * the separator character every [_groupingSize] digits.
242 */
243 void _group(int totalLength, int position) {
244 var distanceFromEnd = totalLength - position;
245 if (distanceFromEnd <= 1 || _groupingSize <= 0) return;
246 if (distanceFromEnd % _groupingSize == 1) {
247 _add(symbols.GROUP_SEP);
248 }
249 }
250
251 /** Returns the code point for the character '0'. */
252 int get _zero => '0'.charCodes()[0];
253
254 /** Returns the code point for the locale's zero digit. */
255 int get _localeZero => symbols.ZERO_DIGIT.charCodeAt(0);
256
257 /**
258 * Returns the prefix for [x] based on whether it's positive or negative.
259 * In en_US this would be '' and '-' respectively.
260 */
261 String _signPrefix(num x) {
262 return x.isNegative() ? _negativePrefix : _positivePrefix;
263 }
264
265 /**
266 * Returns the suffix for [x] based on wether it's positive or negative.
267 * In en_US there are no suffixes for positive or negative.
268 */
269 String _signSuffix(num x) {
270 return x.isNegative() ? _negativeSuffix : _positiveSuffix;
271 }
272 }
OLDNEW
« no previous file with comments | « pkg/intl/message_lookup_local.dart ('k') | pkg/intl/number_symbols.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698