jeffy-g/rm-cstyle-cmts

View on GitHub
src/bench/contractor.ts

Summary

Maintainability
A
0 mins
Test Coverage
/*!
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Copyright (C) 2017 jeffy-g <hirotom1107@gmail.com>
  Released under the MIT license
  https://opensource.org/licenses/mit-license.php
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/

// for String.replace
declare type AverageReplacer = (matchBody: string, loop: string, ms: string, tag: string, deadline: string, index?: number) => string;


interface IBenchmarkResult {
    loop: number;
    ms: number;
    average: number;
}

// entry caption text.
const explain: string = "average for each run";

/**
 * extended contractor pattern?
 */
const Contractor = {
    entries: {} as { [x: string]: IBenchmarkResult[] },
    currentTag: "",

    order(tag: string): void {
        !this.entries[tag] && (this.entries[tag] = []);
        this.currentTag = tag;
    },
    record(sloop: string, sms: string): number {
        const loop = +sloop, ms = +sms;
        /** average for each run */
        const average = (ms / loop);
        // record loop count, time spent, average.
        this.entries[this.currentTag]!.push({
            loop, ms, average
        });
        return average;
    },

    deadline(): void {
        /** list of average per run */
        const lapr: number[] = [];
        /** tag collection */
        const tags = Object.keys(this.entries), that = this;

        let msg = "";
        console.log("");
        tags.forEach(tag => {
            let averageSum = 0, tspentSum = 0;
            const size = that.entries[tag]!.length as number;
            that.entries[tag]!.forEach(result => {
                tspentSum += result.ms;
                averageSum += result.average;
            });
            // average for every run.
            const eachRun = averageSum / size;
            lapr.push(eachRun);
            // format message.
            msg += `[${tag}] {
    average of entries: ${(tspentSum / size).toFixed(6)} ms, total ${explain}: ${eachRun.toFixed(6)} ms
}\n`;
        });

        const min = Math.min(lapr[0]!, lapr[1]!);
        const max = Math.max(lapr[0]!, lapr[1]!);
        // ✈: \u2708
        console.log(`${"\u2708  ".repeat(8)}performance ratio: %s\%`, (min / max * 100).toFixed(6));
        // output result message.
        console.log(msg);
    }
};

/**
 * set true to "showlogPerEntry" param if need.
 * @param showlogPerEntry
 */
const emitReplacer = (showlogPerEntry: boolean): AverageReplacer => {
    const contractor = Contractor;
    // return replacement body.
    return (all, loop, ms, tag, deadline/* , index */) => {
        if (tag) {
            // ✔ :\u2714
            contractor.order(tag), console.log(`\u2714 order => ${tag}`);
        } else if (loop) {
            const average = contractor.record(loop, ms);
            // if want per entiry.
            showlogPerEntry && console.log(
                `loop: ${loop}, ${explain}: %s ms`, average.toFixed(6)
            );
        } else if (deadline) {
            contractor.deadline();
        }
        // NOTE: always return match content.
        return all;
    };
};

/** regex for performance log. */
// FIXED: there is no floting value in the result of "console.time" at node v4
const regex = /loop=(\d+):\s(\d+(?:\.\d+)?)ms|(version:\s.+)|(--done--)/g;

/**
 * Parse the log of inputs using regexp and write the mean to console.
 *
 * @param inputs the performance log text.
 * @param showlogPerEntry set true to "showlogPerEntry" param if need. default false
 */
export const average = (inputs: string, showlogPerEntry: boolean = false): string => {
    return inputs.replace(regex, emitReplacer(showlogPerEntry));
};