@btc-vision/transaction 1.7.4 → 1.7.5

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.
@@ -3,11 +3,9 @@ import { Map } from './Map.js';
3
3
 
4
4
  export class AddressMap<V> {
5
5
  private items: Map<bigint, V>;
6
- private keyOrder: Address[];
7
6
 
8
7
  constructor(iterable?: ReadonlyArray<readonly [Address, V]> | null) {
9
8
  this.items = new Map();
10
- this.keyOrder = [];
11
9
 
12
10
  if (iterable) {
13
11
  for (const [key, value] of iterable) {
@@ -17,15 +15,14 @@ export class AddressMap<V> {
17
15
  }
18
16
 
19
17
  public get size(): number {
20
- return this.keyOrder.length;
18
+ return this.items.size;
21
19
  }
22
20
 
23
- public set(key: Address, value: V): void {
21
+ public set(key: Address, value: V): this {
24
22
  const keyBigInt = key.toBigInt();
25
- if (!this.items.has(keyBigInt)) {
26
- this.keyOrder.push(key);
27
- }
28
23
  this.items.set(keyBigInt, value);
24
+
25
+ return this;
29
26
  }
30
27
 
31
28
  public get(key: Address): V | undefined {
@@ -38,41 +35,35 @@ export class AddressMap<V> {
38
35
 
39
36
  public delete(key: Address): boolean {
40
37
  const keyBigInt = key.toBigInt();
41
- if (this.items.delete(keyBigInt)) {
42
- this.keyOrder = this.keyOrder.filter((k) => k.toBigInt() !== keyBigInt);
43
- return true;
44
- }
45
- return false;
38
+ return this.items.delete(keyBigInt);
46
39
  }
47
40
 
48
41
  public clear(): void {
49
42
  this.items.clear();
50
- this.keyOrder = [];
51
43
  }
52
44
 
53
45
  public indexOf(address: Address): number {
54
- const addressBigInt = address.toBigInt();
55
- for (let i: number = 0; i < this.keyOrder.length; i++) {
56
- if (this.keyOrder[i].toBigInt() === addressBigInt) {
57
- return i;
58
- }
59
- }
60
- return -1;
46
+ return this.items.indexOf(address.toBigInt());
61
47
  }
62
48
 
49
+ /**
50
+ * WARNING, THIS RETURN NEW COPY OF THE KEYS
51
+ */
63
52
  *entries(): IterableIterator<[Address, V]> {
64
- for (const key of this.keyOrder) {
65
- yield [key, this.items.get(key.toBigInt()) as V];
53
+ for (const [keyBigInt, value] of this.items.entries()) {
54
+ yield [Address.fromBigInt(keyBigInt), value];
66
55
  }
67
56
  }
68
57
 
69
58
  *keys(): IterableIterator<Address> {
70
- yield* this.keyOrder;
59
+ for (const keyBigInt of this.items.keys()) {
60
+ yield Address.fromBigInt(keyBigInt);
61
+ }
71
62
  }
72
63
 
73
64
  *values(): IterableIterator<V> {
74
- for (const key of this.keyOrder) {
75
- yield this.items.get(key.toBigInt()) as V;
65
+ for (const value of this.items.values()) {
66
+ yield value;
76
67
  }
77
68
  }
78
69
 
@@ -80,15 +71,13 @@ export class AddressMap<V> {
80
71
  callback: (value: V, key: Address, map: AddressMap<V>) => void,
81
72
  thisArg?: unknown,
82
73
  ): void {
83
- for (const key of this.keyOrder) {
84
- callback.call(thisArg, this.items.get(key.toBigInt()) as V, key, this);
74
+ for (const [keyBigInt, value] of this.items.entries()) {
75
+ const key = Address.fromBigInt(keyBigInt);
76
+ callback.call(thisArg, value, key, this);
85
77
  }
86
78
  }
87
79
 
88
80
  *[Symbol.iterator](): IterableIterator<[Address, V]> {
89
- for (let i = 0; i < this.keyOrder.length; i++) {
90
- const key = this.keyOrder[i];
91
- yield [key, this.items.get(key.toBigInt()) as V];
92
- }
81
+ yield* this.entries();
93
82
  }
94
83
  }
@@ -0,0 +1,316 @@
1
+ export class CustomMap<K, V> {
2
+ private static readonly INITIAL_CAPACITY = 16;
3
+ private static readonly LOAD_FACTOR = 0.75;
4
+
5
+ #keys: (K | undefined)[];
6
+ #values: (V | undefined)[];
7
+
8
+ private deleted: boolean[];
9
+ private capacity: number;
10
+
11
+ constructor() {
12
+ this.capacity = CustomMap.INITIAL_CAPACITY;
13
+ this.#keys = new Array<K>(this.capacity);
14
+ this.#values = new Array<V>(this.capacity);
15
+ this.deleted = new Array<boolean>(this.capacity).fill(false);
16
+ }
17
+
18
+ private _size: number = 0;
19
+
20
+ public get size(): number {
21
+ return this._size;
22
+ }
23
+
24
+ public set(key: K, value: V): boolean {
25
+ let exist: boolean = true;
26
+
27
+ const index = this.findInsertIndex(key);
28
+ if (this.#keys[index] === undefined || this.deleted[index]) {
29
+ this._size++;
30
+ exist = false;
31
+ }
32
+
33
+ this.#keys[index] = key;
34
+ this.#values[index] = value;
35
+ this.deleted[index] = false;
36
+
37
+ if (this._size > this.capacity * CustomMap.LOAD_FACTOR) {
38
+ this.resize();
39
+ }
40
+
41
+ return exist;
42
+ }
43
+
44
+ public get(key: K): V | undefined {
45
+ const index = this.findIndex(key);
46
+ return index === -1 ? undefined : this.#values[index];
47
+ }
48
+
49
+ public has(key: K): boolean {
50
+ return this.findIndex(key) !== -1;
51
+ }
52
+
53
+ public indexOf(key: K): number {
54
+ return this.findIndex(key);
55
+ }
56
+
57
+ public delete(key: K): boolean {
58
+ const index = this.findIndex(key);
59
+
60
+ if (index === -1) {
61
+ return false;
62
+ }
63
+
64
+ this.#keys[index] = undefined;
65
+ this.#values[index] = undefined;
66
+ this.deleted[index] = true;
67
+ this._size--;
68
+
69
+ return true;
70
+ }
71
+
72
+ public clear(): void {
73
+ this.#keys = new Array<K>(this.capacity);
74
+ this.#values = new Array<V>(this.capacity);
75
+ this.deleted = new Array<boolean>(this.capacity).fill(false);
76
+ this._size = 0;
77
+ }
78
+
79
+ public *entries(): MapIterator<[K, V]> {
80
+ for (let i = 0; i < this.capacity; i++) {
81
+ if (this.#keys[i] !== undefined && !this.deleted[i]) {
82
+ yield [this.#keys[i] as K, this.#values[i] as V];
83
+ }
84
+ }
85
+ }
86
+
87
+ public *keys(): MapIterator<K> {
88
+ for (let i = 0; i < this.capacity; i++) {
89
+ if (this.#keys[i] !== undefined && !this.deleted[i]) {
90
+ yield this.#keys[i] as K;
91
+ }
92
+ }
93
+ }
94
+
95
+ public *values(): MapIterator<V> {
96
+ for (let i = 0; i < this.capacity; i++) {
97
+ if (this.#keys[i] !== undefined && !this.deleted[i]) {
98
+ yield this.#values[i] as V;
99
+ }
100
+ }
101
+ }
102
+
103
+ *[Symbol.iterator](): MapIterator<[K, V]> {
104
+ yield* this.entries();
105
+ }
106
+
107
+ private hashBigInt(key: bigint): number {
108
+ // For small bigints that fit in 32 bits, use direct conversion
109
+ if (key >= -2147483648n && key <= 2147483647n) {
110
+ return Number(key) | 0;
111
+ }
112
+
113
+ // For larger bigints, use bit manipulation
114
+ // Mix high and low 32-bit parts
115
+ let hash = 2166136261; // FNV-1a initial value
116
+
117
+ // Process the bigint in 32-bit chunks
118
+ let n = key < 0n ? -key : key;
119
+
120
+ while (n > 0n) {
121
+ // Extract 32-bit chunk
122
+ const chunk = Number(n & 0xffffffffn);
123
+ hash ^= chunk;
124
+ hash = Math.imul(hash, 16777619);
125
+ n = n >> 32n;
126
+ }
127
+
128
+ // Mix in the sign
129
+ if (key < 0n) {
130
+ hash ^= 0x80000000;
131
+ hash = Math.imul(hash, 16777619);
132
+ }
133
+
134
+ return Math.abs(hash);
135
+ }
136
+
137
+ private hash(key: K): number {
138
+ let hash = 0;
139
+
140
+ switch (typeof key) {
141
+ case 'number':
142
+ // Handle NaN and infinity specially
143
+ if (key !== key) return 0x7ff8000000000000; // NaN
144
+ if (!isFinite(key)) return key > 0 ? 0x7ff0000000000000 : 0xfff0000000000000;
145
+ // Use the number itself as hash
146
+ hash = key | 0; // Convert to 32-bit integer
147
+ break;
148
+
149
+ case 'string':
150
+ // FNV-1a hash for strings
151
+ hash = 2166136261;
152
+ for (let i = 0; i < (key as string).length; i++) {
153
+ hash ^= (key as string).charCodeAt(i);
154
+ hash = Math.imul(hash, 16777619);
155
+ }
156
+ break;
157
+
158
+ case 'boolean':
159
+ hash = key ? 1231 : 1237;
160
+ break;
161
+
162
+ case 'symbol': {
163
+ // Symbols need special handling - use description
164
+ const desc = (key as symbol).description || '';
165
+ hash = this.hash(desc as K); // Recursive call with string
166
+ break;
167
+ }
168
+
169
+ case 'bigint':
170
+ // Convert bigint to string for hashing
171
+ hash = this.hashBigInt(key);
172
+ break;
173
+
174
+ case 'undefined':
175
+ hash = 0;
176
+ break;
177
+
178
+ case 'object':
179
+ if (key === null) {
180
+ hash = 0;
181
+ } else if (key instanceof Date) {
182
+ hash = key.getTime() | 0;
183
+ } else if (ArrayBuffer.isView(key) || key instanceof ArrayBuffer) {
184
+ // Handle Buffer, TypedArrays, ArrayBuffer
185
+ hash = this.hashBuffer(key);
186
+ } else if (Array.isArray(key)) {
187
+ // Hash arrays by combining element hashes
188
+ hash = 1;
189
+ for (const item of key) {
190
+ hash = Math.imul(hash, 31) + this.hash(item as K);
191
+ }
192
+ } else {
193
+ throw new Error('Raw object not supported.');
194
+ // For objects, we need reference equality
195
+ // So we'll use linear probing with === comparison
196
+ // Start with a random-ish position
197
+ //hash = 0x42424242;
198
+ }
199
+ break;
200
+
201
+ case 'function':
202
+ // Hash function by its string representation
203
+ hash = this.hash(key.toString() as K);
204
+ break;
205
+ }
206
+
207
+ // Ensure positive index
208
+ return Math.abs(hash) % this.capacity;
209
+ }
210
+
211
+ private hashBuffer(buffer: ArrayBuffer | object): number {
212
+ let bytes: Uint8Array;
213
+
214
+ if (buffer instanceof ArrayBuffer) {
215
+ bytes = new Uint8Array(buffer);
216
+ } else if (ArrayBuffer.isView(buffer)) {
217
+ bytes = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
218
+ } else {
219
+ return 0;
220
+ }
221
+
222
+ // FNV-1a hash for bytes
223
+ let hash = 2166136261;
224
+ for (let i = 0; i < Math.min(bytes.length, 100); i++) {
225
+ // Cap at 100 bytes for performance
226
+ hash ^= bytes[i];
227
+ hash = Math.imul(hash, 16777619);
228
+ }
229
+ return hash;
230
+ }
231
+
232
+ private equals(a: K, b: K): boolean {
233
+ // Handle special cases
234
+ if (a === b) return true;
235
+
236
+ // NaN === NaN should be true for map #keys
237
+ if (typeof a === 'number' && typeof b === 'number' && a !== a && b !== b) {
238
+ return true;
239
+ }
240
+
241
+ // For buffers, do deep comparison
242
+ if (
243
+ (ArrayBuffer.isView(a) || a instanceof ArrayBuffer) &&
244
+ (ArrayBuffer.isView(b) || b instanceof ArrayBuffer)
245
+ ) {
246
+ return this.buffersEqual(a, b);
247
+ }
248
+
249
+ return false;
250
+ }
251
+
252
+ private buffersEqual(a: ArrayBuffer | object, b: ArrayBuffer | object): boolean {
253
+ const bytesA = this.getBytes(a);
254
+ const bytesB = this.getBytes(b);
255
+
256
+ if (bytesA.length !== bytesB.length) return false;
257
+
258
+ for (let i = 0; i < bytesA.length; i++) {
259
+ if (bytesA[i] !== bytesB[i]) return false;
260
+ }
261
+
262
+ return true;
263
+ }
264
+
265
+ private getBytes(buffer: ArrayBuffer | object): Uint8Array {
266
+ if (buffer instanceof ArrayBuffer) {
267
+ return new Uint8Array(buffer);
268
+ } else if (ArrayBuffer.isView(buffer)) {
269
+ return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
270
+ }
271
+ return new Uint8Array(0);
272
+ }
273
+
274
+ private findIndex(key: K): number {
275
+ let index = this.hash(key);
276
+
277
+ while (this.#keys[index] !== undefined || this.deleted[index]) {
278
+ if (this.#keys[index] !== undefined && this.equals(this.#keys[index] as K, key)) {
279
+ return index;
280
+ }
281
+ index = (index + 1) % this.capacity;
282
+ }
283
+
284
+ return -1;
285
+ }
286
+
287
+ private findInsertIndex(key: K): number {
288
+ let index = this.hash(key);
289
+
290
+ while (this.#keys[index] !== undefined && !this.deleted[index]) {
291
+ if (this.equals(this.#keys[index] as K, key)) {
292
+ return index; // Key already exists
293
+ }
294
+ index = (index + 1) % this.capacity;
295
+ }
296
+
297
+ return index;
298
+ }
299
+
300
+ private resize(): void {
301
+ const oldKeys = this.#keys;
302
+ const oldValues = this.#values;
303
+
304
+ this.capacity *= 2;
305
+ this.#keys = new Array<K>(this.capacity);
306
+ this.#values = new Array<V>(this.capacity);
307
+ this.deleted = new Array<boolean>(this.capacity).fill(false);
308
+ this._size = 0;
309
+
310
+ for (let i = 0; i < oldKeys.length; i++) {
311
+ if (oldKeys[i] !== undefined && !this.deleted[i]) {
312
+ this.set(oldKeys[i] as K, oldValues[i] as V);
313
+ }
314
+ }
315
+ }
316
+ }
@@ -1,6 +1,6 @@
1
1
  export class Map<K, V> {
2
2
  protected _keys: K[] = [];
3
- protected _values: V[] = [];
3
+ protected _values: Record<string, V> = {};
4
4
 
5
5
  public get size(): number {
6
6
  return this._keys.length;
@@ -11,66 +11,77 @@ export class Map<K, V> {
11
11
  }
12
12
 
13
13
  public *values(): IterableIterator<V> {
14
- yield* this._values;
14
+ for (const key of this._keys) {
15
+ yield this._values[this.keyToString(key)];
16
+ }
15
17
  }
16
18
 
17
19
  public *entries(): IterableIterator<[K, V]> {
18
- for (let i: number = 0; i < this._keys.length; i++) {
19
- yield [this._keys[i], this._values[i]];
20
+ for (const key of this._keys) {
21
+ yield [key, this._values[this.keyToString(key)]];
20
22
  }
21
23
  }
22
24
 
23
25
  public set(key: K, value: V): void {
24
- const index: number = this.indexOf(key);
25
- if (index == -1) {
26
+ const keyStr = this.keyToString(key);
27
+ if (!this.has(key)) {
26
28
  this._keys.push(key);
27
- this._values.push(value);
28
- } else {
29
- this._values[index] = value;
30
29
  }
30
+
31
+ this._values[keyStr] = value;
31
32
  }
32
33
 
33
34
  public indexOf(key: K): number {
34
- for (let i: number = 0; i < this._keys.length; i++) {
35
- if (this._keys[i] == key) {
35
+ for (let i = 0; i < this._keys.length; i++) {
36
+ if (this._keys[i] === key) {
36
37
  return i;
37
38
  }
38
39
  }
39
-
40
40
  return -1;
41
41
  }
42
42
 
43
43
  public get(key: K): V | undefined {
44
- const index: number = this.indexOf(key);
45
- if (index == -1) {
46
- return undefined;
47
- }
48
- return this._values[index];
44
+ return this._values[this.keyToString(key)];
49
45
  }
50
46
 
51
47
  public has(key: K): boolean {
52
- return this.indexOf(key) != -1;
48
+ return Object.prototype.hasOwnProperty.call(this._values, this.keyToString(key));
53
49
  }
54
50
 
55
51
  public delete(key: K): boolean {
56
- const index: number = this.indexOf(key);
57
- if (index == -1) {
52
+ const index = this.indexOf(key);
53
+ if (index === -1) {
58
54
  return false;
59
55
  }
60
56
 
57
+ const keyStr = this.keyToString(key);
61
58
  this._keys.splice(index, 1);
62
- this._values.splice(index, 1);
59
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
60
+ delete this._values[keyStr];
63
61
  return true;
64
62
  }
65
63
 
66
64
  public clear(): void {
67
65
  this._keys = [];
68
- this._values = [];
66
+ this._values = {};
69
67
  }
70
68
 
71
69
  *[Symbol.iterator](): IterableIterator<[K, V]> {
72
- for (let i: number = 0; i < this._keys.length; i++) {
73
- yield [this._keys[i], this._values[i]];
70
+ for (const key of this._keys) {
71
+ yield [key, this._values[this.keyToString(key)]];
72
+ }
73
+ }
74
+
75
+ private keyToString(key: K): string {
76
+ if (typeof key === 'string') {
77
+ return key;
78
+ }
79
+ if (typeof key === 'number' || typeof key === 'boolean') {
80
+ return String(key);
81
+ }
82
+ if (typeof key === 'object' && key !== null) {
83
+ return JSON.stringify(key);
74
84
  }
85
+ return String(key);
75
86
  }
76
87
  }
package/src/opnet.ts CHANGED
@@ -126,6 +126,7 @@ export * from './keypair/Secp256k1PointDeriver.js';
126
126
  export * from './transaction/ContractAddress.js';
127
127
 
128
128
  export * from './deterministic/Map.js';
129
+ export * from './deterministic/CustomMap.js';
129
130
 
130
131
  declare global {
131
132
  interface Window {