Line data Source code
1 : // Copyright 2023 The terCAD team. All rights reserved.
2 : // Use of this source code is governed by a CC BY-NC-ND 4.0 license that can be found in the LICENSE file.
3 :
4 : import 'dart:collection';
5 :
6 : abstract interface class InterfaceIterator<T extends num, K, M> {
7 : void reset();
8 : int get length;
9 : bool get isFirst;
10 : bool get isFinished;
11 : bool get isEmpty;
12 : M? get next;
13 : void jumpTo(T key);
14 : Iterable<M?> loop();
15 : List<M> chunk(int length);
16 : List<M> getTill(T boundary);
17 : List<M> toList();
18 : }
19 :
20 : class IteratorController<T extends num, K, M> implements InterfaceIterator<T, K, M> {
21 : SplayTreeMap<T, K> data;
22 : T? boundary;
23 : Function? filter;
24 4 : late List<T> keys = data.keys.toList();
25 : int pointer = 0;
26 : // ignore: prefer_final_fields
27 : int _pointer = 0;
28 : Function transform;
29 :
30 1 : IteratorController(this.data, {required this.transform, this.boundary, this.filter});
31 :
32 0 : @override
33 0 : int get length => data.length;
34 :
35 0 : @override
36 0 : void reset() => pointer = 0;
37 :
38 0 : @override
39 0 : bool get isEmpty => data.isEmpty;
40 :
41 0 : @override
42 0 : bool get isFirst => _pointer == pointer;
43 :
44 0 : @override
45 0 : bool get isFinished => keys.length == pointer;
46 :
47 0 : @override
48 : void jumpTo(T key) {
49 0 : final nextKey = data.firstKeyAfter(key);
50 0 : pointer = nextKey != null ? keys.indexOf(nextKey) : keys.length - 1;
51 : }
52 :
53 1 : @override
54 : Iterable<M?> loop() sync* {
55 4 : while (pointer < keys.length) {
56 4 : final index = keys.elementAt(pointer++);
57 1 : if (boundary != null && boundary! < index) {
58 : break;
59 : }
60 4 : M? value = transform(data[index] ?? '');
61 3 : if (filter?.call(value) == true) {
62 : continue;
63 : }
64 : yield value;
65 : }
66 : }
67 :
68 1 : @override
69 : M? get next {
70 2 : final iterator = loop().iterator;
71 2 : return iterator.moveNext() ? iterator.current as M : null;
72 : }
73 :
74 0 : @override
75 : List<M> chunk(int length) {
76 0 : final result = List.generate(length, (_) => next);
77 0 : result.removeWhere((e) => e == null);
78 0 : if (result.isEmpty) return [];
79 0 : return result.cast<M>();
80 : }
81 :
82 1 : @override
83 3 : List<M> toList() => [...loop()].cast();
84 :
85 0 : @override
86 : List<M> getTill(T boundary) {
87 0 : final result = <M>[];
88 0 : while (!isFinished && boundary > keys[pointer]) {
89 0 : final value = next;
90 0 : if (boundary <= keys[pointer - 1]) {
91 0 : pointer--;
92 : break;
93 : }
94 : if (value == null) {
95 : break;
96 : }
97 0 : result.add(value);
98 : }
99 : return result;
100 : }
101 : }
102 :
103 : class IteratorReverseController<T extends num, K, M> extends IteratorController<T, K, M> {
104 1 : IteratorReverseController(super.data, {required super.transform, super.boundary, super.filter}) {
105 5 : pointer = data.keys.length - 1;
106 2 : _pointer = pointer;
107 : }
108 :
109 1 : @override
110 2 : bool get isFinished => pointer < 0;
111 :
112 0 : @override
113 0 : void reset() => data.keys.length - 1;
114 :
115 0 : @override
116 : void jumpTo(T key) {
117 0 : final nextKey = data.lastKeyBefore(key);
118 0 : pointer = nextKey != null ? keys.indexOf(nextKey) : 0;
119 : }
120 :
121 1 : @override
122 : Iterable<M?> loop() sync* {
123 2 : while (pointer >= 0) {
124 4 : final index = keys.elementAt(pointer--);
125 1 : if (boundary != null && boundary! > index) {
126 : break;
127 : }
128 4 : M? value = transform(data[index] ?? '');
129 3 : if (filter?.call(value) == true) {
130 : continue;
131 : }
132 : yield value;
133 : }
134 : }
135 :
136 1 : @override
137 : List<M> getTill(T boundary) {
138 1 : final result = <M>[];
139 5 : while (!isFinished && boundary < keys[pointer]) {
140 1 : final value = next;
141 5 : if (boundary >= keys[pointer + 1]) {
142 0 : pointer++;
143 : break;
144 : }
145 : if (value == null) {
146 : break;
147 : }
148 1 : result.add(value);
149 : }
150 : return result;
151 : }
152 : }
|