#import "Basic";
Procedures#
Builder#
Prepares builder for use. Called by the other procedures when needed, so you rarely call it. buffer_size
sets the size of the buffers allocated after the first (the default is 4 KiB); the builder takes the
current context allocator. Does nothing when already prepared.
Appends length bytes at s to builder. A negative length is an error and sets the builder to
failed.
Appends the bytes of the value pointer points to, as they are in memory.
The number of bytes appended to builder since it was last reset.
Frees the memory builder took from its allocator and returns it to its empty state, also clearing
the failed state. The builder can be used again afterwards.
Empties builder, freeing its extra memory, so it can be used again.
The text in builder, in a new string; the string is allocated with the context allocator, not the
builder's, and the caller frees it. With do_reset (the default) the builder is emptied afterwards,
otherwise it keeps its text. extra_bytes_to_prepend leaves that many unwritten bytes in front of the text.
A builder that has failed gives an empty string.
Writes the text in builder to standard output, or standard error with to_standard_error, and returns the
number of bytes. With do_reset (the default) the builder is emptied afterwards.
Scalar#
Writes the formatted text to standard output, or standard error when requested. Returns the number of bytes written. Formatting uses the same argument grammar and active print style as the string-builder interface.
The capital for an ASCII lower case letter c; any other byte is returned as it is, so non-ASCII text is
not changed.
The lower case letter for an ASCII capital c; any other byte is returned as it is.
Whether c is an ASCII letter. Bytes of UTF-8 text above 127 are not letters.
Whether c is an ASCII digit, 0 to 9.
Whether c is an ASCII letter or digit, or an underscore: whether it can appear in an identifier.
Whether c is white space: a space, tab, line feed, vertical tab, form feed or carriage return.
Whether c is a printable ASCII character, from the space to ~.
Removes the first amount bytes (one by default) from the string s points to. amount must not be
negative or more than the length of the string, or an assert fails.
Reflection#
Parsing#
Reads a whole number of type T (int by default) in the given base (2 to 36) from the start of t.
value, ok, rest := string_to_int(" -42 apples");
assert(ok && value == -42 && rest == " apples");
hex, hex_ok, _ := string_to_int("ff", 16);
assert(hex_ok && hex == 255);
small, small_ok, _ := string_to_int("300", 10, u8);
assert(!small_ok);↗Reads a decimal int from the start of s, as string_to_int does.
_s without its leading white space.
assert(eat_spaces(" \t word") == "word");↗Reads a number into a float64 from the start of _s: leading white space, an optional sign, then a decimal
number with an optional fraction and exponent (-1.5e3), a hexadecimal one (0x1.8p1), inf,
infinity or nan, in either case. The result is the value, whether a number was read and the text after it.
value, ok, rest := string_to_float64("2.5e2 units");
assert(ok && value == 250 && rest == " units");↗Like string_to_float64, but the value is rounded to a float.
value, ok, rest := string_to_float("1.25");
assert(ok && value == 1.25 && rest.count == 0);↗Like string_to_float64, with the success flag first.
Like string_to_float, with the success flag first.
Allocation#
Gives memory back to the context allocator. memory must come from alloc, New, realloc or another
procedure that allocates with the context allocator, and must not be freed twice. Freeing a null
pointer is up to the allocator; do not rely on it.
A string of count bytes in newly allocated memory, with the context allocator. The bytes are not
cleared, so write all of them before reading. Free it with free. With a count of 0 the string is
empty and may have no data.
s := alloc_string(3);
defer free(s);
memcpy(s.data, "abc".data, 3);
assert(s == "abc");↗A copy of s in newly allocated memory, with the context allocator. Free it with free. Use
copy_temporary_string for a copy that needs no freeing.
original := "text";
copy := copy_string(original);
defer free(copy);
assert(copy == original && copy.data != original.data);↗A string that views length bytes at s, without copying them. Nothing is allocated, so the string
is valid as long as the bytes are.
A copy of s in newly allocated memory, followed by a zero byte, for passing to C. It is allocated with
the context allocator; free it with free. A zero byte inside s ends the string for the C side.
c := to_c_string("abc");
defer free(c);
assert(c[3] == 0 && to_string(c, 3) == "abc");↗Allocates a T with context.allocator and returns a pointer to it.
Allocates count elements of T with context.allocator.
Preamble#
Leak reports#
Memory debugger#
Visualization#
Format#
Appends text to builder as format_string describes, and returns whether it worked. Each % takes
the next of args and writes it in its default form; %1, %2, ... pick an argument by position.
A format with too few arguments logs an error. Returns false if the builder ran out of memory.
builder: String_Builder;
print_to_builder(*builder, "% + % = %", 1, 2, 3);
result := builder_to_string(*builder);
defer free(result);
assert(result == "1 + 2 = 3");↗The text format_string makes with args, in a new string. See print_to_builder for the format. When
the formatting fails the result is an empty string and an error has been logged. It is allocated
with the context allocator and the caller frees it with free. Use tprint to avoid freeing.
Like sprint, but the string is in temporary storage. It must not be freed; it lasts until the temporary
storage is reset.
assert(tprint("%-%", 1, 2) == "1-2");
reset_temporary_storage();↗Writes the byte _c to standard output.
Format types#
Wraps a float for print so it comes out with a chosen width, number of decimals or notation.
assert(tprint("%", formatFloat(3.14159, trailing_width = 2)) == "3.14");↗Wraps a struct for print with its own layout instead of the default one.
Format integer#
Wraps an integer for print so it comes out in another base, padded, or grouped.
Format float#
Format aggregate#
Format type names#
Stream helpers#
Logging#
Formats a message as print would and hands it to context.logger.
Stack traces#
Integer128#
Apollo#
Scale the binary significand exactly before truncating sub-femtosecond bits. This avoids overflowing an s64 intermediate for large finite durations.
Calendar text#
Elapsed time#
Clock calendar#
Breaks at into year, month, day and time of day.
Filetime#
Converts a Windows FILETIME (100 ns ticks since 1601) to an Apollo_Time. Windows only. Every FILETIME is
representable.
Converts an Apollo_Time to a Windows FILETIME, with false and a zero value when the time lies before 1601 or beyond
what a FILETIME can hold. Windows only. Times are cut to a multiple of 100 ns.
Temporary#
A string of count bytes in temporary storage. It must not be freed; it lasts until the temporary storage
is reset. The bytes are not cleared.
A copy of s in temporary storage. It must not be freed; it lasts until the temporary storage is
reset.
copy := copy_temporary_string("scratch");
assert(copy == "scratch");
reset_temporary_storage();↗A copy of s in temporary storage followed by a zero byte, for passing to C. It must not be freed; it lasts
until the temporary storage is reset.
Filesystem#
The current working directory of the program, as an absolute path in a new string from context.allocator that the caller frees.
original := get_working_directory();
defer free(original);
assert(original.count > 0);
assert(set_working_directory("."));
same := get_working_directory();
assert(same == original);
free(same);↗Makes s the working directory of the whole program, for every thread, and returns whether it worked. A missing path, a
file, a directory without permission to enter, an empty path and a path with a NUL byte give false and change nothing.
assert(!set_working_directory("jai-doc-no-such-directory/inner"));↗Arguments#
Arrays#
Makes room for at least desired_items elements without changing the count.
values: [..] int;
array_reserve(*values, 100);
assert(values.count == 0 && values.allocated >= 100);
data := values.data;
for 0..99 array_add(*values, it);
assert(values.data == data); // no growth, so nothing moved
array_free(values);↗Appends an element to a dynamic array and returns a pointer to it.
values: [..] int;
array_add(*values, 10);
array_add(*values, 20, 30);
slot := array_add(*values); // a zeroed element, here at the end
slot.* = 40;
assert(values.count == 4 && values[0] == 10 && values[3] == 40);
array_free(values);↗Searches for item; returns whether it was found and the index of its first occurrence, or -1.
values := int.[5, 8, 5, 13];
found, index := array_find(values, 5);
assert(found && index == 0);
found, index = array_find(values, 6);
assert(!found && index == -1);
same_half :: (a: int, b: int) -> bool { return a / 2 == b / 2; }
found, index = array_find(values, 9, same_half); // 8 and 9 share a half
assert(found && index == 1);↗Appends item unless the array already holds an equal element.
values: [..] string;
added, index := array_add_if_unique(*values, "red");
assert(added && index == 0);
added, index = array_add_if_unique(*values, "blue");
assert(added && index == 1);
added, index = array_add_if_unique(*values, "red");
assert(!added && index == 0 && values.count == 2);
array_free(values);↗A view of the elements of array from index on, or of count of them from index.
values := int.[1, 2, 3, 4, 5];
middle := array_view(values, 1, 3);
assert(middle.count == 3 && middle[0] == 2);
tail := array_view(values, 3);
assert(tail.count == 2 && tail[1] == 5);
middle[0] = 20; // writes into `values`
assert(values[1] == 20);
assert(array_view(values, 9).count == 0);↗Inserts item so that it ends up at index, shifting the elements from there on up by one.
list: [..] int;
array_add(*list, 1, 2, 4);
array_insert_at(*list, 3, 2);
assert(list.count == 4 && list[2] == 3 && list[3] == 4);
array_free(list);↗Removes the element at index and shifts the later ones down, keeping their order.
values: [..] int;
array_add(*values, 1, 2, 3, 4);
array_ordered_remove_by_index(*values, 1);
assert(values.count == 3 && values[1] == 3 && values[2] == 4);
array_free(values);↗Removes the element at index by moving the last element into its place, in constant time.
values: [..] int;
array_add(*values, 1, 2, 3, 4);
array_unordered_remove_by_index(*values, 0);
assert(values.count == 3 && values[0] == 4 && values[1] == 2);
array_free(values);↗Removes the first element equal to item (by ==), keeping the order of the rest.
values: [..] int;
array_add(*values, 7, 8, 7);
assert(array_ordered_remove_by_value(*values, 7));
assert(values.count == 2 && values[0] == 8 && values[1] == 7);
assert(!array_ordered_remove_by_value(*values, 99));
array_free(values);↗Removes every element equal to item, each by moving the last element into its place; returns how many were removed.
values: [..] int;
array_add(*values, 1, 2, 1, 3, 1);
removed := array_unordered_remove_by_value(*values, 1);
assert(removed == 3 && values.count == 2);
once := array_unordered_remove_by_value(*values, 2, stop_after_first = true);
assert(once == 1 && values.count == 1 && values[0] == 3);
array_free(values);↗A pointer to the last element, which stays valid until the array is changed. Fails an assert when the array is empty.
The last element of the array, without removing it. Fails an assert when the array is empty.
values := int.[3, 6, 9];
assert(peek(values) == 9);
peek_pointer(values).* = 10;
assert(values[2] == 10);↗Removes the last element and returns it. Fails an assert when the array is empty.
values: [..] int;
array_add(*values, 1, 2, 3);
assert(pop(*values) == 3 && pop(*values) == 2);
assert(values.count == 1);
array_free(values);↗Empties the array but keeps its storage, so refilling it up to the old capacity allocates nothing.
values: [..] int;
array_add(*values, 1, 2, 3);
capacity := values.allocated;
array_reset_keeping_memory(*values);
assert(values.count == 0 && values.allocated == capacity);
array_free(values);↗Frees the storage of an array. A view is freed with free, i.e. through context.allocator; a dynamic
array goes back to the allocator it grew with.
values: [..] int;
array_add(*values, 1, 2, 3);
array_free(values);
values = .{};↗Frees the storage of an array (as array_free does) and sets the array to empty, so it can be reused.
values: [..] int;
array_add(*values, 1, 2, 3);
array_reset(*values);
assert(values.count == 0 && values.data == null);↗Sets the count of an array to new_count, growing the storage if needed.
values: [..] int;
array_resize(*values, 4);
assert(values.count == 4 && values[3] == 0);
array_resize(*values, 2);
assert(values.count == 2);
array_free(values);↗A new array holding a copy of the elements, in memory from context.allocator.
original := int.[1, 2, 3];
copy := array_copy(original);
copy[0] = 100;
assert(original[0] == 1 && copy.count == 3);
array_free(copy);
list: [..] int;
array_copy(*list, original);
assert(list.count == 3 && list[2] == 3);
array_free(list);↗Types#
Constants#
The room, in bytes, a String_Builder has inside it and the default size of each buffer it adds later.