From 073c902a31936c2b53d89245662fb272c9670169 Mon Sep 17 00:00:00 2001 From: JJ Date: Thu, 9 May 2024 18:00:01 -0700 Subject: std: sweeping changes. - replace interfaces with classes - replace : with then and do - solidify memory management as rust-style ownership - replace unsafe blocks with safe/unsafe attributes - add magic and copy attributes - switch Coerce impl from from to to --- std/prelude/strings.pk | 104 ++++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 61 deletions(-) (limited to 'std/prelude/strings.pk') diff --git a/std/prelude/strings.pk b/std/prelude/strings.pk index 2f48b67..e86d520 100644 --- a/std/prelude/strings.pk +++ b/std/prelude/strings.pk @@ -2,100 +2,82 @@ ## This module is imported by default. # reference: https://doc.rust-lang.org/std/string/struct.String.html -use std.pointers - -# possible approaches: list[byte], distinct list[byte], this -# should *really* just rely on lists, i don't want to duplicate slicing logic, but... maybe... -type str = struct - data: ptr[byte] - length: uint - capacity: uint +## A primitive string type. +## +## We do not want methods defined on `list[byte]` to carry over, +## so we define `str` as a newtype. +pub type str = struct + data: list[byte] ## Initialize and return an empty string. -pub func init(): str = - ... +pub func init: str = { data = [] } ## Gets the length of a string. -pub func len(self: str): uint = - self.length - -pub func empty(self: str): bool = - self.length == 0 - -## Gets the internal capacity of a string. -func cap(self: str): uint = - self.capacity - -## Expands the capacity of a string. -func grow(self: mut str) = - ... +## This is an O(n) operation, due to UTF-8 encoding. +pub func len(self: lent str): uint = + var res: uint + for _ in self do + res += 1 + res ## Pushes a character to the end of a mutable string. -pub func push(self: mut str, val: chr) = # todo: `add` alias? - ... +pub func push(self: mut str, val: chr) = + self.data.push(val.byte) # todo: obsolete by from/to conversion?? ## Pushes an owned string to the end of a mutable string. pub func push(self: mut str, val: str) = - ... + self.data.push(val.bytes) # todo: obsolete by from/to conversion?? ## Removes and returns the last character of a string, if it exists. +## +## SAFETY: We return early upon an empty string. +## And decrement by one char for a non-empty string. +@[safe] pub func pop(self: mut str): chr? = - ... + let char = self.chars.rev.next? + self.data.set_len(self.len - char.len) # this is normally unsafe. + Some(char) ## Returns the character at the provided index, if it exists. pub func get(self: str, i: uint): chr? = ... ## Sets the character at the provided index, if it exists. -## todo: what if it does not exist? +## As strings are packed, this may call str.grow and reallocate. +## oh fuck we have to insert + remove anyway pub func set(self: mut str, i: uint, val: chr) = ... ## Inserts a character at an arbitrary position within a string. -## Error handling: todo +## Panics on failure. (todo: can we do better?) pub func insert(self: mut str, i: uint, val: chr) = ... ## Removes and returns a character at an arbitrary position within a string. -## Panics on failure. +## Panics on failure. (todo: can we do better?) pub func remove(self: mut str, i: uint): chr = ... -## Returns the *byte* at an arbitrary position within a string. -## Explicitly distinct from `get` as this breaks safety conventions idk -pub func get_byte(self: str): byte = - ... - -## Sets a byte at the provided index, if it exists. Do we want this? -pub func set_byte(self: mut str, i: uint, val: byte) = - ... - -## Inserts a byte into a string. Breaks string convention. Do we want this? -pub func insert_byte(self: mut str, i: uint, val: byte) = - ... - -## Removes a byte at a given offset from a string. Do we want this? -pub func remove_byte(self: mut str, i: uint): byte? = - ... - -## Converts a given string to a list of bytes for iteration purposes. -pub func bytes(self: str): list[byte] = - ... # many performance considerations - -## Converts a given string to a list of chars for iteration purposes. -pub func chars(self: str): list[chr] # todo: useful? - -## The concatenation operator. -pub func &(a: str, b: str): str = - ... - ## Syntactic sugar for string appending. -pub func &=(a: mut str, b: owned str) = +pub func &=(a: mut str, b: str) = a.push(b) -# todo: many things +## The concatenation operator. Consumes two strings. +pub func &(a: str, b: str): str = + a.push(b) + a + +## Conversion from a string to a list of bytes. Zero-cost. +pub func to(self: str): list[byte] = self.data +## Conversion from a str to a list[chr]. Reallocates. +pub func to(self: str): list[chr] = + var res: list[chr] + for char in self do res.push(char) + res +## Conversion from a char to an array of bytes. Zero-cost. +@[safe] # possibly unsafe?? depends on repr of arrays +pub func to(self: chr): array[byte, 4] = self.cast[array[byte, 4]] -# pub func iter(self: str): StrIter # pub func next(self: mut StrIter) # pub func peek(self: mut StrIter) # pub func peek_nth(self: mut StrIter, i: uint) -- cgit v1.2.3-70-g09d2