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 58 package jdk.nashorn.internal.runtime.doubleconv; 59 60 /** 61 * A buffer for generating string representations of doubles. 62 */ 63 public 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 } else { 180 decimalPoint = 1; 181 } 182 } else if (decimalPoint >= length) { 183 // large integer, add trailing zeroes 184 buffer.append(chars, 0, length); 185 for (int i = length; i < decimalPoint; i++) { 186 buffer.append('0'); 187 } 188 } else if (decimalPoint < length) { 189 // >= 1, split decimals and insert decimalPoint 190 buffer.append(chars, 0, decimalPoint); 191 buffer.append('.'); 192 buffer.append(chars, decimalPoint, length - decimalPoint); 193 } 194 195 // Create trailing zeros if requested 196 if (digitsAfterPoint > 0) { 197 if (decimalPoint >= length) { 198 buffer.append('.'); 199 } 200 for (int i = Math.max(0, length - decimalPoint); i < digitsAfterPoint; i++) { 201 buffer.append('0'); 202 } 203 } 204 } 205 206 private void toExponentialFormat(final StringBuilder buffer) { 207 buffer.append(chars[0]); 208 if (length > 1) { 209 // insert decimal decimalPoint if more than one digit was produced 210 buffer.append('.'); 211 buffer.append(chars, 1, length - 1); 212 } 213 buffer.append('e'); 214 final int exponent = decimalPoint - 1; 215 if (exponent > 0) { 216 buffer.append('+'); 217 } 218 buffer.append(exponent); 219 } 220 221 @Override 222 public String toString() { 223 return "[chars:" + new String(chars, 0, length) + ", decimalPoint:" + decimalPoint + "]"; 224 } 225 }