Comparing version 0.0.694 to 0.0.695
50
cache.ts
@@ -105,3 +105,3 @@ import { max, min, ceil, round } from './alias'; | ||
class Entry<K, V> { | ||
class Entry<K, V> implements List.Node { | ||
constructor( | ||
@@ -339,15 +339,25 @@ public key: K, | ||
} | ||
victim = LRU.head!.prev!; | ||
victim = victim !== skip | ||
? victim | ||
: LRU.length !== 1 | ||
? victim.prev | ||
: undefined; | ||
if (capture && skip === undefined && victim !== undefined) { | ||
assert(victim === LRU.head!.prev); | ||
skip = victim; | ||
size = skip.size; | ||
continue; | ||
if (LRU.length !== 0) { | ||
victim = LRU.head!.prev!; | ||
victim = victim !== skip | ||
? victim | ||
: LRU.length !== 1 | ||
? victim.prev | ||
: undefined; | ||
assert(victim || skip === LRU.head!.prev); | ||
if (capture && skip === undefined && victim !== undefined) { | ||
assert(victim === LRU.head!.prev); | ||
skip = victim; | ||
size = skip.size; | ||
continue; | ||
} | ||
victim ??= LFU.head!.prev!; | ||
} | ||
victim ??= LFU.head!.prev!; | ||
else { | ||
assert(!skip || LFU.length >= 2); | ||
victim = LFU.head!.prev!; | ||
victim = victim !== skip | ||
? victim | ||
: victim.prev!; | ||
} | ||
} | ||
@@ -386,3 +396,3 @@ assert(victim !== skip); | ||
assert(0 < this.size && this.size <= this.resource); | ||
this.dict.set(key, LRU.unshift(new Entry( | ||
entry = new Entry( | ||
key, | ||
@@ -394,7 +404,9 @@ value, | ||
expiration, | ||
))); | ||
); | ||
LRU.unshift(entry); | ||
this.dict.set(key, entry); | ||
assert(this.LRU.length + this.LFU.length === this.dict.size); | ||
assert(this.dict.size <= this.capacity); | ||
if (this.expiration && this.expirations !== undefined && expiration !== Infinity) { | ||
LRU.head!.enode = this.expirations.insert(LRU.head!, expiration); | ||
entry.enode = this.expirations.insert(entry, expiration); | ||
assert(this.expirations.length <= this.length); | ||
@@ -414,2 +426,4 @@ } | ||
this.dict.set(key, entry); | ||
assert(this.LRU.length + this.LFU.length === this.dict.size); | ||
assert(this.dict.size <= this.capacity); | ||
entry.key = key; | ||
@@ -437,3 +451,2 @@ entry.region = 'LRU'; | ||
assert(this.LRU.length + this.LFU.length === this.dict.size); | ||
assert(this.dict.size <= this.capacity); | ||
this.disposer?.(value$, key$); | ||
@@ -841,5 +854,6 @@ return match; | ||
public sweep(): boolean { | ||
const { target } = this; | ||
let lap = false; | ||
if (target.length === 0) return lap; | ||
this.processing ||= true; | ||
const { target } = this; | ||
if (this.direction) { | ||
@@ -846,0 +860,0 @@ if (this.back < 1) { |
@@ -26,3 +26,2 @@ import { max, min, isArray } from '../alias'; | ||
private readonly ix = new Index(); | ||
private HEAD = 0; | ||
private $length = 0; | ||
@@ -32,13 +31,8 @@ public get length() { | ||
} | ||
public set head(index: number) { | ||
this.HEAD = index; | ||
} | ||
public get head(): number { | ||
return this.HEAD; | ||
} | ||
public head = 0; | ||
public get tail(): number { | ||
return this.nexts[this.HEAD]; | ||
return this.nexts[this.head]; | ||
} | ||
public get last(): number { | ||
return this.prevs[this.HEAD]; | ||
return this.prevs[this.head]; | ||
} | ||
@@ -54,3 +48,3 @@ public next(index: number): number { | ||
} | ||
public index(offset: number, index = this.HEAD): number { | ||
public index(offset: number, index = this.head): number { | ||
if (offset > 0) { | ||
@@ -97,10 +91,10 @@ const pointers = this.nexts; | ||
this.ix.clear(); | ||
this.HEAD = 0; | ||
this.head = 0; | ||
this.$length = 0; | ||
} | ||
public add(value: T): number { | ||
const head = this.HEAD; | ||
const head = this.head; | ||
if (this.$length === 0) { | ||
assert(this.length === 0); | ||
const index = this.HEAD = this.ix.pop(); | ||
const index = this.head = this.ix.pop(); | ||
++this.$length; | ||
@@ -114,3 +108,3 @@ this.values[index] = value; | ||
assert(this.length < this.capacity); | ||
const index = this.HEAD = this.ix.pop(); | ||
const index = this.head = this.ix.pop(); | ||
++this.$length; | ||
@@ -127,3 +121,3 @@ const last = this.prevs[head]; | ||
assert(this.ix.length === this.capacity); | ||
const index = this.HEAD = this.prevs[head]; | ||
const index = this.head = this.prevs[head]; | ||
this.values[index] = value; | ||
@@ -147,4 +141,4 @@ return index; | ||
} | ||
if (index === this.HEAD) { | ||
this.HEAD = next; | ||
if (index === this.head) { | ||
this.head = next; | ||
} | ||
@@ -156,6 +150,6 @@ } | ||
public insert(value: T, before: number): number { | ||
const head = this.HEAD; | ||
this.HEAD = before; | ||
const head = this.head; | ||
this.head = before; | ||
const index = this.add(value); | ||
this.HEAD = head; | ||
this.head = head; | ||
return index; | ||
@@ -170,13 +164,13 @@ } | ||
this.values[index] = value; | ||
this.HEAD = index; | ||
this.head = index; | ||
return index; | ||
} | ||
public push(value: T): number { | ||
return this.insert(value, this.HEAD); | ||
return this.insert(value, this.head); | ||
} | ||
public pushRotationally(value: T): number { | ||
if (this.$length === 0) return this.add(value); | ||
const index = this.HEAD; | ||
const index = this.head; | ||
this.values[index] = value; | ||
this.HEAD = this.nexts[index]; | ||
this.head = this.nexts[index]; | ||
return index; | ||
@@ -186,3 +180,3 @@ } | ||
if (this.$length === 0) return; | ||
const index = this.HEAD; | ||
const index = this.head; | ||
const value = this.values[index]; | ||
@@ -219,10 +213,10 @@ this.del(index); | ||
public moveToHead(index: number): void { | ||
this.move(index, this.HEAD); | ||
this.HEAD = index; | ||
this.move(index, this.head); | ||
this.head = index; | ||
} | ||
public moveToLast(index: number): void { | ||
this.move(index, this.HEAD); | ||
this.HEAD = index === this.HEAD | ||
this.move(index, this.head); | ||
this.head = index === this.head | ||
? this.tail | ||
: this.HEAD; | ||
: this.head; | ||
} | ||
@@ -234,8 +228,8 @@ public swap(index1: number, index2: number): boolean { | ||
this.move(index1, index3); | ||
switch (this.HEAD) { | ||
switch (this.head) { | ||
case index1: | ||
this.HEAD = index2; | ||
this.head = index2; | ||
break; | ||
case index2: | ||
this.HEAD = index1; | ||
this.head = index1; | ||
break; | ||
@@ -246,3 +240,3 @@ } | ||
public *[Symbol.iterator](): Iterator<T, undefined, undefined> { | ||
for (let index = this.HEAD, i = 0; i < this.$length; ++i) { | ||
for (let index = this.head, i = 0; i < this.$length; ++i) { | ||
yield this.values[index]; | ||
@@ -249,0 +243,0 @@ index = this.nexts[index]; |
@@ -5,3 +5,9 @@ // Memory-efficient flexible list. | ||
public length = 0; | ||
public head?: N; | ||
public head?: N = undefined; | ||
public get tail(): N | undefined { | ||
return this.head?.next; | ||
} | ||
public get last(): N | undefined { | ||
return this.head?.prev; | ||
} | ||
public insert(node: N, before?: N): N { | ||
@@ -8,0 +14,0 @@ assert(!node.next); |
import { IterableDict } from './dict'; | ||
import { List } from './list'; | ||
class Node<K, V> { | ||
class Node<K, V> implements List.Node { | ||
constructor( | ||
@@ -35,3 +35,3 @@ public key: K, | ||
const { dict, list } = this; | ||
const node = list.head!.prev!; | ||
const node = list.last!; | ||
dict.delete(node.key); | ||
@@ -38,0 +38,0 @@ dict.set(key, node); |
@@ -8,3 +8,3 @@ import { MAX_SAFE_INTEGER } from './alias'; | ||
class Node<T> { | ||
class Node<T> implements List.Node { | ||
constructor( | ||
@@ -210,3 +210,3 @@ public value: T, | ||
const recents: Node<SubscriberItem<N, D, R>>[] = []; | ||
const max = items.head!.prev!.value.id; | ||
const max = items.last!.value.id; | ||
let min = 0; | ||
@@ -236,3 +236,3 @@ let prev: typeof recents[0] | undefined; | ||
const recents: Node<MonitorItem<N, D>>[] = []; | ||
const max = items.head!.prev!.value.id; | ||
const max = items.last!.value.id; | ||
let min = 0; | ||
@@ -239,0 +239,0 @@ let prev: typeof recents[0] | undefined; |
{ | ||
"name": "spica", | ||
"version": "0.0.694", | ||
"version": "0.0.695", | ||
"description": "Supervisor, Coroutine, Channel, select, AtomicPromise, Cancellation, Cache, List, Queue, Stack, and some utils.", | ||
@@ -5,0 +5,0 @@ "private": false, |
@@ -105,3 +105,3 @@ import { max, min, ceil, round } from './alias'; | ||
class Entry<K, V> { | ||
class Entry<K, V> implements List.Node { | ||
constructor( | ||
@@ -339,15 +339,25 @@ public key: K, | ||
} | ||
victim = LRU.head!.prev!; | ||
victim = victim !== skip | ||
? victim | ||
: LRU.length !== 1 | ||
? victim.prev | ||
: undefined; | ||
if (capture && skip === undefined && victim !== undefined) { | ||
assert(victim === LRU.head!.prev); | ||
skip = victim; | ||
size = skip.size; | ||
continue; | ||
if (LRU.length !== 0) { | ||
victim = LRU.head!.prev!; | ||
victim = victim !== skip | ||
? victim | ||
: LRU.length !== 1 | ||
? victim.prev | ||
: undefined; | ||
assert(victim || skip === LRU.head!.prev); | ||
if (capture && skip === undefined && victim !== undefined) { | ||
assert(victim === LRU.head!.prev); | ||
skip = victim; | ||
size = skip.size; | ||
continue; | ||
} | ||
victim ??= LFU.head!.prev!; | ||
} | ||
victim ??= LFU.head!.prev!; | ||
else { | ||
assert(!skip || LFU.length >= 2); | ||
victim = LFU.head!.prev!; | ||
victim = victim !== skip | ||
? victim | ||
: victim.prev!; | ||
} | ||
} | ||
@@ -386,3 +396,3 @@ assert(victim !== skip); | ||
assert(0 < this.size && this.size <= this.resource); | ||
this.dict.set(key, LRU.unshift(new Entry( | ||
entry = new Entry( | ||
key, | ||
@@ -394,7 +404,9 @@ value, | ||
expiration, | ||
))); | ||
); | ||
LRU.unshift(entry); | ||
this.dict.set(key, entry); | ||
assert(this.LRU.length + this.LFU.length === this.dict.size); | ||
assert(this.dict.size <= this.capacity); | ||
if (this.expiration && this.expirations !== undefined && expiration !== Infinity) { | ||
LRU.head!.enode = this.expirations.insert(LRU.head!, expiration); | ||
entry.enode = this.expirations.insert(entry, expiration); | ||
assert(this.expirations.length <= this.length); | ||
@@ -414,2 +426,4 @@ } | ||
this.dict.set(key, entry); | ||
assert(this.LRU.length + this.LFU.length === this.dict.size); | ||
assert(this.dict.size <= this.capacity); | ||
entry.key = key; | ||
@@ -437,3 +451,2 @@ entry.region = 'LRU'; | ||
assert(this.LRU.length + this.LFU.length === this.dict.size); | ||
assert(this.dict.size <= this.capacity); | ||
this.disposer?.(value$, key$); | ||
@@ -841,5 +854,6 @@ return match; | ||
public sweep(): boolean { | ||
const { target } = this; | ||
let lap = false; | ||
if (target.length === 0) return lap; | ||
this.processing ||= true; | ||
const { target } = this; | ||
if (this.direction) { | ||
@@ -846,0 +860,0 @@ if (this.back < 1) { |
@@ -26,3 +26,2 @@ import { max, min, isArray } from '../alias'; | ||
private readonly ix = new Index(); | ||
private HEAD = 0; | ||
private $length = 0; | ||
@@ -32,13 +31,8 @@ public get length() { | ||
} | ||
public set head(index: number) { | ||
this.HEAD = index; | ||
} | ||
public get head(): number { | ||
return this.HEAD; | ||
} | ||
public head = 0; | ||
public get tail(): number { | ||
return this.nexts[this.HEAD]; | ||
return this.nexts[this.head]; | ||
} | ||
public get last(): number { | ||
return this.prevs[this.HEAD]; | ||
return this.prevs[this.head]; | ||
} | ||
@@ -54,3 +48,3 @@ public next(index: number): number { | ||
} | ||
public index(offset: number, index = this.HEAD): number { | ||
public index(offset: number, index = this.head): number { | ||
if (offset > 0) { | ||
@@ -97,10 +91,10 @@ const pointers = this.nexts; | ||
this.ix.clear(); | ||
this.HEAD = 0; | ||
this.head = 0; | ||
this.$length = 0; | ||
} | ||
public add(value: T): number { | ||
const head = this.HEAD; | ||
const head = this.head; | ||
if (this.$length === 0) { | ||
assert(this.length === 0); | ||
const index = this.HEAD = this.ix.pop(); | ||
const index = this.head = this.ix.pop(); | ||
++this.$length; | ||
@@ -114,3 +108,3 @@ this.values[index] = value; | ||
assert(this.length < this.capacity); | ||
const index = this.HEAD = this.ix.pop(); | ||
const index = this.head = this.ix.pop(); | ||
++this.$length; | ||
@@ -127,3 +121,3 @@ const last = this.prevs[head]; | ||
assert(this.ix.length === this.capacity); | ||
const index = this.HEAD = this.prevs[head]; | ||
const index = this.head = this.prevs[head]; | ||
this.values[index] = value; | ||
@@ -147,4 +141,4 @@ return index; | ||
} | ||
if (index === this.HEAD) { | ||
this.HEAD = next; | ||
if (index === this.head) { | ||
this.head = next; | ||
} | ||
@@ -156,6 +150,6 @@ } | ||
public insert(value: T, before: number): number { | ||
const head = this.HEAD; | ||
this.HEAD = before; | ||
const head = this.head; | ||
this.head = before; | ||
const index = this.add(value); | ||
this.HEAD = head; | ||
this.head = head; | ||
return index; | ||
@@ -170,13 +164,13 @@ } | ||
this.values[index] = value; | ||
this.HEAD = index; | ||
this.head = index; | ||
return index; | ||
} | ||
public push(value: T): number { | ||
return this.insert(value, this.HEAD); | ||
return this.insert(value, this.head); | ||
} | ||
public pushRotationally(value: T): number { | ||
if (this.$length === 0) return this.add(value); | ||
const index = this.HEAD; | ||
const index = this.head; | ||
this.values[index] = value; | ||
this.HEAD = this.nexts[index]; | ||
this.head = this.nexts[index]; | ||
return index; | ||
@@ -186,3 +180,3 @@ } | ||
if (this.$length === 0) return; | ||
const index = this.HEAD; | ||
const index = this.head; | ||
const value = this.values[index]; | ||
@@ -219,10 +213,10 @@ this.del(index); | ||
public moveToHead(index: number): void { | ||
this.move(index, this.HEAD); | ||
this.HEAD = index; | ||
this.move(index, this.head); | ||
this.head = index; | ||
} | ||
public moveToLast(index: number): void { | ||
this.move(index, this.HEAD); | ||
this.HEAD = index === this.HEAD | ||
this.move(index, this.head); | ||
this.head = index === this.head | ||
? this.tail | ||
: this.HEAD; | ||
: this.head; | ||
} | ||
@@ -234,8 +228,8 @@ public swap(index1: number, index2: number): boolean { | ||
this.move(index1, index3); | ||
switch (this.HEAD) { | ||
switch (this.head) { | ||
case index1: | ||
this.HEAD = index2; | ||
this.head = index2; | ||
break; | ||
case index2: | ||
this.HEAD = index1; | ||
this.head = index1; | ||
break; | ||
@@ -246,3 +240,3 @@ } | ||
public *[Symbol.iterator](): Iterator<T, undefined, undefined> { | ||
for (let index = this.HEAD, i = 0; i < this.$length; ++i) { | ||
for (let index = this.head, i = 0; i < this.$length; ++i) { | ||
yield this.values[index]; | ||
@@ -249,0 +243,0 @@ index = this.nexts[index]; |
@@ -5,3 +5,9 @@ // Memory-efficient flexible list. | ||
public length = 0; | ||
public head?: N; | ||
public head?: N = undefined; | ||
public get tail(): N | undefined { | ||
return this.head?.next; | ||
} | ||
public get last(): N | undefined { | ||
return this.head?.prev; | ||
} | ||
public insert(node: N, before?: N): N { | ||
@@ -8,0 +14,0 @@ assert(!node.next); |
import { IterableDict } from './dict'; | ||
import { List } from './list'; | ||
class Node<K, V> { | ||
class Node<K, V> implements List.Node { | ||
constructor( | ||
@@ -35,3 +35,3 @@ public key: K, | ||
const { dict, list } = this; | ||
const node = list.head!.prev!; | ||
const node = list.last!; | ||
dict.delete(node.key); | ||
@@ -38,0 +38,0 @@ dict.set(key, node); |
@@ -8,3 +8,3 @@ import { MAX_SAFE_INTEGER } from './alias'; | ||
class Node<T> { | ||
class Node<T> implements List.Node { | ||
constructor( | ||
@@ -210,3 +210,3 @@ public value: T, | ||
const recents: Node<SubscriberItem<N, D, R>>[] = []; | ||
const max = items.head!.prev!.value.id; | ||
const max = items.last!.value.id; | ||
let min = 0; | ||
@@ -236,3 +236,3 @@ let prev: typeof recents[0] | undefined; | ||
const recents: Node<MonitorItem<N, D>>[] = []; | ||
const max = items.head!.prev!.value.id; | ||
const max = items.last!.value.id; | ||
let min = 0; | ||
@@ -239,0 +239,0 @@ let prev: typeof recents[0] | undefined; |
1134609
31813