diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/core/macros.nim | 2 | ||||
-rw-r--r-- | lib/packages/docutils/rstgen.nim | 2 | ||||
-rw-r--r-- | lib/pure/json.nim | 2 | ||||
-rw-r--r-- | lib/std/formatfloat.nim | 142 | ||||
-rw-r--r-- | lib/std/private/dragonbox.nim (renamed from lib/system/dragonbox.nim) | 27 | ||||
-rw-r--r-- | lib/std/private/schubfach.nim (renamed from lib/system/schubfach.nim) | 12 | ||||
-rw-r--r-- | lib/std/syncio.nim | 2 | ||||
-rw-r--r-- | lib/system/chcks.nim | 2 | ||||
-rw-r--r-- | lib/system/dollars.nim | 13 | ||||
-rw-r--r-- | lib/system/formatfloat.nim | 141 | ||||
-rw-r--r-- | lib/system/repr_v2.nim | 3 |
11 files changed, 184 insertions, 164 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim index ad87a0f64..ecf85935f 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -11,7 +11,7 @@ include "system/inclrtl" import std/private/since when defined(nimPreviewSlimSystem): - import std/assertions + import std/[assertions, formatfloat] ## This module contains the interface to the compiler's abstract syntax diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 6232cb0be..791935da8 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -44,7 +44,7 @@ import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] + import std/[assertions, syncio, formatfloat] import ../../std/private/since diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 928bc0fbf..d0b1a4051 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -165,7 +165,7 @@ import options # xxx remove this dependency using same approach as https://githu import std/private/since when defined(nimPreviewSlimSystem): - import std/[syncio, assertions] + import std/[syncio, assertions, formatfloat] export tables.`$` diff --git a/lib/std/formatfloat.nim b/lib/std/formatfloat.nim new file mode 100644 index 000000000..6f2383760 --- /dev/null +++ b/lib/std/formatfloat.nim @@ -0,0 +1,142 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2022 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +when defined(nimPreviewSlimSystem): + import std/assertions +else: + {.deprecated: "formatfloat is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/formatfloat`".} + +proc c_memcpy(a, b: pointer, size: csize_t): pointer {.importc: "memcpy", header: "<string.h>", discardable.} + +proc addCstringN(result: var string, buf: cstring; buflen: int) = + # no nimvm support needed, so it doesn't need to be fast here either + let oldLen = result.len + let newLen = oldLen + buflen + result.setLen newLen + c_memcpy(result[oldLen].addr, buf, buflen.csize_t) + +import std/private/[dragonbox, schubfach] + +proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: BiggestFloat): int = + ## This is the implementation to format floats. + ## + ## returns the amount of bytes written to `buf` not counting the + ## terminating '\0' character. + result = toChars(buf, value, forceTrailingDotZero=true) + buf[result] = '\0' + +proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: float32): int = + result = float32ToChars(buf, value, forceTrailingDotZero=true) + buf[result] = '\0' + +proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>", + importc: "sprintf", varargs, noSideEffect.} + +proc writeToBuffer(buf: var array[65, char]; value: cstring) = + var i = 0 + while value[i] != '\0': + buf[i] = value[i] + inc i + +proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat): int = + ## This is the implementation to format floats. + ## + ## returns the amount of bytes written to `buf` not counting the + ## terminating '\0' character. + var n: int = c_sprintf(addr buf, "%.16g", value) + var hasDot = false + for i in 0..n-1: + if buf[i] == ',': + buf[i] = '.' + hasDot = true + elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: + hasDot = true + if not hasDot: + buf[n] = '.' + buf[n+1] = '0' + buf[n+2] = '\0' + result = n + 2 + else: + result = n + # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)' + # of '-1.#IND' are produced. + # We want to get rid of these here: + if buf[n-1] in {'n', 'N', 'D', 'd', ')'}: + writeToBuffer(buf, "nan") + result = 3 + elif buf[n-1] == 'F': + if buf[0] == '-': + writeToBuffer(buf, "-inf") + result = 4 + else: + writeToBuffer(buf, "inf") + result = 3 + +proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32): int {.inline.} = + when defined(nimPreviewFloatRoundtrip) or defined(nimPreviewSlimSystem): + writeFloatToBufferRoundtrip(buf, value) + else: + writeFloatToBufferSprintf(buf, value) + +proc addFloatRoundtrip*(result: var string; x: float | float32) = + when nimvm: + doAssert false + else: + var buffer {.noinit.}: array[65, char] + let n = writeFloatToBufferRoundtrip(buffer, x) + result.addCstringN(cstring(buffer[0].addr), n) + +proc addFloatSprintf*(result: var string; x: float) = + when nimvm: + doAssert false + else: + var buffer {.noinit.}: array[65, char] + let n = writeFloatToBufferSprintf(buffer, x) + result.addCstringN(cstring(buffer[0].addr), n) + +proc nimFloatToString(a: float): cstring = + ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2 + # print `-0.0` properly + asm """ + function nimOnlyDigitsOrMinus(n) { + return n.toString().match(/^-?\d+$/); + } + if (Number.isSafeInteger(`a`)) + `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0" + else { + `result` = `a`+"" + if(nimOnlyDigitsOrMinus(`result`)){ + `result` = `a`+".0" + } + } + """ + +proc addFloat*(result: var string; x: float | float32) {.inline.} = + ## Converts float to its string representation and appends it to `result`. + runnableExamples: + var + s = "foo:" + b = 45.67 + s.addFloat(45.67) + assert s == "foo:45.67" + template impl = + when defined(nimPreviewFloatRoundtrip) or defined(nimPreviewSlimSystem): + addFloatRoundtrip(result, x) + else: + addFloatSprintf(result, x) + when defined(js): + when nimvm: impl() + else: + result.add nimFloatToString(x) + else: impl() + +when defined(nimPreviewSlimSystem): + func `$`*(x: float | float32): string = + ## Outplace version of `addFloat`. + result.addFloat(x) diff --git a/lib/system/dragonbox.nim b/lib/std/private/dragonbox.nim index 34ae9e210..23adff385 100644 --- a/lib/system/dragonbox.nim +++ b/lib/std/private/dragonbox.nim @@ -30,7 +30,6 @@ when defined(nimPreviewSlimSystem): const dtoaMinBufferLength*: cint = 64 -## -------------------------------------------------------------------------------------------------- ## This file contains an implementation of Junekey Jeon's Dragonbox algorithm. ## ## It is a simplified version of the reference implementation found here: @@ -38,14 +37,13 @@ const ## ## The reference implementation also works with single-precision floating-point numbers and ## has options to configure the rounding mode. -## -------------------------------------------------------------------------------------------------- template dragonbox_Assert*(x: untyped): untyped = assert(x) -## ================================================================================================== -## -## ================================================================================================== +# ================================================================================================== +# +# ================================================================================================== type ValueType* = float @@ -106,10 +104,11 @@ proc isZero*(this: Double): bool {.noSideEffect.} = proc signBit*(this: Double): int {.noSideEffect.} = return ord((this.bits and signMask) != 0) + +# ================================================================================================== +# +# ================================================================================================== ## namespace -## ================================================================================================== -## -## ================================================================================================== ## Returns floor(x / 2^n). ## ## Technically, right-shift of negative integers is implementation defined... @@ -133,9 +132,9 @@ proc floorLog10ThreeQuartersPow2*(e: int32): int32 {.inline.} = dragonbox_Assert(e <= 1500) return floorDivPow2(e * 1262611 - 524031, 22) -## ================================================================================================== -## -## ================================================================================================== +# ================================================================================================== +# +# ================================================================================================== type uint64x2* {.bycopy.} = object @@ -1040,9 +1039,9 @@ proc toDecimal64*(ieeeSignificand: uint64; ieeeExponent: uint64): FloatingDecima dec(q) return FloatingDecimal64(significand: q, exponent: minusK + kappa) -## ================================================================================================== -## ToChars -## ================================================================================================== +# ================================================================================================== +# ToChars +# ================================================================================================== when false: template `+!`(x: cstring; offset: int): cstring = cast[cstring](cast[uint](x) + uint(offset)) diff --git a/lib/system/schubfach.nim b/lib/std/private/schubfach.nim index 7d6861e35..5b965aaa7 100644 --- a/lib/system/schubfach.nim +++ b/lib/std/private/schubfach.nim @@ -3,12 +3,12 @@ ## Distributed under the Boost Software License, Version 1.0. ## (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) -## -------------------------------------------------------------------------------------------------- +# -------------------------------------------------------------------------------------------------- ## This file contains an implementation of the Schubfach algorithm as described in ## ## [1] Raffaello Giulietti, "The Schubfach way to render doubles", ## https://drive.google.com/open?id=1luHhyQF9zKlM8yJ1nebU0OgVYhfC6CBN -## -------------------------------------------------------------------------------------------------- +# -------------------------------------------------------------------------------------------------- import std/private/digitsutils @@ -19,9 +19,9 @@ when defined(nimPreviewSlimSystem): template sf_Assert(x: untyped): untyped = assert(x) -## ================================================================================================== -## -## ================================================================================================== +# ================================================================================================== +# +# ================================================================================================== type ValueType = float32 @@ -68,7 +68,7 @@ proc isZero(this: Single): bool {.noSideEffect.} = proc signBit(this: Single): int {.noSideEffect.} = return int((this.bits and signMask) != 0) -## ================================================================================================== +# ================================================================================================== ## Returns floor(x / 2^n). ## ## Technically, right-shift of negative integers is implementation defined... diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim index eab96254a..22e981198 100644 --- a/lib/std/syncio.nim +++ b/lib/std/syncio.nim @@ -11,7 +11,7 @@ include system/inclrtl import std/private/since -import system/formatfloat +import std/formatfloat # ----------------- IO Part ------------------------------------------------ type diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 1e1ce9c87..bdf2903d2 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -9,6 +9,8 @@ # Implementation of some runtime checks. include system/indexerrors +when defined(nimPreviewSlimSystem): + import std/formatfloat proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = when hostOS == "standalone": diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index b060aedb0..4ff3d0ae6 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -4,8 +4,14 @@ runnableExamples: assert $(-2*3) == "-6" import std/private/[digitsutils, miscdollars] -import system/formatfloat -export addFloat + +when not defined(nimPreviewSlimSystem): + import std/formatfloat + export addFloat + + func `$`*(x: float | float32): string = + ## Outplace version of `addFloat`. + result.addFloat(x) proc `$`*(x: int): string {.raises: [].} = ## Outplace version of `addInt`. @@ -27,9 +33,6 @@ gen(int) gen(uint64) gen(int64) -func `$`*(x: float | float32): string = - ## Outplace version of `addFloat`. - result.addFloat(x) proc `$`*(x: bool): string {.magic: "BoolToStr", noSideEffect.} ## The stringify operator for a boolean argument. Returns `x` diff --git a/lib/system/formatfloat.nim b/lib/system/formatfloat.nim index aada3e1bf..70dd857d5 100644 --- a/lib/system/formatfloat.nim +++ b/lib/system/formatfloat.nim @@ -1,135 +1,6 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2019 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -when defined(nimPreviewSlimSystem): - import std/assertions - -proc c_memcpy(a, b: pointer, size: csize_t): pointer {.importc: "memcpy", header: "<string.h>", discardable.} - -proc addCstringN(result: var string, buf: cstring; buflen: int) = - # no nimvm support needed, so it doesn't need to be fast here either - let oldLen = result.len - let newLen = oldLen + buflen - result.setLen newLen - c_memcpy(result[oldLen].addr, buf, buflen.csize_t) - -import dragonbox, schubfach - -proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: BiggestFloat): int = - ## This is the implementation to format floats. - ## - ## returns the amount of bytes written to `buf` not counting the - ## terminating '\0' character. - result = toChars(buf, value, forceTrailingDotZero=true) - buf[result] = '\0' - -proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: float32): int = - result = float32ToChars(buf, value, forceTrailingDotZero=true) - buf[result] = '\0' - -proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>", - importc: "sprintf", varargs, noSideEffect.} - -proc writeToBuffer(buf: var array[65, char]; value: cstring) = - var i = 0 - while value[i] != '\0': - buf[i] = value[i] - inc i - -proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat): int = - ## This is the implementation to format floats. - ## - ## returns the amount of bytes written to `buf` not counting the - ## terminating '\0' character. - var n: int = c_sprintf(addr buf, "%.16g", value) - var hasDot = false - for i in 0..n-1: - if buf[i] == ',': - buf[i] = '.' - hasDot = true - elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: - hasDot = true - if not hasDot: - buf[n] = '.' - buf[n+1] = '0' - buf[n+2] = '\0' - result = n + 2 - else: - result = n - # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)' - # of '-1.#IND' are produced. - # We want to get rid of these here: - if buf[n-1] in {'n', 'N', 'D', 'd', ')'}: - writeToBuffer(buf, "nan") - result = 3 - elif buf[n-1] == 'F': - if buf[0] == '-': - writeToBuffer(buf, "-inf") - result = 4 - else: - writeToBuffer(buf, "inf") - result = 3 - -proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32): int {.inline.} = - when defined(nimPreviewFloatRoundtrip): - writeFloatToBufferRoundtrip(buf, value) - else: - writeFloatToBufferSprintf(buf, value) - -proc addFloatRoundtrip*(result: var string; x: float | float32) = - when nimvm: - doAssert false - else: - var buffer {.noinit.}: array[65, char] - let n = writeFloatToBufferRoundtrip(buffer, x) - result.addCstringN(cstring(buffer[0].addr), n) - -proc addFloatSprintf*(result: var string; x: float) = - when nimvm: - doAssert false - else: - var buffer {.noinit.}: array[65, char] - let n = writeFloatToBufferSprintf(buffer, x) - result.addCstringN(cstring(buffer[0].addr), n) - -proc nimFloatToString(a: float): cstring = - ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2 - # print `-0.0` properly - asm """ - function nimOnlyDigitsOrMinus(n) { - return n.toString().match(/^-?\d+$/); - } - if (Number.isSafeInteger(`a`)) - `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0" - else { - `result` = `a`+"" - if(nimOnlyDigitsOrMinus(`result`)){ - `result` = `a`+".0" - } - } - """ - -proc addFloat*(result: var string; x: float | float32) {.inline.} = - ## Converts float to its string representation and appends it to `result`. - runnableExamples: - var - s = "foo:" - b = 45.67 - s.addFloat(45.67) - assert s == "foo:45.67" - template impl = - when defined(nimPreviewFloatRoundtrip): - addFloatRoundtrip(result, x) - else: - addFloatSprintf(result, x) - when defined(js): - when nimvm: impl() - else: - result.add nimFloatToString(x) - else: impl() +when not defined(nimPreviewSlimSystem): + import std/formatfloat + export formatfloat + {.deprecated: "use `std/formatfloat`".} +else: + {.error: "use `std/formatfloat`".} diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index 6ab5f3c3f..0e9bec0f3 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -1,5 +1,8 @@ include system/inclrtl +when defined(nimPreviewSlimSystem): + import std/formatfloat + proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} ## imported from typetraits |