-
Notifications
You must be signed in to change notification settings - Fork 170
🎨 [PANA-5260] Consolidate recorder object id tracking code #4049
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
528d7f3
5a557f5
f6dfe33
f63d749
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| import type { EventId, ItemIds, NodeId, StringId, StyleSheetId } from './itemIds' | ||
| import { | ||
| createEventIds, | ||
| createNodeIds, | ||
| createStringIds, | ||
| createStyleSheetIds, | ||
| EventIdConstants, | ||
| NodeIdConstants, | ||
| StringIdConstants, | ||
| StyleSheetIdConstants, | ||
| } from './itemIds' | ||
|
|
||
| describe('ItemIds', () => { | ||
| const describeItemIdVariant = <ItemType, ItemId extends number>( | ||
| name: string, | ||
| createIdMap: () => ItemIds<ItemType, ItemId>, | ||
| createItem: () => ItemType, | ||
| firstId: ItemId | ||
| ) => { | ||
| describe(name, () => { | ||
| let itemIds = createIdMap() | ||
|
|
||
| beforeEach(() => { | ||
| itemIds = createIdMap() | ||
| }) | ||
|
|
||
| describe('clear', () => { | ||
| it('removes all id mappings', () => { | ||
| const item = createItem() | ||
| itemIds.getOrInsert(item) | ||
| expect(itemIds.get(item)).toBe(firstId) | ||
|
|
||
| itemIds.clear() | ||
| expect(itemIds.get(item)).toBeUndefined() | ||
| }) | ||
|
|
||
| it('restarts the id sequence', () => { | ||
| for (let id = firstId; id < firstId + 3; id++) { | ||
| const item = createItem() | ||
| expect(itemIds.getOrInsert(item)).toBe(id) | ||
| expect(itemIds.getOrInsert(item)).toBe(id) | ||
| } | ||
|
|
||
| itemIds.clear() | ||
|
|
||
| for (let id = firstId; id < firstId + 3; id++) { | ||
| const item = createItem() | ||
| expect(itemIds.getOrInsert(item)).toBe(id) | ||
| expect(itemIds.getOrInsert(item)).toBe(id) | ||
| } | ||
| }) | ||
| }) | ||
|
|
||
| describe('get', () => { | ||
| it('returns undefined for items that have not been assigned an id', () => { | ||
| expect(itemIds.get(createItem())).toBe(undefined) | ||
| }) | ||
|
|
||
| it('returns the assigned id if one exists', () => { | ||
| const item = createItem() | ||
| itemIds.getOrInsert(item) | ||
| expect(itemIds.get(item)).toBe(firstId) | ||
| }) | ||
| }) | ||
|
|
||
| describe('getOrInsert', () => { | ||
| it('assigns ids in order', () => { | ||
| for (let id = firstId; id < firstId + 3; id++) { | ||
| const item = createItem() | ||
| expect(itemIds.getOrInsert(item)).toBe(id) | ||
| expect(itemIds.getOrInsert(item)).toBe(id) | ||
| } | ||
| }) | ||
|
|
||
| it('reuses any existing id', () => { | ||
| itemIds.getOrInsert(createItem()) | ||
| itemIds.getOrInsert(createItem()) | ||
| const item = createItem() | ||
| const itemId = itemIds.getOrInsert(item) | ||
| expect(itemIds.getOrInsert(item)).toBe(itemId) | ||
| expect(itemIds.get(item)).toBe(itemId) | ||
| }) | ||
| }) | ||
|
|
||
| describe('size', () => { | ||
| it('increments when an id is assigned', () => { | ||
| expect(itemIds.size).toBe(0) | ||
| itemIds.getOrInsert(createItem()) | ||
| expect(itemIds.size).toBe(1) | ||
| itemIds.getOrInsert(createItem()) | ||
| expect(itemIds.size).toBe(2) | ||
| }) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| describeItemIdVariant( | ||
| 'EventIds', | ||
| createEventIds, | ||
| () => new Event('someCustomEvent'), | ||
| EventIdConstants.FIRST_ID as EventId | ||
| ) | ||
|
|
||
| describeItemIdVariant( | ||
| 'NodeIds', | ||
| createNodeIds, | ||
| () => document.createElement('div'), | ||
| NodeIdConstants.FIRST_ID as NodeId | ||
| ) | ||
|
|
||
| let nextString = 0 | ||
| describeItemIdVariant( | ||
| 'StringIds', | ||
| createStringIds, | ||
| () => `string${nextString++}`, | ||
| StringIdConstants.FIRST_ID as StringId | ||
| ) | ||
|
|
||
| describeItemIdVariant( | ||
| 'StyleSheetIds', | ||
| createStyleSheetIds, | ||
| // The CSSStyleSheet constructor is not available on older browsers. | ||
| () => ({ type: 'CSSStyleSheet' }), | ||
| StyleSheetIdConstants.FIRST_ID as StyleSheetId | ||
| ) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| export type EventId = number & { __brand: 'EventId' } | ||
| export type EventIds = ItemIds<Event, EventId> | ||
| export const enum EventIdConstants { | ||
| FIRST_ID = 1, | ||
| } | ||
| export function createEventIds(): EventIds { | ||
| return createWeakIdMap(EventIdConstants.FIRST_ID as EventId) | ||
| } | ||
|
|
||
| export type NodeId = number & { __brand: 'NodeId' } | ||
| export type NodeIds = ItemIds<Node, NodeId> | ||
| export const enum NodeIdConstants { | ||
| FIRST_ID = 0, | ||
| } | ||
| export function createNodeIds(): NodeIds { | ||
| return createWeakIdMap(NodeIdConstants.FIRST_ID as NodeId) | ||
| } | ||
|
|
||
| export type StringId = number & { __brand: 'StringId' } | ||
| export type StringIds = ItemIds<string, StringId> | ||
| export const enum StringIdConstants { | ||
| FIRST_ID = 0, | ||
| } | ||
| export function createStringIds(): StringIds { | ||
| return createIdMap(StringIdConstants.FIRST_ID as StringId) | ||
| } | ||
|
|
||
| export type StyleSheetId = number & { __brand: 'StyleSheetId' } | ||
| export type StyleSheetIds = ItemIds<CSSStyleSheet, StyleSheetId> | ||
| export const enum StyleSheetIdConstants { | ||
| FIRST_ID = 0, | ||
| } | ||
| export function createStyleSheetIds(): StyleSheetIds { | ||
| return createWeakIdMap(StyleSheetIdConstants.FIRST_ID as StyleSheetId) | ||
| } | ||
|
|
||
| export interface ItemIds<ItemType, ItemId extends number> { | ||
| clear(this: void): void | ||
| get(this: void, item: ItemType): ItemId | undefined | ||
| getOrInsert(this: void, item: ItemType): ItemId | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method was called |
||
| get size(): number | ||
| } | ||
|
|
||
| function createIdMap<ItemType, ItemId extends number>(firstId: ItemId): ItemIds<ItemType, ItemId> { | ||
| return createItemIds(() => new Map<ItemType, ItemId>(), firstId) | ||
| } | ||
|
|
||
| function createWeakIdMap<ItemType extends object, ItemId extends number>(firstId: ItemId): ItemIds<ItemType, ItemId> { | ||
| return createItemIds(() => new WeakMap<ItemType, ItemId>(), firstId) | ||
| } | ||
|
Comment on lines
+44
to
+50
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need two variations here because |
||
|
|
||
| interface MapLike<Key, Value> { | ||
| get(key: Key): Value | undefined | ||
| set(key: Key, value: Value): void | ||
| } | ||
|
|
||
| function createItemIds<ItemType, ItemId extends number>( | ||
| createMap: () => MapLike<ItemType, ItemId>, | ||
| firstId: ItemId | ||
| ): ItemIds<ItemType, ItemId> { | ||
| let map = createMap() | ||
| let nextId = firstId | ||
|
|
||
| const get = (object: ItemType): ItemId | undefined => map.get(object) | ||
|
|
||
| return { | ||
| clear(): void { | ||
| map = createMap() | ||
| nextId = firstId | ||
| }, | ||
| get, | ||
| getOrInsert(object: ItemType): ItemId { | ||
| // Try to reuse any existing id. | ||
| let id = get(object) | ||
| if (id === undefined) { | ||
| id = nextId++ as ItemId | ||
| map.set(object, id) | ||
| } | ||
| return id | ||
| }, | ||
| get size(): number { | ||
| return nextId - firstId | ||
| }, | ||
| } | ||
| } | ||
This file was deleted.
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.