mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-06 10:44:06 +00:00
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:
@@ -42,7 +42,7 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
|
||||
}
|
||||
}
|
||||
case:
|
||||
if strings.contains_rune(field, w.comma) >= 0 {
|
||||
if strings.contains_rune(field, w.comma) {
|
||||
return true
|
||||
}
|
||||
if strings.contains_any(field, CHAR_SET) {
|
||||
|
||||
@@ -38,8 +38,8 @@ Inputs:
|
||||
- c: The char to check for in the Ascii_Set.
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package strings
|
||||
import "core:runtime"
|
||||
import "core:unicode/utf8"
|
||||
import "core:strconv"
|
||||
import "core:mem"
|
||||
import "core:io"
|
||||
/*
|
||||
Type definition for a procedure that flushes a Builder
|
||||
@@ -31,10 +32,11 @@ Inputs:
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
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 {
|
||||
return Builder{buf=make([dynamic]byte, allocator)}
|
||||
builder_make_none :: proc(allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
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
|
||||
@@ -46,10 +48,11 @@ Inputs:
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
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 {
|
||||
return Builder{buf=make([dynamic]byte, len, allocator)}
|
||||
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) or_return }, nil
|
||||
}
|
||||
/*
|
||||
Produces a Builder with a specified length and cap
|
||||
@@ -62,10 +65,11 @@ Inputs:
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
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 {
|
||||
return Builder{buf=make([dynamic]byte, len, cap, allocator)}
|
||||
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) or_return }, nil
|
||||
}
|
||||
// overload simple `builder_make_*` with or without len / cap parameters
|
||||
builder_make :: proc{
|
||||
@@ -84,11 +88,12 @@ Inputs:
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
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 {
|
||||
b.buf = make([dynamic]byte, allocator)
|
||||
return b
|
||||
builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
b.buf = make([dynamic]byte, allocator) or_return
|
||||
return b, nil
|
||||
}
|
||||
/*
|
||||
Initializes a Builder with a specified length and cap, which is max(len,16)
|
||||
@@ -102,11 +107,12 @@ Inputs:
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
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 {
|
||||
b.buf = make([dynamic]byte, len, allocator)
|
||||
return b
|
||||
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) or_return
|
||||
return b, nil
|
||||
}
|
||||
/*
|
||||
Initializes a Builder with a specified length and cap
|
||||
@@ -119,11 +125,12 @@ Inputs:
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
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 {
|
||||
b.buf = make([dynamic]byte, len, cap, allocator)
|
||||
return b
|
||||
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) or_return
|
||||
return b, nil
|
||||
}
|
||||
// Overload simple `builder_init_*` with or without len / ap parameters
|
||||
builder_init :: proc{
|
||||
@@ -169,9 +176,9 @@ Inputs:
|
||||
- b: A pointer to the Builder
|
||||
|
||||
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}
|
||||
}
|
||||
/*
|
||||
@@ -180,10 +187,10 @@ Returns an io.Writer from a Builder
|
||||
Inputs:
|
||||
- b: A pointer to the Builder
|
||||
|
||||
Returns:
|
||||
An io.Writer
|
||||
Returns:
|
||||
- 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))
|
||||
}
|
||||
/*
|
||||
@@ -224,7 +231,7 @@ Inputs:
|
||||
- backing: A slice of bytes to be used as the backing buffer
|
||||
|
||||
Returns:
|
||||
A new Builder
|
||||
- res: The new Builder
|
||||
|
||||
Example:
|
||||
|
||||
@@ -245,17 +252,8 @@ Output:
|
||||
ab
|
||||
|
||||
*/
|
||||
builder_from_bytes :: proc(backing: []byte) -> Builder {
|
||||
s := transmute(runtime.Raw_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,
|
||||
}
|
||||
builder_from_bytes :: proc(backing: []byte) -> (res: Builder) {
|
||||
return Builder{ buf = mem.buffer_from_slice(backing) }
|
||||
}
|
||||
// Alias to `builder_from_bytes`
|
||||
builder_from_slice :: builder_from_bytes
|
||||
@@ -266,9 +264,9 @@ Inputs:
|
||||
- b: A Builder
|
||||
|
||||
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[:])
|
||||
}
|
||||
/*
|
||||
@@ -278,9 +276,9 @@ Inputs:
|
||||
- b: A Builder
|
||||
|
||||
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)
|
||||
}
|
||||
/*
|
||||
@@ -290,9 +288,9 @@ Inputs:
|
||||
- b: A Builder
|
||||
|
||||
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)
|
||||
}
|
||||
/*
|
||||
@@ -302,9 +300,9 @@ Inputs:
|
||||
- b: A Builder
|
||||
|
||||
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)
|
||||
}
|
||||
/*
|
||||
@@ -315,7 +313,7 @@ Inputs:
|
||||
- x: The byte to be appended
|
||||
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Returns:
|
||||
The number of bytes appended
|
||||
- n: The number of bytes appended
|
||||
*/
|
||||
write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
|
||||
n0 := len(b.buf)
|
||||
@@ -380,7 +378,8 @@ Inputs:
|
||||
- r: The rune to be appended
|
||||
|
||||
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.
|
||||
|
||||
@@ -401,7 +400,7 @@ Output:
|
||||
ä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)
|
||||
}
|
||||
/*
|
||||
@@ -412,7 +411,7 @@ Inputs:
|
||||
- r: The rune to be appended
|
||||
|
||||
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.
|
||||
|
||||
@@ -445,7 +444,7 @@ Inputs:
|
||||
- s: The string to be appended
|
||||
|
||||
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.
|
||||
|
||||
@@ -479,7 +478,7 @@ Inputs:
|
||||
- b: A pointer to the Builder
|
||||
|
||||
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) {
|
||||
if len(b.buf) == 0 {
|
||||
@@ -498,7 +497,8 @@ Inputs:
|
||||
- b: A pointer to the Builder
|
||||
|
||||
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) {
|
||||
if len(b.buf) == 0 {
|
||||
@@ -519,7 +519,7 @@ Inputs:
|
||||
- quote: The optional quote character (default is double quotes)
|
||||
|
||||
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.
|
||||
|
||||
@@ -554,7 +554,7 @@ Inputs:
|
||||
- write_quote: Optional boolean flag to wrap in single-quotes (') (default is true)
|
||||
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
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) {
|
||||
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.
|
||||
|
||||
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) {
|
||||
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.
|
||||
|
||||
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) {
|
||||
buf: [384]byte
|
||||
@@ -662,7 +662,7 @@ Inputs:
|
||||
- always_signed: Optional boolean flag to always include the sign
|
||||
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
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) {
|
||||
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.
|
||||
|
||||
Returns:
|
||||
The number of characters written
|
||||
- n: The number of characters written
|
||||
*/
|
||||
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
|
||||
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.
|
||||
|
||||
Returns:
|
||||
The number of characters written
|
||||
- n: The number of characters written
|
||||
*/
|
||||
write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) {
|
||||
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.
|
||||
|
||||
Returns:
|
||||
The number of characters written
|
||||
- n: The number of characters written
|
||||
*/
|
||||
write_uint :: proc(b: ^Builder, i: uint, base: int = 10) -> (n: int) {
|
||||
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.
|
||||
|
||||
Returns:
|
||||
The number of characters written
|
||||
- n: The number of characters written
|
||||
*/
|
||||
write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) {
|
||||
return write_i64(b, i64(i), base)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package strings
|
||||
|
||||
import "core:io"
|
||||
import "core:mem"
|
||||
import "core:unicode"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
@@ -17,15 +18,16 @@ Inputs:
|
||||
WARNING: Allocation does not occur when len(s) == 0
|
||||
|
||||
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 {
|
||||
return ""
|
||||
return "", nil
|
||||
}
|
||||
|
||||
b: Builder
|
||||
builder_init(&b, 0, 0, allocator)
|
||||
builder_init(&b, 0, 0, allocator) or_return
|
||||
|
||||
s := 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])
|
||||
i += w
|
||||
}
|
||||
return to_string(b)
|
||||
return to_string(b), nil
|
||||
}
|
||||
/*
|
||||
Converts the input string `s` to all lowercase characters.
|
||||
@@ -82,7 +84,8 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
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:
|
||||
|
||||
@@ -98,13 +101,13 @@ Output:
|
||||
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
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator) or_return
|
||||
for r in s {
|
||||
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.
|
||||
@@ -116,7 +119,8 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
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:
|
||||
|
||||
@@ -132,13 +136,13 @@ Output:
|
||||
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
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator) or_return
|
||||
for r in s {
|
||||
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 '_').
|
||||
@@ -147,9 +151,9 @@ Inputs:
|
||||
- r: Rune to check for delimiter status.
|
||||
|
||||
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)
|
||||
}
|
||||
/*
|
||||
@@ -159,9 +163,9 @@ Inputs:
|
||||
- r: Rune to check for separator status.
|
||||
|
||||
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 {
|
||||
switch r {
|
||||
case '0' ..= '9':
|
||||
@@ -253,13 +257,14 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
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 = trim_space(s)
|
||||
b: Builder
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator) or_return
|
||||
w := to_writer(&b)
|
||||
|
||||
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`
|
||||
to_upper_camel_case :: to_pascal_case
|
||||
@@ -288,13 +293,14 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
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 = trim_space(s)
|
||||
b: Builder
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator) or_return
|
||||
w := to_writer(&b)
|
||||
|
||||
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
|
||||
@@ -323,7 +329,8 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
Returns:
|
||||
The converted string
|
||||
- res: The converted string
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
|
||||
Example:
|
||||
|
||||
@@ -348,11 +355,11 @@ to_delimiter_case :: proc(
|
||||
delimiter: rune,
|
||||
all_upper_case: bool,
|
||||
allocator := context.allocator,
|
||||
) -> string {
|
||||
) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
s := s
|
||||
s = trim_space(s)
|
||||
b: Builder
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator) or_return
|
||||
w := to_writer(&b)
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
return to_string(b)
|
||||
return to_string(b), nil
|
||||
}
|
||||
/*
|
||||
Converts a string to "snake_case" with all runes lowercased
|
||||
@@ -396,7 +403,8 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
Returns:
|
||||
The converted string
|
||||
- res: The converted string
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
|
||||
Example:
|
||||
|
||||
@@ -414,7 +422,7 @@ Output:
|
||||
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)
|
||||
}
|
||||
// Alias for `to_upper_snake_case`
|
||||
@@ -429,7 +437,8 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
Returns:
|
||||
The converted string
|
||||
- res: The converted string
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
|
||||
Example:
|
||||
|
||||
@@ -445,7 +454,7 @@ Output:
|
||||
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)
|
||||
}
|
||||
/*
|
||||
@@ -458,7 +467,8 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
Returns:
|
||||
The converted string
|
||||
- res: The converted string
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
|
||||
Example:
|
||||
|
||||
@@ -474,7 +484,7 @@ Output:
|
||||
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)
|
||||
}
|
||||
/*
|
||||
@@ -487,7 +497,8 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
Returns:
|
||||
The converted string
|
||||
- res: The converted string
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
|
||||
Example:
|
||||
|
||||
@@ -503,7 +514,7 @@ Output:
|
||||
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)
|
||||
}
|
||||
/*
|
||||
@@ -516,7 +527,8 @@ Inputs:
|
||||
- allocator: (default: context.allocator).
|
||||
|
||||
Returns:
|
||||
The converted string
|
||||
- res: The converted string
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
|
||||
Example:
|
||||
|
||||
@@ -532,11 +544,11 @@ Output:
|
||||
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 = trim_space(s)
|
||||
b: Builder
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator) or_return
|
||||
w := to_writer(&b)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package strings
|
||||
|
||||
import "core:runtime"
|
||||
import "core:mem"
|
||||
|
||||
// Custom string entry struct
|
||||
Intern_Entry :: struct {
|
||||
@@ -29,10 +30,14 @@ Inputs:
|
||||
- m: A pointer to the Intern struct to be initialized
|
||||
- allocator: The allocator for the Intern_Entry strings (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.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`.
|
||||
@@ -58,7 +63,8 @@ Inputs:
|
||||
NOTE: The returned string lives as long as the map entry lives.
|
||||
|
||||
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) {
|
||||
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
|
||||
|
||||
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) {
|
||||
entry := _intern_get_entry(m, text) or_return
|
||||
@@ -93,7 +100,8 @@ Inputs:
|
||||
- text: The string to be looked up or interned
|
||||
|
||||
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 {
|
||||
if prev, ok := m.entries[text]; ok {
|
||||
|
||||
@@ -32,7 +32,7 @@ Inputs:
|
||||
- r: A pointer to a Reader struct
|
||||
|
||||
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) {
|
||||
s.stream_data = r
|
||||
@@ -47,9 +47,9 @@ Inputs:
|
||||
- s: The input string to be read
|
||||
|
||||
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)
|
||||
rr, _ := io.to_reader(reader_to_stream(r))
|
||||
return rr
|
||||
@@ -62,9 +62,9 @@ Inputs:
|
||||
- s: The input string to be read
|
||||
|
||||
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)
|
||||
rr, _ := io.to_reader_at(reader_to_stream(r))
|
||||
return rr
|
||||
@@ -76,9 +76,9 @@ Inputs:
|
||||
- r: A pointer to a Reader struct
|
||||
|
||||
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)) {
|
||||
return 0
|
||||
}
|
||||
@@ -91,9 +91,9 @@ Inputs:
|
||||
- r: A pointer to a Reader struct
|
||||
|
||||
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))
|
||||
}
|
||||
/*
|
||||
@@ -151,7 +151,7 @@ Returns:
|
||||
- The byte read from the Reader
|
||||
- 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
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return 0, .EOF
|
||||
@@ -167,9 +167,9 @@ Inputs:
|
||||
- r: A pointer to a Reader struct
|
||||
|
||||
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 {
|
||||
return .Invalid_Unread
|
||||
}
|
||||
@@ -211,9 +211,9 @@ Inputs:
|
||||
WARNING: May only be used once and after a valid `read_rune` call
|
||||
|
||||
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 {
|
||||
return .Invalid_Unread
|
||||
}
|
||||
@@ -236,7 +236,7 @@ Returns:
|
||||
- The absolute offset after seeking
|
||||
- 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
|
||||
abs: i64
|
||||
switch whence {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ import "core:testing"
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:runtime"
|
||||
import "core:mem"
|
||||
|
||||
TEST_count := 0
|
||||
TEST_fail := 0
|
||||
@@ -105,33 +106,46 @@ Case_Kind :: enum {
|
||||
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},
|
||||
.Upper_Space_Case = {"HELLOPE WORLD", to_upper_space_case},
|
||||
.Lower_Snake_Case = {"hellope_world", strings.to_snake_case},
|
||||
.Upper_Snake_Case = {"HELLOPE_WORLD", strings.to_upper_snake_case},
|
||||
.Lower_Kebab_Case = {"hellope-world", strings.to_kebab_case},
|
||||
.Upper_Kebab_Case = {"HELLOPE-WORLD", strings.to_upper_kebab_case},
|
||||
.Camel_Case = {"hellopeWorld", strings.to_camel_case},
|
||||
.Pascal_Case = {"HellopeWorld", strings.to_pascal_case},
|
||||
.Ada_Case = {"Hellope_World", strings.to_ada_case},
|
||||
.Lower_Snake_Case = {"hellope_world", to_snake_case},
|
||||
.Upper_Snake_Case = {"HELLOPE_WORLD", to_upper_snake_case},
|
||||
.Lower_Kebab_Case = {"hellope-world", to_kebab_case},
|
||||
.Upper_Kebab_Case = {"HELLOPE-WORLD", to_upper_kebab_case},
|
||||
.Camel_Case = {"hellopeWorld", to_camel_case},
|
||||
.Pascal_Case = {"HellopeWorld", to_pascal_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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
// 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_case_conversion :: proc(t: ^testing.T) {
|
||||
for entry 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)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 `
|
||||
// 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
|
||||
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)
|
||||
g_bad_doc = true
|
||||
had_line_error = true
|
||||
|
||||
Reference in New Issue
Block a user