deno.land / x / froebel@v0.23.2 / sortedArray.ts

sortedArray.ts
نووسراو ببینە
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
import type { FilterKeys, λ } from "./types.ts";
class SortedArrayImpl<T> { #data: T[] = []; #cmp: Cmp<T>;
constructor(compare: Cmp<T>, ...values: T[]) { this.#cmp = compare; if (values.length) this.#data = values.sort(compare); return wrap(this); }
static from<T>(compare: Cmp<T>, source: Iterable<T>): SortedArrayImpl<T> { return new SortedArrayImpl(compare, ...source); }
add(...values: T[]) { values.map(this.#addValue); }
#addValue = ((value: T) => { for (let i = 0; i < this.#data.length; i++) { if (this.#cmp(value, this.#data[i]) >= 0) continue; this.#data.splice(i, 0, value); return; } this.#data.push(value); }).bind(this);
delete = (...indices: number[]) => indices .map((i) => (i >= 0 ? i : this.#data.length + i)) .map((i, j, a) => { for (let k = j + 1; k < a.length; k++) if (a[k] > i) a[k]--; return this.#data.splice(i, 1)[0]; });
clear() { this.#data = []; }
#ref<K extends FilterKeys<T[], λ>, I extends number>( method: K, i: I, ): SetArg<T[][K], 0, SetArg<FA<T[][K]>, I, SortedArray<T>>> { return ((f: λ, ...rest: any[]) => (this.#data[method] as any)( (...args: any[]) => f(...args.slice(0, i), this, ...args.slice(i + 1)), ...rest, )) as any; }
#bind = <K extends FilterKeys<T[], λ>>(method: K) => ((...args: any[]) => (this.#data as any)[method](...args)) as T[][K];
#wrap = <F extends λ<any, T[]>>(f: F) => (...args: Parameters<F>): SortedArray<T> => new SortedArrayImpl(this.#cmp, ...f(...(args as any))) as any;
every = this.#ref("every", 2); filter = this.#wrap(this.#ref("filter", 2)); find = this.#ref("find", 2); findIndex = this.#ref("findIndex", 2); forEach = this.#ref("forEach", 2); includes = this.#bind("includes"); indexOf = this.#bind("indexOf"); join = this.#bind("join"); lastIndexOf = this.#bind("lastIndexOf"); map = this.#ref("map", 2); pop = this.#bind("pop"); reduce = this.#ref("reduce", 3); reduceRight = this.#ref("reduceRight", 3); shift = this.#bind("shift"); slice = this.#wrap(this.#bind("slice")); some = this.#ref("some", 2);
at = (this.#data as any).at?.bind(this.#data) ?? ((i: number) => this.#data[i >= 0 ? i : this.#data.length + i]);
get length() { return this.#data.length; }
public [Symbol.iterator]() { return this.#data[Symbol.iterator](); }}
const wrap = <T>(v: T): T => new Proxy(v as any, { get(t, k) { if (k in t || typeof k !== "string") { return typeof t[k] === "function" ? t[k].bind(t) : t[k]; } for (const c of k) if (c < "0" || c > "9") return; return t.at(parseInt(k)); }, deleteProperty(t, k) { if (k in t || typeof k !== "string") return delete t[k]; for (const c of k) if (c < "0" || c > "9") return true; t.delete(parseInt(k)); return true; }, });
/** * Sorted array. Behaves much like a regular array but its elements remain * sorted using the `compare` function supplied in the constructor. * * Contains most of the methods defined on regular JavaScript arrays as long as * they don't modify the array's content in place. * * New elements are added using the `add(...values)` method. * * Elements can still be accessed using bracket notation as in plain JavaScript * arrays but can't be assigned to using bracket notation (as that could change * the element's sort position). * * Elements can be removed using the `delete(...indices)` method, which returns * an array containing the deleted values. * Deleting an element using `delete sorted[index]` will also work, but results * in a TypeScript error because element access is marked readonly. * * Array methods that pass a reference of the array to a callback (e.g. `map`, * `reduce`, `find`) will pass a reference to the SortedArray instance instead. * * The `filter` and `slice` methods will return SortedArray instances instead of * plain arrays. */export interface SortedArray<T> extends SortedArrayImpl<T> { readonly [K: number]: T;}
export default SortedArrayImpl as unknown as & (new <T>( compare: Cmp<T>, ...value: T[] ) => SortedArray<T>) & { from: typeof SortedArrayImpl.from };
type Cmp<T> = (a: T, b: T) => number;
type SetI<T extends any[], I extends number, V> = Tup< { [K in keyof T]: K extends `${I}` ? V : T[K]; }>;
type Tup<T> = T extends any[] ? T : never;
type SetArg<T, I extends number, V> = T extends λ ? (...args: SetI<Parameters<T>, I, V>) => ReturnType<T> : never;
type FA<T> = T extends (..._: [infer F, ...any[]]) => any ? F : never;
froebel

Version Info

Tagged at
a year ago