UNPKG

react-native

Version:

A framework for building native apps using React

191 lines (173 loc) • 6.24 kB
// @flow import invariant from 'invariant'; import AggrowData, { AggrowDoubleColumn, AggrowIntColumn, AggrowStackColumn, AggrowStringColumn } from './AggrowData'; import AggrowExpander from './AggrowExpander'; import type { FlattenedStack } from './StackRegistry'; import StackRegistry from './StackRegistry'; export type FocusConfig = { pattern: RegExp, firstMatch: boolean, leftSide: boolean, } type FocusPredicate = (frameId: number) => boolean; export default class Aggrow { data: AggrowData; expander: AggrowExpander; constructor(aggrowData: AggrowData) { aggrowData.flattenStacks(); this.data = aggrowData; this.expander = new AggrowExpander(aggrowData.rowCount); } addSumAggregator(aggregatorName: string, columnName: string): number { const column = this.data.getColumn(columnName); invariant(column, `Column ${columnName} does not exist.`); invariant(column instanceof AggrowIntColumn || column instanceof AggrowDoubleColumn, `Sum aggregator does not support ${column.constructor.name} columns!`); return this.expander.addAggregator( aggregatorName, (indices: Int32Array): number => { let size = 0; indices.forEach((i: number) => { size += column.get(i); }); return size; }, (value: any): string => value.toLocaleString(), (a: number, b: number): number => b - a, ); } addCountAggregator(aggregatorName: string): number { return this.expander.addAggregator( aggregatorName, (indices: Int32Array): number => indices.length, (value: any): string => value.toLocaleString(), (a: number, b: number): number => b - a, ); } addStringExpander(expanderName: string, columnName: string): number { const column = this.data.getColumn(columnName); invariant(column, `Column ${columnName} does not exist.`); invariant(column instanceof AggrowStringColumn, 'String expander needs a string column.'); const strings = column.strings; return this.expander.addFieldExpander( expanderName, (rowA: number, rowB: number): number => column.get(rowA) - column.get(rowB), (row: number): string => strings.get(column.get(row)), (s: string): string => s, ); } addNumberExpander(expanderName: string, columnName: string): number { const column = this.data.getColumn(columnName); invariant(column, `Column ${columnName} does not exist.`); invariant( column instanceof AggrowIntColumn || column instanceof AggrowDoubleColumn, `Number expander does not support ${column.constructor.name} columns.`); return this.expander.addFieldExpander( expanderName, (rowA: number, rowB: number): number => column.get(rowA) - column.get(rowB), (row: number): number => column.get(row), (n: any): string => n.toLocaleString(), ); } addPointerExpander(expanderName: string, columnName: string): number { const column = this.data.getColumn(columnName); invariant(column, `Column ${columnName} does not exist.`); invariant( column instanceof AggrowIntColumn, `Pointer expander does not support ${column.constructor.name} columns.`); return this.expander.addFieldExpander( expanderName, (rowA: number, rowB: number): number => column.get(rowA) - column.get(rowB), (row: number): number => column.get(row), (p: number): string => `0x${(p >>> 0).toString(16)}`, // eslint-disable-line no-bitwise ); } addStackExpander( expanderName: string, columnName: string, reverse: boolean, focus: ?FocusConfig): number { const column = this.data.getColumn(columnName); invariant(column, `Column ${columnName} does not exist.`); invariant( column instanceof AggrowStackColumn, `Stack expander does not support ${column.constructor.name} columns.`); let stacks = column.stacks; const getter = column.getter; const formatter = column.formatter; if (focus) { const re = focus.pattern; const predicate = (frameId: number): boolean => re.test(formatter(getter(frameId))); stacks = focusStacks(stacks, predicate, focus.firstMatch, focus.leftSide); } return this.expander.addStackExpander( expanderName, stacks.maxDepth, (row: number): FlattenedStack => stacks.get(column.get(row)), getter, formatter, !!reverse, ); } } function focusStacks( stacks: StackRegistry, predicate: FocusPredicate, firstMatch: boolean, leftSide: boolean): FocusedStackRegistry { let stackMapper; if (firstMatch && leftSide) { stackMapper = (stack: FlattenedStack): FlattenedStack => { for (let i = 0; i < stack.length; i++) { if (predicate(stack[i])) { return stack.subarray(0, i + 1); } } return stack.subarray(0, 0); }; } else if (firstMatch && !leftSide) { stackMapper = (stack: FlattenedStack): FlattenedStack => { for (let i = 0; i < stack.length; i++) { if (predicate(stack[i])) { return stack.subarray(i, stack.length); } } return stack.subarray(0, 0); }; } else if (!firstMatch && leftSide) { stackMapper = (stack: FlattenedStack): FlattenedStack => { for (let i = stack.length - 1; i >= 0; i--) { if (predicate(stack[i])) { return stack.subarray(0, i + 1); } } return stack.subarray(0, 0); }; } else { // !firstMatch && !leftSide stackMapper = (stack: FlattenedStack): FlattenedStack => { for (let i = stack.length - 1; i >= 0; i--) { if (predicate(stack[i])) { return stack.subarray(i, stack.length); } } return stack.subarray(0, 0); }; } invariant(stacks.stackIdMap, 'Stacks were not flattened.'); return new FocusedStackRegistry( stacks.stackIdMap.map(stackMapper), stacks.maxDepth); } class FocusedStackRegistry { maxDepth: number; stackIdMap: Array<FlattenedStack>; constructor(stackIdMap: Array<FlattenedStack>, maxDepth: number) { this.maxDepth = maxDepth; this.stackIdMap = stackIdMap; } get(id: number): FlattenedStack { return this.stackIdMap[id]; } }