DtoaBuffer.java revision 1507:549f06563f1c
1/* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26// This file is available under and governed by the GNU General Public 27// License version 2 only, as published by the Free Software Foundation. 28// However, the following notice accompanied the original version of this 29// file: 30// 31// Copyright 2010 the V8 project authors. All rights reserved. 32// Redistribution and use in source and binary forms, with or without 33// modification, are permitted provided that the following conditions are 34// met: 35// 36// * Redistributions of source code must retain the above copyright 37// notice, this list of conditions and the following disclaimer. 38// * Redistributions in binary form must reproduce the above 39// copyright notice, this list of conditions and the following 40// disclaimer in the documentation and/or other materials provided 41// with the distribution. 42// * Neither the name of Google Inc. nor the names of its 43// contributors may be used to endorse or promote products derived 44// from this software without specific prior written permission. 45// 46// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 47// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 48// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 49// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 50// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 51// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 52// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 54// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 56// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 58package jdk.nashorn.internal.runtime.doubleconv; 59 60/** 61 * A buffer for generating string representations of doubles. 62 */ 63public class DtoaBuffer { 64 65 // The character buffer 66 final char[] chars; 67 68 // The number of characters in the buffer 69 int length = 0; 70 71 // The position of the decimal point 72 int decimalPoint = 0; 73 74 // Is this a negative number? 75 boolean isNegative = false; 76 77 /** 78 * Maximal length of numbers converted by FastDtoa 79 */ 80 public static final int kFastDtoaMaximalLength = FastDtoa.kFastDtoaMaximalLength; 81 82 /** 83 * Create a buffer with the given capacity. 84 * @param capacity the capacity of the buffer. 85 */ 86 public DtoaBuffer(final int capacity) { 87 chars = new char[capacity]; 88 } 89 90 /** 91 * Append a character to the buffer, increasing its length. 92 * @param c character 93 */ 94 void append(final char c) { 95 chars[length++] = c; 96 } 97 98 /** 99 * Clear the buffer contents and set its length to {@code 0}. 100 */ 101 public void reset() { 102 length = 0; 103 decimalPoint = 0; 104 } 105 106 /** 107 * Get the raw digits of this buffer as string. 108 * @return the raw buffer contents 109 */ 110 public String getRawDigits() { 111 return new String(chars, 0, length); 112 } 113 114 /** 115 * Get the position of the decimal point. 116 * @return the decimal point position 117 */ 118 public int getDecimalPoint() { 119 return decimalPoint; 120 } 121 122 /** 123 * Returns the number of characters in the buffer. 124 * @return buffer length 125 */ 126 public int getLength() { 127 return length; 128 } 129 130 /** 131 * Returns the formatted buffer content as string, using the specified conversion mode 132 * and padding. 133 * 134 * @param mode conversion mode 135 * @param digitsAfterPoint number of digits after point 136 * @return formatted string 137 */ 138 public String format(final DtoaMode mode, final int digitsAfterPoint) { 139 final StringBuilder buffer = new StringBuilder(); 140 if (isNegative) { 141 buffer.append('-'); 142 } 143 144 // check for minus sign 145 switch (mode) { 146 case SHORTEST: 147 if (decimalPoint < -5 || decimalPoint > 21) { 148 toExponentialFormat(buffer); 149 } else { 150 toFixedFormat(buffer, digitsAfterPoint); 151 } 152 break; 153 case FIXED: 154 toFixedFormat(buffer, digitsAfterPoint); 155 break; 156 case PRECISION: 157 if (decimalPoint < -5 || decimalPoint > length) { 158 toExponentialFormat(buffer); 159 } else { 160 toFixedFormat(buffer, digitsAfterPoint); 161 } 162 break; 163 } 164 165 return buffer.toString(); 166 } 167 168 private void toFixedFormat(final StringBuilder buffer, final int digitsAfterPoint) { 169 if (decimalPoint <= 0) { 170 // < 1, 171 buffer.append('0'); 172 if (length > 0) { 173 buffer.append('.'); 174 final int padding = -decimalPoint; 175 for (int i = 0; i < padding; i++) { 176 buffer.append('0'); 177 } 178 buffer.append(chars, 0, length); 179 } 180 } else if (decimalPoint >= length) { 181 // large integer, add trailing zeroes 182 buffer.append(chars, 0, length); 183 for (int i = length; i < decimalPoint; i++) { 184 buffer.append('0'); 185 } 186 } else if (decimalPoint < length) { 187 // >= 1, split decimals and insert decimalPoint 188 buffer.append(chars, 0, decimalPoint); 189 buffer.append('.'); 190 buffer.append(chars, decimalPoint, length - decimalPoint); 191 } 192 193 // Create trailing zeros if requested 194 if (digitsAfterPoint > 0) { 195 if (decimalPoint >= length) { 196 buffer.append('.'); 197 } 198 for (int i = Math.max(0, length - decimalPoint); i < digitsAfterPoint; i++) { 199 buffer.append('0'); 200 } 201 } 202 } 203 204 private void toExponentialFormat(final StringBuilder buffer) { 205 buffer.append(chars[0]); 206 if (length > 1) { 207 // insert decimal decimalPoint if more than one digit was produced 208 buffer.append('.'); 209 buffer.append(chars, 1, length - 1); 210 } 211 buffer.append('e'); 212 final int exponent = decimalPoint - 1; 213 if (exponent > 0) { 214 buffer.append('+'); 215 } 216 buffer.append(exponent); 217 } 218 219 @Override 220 public String toString() { 221 return "[chars:" + new String(chars, 0, length) + ", decimalPoint:" + decimalPoint + "]"; 222 } 223} 224