-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsieve.mts
93 lines (76 loc) · 2.33 KB
/
sieve.mts
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
import { LinkList, LinkListIterator } from '@js-sdsl/link-list';
export class Entry<K, V> {
constructor(public key: K, public value: V, public visited: boolean = false) {}
}
export class Sieve<K, V> {
private size: number;
private items: Map<K, Entry<K, V>>;
private ll: LinkList<Entry<K, V>>;
private hand: LinkListIterator<Entry<K, V>> | undefined;
constructor(size: number) {
this.size = size;
this.items = new Map<K, Entry<K, V>>();
this.ll = new LinkList<Entry<K, V>>();
}
set(key: K, value: V): void {
if (this.items.has(key)) {
const e = this.items.get(key);
if (e) {
e.value = value;
e.visited = true;
}
return;
}
if (this.ll.length >= this.size) {
this.evict();
}
const e = new Entry<K, V>(key, value);
this.items.set(key, e);
this.ll.pushFront(e);
}
get(key: K): [V | null, boolean] {
if (this.items.has(key)) {
const e = this.items.get(key);
if (e) {
e.visited = true;
return [e.value, true];
}
}
return [null, false];
}
contains(key: K): boolean {
return this.items.has(key);
}
peek(key: K): [V | null, boolean] {
if (this.items.has(key)) {
const e = this.items.get(key);
if (e) {
return [e.value, true];
}
}
return [null, false];
}
len(): number {
// todo: probably worth using a counter somewhere, or look up if it's efficient in the list impl
return this.ll.length;
}
clear(): void {
this.items.clear();
this.ll.clear();
}
private evict(): void {
if (!this.hand || !this.hand.isAccessible()) {
this.hand = this.ll.rBegin(); // start on tail
}
let i: Entry<K, V>;
while ((i = this.hand.pointer) && i.visited) {
i.visited = false;
this.hand.next(); // as we use `rBegin`, this is actually the prev node
if (!this.hand.isAccessible()) {
this.hand = this.ll.rBegin();
}
}
this.items.delete(this.hand.pointer.key);
this.ll.eraseElementByIterator(this.hand);
}
}