1 /*
  2  * Copyright (c) 2025, 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 package oracle.code.json;
 27 
 28 import java.util.Objects;
 29 
 30 /**
 31  * JsonNumber implementation class
 32  */
 33 final class JsonNumberImpl implements JsonNumber, JsonValueImpl {
 34 
 35     private final JsonDocumentInfo docInfo;
 36     private final int startOffset;
 37     private final int endOffset;
 38     private final int endIndex;
 39     private Number theNumber;
 40     private String numString;
 41 
 42     JsonNumberImpl(Number num) {
 43         theNumber = num;
 44         numString = num.toString();
 45         startOffset = 0;
 46         endOffset = 0;
 47         endIndex = 0;
 48         docInfo = null;
 49     }
 50 
 51     JsonNumberImpl(JsonDocumentInfo doc, int offset, int index) {
 52         docInfo = doc;
 53         startOffset = offset;
 54         endIndex = docInfo.nextIndex(index);
 55         endOffset = endIndex != -1 ? docInfo.getOffset(endIndex) : docInfo.getEndOffset();
 56     }
 57 
 58     @Override
 59     public Number value() {
 60         if (theNumber == null) {
 61             theNumber = toNum(string());
 62         }
 63         return theNumber;
 64     }
 65 
 66     private String string() {
 67         if (numString == null) { // Trim back only
 68             numString = docInfo.substring(startOffset, endOffset).stripTrailing();
 69         }
 70         return numString;
 71     }
 72 
 73     @Override
 74     public int getEndIndex() {
 75         return endIndex;
 76     }
 77 
 78     @Override
 79     public boolean equals(Object o) {
 80         return this == o ||
 81             o instanceof JsonNumberImpl ojni &&
 82             Objects.equals(string(), ojni.string());
 83     }
 84 
 85     @Override
 86     public int hashCode() {
 87         return Objects.hash(string());
 88     }
 89 
 90     Number toNum(String numStr) {
 91         // Determine if fp
 92         boolean fp = false;
 93         for (char c : numStr.toCharArray()) {
 94             if (c == 'e' || c == 'E' || c =='.') {
 95                 fp = true;
 96                 break;
 97             }
 98         }
 99 
100         // Make conversion
101         if (!fp) {
102             // integral numbers
103             try {
104                 return Integer.valueOf(numStr);
105             } catch (NumberFormatException _) {
106                 // int overflow. try long
107                 try {
108                     return Long.valueOf(numStr);
109                 } catch (NumberFormatException _) {
110                     // long overflow. convert to Double
111                 }
112             }
113         }
114         var num = Double.valueOf(numStr);
115         if (Double.isInfinite(num)) {
116             throw new NumberFormatException("The number is infinitely large in magnitude");
117         }
118         return num;
119     }
120 
121     @Override
122     public Number toUntyped() {
123         return value();
124     }
125 
126     @Override
127     public String toString() {
128         return string();
129     }
130 }