Contents


docs.std

std.core

std.core.convert
read
convert

std.core.err
assert_ok
print
fail
assert

std.core.num
ok
print
printin
le
ge
lt
gt
leq
geq
eq
neq
not
exists
xor
bits
lshift
rshift
add
mod
sub
mul
div
negative

std.core.range
range
next

std.core.str
next
print
CString
String
IndependentString
is
str
printin
nstr
eq
neq
slice
strip
len
at
Split
key
getch
is_enter
is_left
is_right
is_up
is_down
is_tab
is_delete
is_backspace
is_char
to_char
is_printable

std.file
open
next_line
to_end
next_chunk
ReadFile
WriteFile
File
print
to_start
temp
len
ended
is_file
is_dir
remove_file
create_dir
console

std.map
hash
to_hash_base
StringHash
NumberHash
Hash
is_zero
find
at

std.math
cos
acos
sin
asin
exp
pi
tan
atan
atan2
is_nan
is_inf
sqrt
pow
log

std.mem

std.mem.arena
read
Arena
Circular
clear
Buffer
Dynamic
is
dynamic
allocate
used
Memory
arena
circular
len

std.mem.device
Stack
Heap
MemoryDevice
MB
KB
ContiguousMemory
allocate
__device_file_end

std.mem.grid

std.mem.str
copy
str
nstr
add

std.os
Process
open
to_end
next_chunk
next_line
system

std.rand
__rotl
splitmix64
Rand
next

std.time
sleep
exact_sleep
time

std.vec
Vec
vector
print
dot
put
slice
add
len
sub
mul
at
div

docs.std 🔝

This the documentation of smoλ's standard library. It is automatically kept up to date by periodically running the following command. That pulls from code annotations and overloaded implementations.
./smol docs/std.s --task doc
You may notice that lot of dependencies are marked as unsafe; this is not worrying but only indicates that extra trust should be placed on both the person writing the implementations because some of the language's safety features are turned off to bring to you low-level functionality.

The following functionality that is ready to use without -or with minimal- external dependencies. It is organized into top-level files residing directly under std/ and files under its subfolder. Do not import the latter by themselves to safe development speed. As a final remark, overloaded implementations are split per the file declaring them; foreign imports are not shown.

@mut indicates mutability. If this is absent, the language promises to not modify values - the standard library promises to respect that too when considering whether it is allowed to modify pointer contents.

@access indicates that arguments can view mutable fields, though not necessarily edit them. This marking also imports the function together with those that could result to arguments from the same import file. For example, the following snippet imports all numeric but not string operations from the standard library's core:
@import std.core -> Number

std.core 🔝

Contains basic numeric functionalities and string types.

std.core.convert unsafe 🔝

Standard library wrapping and simplification of C console commands.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

read 🔝

Reads several string and primitive types from the console. The user needs to press enter after entering the input. Invalid inputs create service failures, including in the case where the number is too large to properly process. Example:

printin("Give a number.")
x = f64.read
printin("Rounded.")
print(i64(x+0.5))

read(@access i64) → i64
read(@access u64) → u64
read(@access f64) → f64

convert 🔝

Converts a String representation to various numeric formats. This is lightweight and does not consume additional memory. The current service fails if the conversion is not possible. Example:

x = f64.convert("1.2")
print(x+1) // prints `2.2`

convert(@access i64,cstr _s) → i64
convert(@access i64,nstr _s) → i64
convert(@access i64,str _s) → i64
convert(@access u64,cstr _s) → u64
convert(@access u64,nstr _s) → u64
convert(@access u64,str _s) → u64
convert(@access f64,cstr _s) → f64
convert(@access f64,nstr _s) → f64
convert(@access f64,str _s) → f64

std.core.err unsafe 🔝

Standard library implementations of error utilities.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

assert_ok 🔝

Checks if an error code corresponds to no error. If it does not, the service fails while printing the type of error. Error codes can be user errors, buffer errors, unknown errors, or no errors.

assert_ok(errcode error) → ()

assert 🔝

assert(bool condition,cstr error) → ()

print 🔝

Prints a string interpretation of an error code.

print(errcode error) → ()

fail 🔝

Causes the current service to fail given a String message. This creates a user error code. Example:

printin("Give a number.")
x = i64.read()
if x==0.0
    return fail("Cannot compute the inverse of zero")
printin("Its inverse is.")
print(1.0/x)

fail(cstr error) → ()
fail(nstr error) → ()
fail(str error) → ()

std.core.num unsafe 🔝

Standard library wrapping of C basic arithmetics and printing.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

ok 🔝

ok() → ()

not 🔝

Negation of a boolean. There is no equivalent operator, currying notation should be used for manipulating single values. Here is a simple example, though this is often used in conditional statements.

print(true.not())

not(@access bool x) → bool

exists 🔝

Checks if a pointer is non-null. Pointer access and manipulation is inherently unsafe and you should not encounter that in normal code writing. For those aiming to extend the standard library or who dabble with inherently unsafe use cases, this can be used to check for memory allocation failures and trigger a service failure to safely collapse the current execution state.

exists(@access ptr x) → bool

xor 🔝

xor(@access u64 x,u64 y) → u64

bits 🔝

bits(@access f64 x) → u64

print 🔝

Prints a primitive number, character, or boolean to the console.

print(@access f64 message) → ()
print(@access i64 message) → ()
print(@access u64 message) → ()
print(@access bool message) → ()
print(@access char message) → ()
print() → ()

printin 🔝

Prints a primitive number, character, or boolean to the console without changing line.

printin(@access f64 message) → ()
printin(@access i64 message) → ()
printin(@access u64 message) → ()
printin(@access bool message) → ()
printin(@access char message) → ()

le 🔝

Checks if the first number is less than or equal to the second and overloads the corresponding operator. Only the same number types can be compared, and explicit casts are required otherwise. Example demonstrating the need to use an f64 zero (0.0 and not 0) to compare with another read value of the same type:

x = f64.read()
if x<0.0
    return print("negative")
else
    return print("non-negative")

le(@access u64 x,u64 y) → bool
le(@access f64 x,f64 y) → bool
le(@access i64 x,i64 y) → bool

ge 🔝

Checks if the first number is greater than or equal to the second and overloads the corresponding operator. Only the same number types can be compared, and explicit casts are required otherwise. Example demonstrating the need to use an f64 zero (0.0 and not 0) to compare with another read value of the same type:

x = f64.read()
if x>0.0
    return print("positive")
else
    return print("non-positive")

ge(@access u64 x,u64 y) → bool
ge(@access f64 x,f64 y) → bool
ge(@access i64 x,i64 y) → bool

lt 🔝

Checks if the first number is less than the second and overloads the corresponding operator. Example:

print(1>=2)

lt(@access u64 x,u64 y) → bool
lt(@access f64 x,f64 y) → bool
lt(@access i64 x,i64 y) → bool

gt 🔝

Checks if the first number is greater than the second and overloads the corresponding operator. Example:

print(1>=2)

gt(@access u64 x,u64 y) → bool
gt(@access f64 x,f64 y) → bool
gt(@access i64 x,i64 y) → bool

leq 🔝

Checks if the first number is less than or equal to the second.

leq(@access u64 x,u64 y) → bool
leq(@access f64 x,f64 y) → bool
leq(@access i64 x,i64 y) → bool

geq 🔝

Checks if the first number is greater than or equal to the second.

geq(@access u64 x,u64 y) → bool
geq(@access f64 x,f64 y) → bool
geq(@access i64 x,i64 y) → bool

eq 🔝

Checks if two primitives are equal and overloads the corresponding operator. Equality can be checked for all primitives, and is also defined for other types in the standard library, such as strings. Example:

print(1==2)

eq(@access u64 x,u64 y) → bool
eq(@access f64 x,f64 y) → bool
eq(@access i64 x,i64 y) → bool
eq(@access ptr x,ptr y) → bool
eq(@access bool x,bool y) → bool
eq(@access tag x,tag y) → bool

neq 🔝

Checks if two primitives are not equal and overloads the corresponding operator. Non-equality can be checked for all primitives, and is also defined for other types in the standard library, such as strings. Example:

print(1!=2)

neq(@access u64 x,u64 y) → bool
neq(@access f64 x,f64 y) → bool
neq(@access i64 x,i64 y) → bool
neq(@access ptr x,ptr y) → bool
neq(@access bool x,bool y) → bool
neq(@access tag x,tag y) → bool

lshift 🔝

Performs a left shift on a signed or unsigned integer given an unsigned number of shifted bits. Example:

print(1.lshift(2))

lshift(@access u64 x,u64 y) → u64
lshift(@access i64 x,u64 y) → i64

rshift 🔝

Performs a right shift on a signed or unsigned integer given an unsigned number of shifted bits. Example:

print(8.rshift(2))

rshift(@access u64 x,u64 y) → u64
rshift(@access i64 x,u64 y) → i64

add 🔝

Addition of two numbers of the same type and overloads the corresponding operator. Example:

print(1+2)

add(@access u64 x,u64 y) → u64
add(@access i64 x,i64 y) → i64
add(@access f64 x,f64 y) → f64

mod 🔝

Modulo operation for signed or unsigned integers. For i64, only positive divisors are allowed. Fails on zero divisor. Overloads the corresponding operator. Example:

print(1%2)

mod(@access u64 x,u64 y) → u64
mod(@access i64 x,i64 y) → i64

sub 🔝

Subtraction of two numbers of the same type: Doing so for u64 will create a service failure if the result would be negative. Overloads the corresponding operator for numbers. Example that FAILS because the default integer type is u64. Example:

print(1-2)

sub(@access u64 x,u64 y) → u64
sub(@access i64 x,i64 y) → i64
sub(@access f64 x,f64 y) → f64

mul 🔝

Multiplication of two numbers of the same type and overloads the corresponding operator. Example:

print(3*2)

mul(@access u64 x,u64 y) → u64
mul(@access i64 x,i64 y) → i64
mul(@access f64 x,f64 y) → f64

div 🔝

Division of two numbers of the same type: Division by zero for i64 or u64 creates a service failure, but for f64 it yields NaN. Overloads the corresponding operator. Here is an example that yields zero by performing integer division.

print(1/2)

div(@access u64 x,u64 y) → u64
div(@access i64 x,i64 y) → i64
div(@access f64 x,f64 y) → f64

negative 🔝

Returns the additive inverse (negation) of an i64 or f64. Does NOT overload any operation. Having u64 as the default type helps avoid many spurious negation errors, especially when memory handling is concerned.

Both examples below print -1. Example:

print(0.i64()-1.i64())
print(1.i64)_.negative())

negative(@access i64 x) → i64
negative(@access f64 x) → f64

std.core.range 🔝

Standard library implementation of u64 ranges.

next 🔝

Obtains the next element in the range. Using a combination of a range and next element traversal is safer than manually checking bounds.

Below is the main usage pattern. Notice that next's argument is an in-place constructed u64 number that is mutable to obtain the next value. The function sets the next value, progresses the range's state, and returns whether the iteration ended. The first retrieved value is the starting element of the range. Example:

range(10)
.while next(@mut u64 i)
    then print(i)

next(@mut u64 self.start,@mut u64 self.sup,@mut u64 self.step,@mut u64 self.pos,@mut u64 value) → bool

range 🔝

Defines a u64 range as a structural type (instead of new type). When directly using variables as ranges, the position should be mutable. A couple of calling conventions are provided for default values of 0 for start and 1 for step.

range(u64 start,u64 sup,u64 step) → (u64 start,u64 sup,u64 step,@mut u64 pos)
range(u64 start,u64 sup) → range(u64 start,u64 sup,u64 step)
range(u64 sup) → range(u64 start,u64 sup,u64 step)

std.core.str unsafe 🔝

Standard library implementation of the extensible string model based on C pointers and an implementation for const char arrays.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

next 🔝

Retrieves the next element over a Split string iteration. Example:

Split("I like bananas", " ")
.while next(@mut str word)
    then print(word)

next(@mut Split self,@mut str value) → bool

key 🔝

Represents a keyboard key input captured through getch. Encodes the key's integer representation in data.

key(new,i64 data) → (new,i64 data)

getch 🔝

Retrieves a character from the terminal without printing it. The result is a character encoded in i64 format. This is not stored as a char due to extra symbols, but can be converted to an one-byte character. Example:

s = getch()
if s.is_char()
    print(s.to_char())

getch() → key

is_enter 🔝

Checks if a captured key represents the enter key.

is_enter(key input) → bool

is_left 🔝

Checks if a captured key represents the left arrow key.

is_left(key input) → bool

is_right 🔝

Checks if a captured key represents the right arrow key.

is_right(key input) → bool

is_up 🔝

Checks if a captured key represents the up arrow key.

is_up(key input) → bool

is_down 🔝

Checks if a captured key represents the down arrow key.

is_down(key input) → bool

is_tab 🔝

Checks if a captured key represents the tab key.

is_tab(key input) → bool

is_delete 🔝

Checks if a captured key represents the delete key.

is_delete(key input) → bool

is_backspace 🔝

Checks if a captured key represents the backspace key.

is_backspace(key input) → bool

is_char 🔝

Checks if a key press corresponds to a printable ASCII character.

is_char(key input) → bool

to_char 🔝

Converts a key object representing a printable ASCII character to its char value. Fails if the key is not a character.

to_char(key input) → char

is_printable 🔝

Checks if a captured key represents a printable ASCII character.

is_printable(key input) → bool

print 🔝

Prints strings or bools to the console.

print(@access cstr message) → ()
print(nstr message) → ()
print(str message) → ()
print(str[] messages.dynamic) → ()

CString 🔝

A union between nstr and constant strings cstr.

Main usage is to abstract an argument's type by converting it to nstr. The conversion is a zero cost abstraction in that needless operations will be removed. But it still augments constant strings with length and first element inform if these are needed. Example:

def foo(CString _s)
    s = _s.nstr()
    ...

nstr(new,ptr contents,u64 length,char first,ptr memory) → (new,ptr contents,u64 length,char first,ptr memory)

String 🔝

A union between str, nstr, and constant strings cstr. Constant strings are those that generated by default when enclosing some text in quotients and are stored in the program memory.

Main usage is to abstract an argument's type by converting it to str. The conversion is a zero cost abstraction in that needless operations will be removed. But it still augments constant strings with length and first element inform if these are needed. Example:

def foo(String _s)
    s = _s.str()
    ...

nstr(new,ptr contents,u64 length,char first,ptr memory) → (new,ptr contents,u64 length,char first,ptr memory)
str(new,ptr contents,u64 length,char first,ptr memory) → (new,ptr contents,u64 length,char first,ptr memory)

IndependentString 🔝

A copy of the String union that can be used when a second argument is needed for a string of a potentially different variation.

nstr(new,ptr contents,u64 length,char first,ptr memory) → (new,ptr contents,u64 length,char first,ptr memory)
str(new,ptr contents,u64 length,char first,ptr memory) → (new,ptr contents,u64 length,char first,ptr memory)

is 🔝

Compile-time check of a String exact type matching compared to an arbitrary type.
Example:

def foo(String s)
    case s.is(str)
        ...
    case s.is(cstr)
        ...
    qed

is(@access cstr self,cstr) → cstr
is(nstr self,nstr) → nstr
is(str self,str) → str

str 🔝

A memory allocated string and converters from constant strings and booleans to the type. Other standard library implementations provide more converters.

str(new,ptr contents,u64 length,char first,ptr memory) → (new,ptr contents,u64 length,char first,ptr memory)
str(nstr other) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@access cstr raw) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@access bool value) → str(new,ptr contents,u64 length,char first,ptr memory)

printin 🔝

Prints strings or bools to the console without evoking a new line at the end.

printin(@access cstr message) → ()
printin(nstr message) → ()
printin(str message) → ()

nstr 🔝

A null-terminated variation of str. Many operation produce this string version, as it can be readily converted to str at no cost (for the inverse, you need to copy the string)

nstr(new,ptr contents,u64 length,char first,ptr memory) → (new,ptr contents,u64 length,char first,ptr memory)
nstr(@access cstr raw) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@access bool value) → nstr(new,ptr contents,u64 length,char first,ptr memory)

eq 🔝

Checks for equality between String types when considering their contents. Implementation of this operation varies, ensuring that the cached first element of strings (not available for cstr) is compared first and then the lengths are taken into account to compare memory bytes. Example:

if "me"=="me"
    return print("me!")

eq(@access char x,char y) → bool
eq(@access cstr _x,cstr _y) → bool
eq(nstr _x,cstr _y) → bool
eq(str _x,cstr _y) → bool
eq(@access cstr _x,nstr _y) → bool
eq(nstr _x,nstr _y) → bool
eq(str _x,nstr _y) → bool
eq(@access cstr _x,str _y) → bool
eq(nstr _x,str _y) → bool
eq(str _x,str _y) → bool

neq 🔝

Equivalent to logical inversion of String eq. It is faster to write and run. Example:

if "to be"!="not to be"
    return print("dobedobedoo!")

neq(@access char x,char y) → bool
neq(@access cstr _x,cstr _y) → bool
neq(nstr _x,cstr _y) → bool
neq(str _x,cstr _y) → bool
neq(@access cstr _x,nstr _y) → bool
neq(nstr _x,nstr _y) → bool
neq(str _x,nstr _y) → bool
neq(@access cstr _x,str _y) → bool
neq(nstr _x,str _y) → bool
neq(str _x,str _y) → bool

slice 🔝

Obtains a substring slice out of a String, producing a str result. Null termination cannot be guaranteed for most results - and is dropped even in cases it could be guaranteed to reduce checks. This overloads the slicing operator. Example:

s = "I like bananas!"
print(s[7 upto 14]) // prints `bananas`
print(s[7 to 14])   // prints `banana`

slice(@access cstr self,u64 from,u64 to) → str
slice(nstr self,u64 from,u64 to) → str
slice(str self,u64 from,u64 to) → str
slice(@access cstr self,u64 from) → str
slice(nstr self,u64 from) → str
slice(str self,u64 from) → str

strip 🔝

Removes leading and trailing whitespace characters from a String, including spaces, tabs, carriage returns, and newlines. Returns a substring without allocating new memory. Example:

print("  hi!	".strip()) // prints `hi!`

strip(@access cstr _s) → str
strip(nstr _s) → str
strip(str _s) → str

len 🔝

Returns the length of a string. Works for str, nstr, and cstr. Example:

print(len("banana")) // prints 6

len(str x) → u64
len(nstr x) → u64
len(@access cstr x) → u64

at 🔝

Retrieves a character from a string at a given position. Fails if the position is out of bounds. Example:

print("abc".at(1)) // prints `b`

at(str x,u64 pos) → char
at(nstr x,u64 pos) → char

Split 🔝

An iterator structure that splits a String by a separator. The split is lazy and does not allocate memory, returning slices of the original string. Use next to retrieve each part.

Split(new,str query,str sep,@mut u64 pos) → (new,str query,str sep,@mut u64 pos)
Split(@access cstr _query,@access cstr _sep) → Split(new,str query,str sep,@mut u64 pos)
Split(nstr _query,@access cstr _sep) → Split(new,str query,str sep,@mut u64 pos)
Split(str _query,@access cstr _sep) → Split(new,str query,str sep,@mut u64 pos)
Split(@access cstr _query,nstr _sep) → Split(new,str query,str sep,@mut u64 pos)
Split(nstr _query,nstr _sep) → Split(new,str query,str sep,@mut u64 pos)
Split(str _query,nstr _sep) → Split(new,str query,str sep,@mut u64 pos)
Split(@access cstr _query,str _sep) → Split(new,str query,str sep,@mut u64 pos)
Split(nstr _query,str _sep) → Split(new,str query,str sep,@mut u64 pos)
Split(str _query,str _sep) → Split(new,str query,str sep,@mut u64 pos)

std.file unsafe 🔝

Standard library implementation of file management that uses the C filesystem.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

to_end 🔝

Go to the end of a WriteFile. This is not implemented for ReadFile, as it makes more sense to just close the latter. Returns a boolean indicating a successful operation.

to_end(@mut WriteFile f) → bool

ReadFile 🔝

An opened file that is meant to be read only.

ReadFile(new,ptr contents) → (new,ptr contents)

WriteFile 🔝

An opened file that is meant to be read or written.

WriteFile(new,ptr contents) → (new,ptr contents)

console 🔝

console(@mut WriteFile) → (WriteFile)

open 🔝

Opens a File given a String path. There might be service failure due to external factors. Opening a WriteFile, may also cause failure if it already exists - in that case remove it first and it will be created. On the other hand, a ReadFile must already exist to be opened. Files must be set as mutable variables to allow reads and writes. Otherwise, only a few operations become available. Example for overwriting a file:

if is_file("hi.txt")
    then remove_file("hi.txt")
@mut file = WriteFile.open("tmp.txt")
file:print("Hello world!")
@release file // early release closes the file

open(@mut ReadFile,cstr _path) → ReadFile
open(@mut ReadFile,nstr _path) → ReadFile
open(@mut ReadFile,str _path) → ReadFile
open(@mut WriteFile,cstr _path) → WriteFile
open(@mut WriteFile,nstr _path) → WriteFile
open(@mut WriteFile,str _path) → WriteFile

next_line 🔝

Reads the next line of a file while using it as an iterator. It accommodates Arena, Circular, and Volatile memories. Here is an example where volatile memory is used to avoid repeated or large allocations:

endl="n".str().first // optimized to just setting the new line character
@on Heap:volatile(1024)
ReadFile("README.md")
.open("README.md")
.while next_line(@mut str line)
    if line[line:len-1]==endl
         then line = line[0 to line:len-1]
    then print(line)

next_line(@mut Circular reader,@mut ReadFile f,@mut nstr value) → bool
next_line(@mut Circular reader,@mut WriteFile f,@mut nstr value) → bool
next_line(@mut Arena reader,@mut ReadFile f,@mut nstr value) → bool
next_line(@mut Arena reader,@mut WriteFile f,@mut nstr value) → bool
next_line(@mut Arena reader,@mut ReadFile f,@mut str value) → bool
next_line(@mut Circular reader,@mut ReadFile f,@mut str value) → bool
next_line(@mut Arena reader,@mut WriteFile f,@mut str value) → bool
next_line(@mut Circular reader,@mut WriteFile f,@mut str value) → bool

next_chunk 🔝

Reads the next chunk of a file while using it as an iterator. It accommodates Arena, Circular, and Volatile memories. Here is an example where volatile memory is used to avoid repeated or large allocations:

@on Heap:volatile(1024)
ReadFile
.open("README.md")
.while next_chunk(@mut str chunk)
    then print(chunk)

next_chunk(@mut Circular reader,@mut ReadFile f,@mut nstr value) → bool
next_chunk(@mut Circular reader,@mut WriteFile f,@mut nstr value) → bool
next_chunk(@mut Arena reader,@mut ReadFile f,@mut nstr value) → bool
next_chunk(@mut Arena reader,@mut WriteFile f,@mut nstr value) → bool
next_chunk(@mut Arena reader,@mut ReadFile f,@mut str value) → bool
next_chunk(@mut Circular reader,@mut ReadFile f,@mut str value) → bool
next_chunk(@mut Arena reader,@mut WriteFile f,@mut str value) → bool
next_chunk(@mut Circular reader,@mut WriteFile f,@mut str value) → bool

File 🔝

A union between file types that allows common reading and positioning operations.

ReadFile(new,ptr contents) → (new,ptr contents)
WriteFile(new,ptr contents) → (new,ptr contents)

print 🔝

Writes a string on a WriteFile.

print(@mut WriteFile f,cstr _s) → ()
print(@mut WriteFile f,nstr _s) → ()
print(@mut WriteFile f,str _s) → ()

to_start 🔝

Go to the beginning of a File. You can continue reading or writing from there. This may cause service failure due to external factors.

to_start(@mut ReadFile f) → ()
to_start(@mut WriteFile f) → ()

temp 🔝

Creates a WriteFile of a given size that is constrained to fixed memory provided by a Memory allocator. Due to safety mechanisms provided by operating systems, operations on this file may be slower than simple memory read and writes. If the operating system does not properly support memory mapped files, this may even end up consuming disk storage space of up to the given size by being stored as a temporary file. In general, reads and writes (with print) will be at most as slow as a normal file, with the contract that data cannot be recovered after termination. Some operating systems require manual deletion of temporary file folders if systems are abruptly powered off. This type of file should be mostly used to store temporary data or for testing purposes. Example:

@on Heap.dynamic() // allocator for the file
@mut f = WrteFile.temp(1024)
f.print("hello from withing a temp file!")
f.to_start()
f.next_line(@mut u64 line)
print(line)

temp(@mut Stack memory,@mut WriteFile,u64 size) → WriteFile
temp(@mut Heap memory,@mut WriteFile,u64 size) → WriteFile
temp(@mut Arena memory,@mut WriteFile,u64 size) → WriteFile
temp(@mut Circular memory,@mut WriteFile,u64 size) → WriteFile
temp(@mut Dynamic memory,@mut WriteFile,u64 size) → WriteFile

len 🔝

Computes the size of a File in bytes. This tries to leverage operating system metadata first, but if it fails it explicitly reads through the file once.

len(@mut ReadFile f) → u64
len(@mut WriteFile f) → u64

ended 🔝

Checks if the ending of the file has been reached. This is normal to be true for WriteFile.

ended(@mut ReadFile f) → bool
ended(@mut WriteFile f) → bool

is_file 🔝

Checks if a String path is a file system file.

is_file(cstr _path) → exists
is_file(nstr _path) → exists

is_dir 🔝

Checks if a String path is a file system directory.

is_dir(cstr _path) → bool
is_dir(nstr _path) → bool

remove_file 🔝

Deletes a file from the system. May cause service failure due to external factors, or if the file is already open.

remove_file(cstr _path) → ()
remove_file(nstr _path) → ()
remove_file(str _path) → ()

create_dir 🔝

Creates a directory given a String path. May cause service failure due to external factors, or if the directory already exists.

create_dir(cstr _path) → ()
create_dir(nstr _path) → ()
create_dir(str _path) → ()

std.map 🔝

std/map.s

StringHash 🔝

A container that converts String instances to integer indexes of a given range.

StringHash(new,u64 size) → (new,u64 size,@mut str[] entries.dynamic)

NumberHash 🔝

A container that converts any Number to integer indexes of a given range.

NumberHash(new,u64 size) → (new,u64 size,@mut u64[] entries.dynamic)

hash 🔝

Converts and str or u64 to a u64 hash code.

hash(str k,u64 size) → u64
hash(u64 k,u64 size) → u64

to_hash_base 🔝

Converts any String or Number to corresponding str or u64 for which is_zero and hash are called.

to_hash_base(cstr k) → str
to_hash_base(nstr k) → str
to_hash_base(str k) → str
to_hash_base(u64 k) → u64
to_hash_base(i64 k) → u64
to_hash_base(f64 k) → u64
to_hash_base(StringHash) → str
to_hash_base(NumberHash) → u64

Hash 🔝

A union between StringHash and NumberHash

StringHash(new,u64 size) → (new,u64 size,@mut str[] entries.dynamic)
NumberHash(new,u64 size) → (new,u64 size,@mut u64[] entries.dynamic)

is_zero 🔝

Check that an str is non-empty or a u64 is non-zero

is_zero(str k) → bool
is_zero(u64 k) → bool

find 🔝

Searches for corresponding contents in a Hash and returns whether they exist or not. The search also admits a mutable number that stores the found position. If the entry is not found, the index remain unchanged. Empty strings and zero numbers are always present at the 0 index. Example:

@include std.core
@include std.map

def my_map()
    @mut keys = new.StringHash(100)
    @mut values = u64[].expect(keys.size)
    @on Heap.dynamic()
    values.put(keys["a".copy()], 1)
    values.put(keys["b"], 2)
    values.put(keys[""], 3)
    return keys, values

service main()
    @access map = my_map()
    if map.keys.find("a".str(), @mut u64 pos)
        print(map.values[pos])

find(@mut StringHash self,cstr _k,@mut u64 idx) → bool
find(@mut StringHash self,nstr _k,@mut u64 idx) → bool
find(@mut StringHash self,str _k,@mut u64 idx) → bool

at 🔝

at(@mut StringHash self,cstr _k) → u64
at(@mut StringHash self,nstr _k) → u64
at(@mut StringHash self,str _k) → u64

std.math unsafe 🔝

Standard library wrapping of C math operations.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

cos 🔝

Computes the cosine of an angle given in radians. Example:

print(cos(0.0))       // prints 1.0
print(cos(0.5.pi()))  // prints approximately 0.0

cos(f64 x) → f64

acos 🔝

Computes the arc cosine (inverse cosine) of a value in the range [-1, 1]. Returns an angle in radians. Example:

print(acos(1.0))     // prints 0.0
print(acos(0.0))     // prints approximately 1.5708 (0.5.pi())

acos(f64 x) → f64

sin 🔝

Computes the sine of an angle given in radians. Example:

print(sin(0.0))       // prints 0.0
print(sin(0.5.pi()))  // prints approximately 1.0

sin(f64 x) → f64

asin 🔝

Computes the arc sine (inverse sine) of a value in the range [-1, 1]. Returns an angle in radians. Example:

print(asin(0.0))     // prints 0.0
print(asin(1.0))     // prints approximately 1.5708 (0.5.pi())

asin(f64 x) → f64

exp 🔝

Computes the exponential function e^x. Example:

print(exp(1.0))  // prints approximately 2.71828
print(exp(2.0))  // prints approximately 7.38906

exp(f64 x) → f64

pi 🔝

Multiplies a given number by π (pi). This is often used for angle conversions. Example:

print(1.0.pi())  // prints approximately 3.14159
print(0.5.pi()) // prints approximately 1.5708 (π/2)

pi(f64 x) → f64

tan 🔝

Computes the tangent of an angle given in radians. Example:

print(tan(0.0))        // prints 0.0
print(tan(0.25.pi())) // prints approximately 1.0

tan(f64 x) → f64

atan 🔝

Computes the arc tangent (inverse tangent) of a value, returning an angle in radians. Example:

print(atan(1.0)) // prints approximately 0.785398 (0.25.pi())
print(atan(0.0)) // prints 0.0

atan(f64 x) → f64

atan2 🔝

Computes the arc tangent of y/x using the signs of both arguments to determine the correct quadrant of the result. Returns an angle in radians. Example:

print(atan2(1.0, 1.0))   // prints approximately 0.785398 (0.25.pi())
print(atan2(1.0, -1.0))  // prints approximately 2.35619 (0.75.pi())

atan2(f64 y,f64 x) → f64

is_nan 🔝

Checks if a floating-point number is 'not a number' (NaN). Example:

x = 0.0/0.0
if is_nan(x)
    print("x is NaN")

is_nan(f64 x) → bool

is_inf 🔝

Checks if a floating-point number represents infinity (positive or negative). Example:

x = 1.0/0.0
if is_inf(x)
    print("x is infinite")

is_inf(f64 x) → bool

sqrt 🔝

Computes the square root of a number. Requires a non-negative input. Example:

print(sqrt(9.0)) // prints 3.0
print(sqrt(2.0)) // prints approximately 1.41421

sqrt(f64 x) → f64

pow 🔝

Computes the result of raising a base to an exponent (base^exponent). Yields NaN if the base is negative. Example:

print(pow(2.0, 3.0)) // prints 8.0
print(pow(9.0, 0.5)) // prints 3.0

pow(f64 base,f64 exponent) → f64

log 🔝

Computes the natural logarithm (base e) of a number. Yields NaN on non-positive input. Example:

print(log(exp(1.0))) // prints 1.0
print(log(10.0))     // prints approximately 2.30259

log(f64 x) → f64

std.mem 🔝

std/mem.s

std.mem.arena unsafe 🔝

Standard library implementation of arena allocation. Pointer arithmetics yield offsets within arenas.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

read 🔝

read(@mut Arena self) → str

Arena 🔝

A fixed-sized arena that can be cleared. Data stored on this could be zero-initialized.

Arena(new,ContiguousMemory contents) → (new,ContiguousMemory contents,u64 length)

Circular 🔝

A fixed-sized arena that can be cleared and circularly corrupted. Data stored on this could be zero-initialized.

Circular(new,ContiguousMemory contents) → (new,ContiguousMemory contents,u64 length)

Dynamic 🔝

Dynamic(new) → (new,ptr acquired,u64 size,u64 allocated,u64)

arena 🔝

Allocates an Arena buffer of given size on the given Memory. Allocations on this can be shared and corrupted.

arena(@mut ContiguousMemory self) → Arena

circular 🔝

Allocates a Circular buffer a of given size on the given Memory. Allocations on this can be shared and corrupted.

circular(@mut ContiguousMemory self) → (Circular)

clear 🔝

Clears an Arena or Circular arena by resetting its occupied length to zero. This can lead to overwriting previous data.

clear(@mut Circular self) → ()
clear(@mut Arena self) → ()

Buffer 🔝

Arena(new,ContiguousMemory contents) → (new,ContiguousMemory contents,u64 length)
Circular(new,ContiguousMemory contents) → (new,ContiguousMemory contents,u64 length)

is 🔝

is(@mut Stack self,@mut Stack) → Stack
is(@mut Heap self,@mut Heap) → Heap
is(@mut Arena self,@mut Arena) → Arena
is(@mut Circular self,@mut Circular) → Circular
is(@mut Dynamic self,@mut Dynamic) → Dynamic

dynamic 🔝

dynamic(Heap) → Dynamic
dynamic(Stack) → new

allocate 🔝

allocate(@mut Dynamic self,u64 size) → ContiguousMemory
allocate(@mut Arena self,u64 size) → ContiguousMemory
allocate(@mut Circular self,u64 size) → ContiguousMemory

used 🔝

used(@mut Arena self) → u64
used(@mut Circular self) → u64

Memory 🔝

Arena(new,ContiguousMemory contents) → (new,ContiguousMemory contents,u64 length)
Circular(new,ContiguousMemory contents) → (new,ContiguousMemory contents,u64 length)
Dynamic(new) → (new,ptr acquired,u64 size,u64 allocated,u64)

len 🔝

len(@mut Arena self) → u64
len(@mut Circular self) → u64

std.mem.device unsafe 🔝

Standard library implementation of memory management that accounts for the stack and heap and depends on the runtime.h implementation of heap memory, and GCC implementation of alloca. Stack allocations cannot be returned from services, as the stack is pruned when programming function calls end. Def-based functions are inlined within services, so it is fine to return stack allocations from them.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

Stack 🔝

Represents call stack memory. Allocating on this is near-zero cost by being just an arithmetic addition. But its total size is limited - typically up to a few megabytes. Prefer this for small localized data that need to be processed exceedingly fast. Arena allocators are a close second in terms in performance.

Stack(new) → new

Heap 🔝

Random access memory (RAM) that can be allocated with __runtime_alloc. Writing to it and reading from it can be slow for programs that keep. Modern processors optimize heap usage by prefetching and caching nearby areas as the ones you access. For this reason, prefer creating Arena regions when you have a sense of the exact amount of data you will need. Allocating on the heap can leak memory under certain conditions, but the language's safety mechanism prevents this. Use other allocators in those cases. The standard library provides a Dynamic type that also accesses several heap allocations, though with an additional level of indirection.

Heap(new) → new

MB 🔝

MB(u64 value) → u64

KB 🔝

KB(u64 value) → u64

ContiguousMemory 🔝

Represents allocated memory management. It keeps track of both currently used pointer addresses, for example if these are offsets of allocated base pointers with finally segments calling __runtime_free on those, and the underlying pointer addresses. Importantly, not all this information is retained after compilation, as most of it -perhaps all- is optimized away. But this structure still helps the compiler organize where to place memory releases, if needed. Users of the standard library will not generally work with this type, as it is highly unsafe to get its pointer fields and requires annotation for the language to allow that.

ContiguousMemory(new,u64 size,ptr mem,ptr underlying) → (new,u64 size,ptr mem,ptr underlying)

__device_file_end 🔝

__device_file_end() → ()

MemoryDevice 🔝

Refers to either stack or heap memory.

Stack(new) → new
Heap(new) → new

allocate 🔝

Allocates memory on a predetermined device given a number of entries. Other standard library overloads implement allocation for more memory types, derived from the devices. Allocations throughout the standard library track the raw allocated memory so that usage is finally released only when the last dependent variable (e.g., the last string allocated on a heap arena) is no longer used. See ContiguousMemory.

allocate(Heap,u64 size) → ContiguousMemory
allocate(Stack,u64 size) → ContiguousMemory

std.mem.grid 🔝

std/mem/grid.s

std.mem.str unsafe 🔝

Standard library implementation of string operations using its own allocators and C memory operations.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

copy 🔝

Copies a string on a given Memory allocator. The result is nstr, that is, a string variation is null-terminated. This operation may fail if the allocation fails.

copy(@mut Stack allocator,cstr _s) → nstr
copy(@mut Heap allocator,cstr _s) → nstr
copy(@mut Arena allocator,cstr _s) → nstr
copy(@mut Circular allocator,cstr _s) → nstr
copy(@mut Dynamic allocator,cstr _s) → nstr
copy(@mut Stack allocator,nstr _s) → nstr
copy(@mut Heap allocator,nstr _s) → nstr
copy(@mut Arena allocator,nstr _s) → nstr
copy(@mut Circular allocator,nstr _s) → nstr
copy(@mut Dynamic allocator,nstr _s) → nstr
copy(@mut Stack allocator,str _s) → nstr
copy(@mut Heap allocator,str _s) → nstr
copy(@mut Arena allocator,str _s) → nstr
copy(@mut Circular allocator,str _s) → nstr
copy(@mut Dynamic allocator,str _s) → nstr

str 🔝

Provides methods for converting numbers to strings that are stored on provided Memory allocators. These are not necessarily null-terminated, so use nstr if that is important.

str(ContiguousMemory region) → str(new,ptr contents,u64 length,char first,ptr memory)
str(ContiguousMemory region,u64 size) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Stack allocator,u64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Heap allocator,u64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Arena allocator,u64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Circular allocator,u64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Dynamic allocator,u64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Stack allocator,i64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Heap allocator,i64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Arena allocator,i64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Circular allocator,i64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Dynamic allocator,i64 number) → str(new,ptr contents,u64 length,char first,ptr memory)
str(@mut Stack allocator,f64 number) → (str)
str(@mut Heap allocator,f64 number) → (str)
str(@mut Arena allocator,f64 number) → (str)
str(@mut Circular allocator,f64 number) → (str)
str(@mut Dynamic allocator,f64 number) → (str)

nstr 🔝

Provides methods for converting numbers to strings that are stored on provided Memory allocators. The result is a null-terminated nstr.

nstr(@mut Stack allocator,i64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Heap allocator,i64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Arena allocator,i64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Circular allocator,i64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Dynamic allocator,i64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Stack allocator,u64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Heap allocator,u64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Arena allocator,u64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Circular allocator,u64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Dynamic allocator,u64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Stack allocator,f64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Heap allocator,f64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Arena allocator,f64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Circular allocator,f64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)
nstr(@mut Dynamic allocator,f64 number) → nstr(new,ptr contents,u64 length,char first,ptr memory)

add 🔝

Overloads the + operator to concatenate two strings. The result is nstr, that is, a string variation that is null-terminated. Example:

name = "Mario"
@on Heap.arena(1024)
message = "It's a me, "+name+"!"
print(message)

add(@mut Stack allocator,cstr _x,cstr _y) → nstr
add(@mut Heap allocator,cstr _x,cstr _y) → nstr
add(@mut Arena allocator,cstr _x,cstr _y) → nstr
add(@mut Circular allocator,cstr _x,cstr _y) → nstr
add(@mut Dynamic allocator,cstr _x,cstr _y) → nstr
add(@mut Stack allocator,nstr _x,cstr _y) → nstr
add(@mut Heap allocator,nstr _x,cstr _y) → nstr
add(@mut Arena allocator,nstr _x,cstr _y) → nstr
add(@mut Circular allocator,nstr _x,cstr _y) → nstr
add(@mut Dynamic allocator,nstr _x,cstr _y) → nstr
add(@mut Stack allocator,str _x,cstr _y) → nstr
add(@mut Heap allocator,str _x,cstr _y) → nstr
add(@mut Arena allocator,str _x,cstr _y) → nstr
add(@mut Circular allocator,str _x,cstr _y) → nstr
add(@mut Dynamic allocator,str _x,cstr _y) → nstr
add(@mut Stack allocator,cstr _x,nstr _y) → nstr
add(@mut Heap allocator,cstr _x,nstr _y) → nstr
add(@mut Arena allocator,cstr _x,nstr _y) → nstr
add(@mut Circular allocator,cstr _x,nstr _y) → nstr
add(@mut Dynamic allocator,cstr _x,nstr _y) → nstr
add(@mut Stack allocator,nstr _x,nstr _y) → nstr
add(@mut Heap allocator,nstr _x,nstr _y) → nstr
add(@mut Arena allocator,nstr _x,nstr _y) → nstr
add(@mut Circular allocator,nstr _x,nstr _y) → nstr
add(@mut Dynamic allocator,nstr _x,nstr _y) → nstr
add(@mut Stack allocator,str _x,nstr _y) → nstr
add(@mut Heap allocator,str _x,nstr _y) → nstr
add(@mut Arena allocator,str _x,nstr _y) → nstr
add(@mut Circular allocator,str _x,nstr _y) → nstr
add(@mut Dynamic allocator,str _x,nstr _y) → nstr
add(@mut Stack allocator,cstr _x,str _y) → nstr
add(@mut Heap allocator,cstr _x,str _y) → nstr
add(@mut Arena allocator,cstr _x,str _y) → nstr
add(@mut Circular allocator,cstr _x,str _y) → nstr
add(@mut Dynamic allocator,cstr _x,str _y) → nstr
add(@mut Stack allocator,nstr _x,str _y) → nstr
add(@mut Heap allocator,nstr _x,str _y) → nstr
add(@mut Arena allocator,nstr _x,str _y) → nstr
add(@mut Circular allocator,nstr _x,str _y) → nstr
add(@mut Dynamic allocator,nstr _x,str _y) → nstr
add(@mut Stack allocator,str _x,str _y) → nstr
add(@mut Heap allocator,str _x,str _y) → nstr
add(@mut Arena allocator,str _x,str _y) → nstr
add(@mut Circular allocator,str _x,str _y) → nstr
add(@mut Dynamic allocator,str _x,str _y) → nstr

std.os unsafe 🔝

Standard library wrapping of C system calls and of process management using C popen.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

Process 🔝

A running process whose stdout can be read as a file-like object.

Process(new,ptr contents) → (new,ptr contents)

to_end 🔝

Reads all remaining output from the process without storing it.

to_end(@mut Process p) → ()

open 🔝

Opens a Process given a command string. This starts the process and lets you read its output.When the process is eventually released, services fail if there is pending output or if the exit code is non-zero. Here is an example:

service run(String command)
    @mut process = Process.open(command)
    process.to_end()
    @release process // explicitly release here

service main()
    run("invalid command").err.assert_ok() // synchronize

open(@mut Process,cstr _command) → Process
open(@mut Process,nstr _command) → Process
open(@mut Process,str command) → (Process)

next_chunk 🔝

Reads the next chunk of process output into a provided buffer.

next_chunk(@mut Arena reader,@mut Process p,@mut nstr value) → bool
next_chunk(@mut Circular reader,@mut Process p,@mut nstr value) → bool
next_chunk(@mut Arena memory,@mut Process p,@mut str value) → bool
next_chunk(@mut Circular memory,@mut Process p,@mut str value) → bool

next_line 🔝

Reads the next line of process output into a provided buffer.

next_line(@mut Arena reader,@mut Process p,@mut nstr value) → bool
next_line(@mut Circular reader,@mut Process p,@mut nstr value) → bool
next_line(@mut Arena memory,@mut Process p,@mut str value) → bool
next_line(@mut Circular memory,@mut Process p,@mut str value) → bool

system 🔝

system(cstr command) → ()
system(str command) → ()

std.rand unsafe 🔝

Standard library porting Xoshiro256plus random numbers from https://prng.di.unimi.it/. These and are NOT cryptographically secure.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

__rotl 🔝

__rotl(u64 x,u64 k) → u64

next 🔝

Computes the next random number of a Rand sequence. Example:

@mut rnd = Rand()
range(10)
.while next(@mut u64 i)
    print(rnd.next())

next(@mut u64 self.s0,@mut u64 self.s1,@mut u64 self.s2,@mut u64 self.s3) → f64

splitmix64 🔝

Computes the next random number of a splitmix64 sequence using the mutable unsigned int argument as state to be updated. This is NOT cryptographically secure and also has small period of 2^64 so usage is not recommended for long-running sequences. It is, however, faster than computing a next Rand state with next. If you do not provide a seed, a number obtained from the current time is provided. That can only be the start of a sequence, and marked as a leaking resource to prevent time-based randomization (which is not random). Example:

@mut rnd = splitmix64()
range(10)
.while next(@mut u64 i)
    print(rnd.splitmix64()) // rnd is the state, the result is f64

splitmix64(@mut u64 x) → u64
splitmix64() → u64

Rand 🔝

This a structural type for storing the progress of random number generators on four u64 state fields. It can be initialized with an optional seed, which defaults to a time-based initialization if not provided. Its period is 2^256-1.

For safety against sharing random implementations between services or repeatedly initializing them, state variables are marked as a leaking resource. The whole data type is marked as @noborrow too, to prevent sharing mutable random states across different services. These safety mechanisms help safeguard speed and prevent common mistakes, for example by making impossible to directly re-initialize Rand in each loop to get a next number.

Rand(u64 seed) → (@mut u64 s0,@mut u64 s1,@mut u64 s2,@mut u64 s3)
Rand() → Rand(u64 seed)

std.time unsafe 🔝

Standard library wrapping of C time (provided by posix time.h or windows.h).

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

sleep 🔝

Make the current service wait for AT LEAST a number of f64 seconds. While yielding, other services may be called asynchronously to fill in the missing time. There is no guarantee for this, though. Sleeping for 0.0 duration does not incur delays, but may still run other services. Negative durations skip over this. Use exact_slepp to sleep without yielding and thus get a guarantee on the sleep duration. This method's exact implementation is ported from the runtime. Example:

sleep(1.0) // yields for at least 1 sec

sleep(f64 duration) → ()

exact_sleep 🔝

Make the current service wait for exactly a specified number of f64 seconds. Control flow is not transferred to other services, so use sparingly (e.g., in main game loops). Example:

sleep(1.0) // waits for 1 sec of inactivity

exact_sleep(f64 duration) → ok

time 🔝

Retrieve time elapsed from the start of the program in f64 seconds.

time() → f64

std.vec unsafe 🔝

Standard library implementation of vectors that are allocated with safe memory management but use C pointers for element access.

This file is marked with the unsafe keyword. This means that its internal implementation (only) could be subject to bugs that the language's design otherwise eliminates. By using this file as a direct or indirect dependency you are trusting its implementation. Given this trust, consider other non-unsafe files using it as safe.

Vec 🔝

Represents a vector stored on contiguous memory. Prefer using the vector initializer, which can also generate vectors from random number generators. Vectors always hold f64 to ensure that invalid computations are stored as NaNs. They are also tailored for scientific use, so implementations aim to cut even the smallest corners without compromising safety. Use buffers to work with collections of u64 data instead.

Vec(new,ptr contents,u64 size,ptr surface) → (new,ptr contents,u64 size,ptr surface)

dot 🔝

dot(Vec x1,Vec x2) → f64

vector 🔝

Initializes a vector by using a provided memory allocator. The generated vector is zero-initialized. You can also provide a Rand random state imported from std.rand to initialize with uniformly random values in [0,1]. Example of generating a vector of 10 zero elements:

vec = Heap.dynamic().vector(10)

vector(@mut Stack memory,u64 size) → Vec
vector(@mut Heap memory,u64 size) → Vec
vector(@mut Arena memory,u64 size) → Vec
vector(@mut Circular memory,u64 size) → Vec
vector(@mut Dynamic memory,u64 size) → Vec
vector(@mut Stack memory,@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,u64 size) → Vec
vector(@mut Heap memory,@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,u64 size) → Vec
vector(@mut Arena memory,@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,u64 size) → Vec
vector(@mut Circular memory,@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,u64 size) → Vec
vector(@mut Dynamic memory,@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,u64 size) → Vec
vector(@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,@mut Stack memory,u64 size) → Vec
vector(@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,@mut Heap memory,u64 size) → Vec
vector(@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,@mut Arena memory,u64 size) → Vec
vector(@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,@mut Circular memory,u64 size) → Vec
vector(@mut u64 rand.s0,@mut u64 rand.s1,@mut u64 rand.s2,@mut u64 rand.s3,@mut Dynamic memory,u64 size) → Vec

print 🔝

Prints a vector to the console. To avoid large prints, at most the first 10 elements are printed.

print(Vec v) → ()

put 🔝

put(@mut Vec v,u64 pos,f64 value) → Vec
put(@mut Vec x1,Vec x2) → ()

slice 🔝

Slices a vector from a given to an ending position. This is a transparent view of vector data.

slice(Vec v,u64 from,u64 to) → Vec

add 🔝

Adds two vectors element-by-element and stores the result on either a third mutable vector also of the same size, or on a newly allocated one in the provided memory. This fails if vector sizes are incompatible, or if the provided Memory cannot allocate the required space. Example where an on context is used to allow operator overloading:

@mut rnd = Rand()
@on Heap.dynamic()
v1 = rnd.vector(10)
v2 = rnd.vector(10)
v3 = v1+v2

add(@mut Stack memory,Vec x1,Vec x2) → Vec
add(@mut Heap memory,Vec x1,Vec x2) → Vec
add(@mut Arena memory,Vec x1,Vec x2) → Vec
add(@mut Circular memory,Vec x1,Vec x2) → Vec
add(@mut Dynamic memory,Vec x1,Vec x2) → Vec
add(@mut Vec result,Vec x1,Vec x2) → Vec

len 🔝

Retrieves the length of a vector.

len(Vec v) → u64

sub 🔝

Subtracts two vectors element-by-element and stores the result on either a third mutable vector also of the same size, or on a newly allocated one in the provided memory. This fails if vector sizes are incompatible, or if the provided Memory cannot allocate the required space. Example where an on context is used to allow operator overloading:

@mut rnd = Rand()
@on Heap.dynamic()
v1 = rnd.vector(10)
v2 = rnd.vector(10)
v3 = v1-v2

sub(@mut Stack memory,Vec x1,Vec x2) → Vec
sub(@mut Heap memory,Vec x1,Vec x2) → Vec
sub(@mut Arena memory,Vec x1,Vec x2) → Vec
sub(@mut Circular memory,Vec x1,Vec x2) → Vec
sub(@mut Dynamic memory,Vec x1,Vec x2) → Vec
sub(@mut Vec result,Vec x1,Vec x2) → Vec

mul 🔝

Multiplies two vectors element-by-element and stores the result on either a third mutable vector also of the same size, or on a newly allocated one in the provided memory. This fails if vector sizes are incompatible, or if the provided Memory cannot allocate the required space. Example where an on context is used to allow operator overloading:

@mut rnd = Rand()
@on Heap.dynamic()
v1 = rnd.vector(10)
v2 = rnd.vector(10)
v3 = v1*v2

mul(@mut Stack memory,Vec x1,Vec x2) → Vec
mul(@mut Heap memory,Vec x1,Vec x2) → Vec
mul(@mut Arena memory,Vec x1,Vec x2) → Vec
mul(@mut Circular memory,Vec x1,Vec x2) → Vec
mul(@mut Dynamic memory,Vec x1,Vec x2) → Vec
mul(@mut Vec result,Vec x1,Vec x2) → Vec

at 🔝

Retrieves a specific f64 element from a vector. This overloads the element access operation like this:

vec = Rand().vector(Heap.dynamic(), 10)
print(vev[0])

at(Vec v,u64 pos) → f64

div 🔝

Divides two vectors element-by-element and stores the result on either a third mutable vector also of the same size, or on a newly allocated one in the provided memory. This fails if vector sizes are incompatible, or if the provided Memory cannot allocate the required space. Division may create NaN values. Example where an on context is used to allow operator overloading:

@mut rnd = Rand()
@on Heap.dynamic()
v1 = rnd.vector(10)
v2 = rnd.vector(10)
v3 = v1/v2

div(@mut Stack memory,Vec x1,Vec x2) → Vec
div(@mut Heap memory,Vec x1,Vec x2) → Vec
div(@mut Arena memory,Vec x1,Vec x2) → Vec
div(@mut Circular memory,Vec x1,Vec x2) → Vec
div(@mut Dynamic memory,Vec x1,Vec x2) → Vec
div(@mut Vec result,Vec x1,Vec x2) → Vec