summary refs log tree commit diff
path: root/bin/edi/iter.c
blob: 6331bb176dbc0c09d7f09fa9ebd079f324b66c39 (plain) (blame)
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
/* Copyright (C) 2018  June McEnroe <june@causal.agency>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <wchar.h>

#include "edi.h"

struct Iter iter(const struct Table *table, size_t at) {
	struct Span span = { 0, 0 };
	size_t slice;
	for (slice = 0; slice < table->len; ++slice) {
		span = spanNext(span, table->slices[slice].len);
		if (span.at <= at && span.to > at) break;
	}
	return (struct Iter) {
		.table = table,
		.span = span,
		.slice = slice,
		.at = (at < span.to ? at : span.to),
		.ch = (at < span.to ? table->slices[slice].ptr[at - span.at] : WEOF),
	};
}

struct Iter iterNext(struct Iter it) {
	if (it.at == it.span.to && it.ch == WEOF) return it;
	it.at++;
	if (it.at == it.span.to) {
		if (it.slice + 1 == it.table->len) {
			it.ch = WEOF;
			return it;
		}
		it.slice++;
		it.span = spanNext(it.span, it.table->slices[it.slice].len);
	}
	it.ch = it.table->slices[it.slice].ptr[it.at - it.span.at];
	return it;
}

struct Iter iterPrev(struct Iter it) {
	if (it.at > it.span.to && it.ch == WEOF) return it;
	it.at--;
	if (it.at > it.span.to) {
		it.ch = WEOF;
		return it;
	}
	if (it.at < it.span.at) {
		it.slice--;
		it.span = spanPrev(it.span, it.table->slices[it.slice].len);
	}
	it.ch = it.table->slices[it.slice].ptr[it.at - it.span.at];
	return it;
}

#ifdef TEST
#include <assert.h>

int main() {
	struct Slice slices[2] = {
		{ L"AB", 2 },
		{ L"CD", 2 },
	};
	struct Table table = { .len = 2, .slices = slices };

	assert(L'A' == iter(&table, 0).ch);
	assert(L'B' == iter(&table, 1).ch);
	assert(L'C' == iter(&table, 2).ch);
	assert(L'D' == iter(&table, 3).ch);
	assert(WEOF == iter(&table, 4).ch);

	assert(L'B' == iterNext(iter(&table, 0)).ch);
	assert(L'C' == iterNext(iter(&table, 1)).ch);
	assert(L'D' == iterNext(iter(&table, 2)).ch);
	assert(WEOF == iterNext(iter(&table, 5)).ch);

	assert(WEOF == iterPrev(iter(&table, 0)).ch);
	assert(L'A' == iterPrev(iter(&table, 1)).ch);
	assert(L'B' == iterPrev(iter(&table, 2)).ch);
	assert(L'C' == iterPrev(iter(&table, 3)).ch);

	struct Iter it = iter(&table, 3);
	it = iterNext(it);
	it = iterNext(it);
	assert(WEOF == it.ch);
	it = iterPrev(it);
	assert(L'D' == it.ch);

	it = iter(&table, 0);
	it = iterPrev(it);
	it = iterPrev(it);
	assert(WEOF == it.ch);
	it = iterNext(it);
	assert(L'A' == it.ch);
}

#endif