commit 5101d99b1600acebd796c730bb4ef2d3ff627fb3
parent 991b9323d6c52e02b96f54a16b7032e39560e53b
Author: Byron Torres <b@torresjrjr.com>
Date: Mon, 23 May 2022 11:33:00 +0100
strings: add fromrunes()
Signed-off-by: Byron Torres <b@torresjrjr.com>
Diffstat:
4 files changed, 69 insertions(+), 15 deletions(-)
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -1210,6 +1210,7 @@ strings() {
cstrings.ha \
dup.ha \
iter.ha \
+ runes.ha \
sub.ha \
suffix.ha \
tokenize.ha \
diff --git a/stdlib.mk b/stdlib.mk
@@ -1825,6 +1825,7 @@ stdlib_strings_any_srcs = \
$(STDLIB)/strings/cstrings.ha \
$(STDLIB)/strings/dup.ha \
$(STDLIB)/strings/iter.ha \
+ $(STDLIB)/strings/runes.ha \
$(STDLIB)/strings/sub.ha \
$(STDLIB)/strings/suffix.ha \
$(STDLIB)/strings/tokenize.ha \
@@ -3976,6 +3977,7 @@ testlib_strings_any_srcs = \
$(STDLIB)/strings/cstrings.ha \
$(STDLIB)/strings/dup.ha \
$(STDLIB)/strings/iter.ha \
+ $(STDLIB)/strings/runes.ha \
$(STDLIB)/strings/sub.ha \
$(STDLIB)/strings/suffix.ha \
$(STDLIB)/strings/tokenize.ha \
diff --git a/strings/iter.ha b/strings/iter.ha
@@ -145,18 +145,3 @@ export fn iterstr(iter: *iterator) str = {
assert(next(&s) is void);
assert(prev(&s) as rune == 'に');
};
-
-// Returns a slice of runes for a string in O(n). The caller must free the
-// return value.
-export fn runes(s: str) []rune = {
- let sl: []rune = alloc([], len(s));
- let iter = iter(s);
- for (true) {
- match (next(&iter)) {
- case void => break;
- case let r: rune =>
- append(sl, r);
- };
- };
- return sl;
-};
diff --git a/strings/runes.ha b/strings/runes.ha
@@ -0,0 +1,66 @@
+// License: MPL-2.0
+// (c) 2022 Byron Torres <b@torresjrjr.com>
+use encoding::utf8;
+
+// Returns a slice of runes for a string in O(n). The caller must free the
+// return value.
+export fn runes(s: str) []rune = {
+ let sl: []rune = alloc([], len(s));
+ let iter = iter(s);
+ for (true) {
+ match (next(&iter)) {
+ case void => break;
+ case let r: rune =>
+ append(sl, r);
+ };
+ };
+ return sl;
+};
+
+// Returns a string from a slice of runes. The caller must free the return value.
+export fn fromrunes(rs: []rune) str = {
+ let bytes: []u8 = [];
+ for (let i = 0z; i < len(rs); i += 1) {
+ const bs = encoding::utf8::encoderune(rs[i]);
+ append(bytes, bs...);
+ };
+ return fromutf8(bytes);
+};
+
+@test fn fromrunes() void = {
+ const rs = ['H', 'a', 'r', 'r', 'i', 'e', 't'];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == "Harriet", "strings::fromrunes() error (Harriet)");
+
+ const rs: []rune = [];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == "", "strings::fromrunes() error (empty)");
+
+ const rs = ['.'];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == ".", "strings::fromrunes() error (period)");
+
+ const rs = ['\a', '\b', '\f', '\n', '\r', '\t', '\v'];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == "\a\b\f\n\r\t\v", "strings::fromrunes() error (control chars)");
+
+ const rs = ['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == "Hello, world!", "strings::fromrunes() error (English)");
+
+ const rs = ['¡', 'H', 'o', 'l', 'a', ' ', 'M', 'u', 'n', 'd', 'o', '!'];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == "¡Hola Mundo!", "strings::fromrunes() error (Spanish)");
+
+ const rs = ['Γ', 'ε', 'ι', 'ά', ' ', 'σ', 'ο', 'υ', ' ', 'Κ', 'ό', 'σ', 'μ', 'ε', '!'];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == "Γειά σου Κόσμε!", "strings::fromrunes() error (Greek)");
+
+ const rs = ['П', 'р', 'и', 'в', 'е', 'т', ',', ' ', 'м', 'и', 'р', '!'];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == "Привет, мир!", "strings::fromrunes() error (Russian)");
+
+ const rs = ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!'];
+ const s = fromrunes(rs); defer free(s);
+ assert(s == "こんにちは世界!", "strings::fromrunes() error (Japanese)");
+};