hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit c08cc7e751106913fe3c146f9091fb4b84ddc454
parent 1e28e8ac6853366424048307904de2ceed11522a
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun,  7 Feb 2021 11:45:43 -0500

bytes, strings: add contains

Diffstat:
Abytes/contains.ha | 5+++++
Mbytes/index.ha | 42+++++++++++++++++++++++++++++++++++++++++-
Astrings/contains.ha | 15+++++++++++++++
3 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/bytes/contains.ha b/bytes/contains.ha @@ -0,0 +1,5 @@ +// Returns true if a byte slice contains a byte or a sequence of bytes. +export fn contains(haystack: []u8, needle: (u8 | []u8)) bool = match (needle) { + b: u8 => !(index_byte(haystack, b) is void), + b: []u8 => !(index_slice(haystack, b) is void), +}; diff --git a/bytes/index.ha b/bytes/index.ha @@ -1,6 +1,13 @@ // Returns the offset of the first instance of 'needle' in a 'haystack' of // bytes, or void if it is not found. -export fn index(haystack: []u8, needle: u8) (size | void) = { +export fn index(haystack: []u8, needle: (u8 | []u8)) (size | void) = { + return match (needle) { + b: u8 => index_byte(haystack, b), + b: []u8 => index_slice(haystack, b), + }; +}; + +fn index_byte(haystack: []u8, needle: u8) (size | void) = { for (let i = 0z; i < len(haystack); i += 1z) { if (haystack[i] == needle) { return i; @@ -8,7 +15,26 @@ export fn index(haystack: []u8, needle: u8) (size | void) = { }; }; +fn index_slice(haystack: []u8, needle: []u8) (size | void) = { + if (len(needle) > len(haystack)) { + return; + }; + let i = 0z; + for (i < len(haystack)) { + let n = nequal(haystack[i..], needle); + if (n == len(needle)) { + return i; + } else if (n != 0z) { + i += n; + } else { + i += 1z; + }; + }; +}; + + @test fn index() void = { + // Bytes let a: [4]u8 = [1u8, 3u8, 3u8, 7u8]; match (index(a, 7u8)) { n: size => assert(n == 3z), @@ -22,4 +48,18 @@ export fn index(haystack: []u8, needle: u8) (size | void) = { size => abort(), void => void, }; + + // Slices + match (index(a, [3u8, 3u8])) { + n: size => assert(n == 1z), + void => abort(), + }; + match (index(a, [])) { + n: size => assert(n == 0z), + void => abort(), + }; + match(index(a, [4u8, 2u8])) { + size => abort(), + void => void, + }; }; diff --git a/strings/contains.ha b/strings/contains.ha @@ -0,0 +1,15 @@ +use bytes; +use encoding::utf8; + +// Returns true if a string contains a rune or a sub-string. +export fn contains(haystack: str, needle: (str | rune)) bool = match (needle) { + s: str => bytes::contains(to_utf8(haystack), to_utf8(s)), + r: rune => bytes::contains(to_utf8(haystack), utf8::encode_rune(r)), +}; + +@test fn contains() void = { + assert(contains("hello world", "hello")); + assert(contains("hello world", "world")); + assert(contains("hello world", "")); + assert(!contains("hello world", "foobar")); +};