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
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,47 @@ Benchmark_CalculateTimestamp/fiber-12 1000000000 0.2935 ns/op
Benchmark_CalculateTimestamp/default-12 15740576 73.79 ns/op 0 B/op 0 allocs/op
Benchmark_CalculateTimestamp/default-12 15789036 71.12 ns/op 0 B/op 0 allocs/op

Benchmark_ParseUint/fiber-12 190390941 6.292 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint/fiber-12 187968758 6.400 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint/fiber_bytes-12 181957326 6.809 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint/fiber_bytes-12 182275550 6.558 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint/default-12 88281543 13.52 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint/default-12 88967146 13.41 ns/op 0 B/op 0 allocs/op

Benchmark_ParseInt/fiber-12 181353142 6.723 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt/fiber-12 180631305 6.578 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt/fiber_bytes-12 175220041 6.892 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt/fiber_bytes-12 171838354 7.020 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt/default-12 76055068 15.77 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt/default-12 75963992 15.55 ns/op 0 B/op 0 allocs/op

Benchmark_ParseInt32/fiber-12 179962680 6.631 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt32/fiber-12 181285437 6.570 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt32/fiber_bytes-12 173786900 6.901 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt32/fiber_bytes-12 171283489 7.069 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt32/default-12 69845103 15.75 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt32/default-12 76438194 15.66 ns/op 0 B/op 0 allocs/op

Benchmark_ParseInt8/fiber-12 286492362 4.148 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt8/fiber-12 282957276 4.147 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt8/fiber_bytes-12 270179119 4.481 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt8/fiber_bytes-12 258238294 4.522 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt8/default-12 135063286 8.831 ns/op 0 B/op 0 allocs/op
Benchmark_ParseInt8/default-12 140703313 8.528 ns/op 0 B/op 0 allocs/op

Benchmark_ParseUint32/fiber-12 184411585 6.568 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint32/fiber-12 184338627 6.543 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint32/fiber_bytes-12 178475793 6.759 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint32/fiber_bytes-12 178517788 7.052 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint32/default-12 83775481 13.41 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint32/default-12 88117585 13.51 ns/op 0 B/op 0 allocs/op

Benchmark_ParseUint8/fiber-12 401799110 3.046 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint8/fiber-12 380578648 3.036 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint8/fiber_bytes-12 363442573 3.344 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint8/fiber_bytes-12 357869246 3.346 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint8/default-12 184238403 6.788 ns/op 0 B/op 0 allocs/op
Benchmark_ParseUint8/default-12 186525054 6.454 ns/op 0 B/op 0 allocs/op
```

See all the benchmarks under <https://gofiber.github.io/utils/>
124 changes: 124 additions & 0 deletions parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package utils

import (
"math"
)

type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
type Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

// ParseUint parses a decimal ASCII string or byte slice into a uint64.
// It returns the parsed value and true on success.
// If the input contains non-digit characters, it returns 0 and false.
func ParseUint[S byteSeq](s S) (uint64, bool) {
return parseUnsigned[S, uint64](s, uint64(math.MaxUint64))
}

// ParseInt parses a decimal ASCII string or byte slice into an int64.
// Returns the parsed value and true on success, else 0 and false.
func ParseInt[S byteSeq](s S) (int64, bool) {
return parseSigned[S, int64](s, math.MinInt64, math.MaxInt64)
}

// ParseInt32 parses a decimal ASCII string or byte slice into an int32.
func ParseInt32[S byteSeq](s S) (int32, bool) {
return parseSigned[S, int32](s, math.MinInt32, math.MaxInt32)
}

// ParseInt8 parses a decimal ASCII string or byte slice into an int8.
func ParseInt8[S byteSeq](s S) (int8, bool) {
return parseSigned[S, int8](s, math.MinInt8, math.MaxInt8)
}

// ParseUint32 parses a decimal ASCII string or byte slice into a uint32.
func ParseUint32[S byteSeq](s S) (uint32, bool) {
return parseUnsigned[S, uint32](s, uint32(math.MaxUint32))
}

// ParseUint8 parses a decimal ASCII string or byte slice into a uint8.
func ParseUint8[S byteSeq](s S) (uint8, bool) {
return parseUnsigned[S, uint8](s, uint8(math.MaxUint8))
}

// parseDigits parses a sequence of digits and returns the uint64 value and success.
// Returns (0, false) if any non-digit is encountered or overflow happens.
func parseDigits[S byteSeq](s S, i int) (uint64, bool) {
var n uint64
for ; i < len(s); i++ {
c := s[i] - '0'
if c > 9 {
return 0, false
}
nn := n*10 + uint64(c)
if nn < n {
return 0, false
}

Check warning on line 59 in parse.go

View check run for this annotation

Codecov / codecov/patch

parse.go#L58-L59

Added lines #L58 - L59 were not covered by tests
n = nn
}
return n, true
}

// parseSigned parses a decimal ASCII string or byte slice into a signed integer type T.
// It supports optional '+' or '-' prefix, checks for overflow and underflow, and returns (0, false) on error.
func parseSigned[S byteSeq, T Signed](s S, minRange, maxRange T) (T, bool) {
if len(s) == 0 {
return 0, false
}

neg := false
i := 0
switch s[0] {
case '-':
neg = true
i++
case '+':
i++
}
if i == len(s) {
return 0, false
}

// Parse digits
n, ok := parseDigits(s, i)
if !ok {
return 0, false
}

if !neg {
// Check for overflow
if n > uint64(int64(maxRange)) {
return 0, false
}
return T(n), true
}

// Check for underflow
minAbs := uint64(-int64(minRange))
if n > minAbs {
return 0, false
}

return T(-int64(n)), true
Comment thread
ReneWerner87 marked this conversation as resolved.
}

// parseUnsigned parses a decimal ASCII string or byte slice into an unsigned integer type T.
// It does not support sign prefixes, checks for overflow, and returns (0, false) on error.
func parseUnsigned[S byteSeq, T Unsigned](s S, maxRange T) (T, bool) {
if len(s) == 0 {
return 0, false
}

i := 0

// Parse digits
n, ok := parseDigits(s, i)
// Check for overflow
if !ok || n > uint64(maxRange) {
return 0, false
}
return T(n), true
}
Loading
Loading