Skip to content

Commit

Permalink
dex-data: optimize toID
Browse files Browse the repository at this point in the history
see PR comments for stats and explanations.
  • Loading branch information
larry-the-table-guy committed Oct 8, 2024
1 parent 3be1db2 commit 56cd94b
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 8 deletions.
25 changes: 17 additions & 8 deletions sim/dex-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import {Utils} from '../lib';
/** Unfortunately we do for..in too much to want to deal with the casts */
export interface DexTable<T> {[id: string]: T}


/**
* Do not expose to user input. Only populate with trusted data.
* Populated by ./sim/dex.ts then frozen.
*/
export const _toIDCache: Map<string, ID> = new Map();
/**
* Converts anything to an ID. An ID must have only lowercase alphanumeric
* characters.
Expand All @@ -25,15 +31,18 @@ export interface DexTable<T> {[id: string]: T}
export function toID(text: any): ID {
// The sucrase transformation of optional chaining is too expensive to be used in a hot function like this.
/* eslint-disable @typescript-eslint/prefer-optional-chain */
if (text && text.id) {
text = text.id;
} else if (text && text.userid) {
text = text.userid;
} else if (text && text.roomid) {
text = text.roomid;
if (typeof text === 'string') {
// 99.9% case, skip checks
} else {
if (text) text = text.id || text.userid || text.roomid || text;
if (typeof text === 'number') text = '' + text;
else if (typeof text !== 'string') return '';
}
if (typeof text !== 'string' && typeof text !== 'number') return '';
return ('' + text).toLowerCase().replace(/[^a-z0-9]+/g, '') as ID;
// very often text is already a valid ID.
if (/^[a-z0-9]*$/.test(text)) return text;
// Next, we often produce the same IDs many times.
// Otherwise, fallback to the generic case
return _toIDCache.get(text) || text.toLowerCase().replace(/[^a-z0-9]+/g, '') as ID;
/* eslint-enable @typescript-eslint/prefer-optional-chain */
}

Expand Down
31 changes: 31 additions & 0 deletions sim/dex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,37 @@ dexes['base'] = new ModdedDex();
dexes[BASE_MOD] = dexes['base'];

export const Dex = dexes['base'];

// populate _toIDCache with data from base mod.
// It's representative enough for all other mods, so we don't need to dynamically grow the cache.
{
const cache = Data._toIDCache;
const sources: readonly (readonly BasicEffect[])[] = [
Dex.species.all(), Dex.items.all(), Dex.moves.all(),
Dex.types.all() as any as readonly BasicEffect[], Dex.abilities.all(), Dex.natures.all(),
];
for (const source of sources) {
for (const effect of source) {
const name = effect.name;
if (!name) continue;
// we can't just use effect.id because of cases like hidden power
const id = toID(name);
const old = cache.get(name);
if (old === undefined) cache.set(name, id);
else if (old !== id) throw new Error("internal error with ID logic");
}
}
const aliases = Dex.data.Aliases;
for (const k in aliases) {
const name = aliases[k];
const id = toID(name);
const old = cache.get(name);
if (old === undefined) cache.set(name, id);
else if (old !== id) throw new Error("internal error with ID logic");
}
Object.freeze(cache);
}

export namespace Dex {
export type Species = import('./dex-species').Species;
export type Item = import('./dex-items').Item;
Expand Down

0 comments on commit 56cd94b

Please sign in to comment.