speedscope/utils.ts

60 lines
1.6 KiB
TypeScript
Raw Normal View History

2017-12-04 10:49:20 +03:00
export function atMostOnceAFrame<F extends Function>(fn: F) {
let frameRequest: number | null = null
function ret(...args: any[]) {
if (frameRequest == null) {
frameRequest = requestAnimationFrame(function () {
fn(...args)
frameRequest = null
})
}
}
return ret as any as F
}
export function lastOf<T>(ts: T[]): T | null {
return ts[ts.length-1] || null
2018-01-07 03:37:36 +03:00
}
2018-01-17 09:27:31 +03:00
export function sortBy<T>(ts: T[], key: (t: T) => number | string): void {
function comparator(a: T, b: T) {
return key(a) < key(b) ? -1 : 1
}
ts.sort(comparator)
}
export function getOrInsert<K, V>(map: Map<K, V>, k: K, fallback: (k?: K) => V): V {
if (!map.has(k)) map.set(k, fallback(k))
return map.get(k)!
}
export function getOrElse<K, V>(map: Map<K, V>, k: K, fallback: (k?: K) => V): V {
if (!map.has(k)) return fallback(k)
return map.get(k)!
}
export function* itMap<T, U>(it: Iterable<T>, f: (t: T) => U): Iterable<U> {
for (let t of it) {
yield f(t)
}
}
export function itForEach<T>(it: Iterable<T>, f: (t: T) => void): void {
for (let t of it) { f(t) }
}
export function itReduce<T, U>(it: Iterable<T>, f: (a: U, b: T) => U, init: U): U {
let accum: U = init
for (let t of it) {
accum = f(accum, t)
}
return accum
}
2018-01-07 03:37:36 +03:00
// NOTE: This blindly assumes the same result across contexts.
const measureTextCache = new Map<string, number>()
export function cachedMeasureTextWidth(ctx: CanvasRenderingContext2D, text: string): number {
if (!measureTextCache.has(text)) {
measureTextCache.set(text, ctx.measureText(text).width)
}
return measureTextCache.get(text)!
}