github.com/dgraph-io/simdjson-go@v0.3.0/parse_number_amd64.go (about) 1 //+build !noasm 2 //+build !appengine 3 //+build gc 4 5 /* 6 * MinIO Cloud Storage, (C) 2020 MinIO, Inc. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package simdjson 22 23 import ( 24 "errors" 25 "math" 26 "strconv" 27 ) 28 29 const ( 30 isPartOfNumberFlag = 1 << iota 31 isFloatOnlyFlag 32 isMinusFlag 33 isEOVFlag 34 isDigitFlag 35 isMustHaveDigitNext 36 ) 37 38 var isNumberRune = [256]uint8{ 39 '0': isPartOfNumberFlag | isDigitFlag, 40 '1': isPartOfNumberFlag | isDigitFlag, 41 '2': isPartOfNumberFlag | isDigitFlag, 42 '3': isPartOfNumberFlag | isDigitFlag, 43 '4': isPartOfNumberFlag | isDigitFlag, 44 '5': isPartOfNumberFlag | isDigitFlag, 45 '6': isPartOfNumberFlag | isDigitFlag, 46 '7': isPartOfNumberFlag | isDigitFlag, 47 '8': isPartOfNumberFlag | isDigitFlag, 48 '9': isPartOfNumberFlag | isDigitFlag, 49 '.': isPartOfNumberFlag | isFloatOnlyFlag | isMustHaveDigitNext, 50 '+': isPartOfNumberFlag, 51 '-': isPartOfNumberFlag | isMinusFlag | isMustHaveDigitNext, 52 'e': isPartOfNumberFlag | isFloatOnlyFlag, 53 'E': isPartOfNumberFlag | isFloatOnlyFlag, 54 ',': isEOVFlag, 55 '}': isEOVFlag, 56 ']': isEOVFlag, 57 ' ': isEOVFlag, 58 '\t': isEOVFlag, 59 '\r': isEOVFlag, 60 '\n': isEOVFlag, 61 ':': isEOVFlag, 62 } 63 64 // parseNumber will parse the number starting in the buffer. 65 // Any non-number characters at the end will be ignored. 66 // Returns TagEnd if no valid value found be found. 67 func parseNumber(buf []byte) (tag Tag, val, flags uint64, pos int) { 68 found := uint8(0) 69 for i, v := range buf { 70 t := isNumberRune[v] 71 if t == 0 { 72 //fmt.Println("aborting on", string(v), "in", string(buf[:i])) 73 return TagEnd, 0, 0, pos 74 } 75 if t == isEOVFlag { 76 break 77 } 78 if t&isMustHaveDigitNext > 0 { 79 // A period and minus must be followed by a digit 80 if len(buf) < i+2 || isNumberRune[buf[i+1]]&isDigitFlag == 0 { 81 return TagEnd, 0, 0, pos 82 } 83 } 84 found |= t 85 pos = i + 1 86 } 87 if pos == 0 { 88 return TagEnd, 0, 0, pos 89 } 90 const maxIntLen = 20 91 92 // Only try integers if we didn't find any float exclusive and it can fit in an integer. 93 if found&isFloatOnlyFlag == 0 && pos <= 20 { 94 if found&isMinusFlag == 0 { 95 if pos > 1 && buf[0] == '0' { 96 // Integers cannot have a leading zero. 97 return TagEnd, 0, 0, pos 98 } 99 } else { 100 if pos > 2 && buf[1] == '0' { 101 // Integers cannot have a leading zero after minus. 102 return TagEnd, 0, 0, pos 103 } 104 } 105 i64, err := strconv.ParseInt(string(buf[:pos]), 10, 64) 106 if err == nil { 107 return TagInteger, uint64(i64), 0, pos 108 } 109 if errors.Is(err, strconv.ErrRange) { 110 flags |= uint64(FloatOverflowedInteger) 111 } 112 113 if found&isMinusFlag == 0 { 114 u64, err := strconv.ParseUint(string(buf[:pos]), 10, 64) 115 if err == nil { 116 return TagUint, u64, 0, pos 117 } 118 if errors.Is(err, strconv.ErrRange) { 119 flags |= uint64(FloatOverflowedInteger) 120 } 121 } 122 } else if found&isFloatOnlyFlag == 0 { 123 flags |= uint64(FloatOverflowedInteger) 124 } 125 126 if pos > 1 && buf[0] == '0' && isNumberRune[buf[1]]&isFloatOnlyFlag == 0 { 127 // Float can only have have a leading 0 when followed by a period. 128 return TagEnd, 0, 0, pos 129 } 130 f64, err := strconv.ParseFloat(string(buf[:pos]), 64) 131 if err == nil { 132 return TagFloat, math.Float64bits(f64), flags, pos 133 } 134 return TagEnd, 0, 0, pos 135 }