1
10
11export class OpStack<T> {
12 private past: T[] = [];
13 private future: T[] = [];
14 private current: T;
15 readonly capacity: number;
16
17 constructor(initial: T, capacity = 100) {
18 if (capacity < 1) throw new Error("capacity must be ≥ 1");
19 this.current = initial;
20 this.capacity = capacity;
21 }
22
23
24 push(next: T): void {
25 if (Object.is(next, this.current)) return;
26 this.past.push(this.current);
27 if (this.past.length > this.capacity) this.past.shift();
28 this.current = next;
29 this.future = [];
30 this.pushed++;
31 }
32
33
35 reset(next: T): void {
36 this.past = [];
37 this.future = [];
38 this.current = next;
39 this.pushed = 0;
40 }
41
42 get present(): T {
43 return this.current;
44 }
45
46 canUndo(): boolean {
47 return this.past.length > 0;
48 }
49 canRedo(): boolean {
50 return this.future.length > 0;
51 }
52
53 get depth(): number {
54 return this.past.length;
55 }
56
57 get truncated(): boolean {
58
59
60 return this.pushed > this.capacity;
61 }
62
63 undo(): T {
64 if (!this.canUndo()) return this.current;
65 this.future.push(this.current);
66 this.current = this.past.pop()!;
67 return this.current;
68 }
69
70 redo(): T {
71 if (!this.canRedo()) return this.current;
72 this.past.push(this.current);
73 this.current = this.future.pop()!;
74 return this.current;
75 }
76
77 private pushed = 0;
78}
79