Created
September 18, 2023 04:24
-
-
Save devlato/c1d4ca0250a8cd64b5f1adf4aa1093aa to your computer and use it in GitHub Desktop.
ArrayView for JS Arrays
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// `ReadonlyArrayView` class allows to avoid copying when creating array slices | |
// It can be used as a drop-in replacement instead of an array but only gives read access to the original array | |
// Worth remembering that this class doesn't track index change, element reordering, etc., so use it at your own risk | |
// | |
// Demo: | |
// https://www.typescriptlang.org/play?module=1#code/C4TwDgpgBASghgOwObQLxQN4FgBQUoBmATgPYC2AkggCYQAeAXFAgK5kBGERA3LvsCSq1GzNpx64Avrxy56YEkWBQAxgBs4AZ02wIcaiQRqQAQSJE4IAGoBLCAHcAPABUAfFBtkwaiGQgJgHTMLEAAZGwBrCBd3bDwoIj0DIxAoAG0EJlYOLgBdJmdcPigwIhsANzhgaBVDTWAiFhUBIgAKUoqq6ET9Q2MoOHNLArTcgBoSssrqhKS+1ItkCCZ4JYBKTEki+PqqmxUoEgIY1sGQkfGExBQV64g1lbmU4MtbBxjMYvxahHqocrs9ig6AQDl0vWeQ2sgJOZ0sE0WKDWMi+qjqygQhgAwnA1Bp2D5gVBWhtULFUfwABakIGgoEAUXMilaAHIcQhMcoVLi1FBgJSbDotANCCwEM0bIYWcjUdJtvh8IlgCwiAhmGCAAqkOggVoAhwTOIKhVwMDeEBZbE8uAEiBjClo34NJrAS0IHF4m0+e3xY20Ag2UFakiQJQW5hWz22n3G-C0HzVYOh0Buj3470Okj2BAAaQgIE0TBJwPcaRZPmQ-JZExZUQL1agLMqahYEE0DZZAgAyg1A0gWeMHShXcTgINhxMwBMAPqk8m+2M2AjEsAeNVjojDjZG2PGpUq9fjiDANKr4WIEC5GS7-BbWQL41LldrvlH4AAOjhIG3Dr3x4Pr6bsen5QqeAxCggl7Xjed6-rMyqqlAYr+oGEDUNBxqSDGsaUloRYbhOJRzp8D4KvuiGroGgHDlAAA+tElC+BHAV+GEKlhDqCvSdDVL8Ni2kWxEELimh2g6pQQOU-jANxvGaJKvyCSWfKNGJpGicAwYCKAkAAPIEKm1rRrKMrxLB8Q0RWSD8sWO6Kv+iH8oK76IhA77EOQQj0FAAC0fICpoLl3O+AheXQ0HmfgABUdaaLZqIEIoxIJh4RJOYFrnuaQlA0PQ3CpY4-nOZloW5eFHgANQVT+pEgHYajUB4bF3re8pQFFzatnFNXGolRDJceqVHEVgWxSSPWxnVEANSNIEhGkNhXrKxSRXyJA9mUyDxQu5Fqmk74Hel76dW2JK5CF629ltpmtfe-AkAAUl2ukAHLbX+CFqk9r3vvUm1IEuur7YdAXHbiXVnTdUCrVFaRdiAHAkGo742NUFgtLk70Kn1A3KDYhzLkdY1rBNxpTTNR1fgtS0Li10NSNsPx-GcjwQsYLzQu8f19u46AwE87NQm89jvkcrRliYHYAEIdliHYACIdvSHYAGIdgA4h2AASA6GoQ2VhUwABMEylcITAACzQ6ZTPKGcAAMRJnGk9s00zSNuWoJBIKyDsNg7pk460KX48NZwTe7Pjvl7PsAAbOwAJBgNiSLkscTDYpl3pHnve775jvsTDbA3Nhf5t1uQ23UHvR3nLJnGDLanWsxcHaXJ0V1Xvw1zH+dEBdG19iS-sF92V0+yTMg57XPsst9L2-VdAZILqLcTPPi--YDpzmJPuBAA | |
export class ReadonlyArrayView<T> implements ArrayLike<T> { | |
readonly [n: number]: T | |
private constructor(private readonly array: T[], private readonly range: Range) {} | |
static of<T>(array: T[], range: Range): ReadonlyArrayView<T> { | |
const view = new ReadonlyArrayView<T>(array, range); | |
const nonCallable = () => { | |
throw new Error('Cannot call this as a function'); | |
}; | |
return new Proxy(view, { | |
apply: nonCallable, | |
construct: nonCallable, | |
defineProperty: nonCallable, | |
deleteProperty: nonCallable, | |
ownKeys: () => ['length', 'keys', 'values', 'toString'], | |
get: (target, p, _) => { | |
if (p in target) { | |
return target[p as any]; | |
} | |
if (p in target.array) { | |
return target.array[p as any]; | |
} | |
return undefined; | |
}, | |
has: (target, p) => { | |
return p in target || p in target.array; | |
}, | |
isExtensible: () => false, | |
preventExtensions: () => true, | |
setPrototypeOf: nonCallable, | |
}); | |
} | |
get length() { | |
return this.range.fromIndex - this.range.toIndex; | |
} | |
*keys() { | |
for (let i = this.range.fromIndex; i < this.range.toIndex; i++) { | |
yield i; | |
} | |
} | |
*values() { | |
for (const i of this.keys()) { | |
yield this.array[i]; | |
} | |
} | |
toString() { | |
return [...this.values()].toString(); | |
} | |
toJSON() { | |
return JSON.stringify([...this.values()]); | |
} | |
*[Symbol.iterator]() { | |
for (const i of this.keys()) { | |
yield this.array[i]; | |
} | |
} | |
} | |
type Range = { | |
fromIndex: number, | |
toIndex: number, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment