Merge pull request #2445 from Lperlind/documentation/strings_returns

Document return values of strings and add allocator errors where possible
This commit is contained in:
Jeroen van Rijn
2023-04-08 10:05:39 +02:00
committed by GitHub
9 changed files with 504 additions and 425 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
} }
} }
case: case:
if strings.contains_rune(field, w.comma) >= 0 { if strings.contains_rune(field, w.comma) {
return true return true
} }
if strings.contains_any(field, CHAR_SET) { if strings.contains_any(field, CHAR_SET) {
+2 -2
View File
@@ -38,8 +38,8 @@ Inputs:
- c: The char to check for in the Ascii_Set. - c: The char to check for in the Ascii_Set.
Returns: Returns:
A boolean indicating if the byte is contained in the Ascii_Set (true) or not (false). - res: A boolean indicating if the byte is contained in the Ascii_Set (true) or not (false).
*/ */
ascii_set_contains :: proc(as: Ascii_Set, c: byte) -> bool #no_bounds_check { ascii_set_contains :: proc(as: Ascii_Set, c: byte) -> (res: bool) #no_bounds_check {
return as[c>>5] & (1<<(c&31)) != 0 return as[c>>5] & (1<<(c&31)) != 0
} }
+65 -65
View File
@@ -3,6 +3,7 @@ package strings
import "core:runtime" import "core:runtime"
import "core:unicode/utf8" import "core:unicode/utf8"
import "core:strconv" import "core:strconv"
import "core:mem"
import "core:io" import "core:io"
/* /*
Type definition for a procedure that flushes a Builder Type definition for a procedure that flushes a Builder
@@ -31,10 +32,11 @@ Inputs:
- allocator: (default is context.allocator) - allocator: (default is context.allocator)
Returns: Returns:
A new Builder - res: The new Builder
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_make_none :: proc(allocator := context.allocator) -> Builder { builder_make_none :: proc(allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
return Builder{buf=make([dynamic]byte, allocator)} return Builder{buf=make([dynamic]byte, allocator) or_return }, nil
} }
/* /*
Produces a Builder with a specified length and cap of max(16,len) byte buffer Produces a Builder with a specified length and cap of max(16,len) byte buffer
@@ -46,10 +48,11 @@ Inputs:
- allocator: (default is context.allocator) - allocator: (default is context.allocator)
Returns: Returns:
A new Builder - res: The new Builder
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_make_len :: proc(len: int, allocator := context.allocator) -> Builder { builder_make_len :: proc(len: int, allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
return Builder{buf=make([dynamic]byte, len, allocator)} return Builder{buf=make([dynamic]byte, len, allocator) or_return }, nil
} }
/* /*
Produces a Builder with a specified length and cap Produces a Builder with a specified length and cap
@@ -62,10 +65,11 @@ Inputs:
- allocator: (default is context.allocator) - allocator: (default is context.allocator)
Returns: Returns:
A new Builder - res: The new Builder
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder { builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
return Builder{buf=make([dynamic]byte, len, cap, allocator)} return Builder{buf=make([dynamic]byte, len, cap, allocator) or_return }, nil
} }
// overload simple `builder_make_*` with or without len / cap parameters // overload simple `builder_make_*` with or without len / cap parameters
builder_make :: proc{ builder_make :: proc{
@@ -84,11 +88,12 @@ Inputs:
- allocator: (default is context.allocator) - allocator: (default is context.allocator)
Returns: Returns:
initialized ^Builder - res: A pointer to the initialized Builder
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> ^Builder { builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
b.buf = make([dynamic]byte, allocator) b.buf = make([dynamic]byte, allocator) or_return
return b return b, nil
} }
/* /*
Initializes a Builder with a specified length and cap, which is max(len,16) Initializes a Builder with a specified length and cap, which is max(len,16)
@@ -102,11 +107,12 @@ Inputs:
- allocator: (default is context.allocator) - allocator: (default is context.allocator)
Returns: Returns:
Initialized ^Builder - res: A pointer to the initialized Builder
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> ^Builder { builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
b.buf = make([dynamic]byte, len, allocator) b.buf = make([dynamic]byte, len, allocator) or_return
return b return b, nil
} }
/* /*
Initializes a Builder with a specified length and cap Initializes a Builder with a specified length and cap
@@ -119,11 +125,12 @@ Inputs:
- allocator: (default is context.allocator) - allocator: (default is context.allocator)
Returns: Returns:
A pointer to the initialized Builder - res: A pointer to the initialized Builder
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> ^Builder { builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
b.buf = make([dynamic]byte, len, cap, allocator) b.buf = make([dynamic]byte, len, cap, allocator) or_return
return b return b, nil
} }
// Overload simple `builder_init_*` with or without len / ap parameters // Overload simple `builder_init_*` with or without len / ap parameters
builder_init :: proc{ builder_init :: proc{
@@ -169,9 +176,9 @@ Inputs:
- b: A pointer to the Builder - b: A pointer to the Builder
Returns: Returns:
An io.Stream - res: the io.Stream
*/ */
to_stream :: proc(b: ^Builder) -> io.Stream { to_stream :: proc(b: ^Builder) -> (res: io.Stream) {
return io.Stream{stream_vtable=_builder_stream_vtable, stream_data=b} return io.Stream{stream_vtable=_builder_stream_vtable, stream_data=b}
} }
/* /*
@@ -180,10 +187,10 @@ Returns an io.Writer from a Builder
Inputs: Inputs:
- b: A pointer to the Builder - b: A pointer to the Builder
Returns: Returns:
An io.Writer - res: The io.Writer
*/ */
to_writer :: proc(b: ^Builder) -> io.Writer { to_writer :: proc(b: ^Builder) -> (res: io.Writer) {
return io.to_writer(to_stream(b)) return io.to_writer(to_stream(b))
} }
/* /*
@@ -224,7 +231,7 @@ Inputs:
- backing: A slice of bytes to be used as the backing buffer - backing: A slice of bytes to be used as the backing buffer
Returns: Returns:
A new Builder - res: The new Builder
Example: Example:
@@ -245,17 +252,8 @@ Output:
ab ab
*/ */
builder_from_bytes :: proc(backing: []byte) -> Builder { builder_from_bytes :: proc(backing: []byte) -> (res: Builder) {
s := transmute(runtime.Raw_Slice)backing return Builder{ buf = mem.buffer_from_slice(backing) }
d := runtime.Raw_Dynamic_Array{
data = s.data,
len = 0,
cap = s.len,
allocator = runtime.nil_allocator(),
}
return Builder{
buf = transmute([dynamic]byte)d,
}
} }
// Alias to `builder_from_bytes` // Alias to `builder_from_bytes`
builder_from_slice :: builder_from_bytes builder_from_slice :: builder_from_bytes
@@ -266,9 +264,9 @@ Inputs:
- b: A Builder - b: A Builder
Returns: Returns:
The contents of the Builder's buffer, as a string - res: The contents of the Builder's buffer, as a string
*/ */
to_string :: proc(b: Builder) -> string { to_string :: proc(b: Builder) -> (res: string) {
return string(b.buf[:]) return string(b.buf[:])
} }
/* /*
@@ -278,9 +276,9 @@ Inputs:
- b: A Builder - b: A Builder
Returns: Returns:
The length of the Builder's buffer - res: The length of the Builder's buffer
*/ */
builder_len :: proc(b: Builder) -> int { builder_len :: proc(b: Builder) -> (res: int) {
return len(b.buf) return len(b.buf)
} }
/* /*
@@ -290,9 +288,9 @@ Inputs:
- b: A Builder - b: A Builder
Returns: Returns:
The capacity of the Builder's buffer - res: The capacity of the Builder's buffer
*/ */
builder_cap :: proc(b: Builder) -> int { builder_cap :: proc(b: Builder) -> (res: int) {
return cap(b.buf) return cap(b.buf)
} }
/* /*
@@ -302,9 +300,9 @@ Inputs:
- b: A Builder - b: A Builder
Returns: Returns:
The available space left in the Builder's buffer - res: The available space left in the Builder's buffer
*/ */
builder_space :: proc(b: Builder) -> int { builder_space :: proc(b: Builder) -> (res: int) {
return cap(b.buf) - len(b.buf) return cap(b.buf) - len(b.buf)
} }
/* /*
@@ -315,7 +313,7 @@ Inputs:
- x: The byte to be appended - x: The byte to be appended
Returns: Returns:
The number of bytes appended - n: The number of bytes appended
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
@@ -364,7 +362,7 @@ Example:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of bytes appended - n: The number of bytes appended
*/ */
write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) { write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
n0 := len(b.buf) n0 := len(b.buf)
@@ -380,7 +378,8 @@ Inputs:
- r: The rune to be appended - r: The rune to be appended
Returns: Returns:
The number of bytes written and an io.Error (if any) - res: The number of bytes written
- err: An io.Error if one occured, `nil` otherwise
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
@@ -401,7 +400,7 @@ Output:
äb äb
*/ */
write_rune :: proc(b: ^Builder, r: rune) -> (int, io.Error) { write_rune :: proc(b: ^Builder, r: rune) -> (res: int, err: io.Error) {
return io.write_rune(to_writer(b), r) return io.write_rune(to_writer(b), r)
} }
/* /*
@@ -412,7 +411,7 @@ Inputs:
- r: The rune to be appended - r: The rune to be appended
Returns: Returns:
The number of bytes written - n: The number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
@@ -445,7 +444,7 @@ Inputs:
- s: The string to be appended - s: The string to be appended
Returns: Returns:
The number of bytes written - n: The number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
@@ -479,7 +478,7 @@ Inputs:
- b: A pointer to the Builder - b: A pointer to the Builder
Returns: Returns:
The last byte in the Builder or 0 if empty - r: The last byte in the Builder or 0 if empty
*/ */
pop_byte :: proc(b: ^Builder) -> (r: byte) { pop_byte :: proc(b: ^Builder) -> (r: byte) {
if len(b.buf) == 0 { if len(b.buf) == 0 {
@@ -498,7 +497,8 @@ Inputs:
- b: A pointer to the Builder - b: A pointer to the Builder
Returns: Returns:
The popped rune and its rune width or (0, 0) if empty - r: The popped rune
- width: The rune width or 0 if the builder was empty
*/ */
pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) { pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
if len(b.buf) == 0 { if len(b.buf) == 0 {
@@ -519,7 +519,7 @@ Inputs:
- quote: The optional quote character (default is double quotes) - quote: The optional quote character (default is double quotes)
Returns: Returns:
The number of bytes written - n: The number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
@@ -554,7 +554,7 @@ Inputs:
- write_quote: Optional boolean flag to wrap in single-quotes (') (default is true) - write_quote: Optional boolean flag to wrap in single-quotes (') (default is true)
Returns: Returns:
The number of bytes written - n: The number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
@@ -598,7 +598,7 @@ Inputs:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of bytes written - n: The number of bytes written
*/ */
write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) { write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe) n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe)
@@ -618,7 +618,7 @@ Inputs:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of characters written - n: The number of characters written
*/ */
write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) { write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) {
buf: [384]byte buf: [384]byte
@@ -642,7 +642,7 @@ Inputs:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of characters written - n: The number of characters written
*/ */
write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) { write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) {
buf: [384]byte buf: [384]byte
@@ -662,7 +662,7 @@ Inputs:
- always_signed: Optional boolean flag to always include the sign - always_signed: Optional boolean flag to always include the sign
Returns: Returns:
The number of characters written - n: The number of characters written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
@@ -704,7 +704,7 @@ Inputs:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of characters written - n: The number of characters written
*/ */
write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) { write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) {
buf: [384]byte buf: [384]byte
@@ -725,7 +725,7 @@ Inputs:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of characters written - n: The number of characters written
*/ */
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) { write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
buf: [32]byte buf: [32]byte
@@ -743,7 +743,7 @@ Inputs:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of characters written - n: The number of characters written
*/ */
write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) { write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) {
buf: [32]byte buf: [32]byte
@@ -761,7 +761,7 @@ Inputs:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of characters written - n: The number of characters written
*/ */
write_uint :: proc(b: ^Builder, i: uint, base: int = 10) -> (n: int) { write_uint :: proc(b: ^Builder, i: uint, base: int = 10) -> (n: int) {
return write_u64(b, u64(i), base) return write_u64(b, u64(i), base)
@@ -777,7 +777,7 @@ Inputs:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written. NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Returns: Returns:
The number of characters written - n: The number of characters written
*/ */
write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) { write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) {
return write_i64(b, i64(i), base) return write_i64(b, i64(i), base)
+53 -41
View File
@@ -1,6 +1,7 @@
package strings package strings
import "core:io" import "core:io"
import "core:mem"
import "core:unicode" import "core:unicode"
import "core:unicode/utf8" import "core:unicode/utf8"
@@ -17,15 +18,16 @@ Inputs:
WARNING: Allocation does not occur when len(s) == 0 WARNING: Allocation does not occur when len(s) == 0
Returns: Returns:
A valid UTF-8 string with invalid sequences replaced by `replacement`. - res: A valid UTF-8 string with invalid sequences replaced by `replacement`.
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> string { to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
if len(s) == 0 { if len(s) == 0 {
return "" return "", nil
} }
b: Builder b: Builder
builder_init(&b, 0, 0, allocator) builder_init(&b, 0, 0, allocator) or_return
s := s s := s
for c, i in s { for c, i in s {
@@ -70,7 +72,7 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
write_string(&b, s[i:][:w]) write_string(&b, s[i:][:w])
i += w i += w
} }
return to_string(b) return to_string(b), nil
} }
/* /*
Converts the input string `s` to all lowercase characters. Converts the input string `s` to all lowercase characters.
@@ -82,7 +84,8 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
A new string with all characters converted to lowercase. - res: The new string with all characters converted to lowercase
- err: An optional allocator error if one occured, `nil` otherwise
Example: Example:
@@ -98,13 +101,13 @@ Output:
test test
*/ */
to_lower :: proc(s: string, allocator := context.allocator) -> string { to_lower :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
b: Builder b: Builder
builder_init(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator) or_return
for r in s { for r in s {
write_rune(&b, unicode.to_lower(r)) write_rune(&b, unicode.to_lower(r))
} }
return to_string(b) return to_string(b), nil
} }
/* /*
Converts the input string `s` to all uppercase characters. Converts the input string `s` to all uppercase characters.
@@ -116,7 +119,8 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
A new string with all characters converted to uppercase. - res: The new string with all characters converted to uppercase
- err: An optional allocator error if one occured, `nil` otherwise
Example: Example:
@@ -132,13 +136,13 @@ Output:
TEST TEST
*/ */
to_upper :: proc(s: string, allocator := context.allocator) -> string { to_upper :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
b: Builder b: Builder
builder_init(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator) or_return
for r in s { for r in s {
write_rune(&b, unicode.to_upper(r)) write_rune(&b, unicode.to_upper(r))
} }
return to_string(b) return to_string(b), nil
} }
/* /*
Checks if the rune `r` is a delimiter (' ', '-', or '_'). Checks if the rune `r` is a delimiter (' ', '-', or '_').
@@ -147,9 +151,9 @@ Inputs:
- r: Rune to check for delimiter status. - r: Rune to check for delimiter status.
Returns: Returns:
True if `r` is a delimiter, false otherwise. - res: True if `r` is a delimiter, false otherwise.
*/ */
is_delimiter :: proc(r: rune) -> bool { is_delimiter :: proc(r: rune) -> (res: bool) {
return r == '-' || r == '_' || is_space(r) return r == '-' || r == '_' || is_space(r)
} }
/* /*
@@ -159,9 +163,9 @@ Inputs:
- r: Rune to check for separator status. - r: Rune to check for separator status.
Returns: Returns:
True if `r` is a non-alpha or `unicode.is_space` rune. - res: True if `r` is a non-alpha or `unicode.is_space` rune.
*/ */
is_separator :: proc(r: rune) -> bool { is_separator :: proc(r: rune) -> (res: bool) {
if r <= 0x7f { if r <= 0x7f {
switch r { switch r {
case '0' ..= '9': case '0' ..= '9':
@@ -253,13 +257,14 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
A "lowerCamelCase" formatted string. - res: The converted string
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
to_camel_case :: proc(s: string, allocator := context.allocator) -> string { to_camel_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
s := s s := s
s = trim_space(s) s = trim_space(s)
b: Builder b: Builder
builder_init(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator) or_return
w := to_writer(&b) w := to_writer(&b)
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) { string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
@@ -274,7 +279,7 @@ to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
} }
}) })
return to_string(b) return to_string(b), nil
} }
// Alias to `to_pascal_case` // Alias to `to_pascal_case`
to_upper_camel_case :: to_pascal_case to_upper_camel_case :: to_pascal_case
@@ -288,13 +293,14 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
A "PascalCase" formatted string. - res: The converted string
- err: An optional allocator error if one occured, `nil` otherwise
*/ */
to_pascal_case :: proc(s: string, allocator := context.allocator) -> string { to_pascal_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
s := s s := s
s = trim_space(s) s = trim_space(s)
b: Builder b: Builder
builder_init(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator) or_return
w := to_writer(&b) w := to_writer(&b)
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) { string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
@@ -309,7 +315,7 @@ to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
} }
}) })
return to_string(b) return to_string(b), nil
} }
/* /*
Returns a string converted to a delimiter-separated case with configurable casing Returns a string converted to a delimiter-separated case with configurable casing
@@ -323,7 +329,8 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
The converted string - res: The converted string
- err: An optional allocator error if one occured, `nil` otherwise
Example: Example:
@@ -348,11 +355,11 @@ to_delimiter_case :: proc(
delimiter: rune, delimiter: rune,
all_upper_case: bool, all_upper_case: bool,
allocator := context.allocator, allocator := context.allocator,
) -> string { ) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
s := s s := s
s = trim_space(s) s = trim_space(s)
b: Builder b: Builder
builder_init(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator) or_return
w := to_writer(&b) w := to_writer(&b)
adjust_case := unicode.to_upper if all_upper_case else unicode.to_lower adjust_case := unicode.to_upper if all_upper_case else unicode.to_lower
@@ -384,7 +391,7 @@ to_delimiter_case :: proc(
io.write_rune(w, adjust_case(curr)) io.write_rune(w, adjust_case(curr))
} }
return to_string(b) return to_string(b), nil
} }
/* /*
Converts a string to "snake_case" with all runes lowercased Converts a string to "snake_case" with all runes lowercased
@@ -396,7 +403,8 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
The converted string - res: The converted string
- err: An optional allocator error if one occured, `nil` otherwise
Example: Example:
@@ -414,7 +422,7 @@ Output:
hello_world hello_world
*/ */
to_snake_case :: proc(s: string, allocator := context.allocator) -> string { to_snake_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
return to_delimiter_case(s, '_', false, allocator) return to_delimiter_case(s, '_', false, allocator)
} }
// Alias for `to_upper_snake_case` // Alias for `to_upper_snake_case`
@@ -429,7 +437,8 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
The converted string - res: The converted string
- err: An optional allocator error if one occured, `nil` otherwise
Example: Example:
@@ -445,7 +454,7 @@ Output:
HELLO_WORLD HELLO_WORLD
*/ */
to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> string { to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
return to_delimiter_case(s, '_', true, allocator) return to_delimiter_case(s, '_', true, allocator)
} }
/* /*
@@ -458,7 +467,8 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
The converted string - res: The converted string
- err: An optional allocator error if one occured, `nil` otherwise
Example: Example:
@@ -474,7 +484,7 @@ Output:
hello-world hello-world
*/ */
to_kebab_case :: proc(s: string, allocator := context.allocator) -> string { to_kebab_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
return to_delimiter_case(s, '-', false, allocator) return to_delimiter_case(s, '-', false, allocator)
} }
/* /*
@@ -487,7 +497,8 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
The converted string - res: The converted string
- err: An optional allocator error if one occured, `nil` otherwise
Example: Example:
@@ -503,7 +514,7 @@ Output:
HELLO-WORLD HELLO-WORLD
*/ */
to_upper_kebab_case :: proc(s: string, allocator := context.allocator) -> string { to_upper_kebab_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
return to_delimiter_case(s, '-', true, allocator) return to_delimiter_case(s, '-', true, allocator)
} }
/* /*
@@ -516,7 +527,8 @@ Inputs:
- allocator: (default: context.allocator). - allocator: (default: context.allocator).
Returns: Returns:
The converted string - res: The converted string
- err: An optional allocator error if one occured, `nil` otherwise
Example: Example:
@@ -532,11 +544,11 @@ Output:
Hello_World Hello_World
*/ */
to_ada_case :: proc(s: string, allocator := context.allocator) -> string { to_ada_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
s := s s := s
s = trim_space(s) s = trim_space(s)
b: Builder b: Builder
builder_init(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator) or_return
w := to_writer(&b) w := to_writer(&b)
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) { string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
@@ -552,5 +564,5 @@ to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
} }
}) })
return to_string(b) return to_string(b), nil
} }
+13 -5
View File
@@ -1,6 +1,7 @@
package strings package strings
import "core:runtime" import "core:runtime"
import "core:mem"
// Custom string entry struct // Custom string entry struct
Intern_Entry :: struct { Intern_Entry :: struct {
@@ -29,10 +30,14 @@ Inputs:
- m: A pointer to the Intern struct to be initialized - m: A pointer to the Intern struct to be initialized
- allocator: The allocator for the Intern_Entry strings (Default: context.allocator) - allocator: The allocator for the Intern_Entry strings (Default: context.allocator)
- map_allocator: The allocator for the map of entries (Default: context.allocator) - map_allocator: The allocator for the map of entries (Default: context.allocator)
Returns:
- err: An allocator error if one occured, `nil` otherwise
*/ */
intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator) { intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator) -> (err: mem.Allocator_Error) {
m.allocator = allocator m.allocator = allocator
m.entries = make(map[string]^Intern_Entry, 16, map_allocator) m.entries = make(map[string]^Intern_Entry, 16, map_allocator) or_return
return nil
} }
/* /*
Frees the map and all its content allocated using the `.allocator`. Frees the map and all its content allocated using the `.allocator`.
@@ -58,7 +63,8 @@ Inputs:
NOTE: The returned string lives as long as the map entry lives. NOTE: The returned string lives as long as the map entry lives.
Returns: Returns:
The interned string and an allocator error if any - str: The interned string
- err: An allocator error if one occured, `nil` otherwise
*/ */
intern_get :: proc(m: ^Intern, text: string) -> (str: string, err: runtime.Allocator_Error) { intern_get :: proc(m: ^Intern, text: string) -> (str: string, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) or_return entry := _intern_get_entry(m, text) or_return
@@ -76,7 +82,8 @@ Inputs:
NOTE: The returned cstring lives as long as the map entry lives NOTE: The returned cstring lives as long as the map entry lives
Returns: Returns:
The interned cstring and an allocator error if any - str: The interned cstring
- err: An allocator error if one occured, `nil` otherwise
*/ */
intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) { intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) or_return entry := _intern_get_entry(m, text) or_return
@@ -93,7 +100,8 @@ Inputs:
- text: The string to be looked up or interned - text: The string to be looked up or interned
Returns: Returns:
The new or existing interned entry and an allocator error if any - new_entry: The interned cstring
- err: An allocator error if one occured, `nil` otherwise
*/ */
_intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check { _intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check {
if prev, ok := m.entries[text]; ok { if prev, ok := m.entries[text]; ok {
+15 -15
View File
@@ -32,7 +32,7 @@ Inputs:
- r: A pointer to a Reader struct - r: A pointer to a Reader struct
Returns: Returns:
An io.Stream for the given Reader - s: An io.Stream for the given Reader
*/ */
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) { reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
s.stream_data = r s.stream_data = r
@@ -47,9 +47,9 @@ Inputs:
- s: The input string to be read - s: The input string to be read
Returns: Returns:
An io.Reader for the given string - res: An io.Reader for the given string
*/ */
to_reader :: proc(r: ^Reader, s: string) -> io.Reader { to_reader :: proc(r: ^Reader, s: string) -> (res: io.Reader) {
reader_init(r, s) reader_init(r, s)
rr, _ := io.to_reader(reader_to_stream(r)) rr, _ := io.to_reader(reader_to_stream(r))
return rr return rr
@@ -62,9 +62,9 @@ Inputs:
- s: The input string to be read - s: The input string to be read
Returns: Returns:
An `io.Reader_At` for the given string - res: An `io.Reader_At` for the given string
*/ */
to_reader_at :: proc(r: ^Reader, s: string) -> io.Reader_At { to_reader_at :: proc(r: ^Reader, s: string) -> (res: io.Reader_At) {
reader_init(r, s) reader_init(r, s)
rr, _ := io.to_reader_at(reader_to_stream(r)) rr, _ := io.to_reader_at(reader_to_stream(r))
return rr return rr
@@ -76,9 +76,9 @@ Inputs:
- r: A pointer to a Reader struct - r: A pointer to a Reader struct
Returns: Returns:
The remaining length of the Reader - res: The remaining length of the Reader
*/ */
reader_length :: proc(r: ^Reader) -> int { reader_length :: proc(r: ^Reader) -> (res: int) {
if r.i >= i64(len(r.s)) { if r.i >= i64(len(r.s)) {
return 0 return 0
} }
@@ -91,9 +91,9 @@ Inputs:
- r: A pointer to a Reader struct - r: A pointer to a Reader struct
Returns: Returns:
The length of the string stored in the Reader - res: The length of the string stored in the Reader
*/ */
reader_size :: proc(r: ^Reader) -> i64 { reader_size :: proc(r: ^Reader) -> (res: i64) {
return i64(len(r.s)) return i64(len(r.s))
} }
/* /*
@@ -151,7 +151,7 @@ Returns:
- The byte read from the Reader - The byte read from the Reader
- err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success. - err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
*/ */
reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) { reader_read_byte :: proc(r: ^Reader) -> (res: byte, err: io.Error) {
r.prev_rune = -1 r.prev_rune = -1
if r.i >= i64(len(r.s)) { if r.i >= i64(len(r.s)) {
return 0, .EOF return 0, .EOF
@@ -167,9 +167,9 @@ Inputs:
- r: A pointer to a Reader struct - r: A pointer to a Reader struct
Returns: Returns:
An `io.Error` if `r.i <= 0` (`.Invalid_Unread`), otherwise `nil` denotes success. - err: An `io.Error` if `r.i <= 0` (`.Invalid_Unread`), otherwise `nil` denotes success.
*/ */
reader_unread_byte :: proc(r: ^Reader) -> io.Error { reader_unread_byte :: proc(r: ^Reader) -> (err: io.Error) {
if r.i <= 0 { if r.i <= 0 {
return .Invalid_Unread return .Invalid_Unread
} }
@@ -211,9 +211,9 @@ Inputs:
WARNING: May only be used once and after a valid `read_rune` call WARNING: May only be used once and after a valid `read_rune` call
Returns: Returns:
An `io.Error` if an error occurs while unreading (`.Invalid_Unread`), else `nil` denotes success. - err: An `io.Error` if an error occurs while unreading (`.Invalid_Unread`), else `nil` denotes success.
*/ */
reader_unread_rune :: proc(r: ^Reader) -> io.Error { reader_unread_rune :: proc(r: ^Reader) -> (err: io.Error) {
if r.i <= 0 { if r.i <= 0 {
return .Invalid_Unread return .Invalid_Unread
} }
@@ -236,7 +236,7 @@ Returns:
- The absolute offset after seeking - The absolute offset after seeking
- err: An `io.Error` if an error occurs while seeking (`.Invalid_Whence`, `.Invalid_Offset`) - err: An `io.Error` if an error occurs while seeking (`.Invalid_Whence`, `.Invalid_Offset`)
*/ */
reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.Error) { reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (res: i64, err: io.Error) {
r.prev_rune = -1 r.prev_rune = -1
abs: i64 abs: i64
switch whence { switch whence {
+328 -283
View File
File diff suppressed because it is too large Load Diff
+26 -12
View File
@@ -5,6 +5,7 @@ import "core:testing"
import "core:fmt" import "core:fmt"
import "core:os" import "core:os"
import "core:runtime" import "core:runtime"
import "core:mem"
TEST_count := 0 TEST_count := 0
TEST_fail := 0 TEST_fail := 0
@@ -105,33 +106,46 @@ Case_Kind :: enum {
Ada_Case, Ada_Case,
} }
test_cases := [Case_Kind]struct{s: string, p: proc(r: string, allocator: runtime.Allocator) -> string}{ Case_Proc :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error)
test_cases := [Case_Kind]struct{s: string, p: Case_Proc}{
.Lower_Space_Case = {"hellope world", to_lower_space_case}, .Lower_Space_Case = {"hellope world", to_lower_space_case},
.Upper_Space_Case = {"HELLOPE WORLD", to_upper_space_case}, .Upper_Space_Case = {"HELLOPE WORLD", to_upper_space_case},
.Lower_Snake_Case = {"hellope_world", strings.to_snake_case}, .Lower_Snake_Case = {"hellope_world", to_snake_case},
.Upper_Snake_Case = {"HELLOPE_WORLD", strings.to_upper_snake_case}, .Upper_Snake_Case = {"HELLOPE_WORLD", to_upper_snake_case},
.Lower_Kebab_Case = {"hellope-world", strings.to_kebab_case}, .Lower_Kebab_Case = {"hellope-world", to_kebab_case},
.Upper_Kebab_Case = {"HELLOPE-WORLD", strings.to_upper_kebab_case}, .Upper_Kebab_Case = {"HELLOPE-WORLD", to_upper_kebab_case},
.Camel_Case = {"hellopeWorld", strings.to_camel_case}, .Camel_Case = {"hellopeWorld", to_camel_case},
.Pascal_Case = {"HellopeWorld", strings.to_pascal_case}, .Pascal_Case = {"HellopeWorld", to_pascal_case},
.Ada_Case = {"Hellope_World", strings.to_ada_case}, .Ada_Case = {"Hellope_World", to_ada_case},
} }
to_lower_space_case :: proc(r: string, allocator: runtime.Allocator) -> string { to_lower_space_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) {
return strings.to_delimiter_case(r, ' ', false, allocator) return strings.to_delimiter_case(r, ' ', false, allocator)
} }
to_upper_space_case :: proc(r: string, allocator: runtime.Allocator) -> string { to_upper_space_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) {
return strings.to_delimiter_case(r, ' ', true, allocator) return strings.to_delimiter_case(r, ' ', true, allocator)
} }
// NOTE: we have these wrappers as having #optional_allocator_error changes the type to not be equivalent
to_snake_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_snake_case(r, allocator) }
to_upper_snake_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_upper_snake_case(r, allocator) }
to_kebab_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_kebab_case(r, allocator) }
to_upper_kebab_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_upper_kebab_case(r, allocator) }
to_camel_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_camel_case(r, allocator) }
to_pascal_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_pascal_case(r, allocator) }
to_ada_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_ada_case(r, allocator) }
@test @test
test_case_conversion :: proc(t: ^testing.T) { test_case_conversion :: proc(t: ^testing.T) {
for entry in test_cases { for entry in test_cases {
for test_case, case_kind in test_cases { for test_case, case_kind in test_cases {
result := entry.p(test_case.s, context.allocator) result, err := entry.p(test_case.s, context.allocator)
msg := fmt.tprintf("ERROR: We got the allocation error '{}'\n", err)
expect(t, err == nil, msg)
defer delete(result) defer delete(result)
msg := fmt.tprintf("ERROR: Input `{}` to converter {} does not match `{}`, got `{}`.\n", test_case.s, case_kind, entry.s, result) msg = fmt.tprintf("ERROR: Input `{}` to converter {} does not match `{}`, got `{}`.\n", test_case.s, case_kind, entry.s, result)
expect(t, result == entry.s, msg) expect(t, result == entry.s, msg)
} }
} }
@@ -411,7 +411,7 @@ main :: proc() {
// NOTE: this will escape the multiline string. Even with a backslash it still escapes due to the semantics of ` // NOTE: this will escape the multiline string. Even with a backslash it still escapes due to the semantics of `
// I don't think any examples would really need this specific character so let's just make it forbidden and change // I don't think any examples would really need this specific character so let's just make it forbidden and change
// in the future if we really need to // in the future if we really need to
if strings.contains_rune(line, '`') >= 0 { if strings.contains_rune(line, '`') {
fmt.eprintf("The line %q in the output for \"%s.%s\" contains a ` which is not allowed\n", line, test.package_name, test.entity_name) fmt.eprintf("The line %q in the output for \"%s.%s\" contains a ` which is not allowed\n", line, test.package_name, test.entity_name)
g_bad_doc = true g_bad_doc = true
had_line_error = true had_line_error = true