move formatfloat out of system (#20195)

* move formatfloat out of system

* fixes doc

* Update changelog.md

* careless

* fixes

* deprecate system/formatfloat

* better handling
This commit is contained in:
ringabout
2022-08-24 19:38:30 +08:00
committed by GitHub
parent 12f23d5ae8
commit b6bfe38ff5
23 changed files with 201 additions and 176 deletions

View File

@@ -6,8 +6,7 @@
- `addr` is now available for all addressable locations,
`unsafeAddr` is now deprecated and an alias for `addr`.
- `io` and `assertions` are about to move out of the `system` module.
You may instead import `std/syncio` and `std/assertions`.
- `io`, `assertions`, `formatfloat` are about to move out of the `system` module. You may instead import `std/syncio`, `std/assertions` and `std/formatfloat`.
The `-d:nimPreviewSlimSystem` option makes these imports required.
- The `gc:v2` option is removed.

View File

@@ -15,7 +15,7 @@ import ".." / [ast, idents, lineinfos, msgs, ropes, options,
from os import removeFile, isAbsolute
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import std/[syncio, assertions, formatfloat]
type
PackedConfig* = object

View File

@@ -20,7 +20,7 @@ import
wordrecg, lineinfos, pathutils, parseutils
when defined(nimPreviewSlimSystem):
import std/assertions
import std/[assertions, formatfloat]
const
MaxLineLength* = 80 # lines longer than this lead to a warning

View File

@@ -18,7 +18,7 @@ import
lexer, options, idents, strutils, ast, msgs, lineinfos
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import std/[syncio, assertions, formatfloat]
type
TRenderFlag* = enum

View File

@@ -42,7 +42,7 @@ when not declared(signbit):
proc signbit*(x: SomeFloat): bool {.inline.} =
result = c_signbit(x) != 0
import system/formatfloat
import std/formatfloat
proc toStrMaxPrecision*(f: BiggestFloat | float32): string =
const literalPostfix = when f is float32: "f" else: ""

View File

@@ -61,7 +61,7 @@ import
from pathutils import AbsoluteFile
when defined(nimPreviewSlimSystem):
import std/[assertions, syncio]
import std/[assertions, syncio, formatfloat]
type

View File

@@ -25,6 +25,9 @@ when defined(nimfix):
when not defined(leanCompiler):
import spawn
when defined(nimPreviewSlimSystem):
import std/formatfloat
# implementation
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode

View File

@@ -18,7 +18,7 @@ import
from system/memory import nimCStrLen
when defined(nimPreviewSlimSystem):
import std/assertions
import std/[assertions, formatfloat]
proc errorType*(g: ModuleGraph): PType =
## creates a type representing an error state

View File

@@ -14,7 +14,7 @@ import
lineinfos, int128, modulegraphs, astmsgs
when defined(nimPreviewSlimSystem):
import std/assertions
import std/[assertions, formatfloat]
type
TPreferedDesc* = enum

View File

@@ -18,6 +18,9 @@ import
gorgeimpl, lineinfos, btrees, macrocacheimpl,
modulegraphs, sighashes, int128, vmprofiler
when defined(nimPreviewSlimSystem):
import std/formatfloat
import ast except getstr
from semfold import leValueConv, ordinalValToString
from evaltempl import evalTemplate

View File

@@ -13,7 +13,7 @@ import streams, json, intsets, tables, ast, astalgo, idents, types, msgs,
options, lineinfos
when defined(nimPreviewSlimSystem):
import std/assertions
import std/[assertions, formatfloat]
proc ptrToInt(x: PNode): int {.inline.} =
result = cast[int](x) # don't skip alignment

View File

@@ -28,12 +28,12 @@ from std/os import getEnv, existsEnv, delEnv, putEnv, envPairs,
from std/times import cpuTime
from std/hashes import hash
from std/osproc import nil
from system/formatfloat import addFloatRoundtrip, addFloatSprintf
when defined(nimPreviewSlimSystem):
import std/syncio
else:
from std/formatfloat import addFloatRoundtrip, addFloatSprintf
# There are some useful procs in vmconv.
import vmconv, vmmarshal

View File

@@ -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

View File

@@ -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

View File

@@ -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.`$`

142
lib/std/formatfloat.nim Normal file
View File

@@ -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)

View File

@@ -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))

View File

@@ -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...

View File

@@ -11,7 +11,7 @@
include system/inclrtl
import std/private/since
import system/formatfloat
import std/formatfloat
# ----------------- IO Part ------------------------------------------------
type

View File

@@ -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":

View File

@@ -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`

View File

@@ -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`".}

View File

@@ -1,5 +1,8 @@
include system/inclrtl
when defined(nimPreviewSlimSystem):
import std/formatfloat
proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
## imported from typetraits