@@ -3,6 +3,8 @@ package decimal
33import (
44 "math/big"
55 "math/bits"
6+
7+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
68)
79
810const (
@@ -97,56 +99,27 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
9799 return v , nil
98100 }
99101
100- s , neg , specialValue := setSpecialValue (s , v )
101- if specialValue != nil {
102- return specialValue , nil
103- }
104- var err error
105- v , err = parseNumber (s , v , precision , scale , neg )
106- if err != nil {
107- return nil , err
108- }
109-
110- return v , nil
111- }
112-
113- func setSpecialValue (s string , v * big.Int ) (string , bool , * big.Int ) {
114- s , neg := parseSign (s )
115-
116- return parseSpecialValue (s , neg , v )
117- }
118-
119- func parseSign (s string ) (string , bool ) {
120102 neg := s [0 ] == '-'
121103 if neg || s [0 ] == '+' {
122104 s = s [1 :]
123105 }
124-
125- return s , neg
126- }
127-
128- func parseSpecialValue (s string , neg bool , v * big.Int ) (string , bool , * big.Int ) {
129106 if isInf (s ) {
130107 if neg {
131- return s , neg , v .Set (neginf )
108+ return v .Set (neginf ), nil
132109 }
133110
134- return s , neg , v .Set (inf )
111+ return v .Set (inf ), nil
135112 }
136113 if isNaN (s ) {
137114 if neg {
138- return s , neg , v .Set (negnan )
115+ return v .Set (negnan ), nil
139116 }
140117
141- return s , neg , v .Set (nan )
118+ return v .Set (nan ), nil
142119 }
143120
144- return s , neg , nil
145- }
146-
147- func parseNumber (s string , v * big.Int , precision , scale uint32 , neg bool ) (* big.Int , error ) {
148- var err error
149121 integral := precision - scale
122+
150123 var dot bool
151124 for ; len (s ) > 0 ; s = s [1 :] {
152125 c := s [0 ]
@@ -158,10 +131,12 @@ func parseNumber(s string, v *big.Int, precision, scale uint32, neg bool) (*big.
158131
159132 continue
160133 }
161- if dot && scale > 0 {
162- scale --
163- } else if dot {
164- break
134+ if dot {
135+ if scale > 0 {
136+ scale --
137+ } else {
138+ break
139+ }
165140 }
166141
167142 if ! isDigit (c ) {
@@ -180,10 +155,30 @@ func parseNumber(s string, v *big.Int, precision, scale uint32, neg bool) (*big.
180155 }
181156 integral --
182157 }
158+ //nolint:nestif
183159 if len (s ) > 0 { // Characters remaining.
184- v , err = handleRemainingDigits (s , v , precision )
185- if err != nil {
186- return nil , err
160+ c := s [0 ]
161+ if ! isDigit (c ) {
162+ return nil , syntaxError (s )
163+ }
164+ plus := c > '5'
165+ if ! plus && c == '5' {
166+ var x big.Int
167+ plus = x .And (v , one ).Cmp (zero ) != 0 // Last digit is not a zero.
168+ for ! plus && len (s ) > 1 {
169+ s = s [1 :]
170+ c := s [0 ]
171+ if ! isDigit (c ) {
172+ return nil , syntaxError (s )
173+ }
174+ plus = c != '0'
175+ }
176+ }
177+ if plus {
178+ v .Add (v , one )
179+ if v .Cmp (pow (ten , precision )) >= 0 {
180+ v .Set (inf )
181+ }
187182 }
188183 }
189184 v .Mul (v , pow (ten , scale ))
@@ -194,56 +189,26 @@ func parseNumber(s string, v *big.Int, precision, scale uint32, neg bool) (*big.
194189 return v , nil
195190}
196191
197- func handleRemainingDigits (s string , v * big.Int , precision uint32 ) (* big.Int , error ) {
198- c := s [0 ]
199- if ! isDigit (c ) {
200- return nil , syntaxError (s )
201- }
202- plus := c > '5'
203- if ! plus && c == '5' {
204- var x big.Int
205- plus = x .And (v , one ).Cmp (zero ) != 0 // Last digit is not a zero.
206- for ! plus && len (s ) > 1 {
207- s = s [1 :]
208- c := s [0 ]
209- if ! isDigit (c ) {
210- return nil , syntaxError (s )
211- }
212- plus = c != '0'
213- }
214- }
215- if plus {
216- v .Add (v , one )
217- if v .Cmp (pow (ten , precision )) >= 0 {
218- v .Set (inf )
219- }
220- }
221-
222- return v , nil
223- }
224-
225192// Format returns the string representation of x with the given precision and
226193// scale.
227- //
228- //nolint:funlen
229194func Format (x * big.Int , precision , scale uint32 ) string {
230- // Check for special values and nil pointer upfront.
231- if x == nil {
232- return "0"
233- }
234- if x .CmpAbs (inf ) == 0 {
195+ switch {
196+ case x .CmpAbs (inf ) == 0 :
235197 if x .Sign () < 0 {
236198 return "-inf"
237199 }
238200
239201 return "inf"
240- }
241- if x .CmpAbs (nan ) == 0 {
202+
203+ case x .CmpAbs (nan ) == 0 :
242204 if x .Sign () < 0 {
243205 return "-nan"
244206 }
245207
246208 return "nan"
209+
210+ case x == nil :
211+ return "0"
247212 }
248213
249214 v := big .NewInt (0 ).Set (x )
@@ -267,59 +232,42 @@ func Format(x *big.Int, precision, scale uint32) string {
267232
268233 digit .Mod (v , ten )
269234 d := int (digit .Int64 ())
270-
271- pos --
272- if d != 0 || scale == 0 || pos >= 0 {
273- setDigitAtPosition ( bts , pos , d )
235+ if d != 0 || scale == 0 || pos > 0 {
236+ const numbers = "0123456789"
237+ pos --
238+ bts [ pos ] = numbers [ d ]
274239 }
275-
276240 if scale > 0 {
277241 scale --
278242 if scale == 0 && pos > 0 {
279- bts [pos - 1 ] = '.'
280243 pos --
244+ bts [pos ] = '.'
281245 }
282246 }
283247 }
284-
285- for ; scale > 0 ; scale -- {
286- if precision == 0 {
287- pos = 0
288-
289- break
248+ if scale > 0 {
249+ for ; scale > 0 ; scale -- {
250+ if precision == 0 {
251+ return errorTag
252+ }
253+ precision --
254+ pos --
255+ bts [pos ] = '0'
290256 }
291- precision --
257+
292258 pos --
293- bts [pos ] = '0 '
259+ bts [pos ] = '. '
294260 }
295-
296261 if bts [pos ] == '.' {
297262 pos --
298263 bts [pos ] = '0'
299264 }
300-
301265 if neg {
302266 pos --
303267 bts [pos ] = '-'
304268 }
305269
306- return string (bts [pos :])
307- }
308-
309- func abs (x * big.Int ) (* big.Int , bool ) {
310- v := big .NewInt (0 ).Set (x )
311- neg := x .Sign () < 0
312- if neg {
313- // Convert negative to positive.
314- v .Neg (x )
315- }
316-
317- return v , neg
318- }
319-
320- func setDigitAtPosition (bts []byte , pos , digit int ) {
321- const numbers = "0123456789"
322- bts [pos ] = numbers [digit ]
270+ return xstring .FromBytes (bts [pos :])
323271}
324272
325273// BigIntToByte returns the 16-byte array representation of x.
0 commit comments