File: index.ha

package info (click to toggle)
hare 0.25.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,948 kB
  • sloc: asm: 1,264; makefile: 123; sh: 114; lisp: 101
file content (162 lines) | stat: -rw-r--r-- 4,531 bytes parent folder | download | duplicates (2)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use bytes;
use encoding::utf8;

// Returns the index of the first occurance of 'needle' in the 'haystack', or
// void if not present. The index returned is the rune-wise index, not the
// byte-wise index.
export fn index(haystack: str, needle: (str | rune)) (size | void) = {
	match (needle) {
	case let r: rune =>
		return index_rune(haystack, r);
	case let s: str =>
		return index_string(haystack, s);
	};
};

// Returns the index of the last occurance of 'needle' in the 'haystack', or
// void if not present. The index returned is the rune-wise index, not the
// byte-wise index.
export fn rindex(haystack: str, needle: (str | rune)) (size | void) = {
	match (needle) {
	case let r: rune =>
		return rindex_rune(haystack, r);
	case let s: str =>
		return rindex_string(haystack, s);
	};
};

fn index_rune(s: str, r: rune) (size | void) = {
	let iter = iter(s);
	for (let i = 0z; true; i += 1) {
		match (next(&iter)) {
		case let n: rune =>
			if (r == n) {
				return i;
			};
		case done =>
			break;
		};
	};
};

fn rindex_rune(s: str, r: rune) (size | void) = {
	let iter = riter(s);
	for (let i = len(s) - 1; true; i -= 1) {
		match (next(&iter)) {
		case let n: rune =>
			if (r == n) {
				return i;
			};
		case done =>
			break;
		};
	};
};

fn index_string(s: str, needle: str) (size | void) = {
	let s_iter = iter(s);
	for (let i = 0z; true; i += 1) {
		let rest_iter = s_iter;
		let needle_iter = iter(needle);
		for (true) {
			const rest_rune = next(&rest_iter);
			const needle_rune = next(&needle_iter);
			if (rest_rune is done && !(needle_rune is done)) {
				break;
			};
			if (needle_rune is done) {
				return i;
			};
			if ((rest_rune as rune) != (needle_rune as rune)) {
				break;
			};
		};
		if (next(&s_iter) is done) {
			break;
		};
	};
};

fn rindex_string(s: str, needle: str) (size | void) = {
	let s_iter = riter(s);
	for (let i = len(s); true; i -= 1) {
		let rest_iter = s_iter;
		let needle_iter = riter(needle);
		for (true) {
			const rest_rune = next(&rest_iter);
			const needle_rune = next(&needle_iter);
			if (rest_rune is done && !(needle_rune is done)) {
				break;
			};
			if (needle_rune is done) {
				return i - len(needle);
			};
			if ((rest_rune as rune) != (needle_rune as rune)) {
				break;
			};
		};
		if (next(&s_iter) is done) {
			break;
		};
	};
};


@test fn index() void = {
	assert(index("hello world", 'w') as size == 6);
	assert(index("こんにちは", 'ち') as size == 3);
	assert(index("こんにちは", 'q') is void);

	assert(index("hello", "hello") as size == 0);
	assert(index("hello world!", "hello") as size == 0);
	assert(index("hello world!", "world") as size == 6);
	assert(index("hello world!", "orld!") as size == 7);
	assert(index("hello world!", "word") is void);
	assert(index("こんにちは", "ちは") as size == 3);
	assert(index("こんにちは", "きょうは") is void);

	assert(index("hello world!", "o") as size == 4);
	assert(rindex("hello world!", "o") as size == 7);
};

// Returns the byte-wise index of the first occurance of 'needle' in the
// 'haystack', or void if not present.
export fn byteindex(haystack: str, needle: (str | rune)) (size | void) = {
	return bytes::index(toutf8(haystack), match (needle) {
	case let s: str =>
		yield toutf8(s);
	case let r: rune =>
		yield if (r: u32 <= 0x7f) r: u8 else utf8::encoderune(r);
	});
};

// Returns the byte-wise index of the last occurance of 'needle' in the
// 'haystack', or void if not present.
export fn rbyteindex(haystack: str, needle: (str | rune)) (size | void) = {
	return bytes::rindex(toutf8(haystack), match (needle) {
	case let s: str =>
		yield toutf8(s);
	case let r: rune =>
		yield if (r: u32 <= 0x7f) r: u8 else utf8::encoderune(r);
	});
};

@test fn byteindex() void = {
	assert(byteindex("hello world", 'w') as size == 6);
	assert(byteindex("こんにちは", 'ち') as size == 9);
	assert(byteindex("こんにちは", 'q') is void);

	assert(byteindex("hello", "hello") as size == 0);
	assert(byteindex("hello world!", "hello") as size == 0);
	assert(byteindex("hello world!", "world") as size == 6);
	assert(byteindex("hello world!", "orld!") as size == 7);
	assert(byteindex("hello world!", "word") is void);
	assert(byteindex("こんにちは", "ちは") as size == 9);
	assert(byteindex("こんにちは", "きょうは") is void);

	assert(byteindex("またあったね", "た") as size == 3);
	assert(rbyteindex("またあったね", "た") as size == 12);
};