File: ops.ha

package info (click to toggle)
hare 0.26.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 7,352 kB
  • sloc: asm: 1,374; makefile: 123; sh: 117; lisp: 101
file content (134 lines) | stat: -rw-r--r-- 4,298 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use encoding::utf8;
use io;
use strings;

// Appends zero or more strings to an [[io::handle]]. The output needn't be a
// memio stream, but it's generally more efficient if it is. Returns the number
// of bytes written, or an error.
export fn concat(out: io::handle, strs: str...) (size | io::error) =
	join(out, "", strs...);

@test fn concat() void = {
	let st = dynamic();
	defer io::close(&st)!;
	let tests: [_]([]str, str) = [
		([], ""),
		([""], ""),
		(["", ""], ""),
		(["hello"], "hello"),
		(["hello", " ", "world"], "hello world"),
		(["", "hello", " ", "world"], "hello world"),
		(["hello", " ", "world", ""], "hello world"),
		(["hello", "", " ", "world"], "hello world")
	];
	for (let i = 0z; i < len(tests); i += 1) {
		let ln = concat(&st, tests[i].0...) as size;
		assert(ln == len(tests[i].1) && string(&st)! == tests[i].1);
		reset(&st);
	};
};

// Joins several strings together by a delimiter and writes them to a handle.
// The output needn't be a memio stream, but it's generally more efficient if it
// is. Returns the number of bytes written, or an error.
export fn join(out: io::handle, delim: str, strs: str...) (size | io::error) = {
	let n = 0z;
	let delim = strings::toutf8(delim);
	for (let i = 0z; i < len(strs); i += 1) {
		n += io::writeall(out, strings::toutf8(strs[i]))?;
		if (len(delim) != 0 && i + 1 < len(strs)) {
			n += io::writeall(out, delim)?;
		};
	};
	return n;
};

@test fn join() void = {
	let st = dynamic();
	defer io::close(&st)!;
	let tests: [_](str, []str, str) = [
		("::", [], ""),
		("::", [""], ""),
		("::", ["", ""], "::"),
		("::", ["", "", ""], "::::"),
		("::", ["hello"], "hello"),
		("::", ["hello", "world"], "hello::world"),
		("::", ["", "hello", "world"], "::hello::world"),
		("::", ["hello", "world", ""], "hello::world::"),
		("::", ["hello", "", "world"], "hello::::world"),
	];
	for (let i = 0z; i < len(tests); i += 1) {
		let ln = join(&st, tests[i].0, tests[i].1...) as size;
		assert(ln == len(tests[i].2) && string(&st)! == tests[i].2);
		reset(&st);
	};
};

// Appends zero or more strings to an [[io::handle]], in reverse order. The
// output needn't be a memio stream, but it's generally more efficient if it is.
// Returns the number of bytes written, or an error.
export fn rconcat(out: io::handle, strs: str...) (size | io::error) =
	rjoin(out, "", strs...);

@test fn rconcat() void = {
	let st = dynamic();
	defer io::close(&st)!;
	let tests: [_]([]str, str) = [
		([], ""),
		([""], ""),
		(["", ""], ""),
		(["hello"], "hello"),
		(["hello", " ", "world"], "world hello"),
		(["", "hello", " ", "world"], "world hello"),
		(["hello", " ", "world", ""], "world hello"),
		(["hello", "", " ", "world"], "world hello")
	];
	for (let i = 0z; i < len(tests); i += 1) {
		let ln = rconcat(&st, tests[i].0...) as size;
		assert(ln == len(tests[i].1) && string(&st)! == tests[i].1);
		reset(&st);
	};
};

// Joins several strings together by a delimiter and writes them to a handle, in
// reverse order. The output needn't be a memio stream, but it's generally more
// efficient if it is. Returns the number of bytes written, or an error.
export fn rjoin(out: io::handle, delim: str, strs: str...) (size | io::error) = {
	let n = 0z;
	let delim = strings::toutf8(delim);
	for (let i = len(strs); i > 0; i -= 1) {
		n += io::writeall(out, strings::toutf8(strs[i - 1]))?;
		if (len(delim) != 0 && i - 1 > 0) {
			n += io::writeall(out, delim)?;
		};
	};
	return n;
};

@test fn rjoin() void = {
	let st = dynamic();
	defer io::close(&st)!;
	let tests: [_](str, []str, str) = [
		("::", [], ""),
		("::", [""], ""),
		("::", ["", ""], "::"),
		("::", ["", "", ""], "::::"),
		("::", ["hello"], "hello"),
		("::", ["hello", "world"], "world::hello"),
		("::", ["", "hello", "world"], "world::hello::"),
		("::", ["hello", "world", ""], "::world::hello"),
		("::", ["hello", "", "world"], "world::::hello"),
	];
	for (let i = 0z; i < len(tests); i += 1) {
		let ln = rjoin(&st, tests[i].0, tests[i].1...) as size;
		assert(ln == len(tests[i].2) && string(&st)! == tests[i].2);
		reset(&st);
	};
};

// Appends a rune to a stream.
export fn appendrune(out: io::handle, r: rune) (size | io::error) =
	io::writeall(out, utf8::encoderune(r));