зеркало из https://github.com/microsoft/tiny-calc.git
FrugalList
This commit is contained in:
Родитель
ee7d719274
Коммит
4b2e098640
|
@ -3,6 +3,7 @@ dependencies:
|
|||
'@rush-temp/es': 'file:projects/es.tgz'
|
||||
'@rush-temp/eslint-config': 'file:projects/eslint-config.tgz_eslint@7.14.0+typescript@4.1.2'
|
||||
'@rush-temp/example': 'file:projects/example.tgz'
|
||||
'@rush-temp/frugallist': 'file:projects/frugallist.tgz'
|
||||
'@rush-temp/graph': 'file:projects/graph.tgz'
|
||||
'@rush-temp/handletable': 'file:projects/handletable.tgz'
|
||||
'@rush-temp/heap': 'file:projects/heap.tgz'
|
||||
|
@ -2875,6 +2876,23 @@ packages:
|
|||
integrity: sha512-hKDbQi6qxpzLLPswZI9hv3c6UaImw/3ypjPw8TxBdBgch4t8DrpjtFjKZOr5B7mgPdAk7ZA67NF2vY5xTM+a6g==
|
||||
tarball: 'file:projects/example.tgz'
|
||||
version: 0.0.0
|
||||
'file:projects/frugallist.tgz':
|
||||
dependencies:
|
||||
'@types/mocha': 8.0.4
|
||||
'@types/node': 14.14.10
|
||||
best-random: 1.0.3
|
||||
eslint: 7.14.0
|
||||
hotloop: 1.2.0
|
||||
mocha: 8.2.1
|
||||
rimraf: 3.0.2
|
||||
ts-node: 9.0.0_typescript@4.1.2
|
||||
typescript: 4.1.2
|
||||
dev: false
|
||||
name: '@rush-temp/frugallist'
|
||||
resolution:
|
||||
integrity: sha512-VbPT6NIgsrDGg3UU/3y5ORe4J+Mqy24aXfgzvM48RtdM2CSMxnM2lVWZliJstSlz8q+0BGi2+fyPc5+bqXCpDA==
|
||||
tarball: 'file:projects/frugallist.tgz'
|
||||
version: 0.0.0
|
||||
'file:projects/graph.tgz':
|
||||
dependencies:
|
||||
'@types/mocha': 8.0.4
|
||||
|
@ -3059,6 +3077,7 @@ specifiers:
|
|||
'@rush-temp/es': 'file:./projects/es.tgz'
|
||||
'@rush-temp/eslint-config': 'file:./projects/eslint-config.tgz'
|
||||
'@rush-temp/example': 'file:./projects/example.tgz'
|
||||
'@rush-temp/frugallist': 'file:./projects/frugallist.tgz'
|
||||
'@rush-temp/graph': 'file:./projects/graph.tgz'
|
||||
'@rush-temp/handletable': 'file:./projects/handletable.tgz'
|
||||
'@rush-temp/heap': 'file:./projects/heap.tgz'
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
"extends": [ "@tiny-calc/eslint-config" ],
|
||||
parserOptions: {
|
||||
project: './tsconfig.eslint.json',
|
||||
},
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
# NPM dependencies
|
||||
/node_modules
|
||||
|
||||
# Build artifacts
|
||||
/dist
|
||||
|
||||
# Typescript incremental build cache
|
||||
/*.tsbuildinfo
|
|
@ -0,0 +1,21 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { getTestArgs } from "hotloop";
|
||||
import { forEachBench } from "./foreach";
|
||||
|
||||
const { count } = getTestArgs();
|
||||
const list: number[] = new Array(count).fill(0).map((value, index) => index);
|
||||
|
||||
forEachBench(
|
||||
"Array",
|
||||
count,
|
||||
list,
|
||||
(array, callback) => {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
callback(array[i]);
|
||||
}
|
||||
}
|
||||
)
|
|
@ -0,0 +1,22 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { getTestArgs } from "hotloop";
|
||||
import { FrugalList, FrugalList_push, FrugalList_forEach } from "../src";
|
||||
import { forEachBench } from "./foreach";
|
||||
|
||||
const { count } = getTestArgs();
|
||||
|
||||
let list: FrugalList<number> = undefined;
|
||||
for (let i = 0; i < count; i++) {
|
||||
list = FrugalList_push(list, i);
|
||||
}
|
||||
|
||||
forEachBench(
|
||||
"FrugalList",
|
||||
count,
|
||||
list,
|
||||
FrugalList_forEach
|
||||
)
|
|
@ -0,0 +1,22 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { getTestArgs } from "hotloop";
|
||||
import { TwoField, TwoField_push, TwoField_forEach } from "./impl/twofield";
|
||||
import { forEachBench } from "./foreach";
|
||||
|
||||
const { count } = getTestArgs();
|
||||
|
||||
const list: TwoField<number> = {};
|
||||
for (let i = 0; i < count; i++) {
|
||||
TwoField_push(list, i);
|
||||
}
|
||||
|
||||
forEachBench(
|
||||
"TwoField",
|
||||
count,
|
||||
list,
|
||||
TwoField_forEach
|
||||
)
|
|
@ -0,0 +1,43 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { strict as assert } from "assert";
|
||||
import { benchmark } from "hotloop";
|
||||
|
||||
let consumedCount = 0;
|
||||
let consumedCache: any;
|
||||
|
||||
export function forEachBench<TSelf, TConsumer>(
|
||||
name: string,
|
||||
count: number,
|
||||
self: TSelf,
|
||||
forEach: (self: TSelf, callback: (consumer: TConsumer) => void) => void
|
||||
): void {
|
||||
// Sanity check that list was initialized correctly.
|
||||
let sum = 0;
|
||||
forEach(self, () => {
|
||||
sum++;
|
||||
});
|
||||
assert.equal(sum, count);
|
||||
|
||||
benchmark(`${name}: ForEach(length=${count})`, () => {
|
||||
forEach(self, (item) => {
|
||||
// Paranoid defense against dead code elimination.
|
||||
consumedCount++;
|
||||
consumedCount |= 0;
|
||||
|
||||
if (consumedCount === 0) {
|
||||
consumedCache = item;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Prevent v8's optimizer from identifying 'cached' as an unused value.
|
||||
process.on('exit', () => {
|
||||
if (consumedCount === -1) {
|
||||
console.log(`Ignore this: ${consumedCache}`);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,45 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export type TwoFieldItem<T> = Exclude<T, undefined>
|
||||
|
||||
export type TwoField<T> = {
|
||||
item0?: T;
|
||||
items?: T[];
|
||||
}
|
||||
|
||||
export function TwoField_push<T>(self: TwoField<T>, consumer: TwoFieldItem<T>) {
|
||||
if (self.item0 === undefined) {
|
||||
self.item0 = consumer;
|
||||
} else if (self.items === undefined) {
|
||||
self.items = [consumer];
|
||||
} else {
|
||||
self.items.push(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
export function TwoField_delete<T>(self: TwoField<T>, consumer: TwoFieldItem<T>) {
|
||||
if (self.item0 === undefined) {
|
||||
self.item0 = consumer;
|
||||
} else if (self.items === undefined) {
|
||||
self.items = [consumer];
|
||||
} else {
|
||||
self.items.push(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
export function TwoField_forEach<T>(self: TwoField<T>, callback: (consumer: T) => void): void {
|
||||
if (self.item0 === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(self.item0);
|
||||
|
||||
if (self.items !== undefined) {
|
||||
for (let i = 0; i < self.items.length; i++) {
|
||||
callback(self.items[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { run } from "hotloop";
|
||||
|
||||
// eslint-disable-next-line no-void
|
||||
void (async () => {
|
||||
let count = 0;
|
||||
console.group(`ConsumerSet (length=${count})`)
|
||||
await run([
|
||||
{ "path": "./foreach-array.ts", args: { count }},
|
||||
{ "path": "./foreach-frugallist.ts", args: { count }},
|
||||
{ "path": "./foreach-twofield.ts", args: { count }},
|
||||
]);
|
||||
console.groupEnd();
|
||||
|
||||
count = 1;
|
||||
console.group(`ConsumerSet (length=${count})`)
|
||||
await run([
|
||||
{ "path": "./foreach-array.ts", args: { count }},
|
||||
{ "path": "./foreach-frugallist.ts", args: { count }},
|
||||
{ "path": "./foreach-twofield.ts", args: { count }},
|
||||
]);
|
||||
console.groupEnd();
|
||||
|
||||
count = 2;
|
||||
console.group(`ConsumerSet (length=${count})`)
|
||||
await run([
|
||||
{ "path": "./foreach-array.ts", args: { count }},
|
||||
{ "path": "./foreach-frugallist.ts", args: { count }},
|
||||
{ "path": "./foreach-twofield.ts", args: { count }},
|
||||
]);
|
||||
console.groupEnd();
|
||||
})();
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "@tiny-calc/frugallist",
|
||||
"version": "0.0.0-alpha.5",
|
||||
"main": "dist/index.js",
|
||||
"sideEffects": "false",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/tiny-calc.git"
|
||||
},
|
||||
"author": "Microsoft",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"bench": "cd bench && ts-node index.ts",
|
||||
"build": "tsc",
|
||||
"clean": "rimraf ./dist *.build.log",
|
||||
"dev": "npm run build -- --watch",
|
||||
"lint": "eslint --ext=ts --format visualstudio src",
|
||||
"test": "mocha -r ts-node/register test/**/*.spec.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tiny-calc/eslint-config": "0.0.0-alpha.5",
|
||||
"@tiny-calc/ts-config": "0.0.0-alpha.5",
|
||||
"@types/mocha": "^8.0.4",
|
||||
"@types/node": "^14.14.10",
|
||||
"best-random": "^1.0.3",
|
||||
"eslint": "^7.13.0",
|
||||
"hotloop": "^1.2.0",
|
||||
"mocha": "^8.2.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^9.0.0",
|
||||
"typescript": "^4.0.5"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { FrugalList, FrugalListItem } from "./types";
|
||||
|
||||
export function FrugalList_forEach<T>(self: FrugalList<T>, callback: (value: FrugalListItem<T>) => void): void {
|
||||
if (self !== undefined) {
|
||||
if (Array.isArray(self)) {
|
||||
for (let index = 0; index < self.length; index++) {
|
||||
callback(self[index]);
|
||||
}
|
||||
} else {
|
||||
callback(/* value: */ self);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export { FrugalList, FrugalListItem } from "./types";
|
||||
export { FrugalList_forEach } from "./forEach";
|
||||
export { FrugalList_push } from "./push";
|
||||
export { FrugalList_removeFirst } from "./removeFirst";
|
|
@ -0,0 +1,19 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { FrugalList, FrugalListItem } from "./types";
|
||||
|
||||
export function FrugalList_push<T>(self: FrugalList<T>, value: FrugalListItem<T>): FrugalList<T> {
|
||||
if (self === undefined) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Array.isArray(self)) {
|
||||
self.push(value);
|
||||
return self;
|
||||
} else {
|
||||
return [self, value];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { FrugalList, FrugalListItem } from "./types";
|
||||
|
||||
export function FrugalList_removeFirst<T>(self: FrugalList<T>, value: FrugalListItem<T>): FrugalList<T> {
|
||||
if (self === value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (Array.isArray(self)) {
|
||||
const index = self.indexOf(value);
|
||||
if (index >= 0) {
|
||||
self.splice(/* start: */ index, /* deleteCount: */ 1);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Must not store the value 'undefined' or any Array type inside a FrugalList.
|
||||
*/
|
||||
export type FrugalListItem<T> = Exclude<T, undefined | Array<any>>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
export type FrugalList<T> = undefined | FrugalListItem<T> | Array<FrugalListItem<T>>;
|
|
@ -0,0 +1,57 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import "mocha";
|
||||
import { TestFixture } from "./testfixture";
|
||||
|
||||
describe("FrugalList", () => {
|
||||
const values = [0, 1, 2];
|
||||
let list: TestFixture<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
list = new TestFixture<number>();
|
||||
});
|
||||
|
||||
it("push", () => {
|
||||
for (const value of values) {
|
||||
list.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
it("remove in order", () => {
|
||||
for (const value of values) {
|
||||
list.push(value);
|
||||
}
|
||||
|
||||
for (const value of values) {
|
||||
list.removeFirst(value);
|
||||
}
|
||||
});
|
||||
|
||||
it("remove in reverse order", () => {
|
||||
for (const value of values) {
|
||||
list.push(value);
|
||||
}
|
||||
|
||||
const reversed = values.slice(0).reverse();
|
||||
for (const value of reversed) {
|
||||
list.removeFirst(value);
|
||||
}
|
||||
});
|
||||
|
||||
it("remove with duplicates", () => {
|
||||
for (const value of values) {
|
||||
list.push(value);
|
||||
}
|
||||
|
||||
for (const value of values) {
|
||||
list.push(value);
|
||||
}
|
||||
|
||||
for (const value of values) {
|
||||
list.removeFirst(value);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,45 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import "mocha";
|
||||
import { strict as assert } from "assert";
|
||||
import {
|
||||
FrugalList,
|
||||
FrugalList_push,
|
||||
FrugalListItem,
|
||||
FrugalList_removeFirst,
|
||||
FrugalList_forEach
|
||||
} from "../src";
|
||||
|
||||
export class TestFixture<T> {
|
||||
private actual: FrugalList<T>;
|
||||
private expected: FrugalListItem<T>[] = [];
|
||||
|
||||
public push(item: FrugalListItem<T>): void {
|
||||
this.actual = FrugalList_push(this.actual, item);
|
||||
this.expected.push(item);
|
||||
|
||||
this.vet();
|
||||
}
|
||||
|
||||
public removeFirst(item: FrugalListItem<T>): void {
|
||||
this.actual = FrugalList_removeFirst(this.actual, item);
|
||||
const index = this.expected.indexOf(item);
|
||||
if (index >= 0) {
|
||||
this.expected.splice(/* start: */ index, /* deleteCount: */ 1);
|
||||
}
|
||||
|
||||
this.vet();
|
||||
}
|
||||
|
||||
private vet() {
|
||||
const actual: FrugalListItem<T>[] = [];
|
||||
FrugalList_forEach(this.actual, (item) => {
|
||||
actual.push(item);
|
||||
})
|
||||
|
||||
assert.deepEqual(actual, this.expected);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
// extend your base config so you don't have to redefine your compilerOptions
|
||||
"extends": "./tsconfig.json",
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"test/**/*.ts",
|
||||
"bench/**/*.ts",
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "@tiny-calc/ts-config/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"declarationDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
|
@ -46,6 +46,12 @@
|
|||
"reviewCategory": "production",
|
||||
"versionPolicyName": "public"
|
||||
},
|
||||
{
|
||||
"packageName": "@tiny-calc/frugallist",
|
||||
"projectFolder": "packages/common/datastructures/frugallist",
|
||||
"reviewCategory": "production",
|
||||
"versionPolicyName": "public"
|
||||
},
|
||||
{
|
||||
"packageName": "@tiny-calc/handletable",
|
||||
"projectFolder": "packages/common/datastructures/handletable",
|
||||
|
|
Загрузка…
Ссылка в новой задаче