Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions conv/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"math"
"strconv"
"strings"
"unsafe"
)

// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
Expand Down Expand Up @@ -54,11 +53,8 @@ func IsFloat64AJSONInteger(f float64) bool {

// ConvertFloat turns a string into a float numerical value.
func ConvertFloat[T Float](str string) (T, error) {
// NOTE: [unsafe.SizeOf] simply returns the size in bytes of the value.
// For primitive types T, the generic stencil is precompiled and this value
// is resolved at compile time, resulting in an immediate call to [strconv.ParseFloat].
var v T
f, err := strconv.ParseFloat(str, int(unsafe.Sizeof(v))*8)
f, err := strconv.ParseFloat(str, bitsize(v))
if err != nil {
return 0, err
}
Expand All @@ -69,7 +65,7 @@ func ConvertFloat[T Float](str string) (T, error) {
// ConvertInteger turns a string into a signed integer.
func ConvertInteger[T Signed](str string) (T, error) {
var v T
f, err := strconv.ParseInt(str, 10, int(unsafe.Sizeof(v))*8)
f, err := strconv.ParseInt(str, 10, bitsize(v))
if err != nil {
return 0, err
}
Expand All @@ -80,7 +76,7 @@ func ConvertInteger[T Signed](str string) (T, error) {
// ConvertUinteger turns a string into an unsigned integer.
func ConvertUinteger[T Unsigned](str string) (T, error) {
var v T
f, err := strconv.ParseUint(str, 10, int(unsafe.Sizeof(v))*8)
f, err := strconv.ParseUint(str, 10, bitsize(v))
if err != nil {
return 0, err
}
Expand Down
6 changes: 1 addition & 5 deletions conv/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package conv

import (
"strconv"
"unsafe"
)

// FormatInteger turns an integer type into a string.
Expand All @@ -31,10 +30,7 @@ func FormatUinteger[T Unsigned](value T) string {

// FormatFloat turns a floating point numerical value into a string.
func FormatFloat[T Float](value T) string {
// NOTE: [unsafe.SizeOf] simply returns the size in bytes of the value.
// For primitive types T, the generic stencil is precompiled and this value
// is resolved at compile time, resulting in an immediate call to [strconv.FormatFloat].
return strconv.FormatFloat(float64(value), 'f', -1, int(unsafe.Sizeof(value))*8)
return strconv.FormatFloat(float64(value), 'f', -1, bitsize(value))
}

// FormatBool turns a boolean into a string.
Expand Down
17 changes: 17 additions & 0 deletions conv/sizeof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package conv

import "unsafe"

// bitsize returns the size in bits of a type.
//
// NOTE: [unsafe.SizeOf] simply returns the size in bytes of the value.
// For primitive types T, the generic stencil is precompiled and this value
// is resolved at compile time, resulting in an immediate call to [strconv.ParseFloat].
//
// We may leave up to the go compiler to simplify this function into a
// constant value, which happens in practice at least for primitive types
// (e.g. numerical types).
func bitsize[T Numerical](value T) int {
const bitsPerByte = 8
return int(unsafe.Sizeof(value)) * bitsPerByte
}
5 changes: 5 additions & 0 deletions conv/type_constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ type (
Float interface {
~float32 | ~float64
}

// Numerical types
Numerical interface {
Signed | Unsigned | Float
}
)
Loading