@isograph/reference-counted-pointer 0.0.0-main-55364d41 → 0.0.0-main-2c275831
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,17 +57,17 @@ class RefCounter {
|
|
57
57
|
let disposed = false;
|
58
58
|
const dispose = () => {
|
59
59
|
if (disposed) {
|
60
|
-
throw new Error(
|
60
|
+
throw new Error('Do not dispose an already-disposed ActiveReference.');
|
61
61
|
}
|
62
62
|
disposed = true;
|
63
63
|
if (activeReference.__original === null) {
|
64
|
-
throw new Error(
|
65
|
-
|
64
|
+
throw new Error('Attempted to dispose an active reference, but it was already disposed. ' +
|
65
|
+
'This indicates a bug in reference-counted-pointer.');
|
66
66
|
}
|
67
67
|
activeReference.__original = null;
|
68
68
|
if (this.__state === null) {
|
69
|
-
throw new Error(
|
70
|
-
|
69
|
+
throw new Error('Attempted to dispose, but the underlying reference counted pointer was disposed. ' +
|
70
|
+
'This indicates a bug in reference-counted-pointer.');
|
71
71
|
}
|
72
72
|
this.__state.activeReferenceCount--;
|
73
73
|
this.__maybeDispose();
|
@@ -80,8 +80,8 @@ class RefCounter {
|
|
80
80
|
}
|
81
81
|
__maybeDispose() {
|
82
82
|
if (this.__state === null) {
|
83
|
-
throw new Error(
|
84
|
-
|
83
|
+
throw new Error('__maybeDispose was called, but the reference counted pointer was disposed. ' +
|
84
|
+
'This indicates a bug in reference-counted-pointer.');
|
85
85
|
}
|
86
86
|
if (this.__state.activeReferenceCount === 0) {
|
87
87
|
this.__state.dispose();
|
package/dist/index.d.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export * from
|
1
|
+
export * from './createReferenceCountedPointer';
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@isograph/reference-counted-pointer",
|
3
|
-
"version": "0.0.0-main-
|
3
|
+
"version": "0.0.0-main-2c275831",
|
4
4
|
"description": "Reference counted pointers enable sharing of disposable items.",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"types": "dist/index.d.ts",
|
@@ -14,7 +14,7 @@
|
|
14
14
|
"coverage": "vitest run --coverage"
|
15
15
|
},
|
16
16
|
"dependencies": {
|
17
|
-
"@isograph/disposable-types": "0.0.0-main-
|
17
|
+
"@isograph/disposable-types": "0.0.0-main-2c275831",
|
18
18
|
"react": "^18.2.0"
|
19
19
|
},
|
20
20
|
"devDependencies": {
|
@@ -1,25 +1,19 @@
|
|
1
|
-
import { describe, test, vi, expect, assert } from
|
2
|
-
import { createReferenceCountedPointer } from
|
1
|
+
import { describe, test, vi, expect, assert } from 'vitest';
|
2
|
+
import { createReferenceCountedPointer } from './createReferenceCountedPointer';
|
3
3
|
|
4
|
-
describe(
|
5
|
-
describe(
|
6
|
-
test(
|
4
|
+
describe('createReferenceCountedPointer', () => {
|
5
|
+
describe('it should not dispose the underlying item until all outstanding pointers are disposed', () => {
|
6
|
+
test('one pointer', () => {
|
7
7
|
const disposeItem = vi.fn();
|
8
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
9
|
-
1,
|
10
|
-
disposeItem,
|
11
|
-
]);
|
8
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
12
9
|
expect(disposeItem).not.toHaveBeenCalled();
|
13
10
|
disposePointer();
|
14
11
|
expect(disposeItem).toHaveBeenCalled();
|
15
12
|
});
|
16
13
|
|
17
|
-
test(
|
14
|
+
test('linked list, FIFO', () => {
|
18
15
|
const disposeItem = vi.fn();
|
19
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
20
|
-
1,
|
21
|
-
disposeItem,
|
22
|
-
]);
|
16
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
23
17
|
const [pointer2, disposePointer2] = pointer.cloneIfNotDisposed()!;
|
24
18
|
const [pointer3, disposePointer3] = pointer2.cloneIfNotDisposed()!;
|
25
19
|
const [pointer4, disposePointer4] = pointer3.cloneIfNotDisposed()!;
|
@@ -32,12 +26,9 @@ describe("createReferenceCountedPointer", () => {
|
|
32
26
|
expect(disposeItem).toHaveBeenCalled();
|
33
27
|
});
|
34
28
|
|
35
|
-
test(
|
29
|
+
test('linked list, LIFO', () => {
|
36
30
|
const disposeItem = vi.fn();
|
37
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
38
|
-
1,
|
39
|
-
disposeItem,
|
40
|
-
]);
|
31
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
41
32
|
const [pointer2, disposePointer2] = pointer.cloneIfNotDisposed()!;
|
42
33
|
const [pointer3, disposePointer3] = pointer2.cloneIfNotDisposed()!;
|
43
34
|
const [pointer4, disposePointer4] = pointer3.cloneIfNotDisposed()!;
|
@@ -50,12 +41,9 @@ describe("createReferenceCountedPointer", () => {
|
|
50
41
|
expect(disposeItem).toHaveBeenCalled();
|
51
42
|
});
|
52
43
|
|
53
|
-
test(
|
44
|
+
test('linked list, mixed order', () => {
|
54
45
|
const disposeItem = vi.fn();
|
55
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
56
|
-
1,
|
57
|
-
disposeItem,
|
58
|
-
]);
|
46
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
59
47
|
const [pointer2, disposePointer2] = pointer.cloneIfNotDisposed()!;
|
60
48
|
const [pointer3, disposePointer3] = pointer2.cloneIfNotDisposed()!;
|
61
49
|
const [pointer4, disposePointer4] = pointer3.cloneIfNotDisposed()!;
|
@@ -68,12 +56,9 @@ describe("createReferenceCountedPointer", () => {
|
|
68
56
|
expect(disposeItem).toHaveBeenCalled();
|
69
57
|
});
|
70
58
|
|
71
|
-
test(
|
59
|
+
test('DAG, from root', () => {
|
72
60
|
const disposeItem = vi.fn();
|
73
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
74
|
-
1,
|
75
|
-
disposeItem,
|
76
|
-
]);
|
61
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
77
62
|
const [pointerA, disposePointerA] = pointer.cloneIfNotDisposed()!;
|
78
63
|
const [pointerA_1, disposePointerA_1] = pointerA.cloneIfNotDisposed()!;
|
79
64
|
const [pointerA_2, disposePointerA_2] = pointerA.cloneIfNotDisposed()!;
|
@@ -92,12 +77,9 @@ describe("createReferenceCountedPointer", () => {
|
|
92
77
|
expect(disposeItem).toHaveBeenCalled();
|
93
78
|
});
|
94
79
|
|
95
|
-
test(
|
80
|
+
test('DAG, from leaves', () => {
|
96
81
|
const disposeItem = vi.fn();
|
97
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
98
|
-
1,
|
99
|
-
disposeItem,
|
100
|
-
]);
|
82
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
101
83
|
const [pointerA, disposePointerA] = pointer.cloneIfNotDisposed()!;
|
102
84
|
const [pointerA_1, disposePointerA_1] = pointerA.cloneIfNotDisposed()!;
|
103
85
|
const [pointerA_2, disposePointerA_2] = pointerA.cloneIfNotDisposed()!;
|
@@ -116,12 +98,9 @@ describe("createReferenceCountedPointer", () => {
|
|
116
98
|
expect(disposeItem).toHaveBeenCalled();
|
117
99
|
});
|
118
100
|
|
119
|
-
test(
|
101
|
+
test('DAG, random', () => {
|
120
102
|
const disposeItem = vi.fn();
|
121
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
122
|
-
1,
|
123
|
-
disposeItem,
|
124
|
-
]);
|
103
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
125
104
|
const [pointerA, disposePointerA] = pointer.cloneIfNotDisposed()!;
|
126
105
|
const [pointerA_1, disposePointerA_1] = pointerA.cloneIfNotDisposed()!;
|
127
106
|
const [pointerA_2, disposePointerA_2] = pointerA.cloneIfNotDisposed()!;
|
@@ -141,56 +120,41 @@ describe("createReferenceCountedPointer", () => {
|
|
141
120
|
});
|
142
121
|
});
|
143
122
|
|
144
|
-
test(
|
123
|
+
test('it should throw when disposed twice', () => {
|
145
124
|
const disposeItem = vi.fn();
|
146
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
147
|
-
1,
|
148
|
-
disposeItem,
|
149
|
-
]);
|
125
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
150
126
|
disposePointer();
|
151
127
|
expect(() => {
|
152
128
|
disposePointer();
|
153
129
|
}).toThrow();
|
154
130
|
});
|
155
131
|
|
156
|
-
test(
|
132
|
+
test('it should return null when you attempt to retain a disposed pointer', () => {
|
157
133
|
const disposeItem = vi.fn();
|
158
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
159
|
-
1,
|
160
|
-
disposeItem,
|
161
|
-
]);
|
134
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
162
135
|
disposePointer();
|
163
136
|
expect(pointer.cloneIfNotDisposed()).toBe(null);
|
164
137
|
});
|
165
138
|
|
166
|
-
test(
|
139
|
+
test('it should expose the underlying object only when undisposed', () => {
|
167
140
|
const disposeItem = vi.fn();
|
168
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
169
|
-
1,
|
170
|
-
disposeItem,
|
171
|
-
]);
|
141
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
172
142
|
expect(pointer.getItemIfNotDisposed()).toBe(1);
|
173
143
|
disposePointer();
|
174
144
|
expect(pointer.getItemIfNotDisposed()).toBe(null);
|
175
145
|
});
|
176
146
|
|
177
|
-
test(
|
147
|
+
test('it should accurately report its disposed status', () => {
|
178
148
|
const disposeItem = vi.fn();
|
179
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
180
|
-
1,
|
181
|
-
disposeItem,
|
182
|
-
]);
|
149
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
183
150
|
expect(pointer.isDisposed()).toBe(false);
|
184
151
|
disposePointer();
|
185
152
|
expect(pointer.isDisposed()).toBe(true);
|
186
153
|
});
|
187
154
|
|
188
|
-
test(
|
155
|
+
test('disposable status is unaffected by the presence of other undisposed pointers', () => {
|
189
156
|
const disposeItem = vi.fn();
|
190
|
-
const [pointer, disposePointer] = createReferenceCountedPointer([
|
191
|
-
1,
|
192
|
-
disposeItem,
|
193
|
-
]);
|
157
|
+
const [pointer, disposePointer] = createReferenceCountedPointer([1, disposeItem]);
|
194
158
|
const pointer2 = pointer.cloneIfNotDisposed();
|
195
159
|
assert(pointer2 != null);
|
196
160
|
expect(pointer2[0].isDisposed()).toBe(false);
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import type { CleanupFn, ItemCleanupPair } from
|
1
|
+
import type { CleanupFn, ItemCleanupPair } from '@isograph/disposable-types';
|
2
2
|
|
3
3
|
// TODO cloneIfNotDisposed should also return the underlying item
|
4
4
|
|
@@ -25,7 +25,7 @@ import type { CleanupFn, ItemCleanupPair } from "@isograph/disposable-types";
|
|
25
25
|
* was never disposed, and we could reuse it between states.
|
26
26
|
*/
|
27
27
|
export function createReferenceCountedPointer<T>(
|
28
|
-
pair: ItemCleanupPair<T
|
28
|
+
pair: ItemCleanupPair<T>,
|
29
29
|
): ItemCleanupPair<ReferenceCountedPointer<T>> {
|
30
30
|
const originalReferenceCountedPointer = new RefCounter(pair);
|
31
31
|
|
@@ -83,22 +83,20 @@ class RefCounter<T> {
|
|
83
83
|
let disposed = false;
|
84
84
|
const dispose = () => {
|
85
85
|
if (disposed) {
|
86
|
-
throw new Error(
|
87
|
-
"Do not dispose an already-disposed ActiveReference."
|
88
|
-
);
|
86
|
+
throw new Error('Do not dispose an already-disposed ActiveReference.');
|
89
87
|
}
|
90
88
|
disposed = true;
|
91
89
|
if (activeReference.__original === null) {
|
92
90
|
throw new Error(
|
93
|
-
|
94
|
-
|
91
|
+
'Attempted to dispose an active reference, but it was already disposed. ' +
|
92
|
+
'This indicates a bug in reference-counted-pointer.',
|
95
93
|
);
|
96
94
|
}
|
97
95
|
activeReference.__original = null;
|
98
96
|
if (this.__state === null) {
|
99
97
|
throw new Error(
|
100
|
-
|
101
|
-
|
98
|
+
'Attempted to dispose, but the underlying reference counted pointer was disposed. ' +
|
99
|
+
'This indicates a bug in reference-counted-pointer.',
|
102
100
|
);
|
103
101
|
}
|
104
102
|
this.__state.activeReferenceCount--;
|
@@ -114,8 +112,8 @@ class RefCounter<T> {
|
|
114
112
|
private __maybeDispose() {
|
115
113
|
if (this.__state === null) {
|
116
114
|
throw new Error(
|
117
|
-
|
118
|
-
|
115
|
+
'__maybeDispose was called, but the reference counted pointer was disposed. ' +
|
116
|
+
'This indicates a bug in reference-counted-pointer.',
|
119
117
|
);
|
120
118
|
}
|
121
119
|
if (this.__state.activeReferenceCount === 0) {
|
package/src/index.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export * from
|
1
|
+
export * from './createReferenceCountedPointer';
|