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 : 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 3 : IteratorController(this.data, {required this.transform, this.boundary, this.filter}); 31 : 32 1 : @override 33 2 : 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 0 : @override 54 : Iterable<M?> loop() sync* { 55 0 : while (pointer < keys.length) { 56 0 : final index = keys.elementAt(pointer++); 57 0 : if (boundary != null && boundary! < index) { 58 : break; 59 : } 60 0 : M? value = transform(data[index] ?? ''); 61 0 : if (filter?.call(value) == true) { 62 : continue; 63 : } 64 : yield value; 65 : } 66 : } 67 : 68 0 : @override 69 : M? get next { 70 0 : final iterator = loop().iterator; 71 0 : 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 : return result.cast<M>(); 79 : } 80 : 81 0 : @override 82 0 : List<M> toList() => [...loop()].cast(); 83 : 84 0 : @override 85 : List<M> getTill(T boundary) { 86 0 : final result = <M>[]; 87 0 : while (!isFinished && boundary > keys[pointer]) { 88 0 : final value = next; 89 0 : if (boundary <= keys[pointer - 1]) { 90 0 : pointer--; 91 : break; 92 : } 93 : if (value == null) { 94 : break; 95 : } 96 0 : result.add(value); 97 : } 98 : return result; 99 : } 100 : } 101 : 102 : class IteratorReverseController<T extends num, K, M> extends IteratorController<T, K, M> { 103 3 : IteratorReverseController(super.data, {required super.transform, super.boundary, super.filter}) { 104 15 : pointer = data.keys.length - 1; 105 6 : _pointer = pointer; 106 : } 107 : 108 0 : @override 109 0 : bool get isFinished => pointer < 0; 110 : 111 0 : @override 112 0 : void reset() => data.keys.length - 1; 113 : 114 0 : @override 115 : void jumpTo(T key) { 116 0 : final nextKey = data.lastKeyBefore(key); 117 0 : pointer = nextKey != null ? keys.indexOf(nextKey) : 0; 118 : } 119 : 120 0 : @override 121 : Iterable<M?> loop() sync* { 122 0 : while (pointer >= 0) { 123 0 : final index = keys.elementAt(pointer--); 124 0 : if (boundary != null && boundary! > index) { 125 : break; 126 : } 127 0 : M? value = transform(data[index] ?? ''); 128 0 : if (filter?.call(value) == true) { 129 : continue; 130 : } 131 : yield value; 132 : } 133 : } 134 : 135 0 : @override 136 : List<M> getTill(T boundary) { 137 0 : final result = <M>[]; 138 0 : while (!isFinished && boundary < keys[pointer]) { 139 0 : final value = next; 140 0 : if (boundary >= keys[pointer + 1]) { 141 0 : pointer++; 142 : break; 143 : } 144 : if (value == null) { 145 : break; 146 : } 147 0 : result.add(value); 148 : } 149 : return result; 150 : } 151 : }