Merge pull request #2421 from jon-lipstate/strconv_docs

Code Docs for strconv
This commit is contained in:
Jeroen van Rijn
2023-04-06 15:38:32 +02:00
committed by GitHub
6 changed files with 869 additions and 177 deletions

View File

@@ -8,7 +8,17 @@ Decimal :: struct {
decimal_point: int,
neg, trunc: bool,
}
/*
Sets a Decimal from a given string `s`. The string is expected to represent a float. Stores parsed number in the given Decimal structure.
If parsing fails, the Decimal will be left in an undefined state.
**Inputs**
- d: Pointer to a Decimal struct where the parsed result will be stored
- s: The input string representing the floating-point number
**Returns**
- ok: A boolean indicating whether the parsing was successful
*/
set :: proc(d: ^Decimal, s: string) -> (ok: bool) {
d^ = {}
@@ -91,7 +101,16 @@ set :: proc(d: ^Decimal, s: string) -> (ok: bool) {
return i == len(s)
}
/*
Converts a Decimal to a string representation, using the provided buffer as storage.
**Inputs**
- buf: A byte slice buffer to hold the resulting string
- a: The struct to be converted to a string
**Returns**
- A string representation of the Decimal
*/
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
digit_zero :: proc(buf: []byte) -> int {
for _, i in buf {
@@ -100,7 +119,6 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
return len(buf)
}
n := 10 + a.count + abs(a.decimal_point)
// TODO(bill): make this work with a buffer that's not big enough
@@ -129,8 +147,12 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
return string(b[0:w])
}
/*
Trims trailing zeros in the given Decimal, updating the count and decimal_point values as needed.
// trim trailing zeros
**Inputs**
- a: Pointer to the Decimal struct to be trimmed
*/
trim :: proc(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' {
a.count -= 1
@@ -139,8 +161,15 @@ trim :: proc(a: ^Decimal) {
a.decimal_point = 0
}
}
/*
Converts a given u64 integer `idx` to its Decimal representation in the provided Decimal struct.
**Used for internal Decimal Operations.**
**Inputs**
- a: Where the result will be stored
- idx: The value to be assigned to the Decimal
*/
assign :: proc(a: ^Decimal, idx: u64) {
buf: [64]byte
n := 0
@@ -160,9 +189,15 @@ assign :: proc(a: ^Decimal, idx: u64) {
a.decimal_point = a.count
trim(a)
}
/*
Shifts the Decimal value to the right by k positions.
**Used for internal Decimal Operations.**
**Inputs**
- a: The Decimal struct to be shifted
- k: The number of positions to shift right
*/
shift_right :: proc(a: ^Decimal, k: uint) {
r := 0 // read index
w := 0 // write index
@@ -304,7 +339,15 @@ _shift_left_offsets := [?]struct{delta: int, cutoff: string}{
{18, "173472347597680709441192448139190673828125"},
{19, "867361737988403547205962240695953369140625"},
}
/*
Shifts the decimal of the input value to the left by `k` places
WARNING: asserts `k < 61`
**Inputs**
- a: The Decimal to be modified
- k: The number of places to shift the decimal to the left
*/
shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check {
prefix_less :: #force_inline proc "contextless" (b: []byte, s: string) -> bool #no_bounds_check {
for i in 0..<len(s) {
@@ -359,7 +402,13 @@ shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check {
a.count = clamp(a.count, 0, len(a.digits))
trim(a)
}
/*
Shifts the decimal of the input value by the specified number of places
**Inputs**
- a: The Decimal to be modified
- i: The number of places to shift the decimal (positive for left shift, negative for right shift)
*/
shift :: proc(a: ^Decimal, i: int) {
uint_size :: 8*size_of(uint)
max_shift :: uint_size-4
@@ -383,7 +432,15 @@ shift :: proc(a: ^Decimal, i: int) {
shift_right(a, uint(-k))
}
}
/*
Determines if the Decimal can be rounded up at the given digit index
**Inputs**
- a: The Decimal to check
- nd: The digit index to consider for rounding up
**Returns** Boolean if can be rounded up at the given index (>=5)
*/
can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
if nd < 0 || nd >= a.count { return false }
if a.digits[nd] == '5' && nd+1 == a.count {
@@ -395,7 +452,13 @@ can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
return a.digits[nd] >= '5'
}
/*
Rounds the Decimal at the given digit index
**Inputs**
- a: The Decimal to be modified
- nd: The digit index to round
*/
round :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return }
if can_round_up(a, nd) {
@@ -404,7 +467,13 @@ round :: proc(a: ^Decimal, nd: int) {
round_down(a, nd)
}
}
/*
Rounds the Decimal up at the given digit index
**Inputs**
- a: The Decimal to be modified
- nd: The digit index to round up
*/
round_up :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return }
@@ -421,15 +490,62 @@ round_up :: proc(a: ^Decimal, nd: int) {
a.count = 1
a.decimal_point += 1
}
/*
Rounds down the decimal value to the specified number of decimal places
**Inputs**
- a: The Decimal value to be rounded down
- nd: The number of decimal places to round down to
Example:
import "core:fmt"
import "core:strconv"
strconv_round_down_example :: proc {
d: decimal.Decimal
str := [64]u8{}
ok := decimal.set(&d, "123.456")
decimal.round_down(&d, 5)
fmt.println(decimal.decimal_to_string(str[:], &d))
}
Output:
123.45
*/
round_down :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return }
a.count = nd
trim(a)
}
/*
Extracts the rounded integer part of a decimal value
**Inputs**
- a: A pointer to the Decimal value to extract the rounded integer part from
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
WARNING: There are no guarantees about overflow.
**Returns** The rounded integer part of the input decimal value
Example:
import "core:fmt"
import "core:strconv"
strconv_rounded_integer_example :: proc {
d: decimal.Decimal
ok := decimal.set(&d, "123.456")
fmt.println(decimal.rounded_integer(&d))
}
Output:
123
*/
rounded_integer :: proc(a: ^Decimal) -> u64 {
if a.decimal_point > 20 {
return 0xffff_ffff_ffff_ffff

View File

@@ -20,7 +20,29 @@ _f16_info := Float_Info{10, 5, -15}
_f32_info := Float_Info{23, 8, -127}
_f64_info := Float_Info{52, 11, -1023}
/*
Converts a floating-point number to a string with the specified format and precision.
**Inputs**
buf: A byte slice to store the resulting string
val: The floating-point value to be converted
fmt: The formatting byte, accepted values are 'e', 'E', 'f', 'F', 'g', 'G'
precision: The number of decimal places to round to
bit_size: The size of the floating-point number in bits, valid values are 16, 32, 64
Example:
buf: [32]byte
val := 3.141592
fmt := 'f'
precision := 2
bit_size := 64
result := strconv.generic_ftoa(buf[:], val, fmt, precision, bit_size) -> "3.14"
**Returns**
- A byte slice containing the formatted string
*/
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte {
bits: u64
flt: ^Float_Info
@@ -95,8 +117,20 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int)
return format_digits(buf, shortest, neg, digs, prec, fmt)
}
/*
Converts a decimal floating-point number into a byte buffer with the given format
**Inputs**
- buf: The byte buffer to store the formatted number
- shortest: If true, generates the shortest representation of the number
- neg: If true, the number is negative
- digs: The decimal number to be formatted
- precision: The number of digits after the decimal point
- fmt: The format specifier (accepted values: 'f', 'F', 'e', 'E', 'g', 'G')
**Returns**
- A byte slice containing the formatted decimal floating-point number
*/
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, precision: int, fmt: byte) -> []byte {
Buffer :: struct {
b: []byte,
@@ -217,7 +251,15 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
}
/*
Rounds the given decimal number to its shortest representation, considering the provided floating-point format
**Inputs**
- d: The decimal number to round
- mant: The mantissa of the floating-point number
- exp: The exponent of the floating-point number
- flt: Pointer to the Float_Info structure containing information about the floating-point format
*/
round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Info) {
if mant == 0 { // If mantissa is zero, the number is zero
d.count = 0
@@ -284,7 +326,17 @@ round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Inf
}
}
/*
Converts a decimal number to its floating-point representation with the given format and returns the resulting bits
**Inputs**
- d: Pointer to the decimal number to convert
- info: Pointer to the Float_Info structure containing information about the floating-point format
**Returns**
- b: The bits representing the floating-point number
- overflow: A boolean indicating whether an overflow occurred during conversion
*/
@(private)
decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64, overflow: bool) {
end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (bits: u64) {

View File

@@ -9,7 +9,18 @@ Int_Flags :: bit_set[Int_Flag]
MAX_BASE :: 32
digits := "0123456789abcdefghijklmnopqrstuvwxyz"
/*
Determines whether the given unsigned 64-bit integer is a negative value by interpreting it as a signed integer with the specified bit size.
**Inputs**
- x: The unsigned 64-bit integer to check for negativity
- is_signed: A boolean indicating if the input should be treated as a signed integer
- bit_size: The bit size of the signed integer representation (8, 16, 32, or 64)
**Returns**
- u: The absolute value of the input integer
- neg: A boolean indicating whether the input integer is negative
*/
is_integer_negative :: proc(x: u64, is_signed: bool, bit_size: int) -> (u: u64, neg: bool) {
u = x
if is_signed {
@@ -36,7 +47,21 @@ is_integer_negative :: proc(x: u64, is_signed: bool, bit_size: int) -> (u: u64,
}
return
}
/*
Appends the string representation of an integer to a buffer with specified base, flags, and digit set.
**Inputs**
- buf: The buffer to append the integer representation to
- x: The integer value to convert
- base: The base for the integer representation (2 <= base <= MAX_BASE)
- is_signed: A boolean indicating if the input should be treated as a signed integer
- bit_size: The bit size of the signed integer representation (8, 16, 32, or 64)
- digits: The digit set used for the integer representation
- flags: The Int_Flags bit set to control integer formatting
**Returns**
- The string containing the integer representation appended to the buffer
*/
append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits")
@@ -78,7 +103,18 @@ append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: i
copy(buf, out)
return string(buf[0:len(out)])
}
/*
Determines whether the given unsigned 128-bit integer is a negative value by interpreting it as a signed integer with the specified bit size.
**Inputs**
- x: The unsigned 128-bit integer to check for negativity
- is_signed: A boolean indicating if the input should be treated as a signed integer
- bit_size: The bit size of the signed integer representation (8, 16, 32, 64, or 128)
**Returns**
- u: The absolute value of the input integer
- neg: A boolean indicating whether the input integer is negative
*/
is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u: u128, neg: bool) {
u = x
if is_signed {
@@ -109,9 +145,21 @@ is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u:
}
return
}
/*
Appends the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set.
// import "core:runtime"
**Inputs**
- buf: The buffer to append the integer representation to
- x: The 128-bit integer value to convert
- base: The base for the integer representation (2 <= base <= MAX_BASE)
- is_signed: A boolean indicating if the input should be treated as a signed integer
- bit_size: The bit size of the signed integer representation (8, 16, 32, 64, or 128)
- digits: The digit set used for the integer representation
- flags: The Int_Flags bit set to control integer formatting
**Returns**
- The string containing the integer representation appended to the buffer
*/
append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits")

File diff suppressed because it is too large Load Diff

View File

@@ -1081,7 +1081,6 @@ split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) {
}
/*
Splits the input string by the separator string in an iterator fashion.
Destructively consumes the original string until the end.
Inputs:
- s: Pointer to the input string, which is modified during the search.
@@ -1116,7 +1115,6 @@ split_iterator :: proc(s: ^string, sep: string) -> (string, bool) {
}
/*
Splits the input string after every separator string in an iterator fashion.
Destructively consumes the original string until the end.
Inputs:
- s: Pointer to the input string, which is modified during the search.

View File

@@ -409,7 +409,7 @@ foreign kernel32 {
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setfilecompletionnotificationmodes)
SetFileCompletionNotificationModes :: proc(FileHandle: HANDLE, Flags: u8) -> BOOL ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-createiocompletionport)
CreateIoCompletionPort :: proc(FileHandle: HANDLE, ExistingCompletionPort: HANDLE, CompletionKey: uintptr, NumberOfConcurrentThreads: DWORD) -> HANDLE ---
CreateIoCompletionPort :: proc(FileHandle: HANDLE, ExistingCompletionPort: HANDLE, CompletionKey: ^uintptr, NumberOfConcurrentThreads: DWORD) -> HANDLE ---
//[MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatus)
GetQueuedCompletionStatus :: proc(CompletionPort: HANDLE, lpNumberOfBytesTransferred: ^DWORD, lpCompletionKey: uintptr, lpOverlapped: ^^OVERLAPPED, dwMilliseconds: DWORD) -> BOOL ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatusex)