├── packages ├── list │ ├── .babelrc │ ├── tslint.json │ ├── src │ │ ├── List.ts │ │ ├── index.ts │ │ ├── functions │ │ │ ├── size.ts │ │ │ ├── isEmpty.ts │ │ │ ├── toArray.ts │ │ │ ├── first.ts │ │ │ ├── last.ts │ │ │ ├── get.ts │ │ │ ├── iterate.ts │ │ │ ├── join.ts │ │ │ ├── hasIndex.ts │ │ │ ├── fromIterable.ts │ │ │ ├── fromArgs.ts │ │ │ ├── concatLeft.ts │ │ │ ├── remove.ts │ │ │ ├── insert.ts │ │ │ ├── prependIterable.ts │ │ │ ├── of.ts │ │ │ ├── insertIterable.ts │ │ │ ├── mapToArray.ts │ │ │ ├── empty.ts │ │ │ ├── set.ts │ │ │ ├── removeRange.ts │ │ │ ├── prependArray.ts │ │ │ ├── insertArray.ts │ │ │ ├── updateList.ts │ │ │ ├── appendArrayMapped.ts │ │ │ ├── prependArrayMapped.ts │ │ │ ├── take.ts │ │ │ ├── concatAll.ts │ │ │ ├── insertArrayMapped.ts │ │ │ ├── skip.ts │ │ │ ├── skipLast.ts │ │ │ ├── takeLast.ts │ │ │ ├── slice.ts │ │ │ ├── fromArray.ts │ │ │ ├── concat.ts │ │ │ ├── fromArrayMapped.ts │ │ │ ├── equality.ts │ │ │ ├── map.ts │ │ │ ├── update.ts │ │ │ ├── appendIterable.ts │ │ │ └── appendArray.ts │ │ └── internals │ │ │ ├── index.ts │ │ │ └── fold.ts │ ├── .npmignore │ ├── tsconfig.es2015.json │ ├── tsconfig.commonjs.json │ ├── tsconfig.tests.json │ ├── tests │ │ └── functions │ │ │ ├── of.ts │ │ │ ├── empty.ts │ │ │ ├── unwrap.ts │ │ │ ├── last.ts │ │ │ ├── first.ts │ │ │ ├── size.ts │ │ │ ├── appendArray.ts │ │ │ ├── prependArray.ts │ │ │ ├── prependIterable.ts │ │ │ ├── appendIterable.ts │ │ │ ├── appendArrayMapped.ts │ │ │ ├── updateList.ts │ │ │ ├── prependArrayMapped.ts │ │ │ ├── append.ts │ │ │ ├── prepend.ts │ │ │ └── fromArray.ts │ └── tsconfig.json ├── collectable │ ├── src │ │ ├── index.ts │ │ ├── internals │ │ │ ├── index.ts │ │ │ └── common.ts │ │ └── functions │ │ │ ├── index.ts │ │ │ ├── has.ts │ │ │ └── get.ts │ ├── tslint.json │ ├── .npmignore │ ├── tsconfig.es2015.json │ ├── tsconfig.commonjs.json │ ├── tsconfig.tests.json │ ├── tsconfig.json │ └── README.md ├── map │ ├── src │ │ ├── internals │ │ │ ├── nodes │ │ │ │ ├── ArrayNode │ │ │ │ │ ├── index.ts │ │ │ │ │ └── toIndexNode.ts │ │ │ │ ├── IndexedNode │ │ │ │ │ ├── index.ts │ │ │ │ │ └── toArrayNode.ts │ │ │ │ ├── CollisionNode │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── LeafNode │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── common │ │ │ │ ├── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── stringHash.ts │ │ │ │ └── bitwise-operations.ts │ │ │ └── primitives │ │ │ │ ├── index.ts │ │ │ │ ├── findHash.ts │ │ │ │ ├── unwrap.ts │ │ │ │ └── setKeyValue.ts │ │ ├── HashMap.ts │ │ ├── index.ts │ │ └── functions │ │ │ ├── isMap.ts │ │ │ ├── size.ts │ │ │ ├── fromNativeMap.ts │ │ │ ├── isEmpty.ts │ │ │ ├── get.ts │ │ │ ├── clone.ts │ │ │ ├── forEach.ts │ │ │ ├── reduce.ts │ │ │ ├── entries.ts │ │ │ ├── keys.ts │ │ │ ├── has.ts │ │ │ ├── values.ts │ │ │ ├── empty.ts │ │ │ ├── update.ts │ │ │ ├── set.ts │ │ │ ├── filter.ts │ │ │ ├── fromArray.ts │ │ │ ├── remove.ts │ │ │ ├── updateMap.ts │ │ │ ├── index.ts │ │ │ ├── map.ts │ │ │ ├── fromIterable.ts │ │ │ ├── fromObject.ts │ │ │ └── isEqual.ts │ ├── tslint.json │ ├── .npmignore │ ├── tsconfig.es2015.json │ ├── tsconfig.commonjs.json │ ├── tsconfig.tests.json │ ├── tsconfig.json │ └── tests │ │ ├── get.ts │ │ ├── commit.ts │ │ ├── getSize.ts │ │ ├── fromArray.ts │ │ ├── fromNativeMap.ts │ │ ├── fromObject.ts │ │ ├── has.ts │ │ ├── fromIterable.ts │ │ └── forEach.ts ├── core │ ├── tests │ │ └── functions │ │ │ └── index.ts │ ├── tslint.json │ ├── .npmignore │ ├── src │ │ ├── index.ts │ │ ├── common.ts │ │ └── iterator.ts │ ├── tsconfig.tests.json │ ├── tsconfig.es2015.json │ ├── tsconfig.commonjs.json │ └── tsconfig.json ├── set │ ├── src │ │ ├── internals │ │ │ ├── index.ts │ │ │ └── iterate.ts │ │ ├── HashSet.ts │ │ ├── index.ts │ │ └── functions │ │ │ ├── toArray.ts │ │ │ ├── isSet.ts │ │ │ ├── fromArray.ts │ │ │ ├── values.ts │ │ │ ├── fromNativeSet.ts │ │ │ ├── fromIterable.ts │ │ │ ├── size.ts │ │ │ ├── toNativeSet.ts │ │ │ ├── has.ts │ │ │ ├── isEmpty.ts │ │ │ ├── empty.ts │ │ │ ├── isEqual.ts │ │ │ ├── clone.ts │ │ │ ├── add.ts │ │ │ ├── remove.ts │ │ │ ├── update.ts │ │ │ ├── forEach.ts │ │ │ ├── filter.ts │ │ │ ├── reduce.ts │ │ │ ├── map.ts │ │ │ └── index.ts │ ├── tslint.json │ ├── .npmignore │ ├── tsconfig.es2015.json │ ├── tsconfig.commonjs.json │ ├── tsconfig.tests.json │ ├── tests │ │ ├── functions │ │ │ ├── empty.ts │ │ │ ├── size.ts │ │ │ ├── isEmpty.ts │ │ │ ├── isSet.ts │ │ │ ├── values.ts │ │ │ ├── has.ts │ │ │ ├── toArray.ts │ │ │ ├── toNativeSet.ts │ │ │ ├── remove.notexists.ts │ │ │ ├── fromArray.ts │ │ │ ├── add.exists.ts │ │ │ ├── fromNativeSet.ts │ │ │ ├── forEach.ts │ │ │ ├── fromIterable.ts │ │ │ └── union.Iterable.mutable.ts │ │ ├── test-utils.ts │ │ └── internals │ │ │ └── HashSet.ts │ └── tsconfig.json ├── red-black-tree │ ├── tslint.json │ ├── .npmignore │ ├── tsconfig.es2015.json │ ├── tsconfig.commonjs.json │ ├── src │ │ ├── internals │ │ │ └── index.ts │ │ ├── RedBlackTree.ts │ │ ├── index.ts │ │ └── functions │ │ │ ├── iterateKeysFromLast.ts │ │ │ ├── iterateValuesFromLast.ts │ │ │ ├── emptyWithStringKeys.ts │ │ │ ├── emptyWithNumericKeys.ts │ │ │ ├── iterateKeysFromIndex.ts │ │ │ ├── iterateKeysFrom.ts │ │ │ ├── iterateValuesFromIndex.ts │ │ │ ├── iterateValuesFrom.ts │ │ │ ├── fromStringKeys.ts │ │ │ ├── fromNumericKeys.ts │ │ │ ├── fromPairsWithStringKeys.ts │ │ │ ├── fromPairsWithNumericKeys.ts │ │ │ ├── size.ts │ │ │ ├── isEmpty.ts │ │ │ ├── isRedBlackTree.ts │ │ │ ├── lastKey.ts │ │ │ ├── clone.ts │ │ │ ├── firstKey.ts │ │ │ ├── lastValue.ts │ │ │ ├── indexOf.ts │ │ │ ├── last.ts │ │ │ ├── firstValue.ts │ │ │ ├── first.ts │ │ │ └── fromKeys.ts │ ├── tests │ │ └── functions │ │ │ ├── emptyWithNumericKeys.ts │ │ │ ├── fromObject.ts │ │ │ ├── fromKeys.ts │ │ │ ├── fromPairs.ts │ │ │ ├── updateTree.ts │ │ │ ├── iterateFromKey.ts │ │ │ ├── indexOf.ts │ │ │ ├── isEmpty.ts │ │ │ ├── firstKey.ts │ │ │ ├── size.ts │ │ │ ├── isRedBlackTree.ts │ │ │ ├── lastKey.ts │ │ │ ├── firstValue.ts │ │ │ ├── lastValue.ts │ │ │ ├── first.ts │ │ │ ├── get.ts │ │ │ ├── last.ts │ │ │ ├── keyAt.ts │ │ │ ├── iterateFromFirst.ts │ │ │ ├── iterateFromLast.ts │ │ │ └── valueAt.ts │ ├── tsconfig.tests.json │ └── tsconfig.json ├── sorted-map │ ├── tslint.json │ ├── .npmignore │ ├── src │ │ ├── internals │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── SortedMap.ts │ │ ├── index.ts │ │ └── functions │ │ │ ├── toArray.ts │ │ │ ├── keys.ts │ │ │ ├── last.ts │ │ │ ├── first.ts │ │ │ ├── values.ts │ │ │ ├── entries.ts │ │ │ ├── isSortedMap.ts │ │ │ ├── toNativeMap.ts │ │ │ ├── at.ts │ │ │ ├── size.ts │ │ │ ├── has.ts │ │ │ ├── isEmpty.ts │ │ │ ├── clone.ts │ │ │ ├── lastKey.ts │ │ │ ├── firstKey.ts │ │ │ ├── firstValue.ts │ │ │ ├── lastValue.ts │ │ │ ├── get.ts │ │ │ ├── keyAt.ts │ │ │ ├── valueAt.ts │ │ │ ├── remove.ts │ │ │ ├── set.ts │ │ │ ├── updateMap.ts │ │ │ ├── update.ts │ │ │ ├── reduce.ts │ │ │ ├── forEach.ts │ │ │ ├── fromArray.ts │ │ │ ├── fromIterable.ts │ │ │ ├── isEqual.ts │ │ │ └── index.ts │ ├── tsconfig.es2015.json │ ├── tsconfig.commonjs.json │ ├── tsconfig.tests.json │ ├── tests │ │ ├── functions │ │ │ ├── empty.ts │ │ │ ├── size.ts │ │ │ ├── isEmpty.ts │ │ │ ├── isSortedMap.ts │ │ │ ├── keys.ts │ │ │ ├── has.ts │ │ │ ├── values.ts │ │ │ ├── toArray.ts │ │ │ ├── toNativeMap.ts │ │ │ ├── remove.notexists.ts │ │ │ ├── get.ts │ │ │ ├── firstKey.ts │ │ │ ├── set.exists.ts │ │ │ ├── first.ts │ │ │ ├── firstValue.ts │ │ │ ├── lastKey.ts │ │ │ ├── keyAt.ts │ │ │ ├── lastValue.ts │ │ │ ├── at.ts │ │ │ ├── last.ts │ │ │ ├── valueAt.ts │ │ │ ├── fromArray.ts │ │ │ ├── entries.ts │ │ │ ├── forEach.ts │ │ │ ├── set.notexists.mutable.ts │ │ │ ├── fromIterable.ts │ │ │ └── filter.ts │ │ └── internals │ │ │ └── SortedMap.ts │ └── tsconfig.json └── sorted-set │ ├── tslint.json │ ├── .npmignore │ ├── src │ ├── SortedSet.ts │ ├── internals │ │ ├── index.ts │ │ ├── types.ts │ │ └── iterate.ts │ ├── index.ts │ └── functions │ │ ├── toArray.ts │ │ ├── values.ts │ │ ├── isSortedSet.ts │ │ ├── has.ts │ │ ├── toNativeSet.ts │ │ ├── size.ts │ │ ├── isEmpty.ts │ │ ├── clone.ts │ │ ├── last.ts │ │ ├── first.ts │ │ ├── get.ts │ │ ├── remove.ts │ │ ├── add.ts │ │ ├── reduce.ts │ │ ├── update.ts │ │ ├── forEach.ts │ │ ├── fromArray.ts │ │ ├── fromIterable.ts │ │ ├── index.ts │ │ ├── isEqual.ts │ │ ├── map.ts │ │ └── filter.ts │ ├── tsconfig.es2015.json │ ├── tsconfig.commonjs.json │ ├── tsconfig.tests.json │ ├── tests │ ├── functions │ │ ├── empty.ts │ │ ├── size.ts │ │ ├── isEmpty.ts │ │ ├── isSet.ts │ │ ├── values.ts │ │ ├── has.ts │ │ ├── toArray.ts │ │ ├── toNativeSet.ts │ │ ├── remove.notexists.ts │ │ ├── add.exists.ts │ │ ├── fromArray.ts │ │ ├── fromIterable.ts │ │ ├── forEach.ts │ │ ├── add.notexists.mutable.ts │ │ └── filter.ts │ └── internals │ │ └── SortedSet.ts │ └── tsconfig.json ├── .assets └── logo.png ├── .travis.yml ├── lerna.default.json ├── .gitignore ├── .vscode └── settings.json └── package.json /packages/list/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"] 3 | } -------------------------------------------------------------------------------- /packages/collectable/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './functions'; -------------------------------------------------------------------------------- /packages/collectable/src/internals/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; -------------------------------------------------------------------------------- /.assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frptools/collectable/HEAD/.assets/logo.png -------------------------------------------------------------------------------- /packages/map/src/internals/nodes/ArrayNode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ArrayNode'; 2 | -------------------------------------------------------------------------------- /packages/map/src/internals/nodes/IndexedNode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IndexedNode'; 2 | -------------------------------------------------------------------------------- /packages/core/tests/functions/index.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | test(t => t.pass()); -------------------------------------------------------------------------------- /packages/map/src/internals/nodes/CollisionNode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CollisionNode'; 2 | -------------------------------------------------------------------------------- /packages/set/src/internals/index.ts: -------------------------------------------------------------------------------- 1 | export * from './HashSet'; 2 | export * from './iterate'; -------------------------------------------------------------------------------- /packages/core/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@frptools/config/tslint-base" 4 | ] 5 | } -------------------------------------------------------------------------------- /packages/list/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@frptools/config/tslint-base" 4 | ] 5 | } -------------------------------------------------------------------------------- /packages/map/src/internals/nodes/constants.ts: -------------------------------------------------------------------------------- 1 | export const NOTHING: {} = Object.create(null); 2 | -------------------------------------------------------------------------------- /packages/map/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@frptools/config/tslint-base" 4 | ] 5 | } -------------------------------------------------------------------------------- /packages/set/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@frptools/config/tslint-base" 4 | ] 5 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 8 5 | - 6 6 | script: npm run ci-build -------------------------------------------------------------------------------- /packages/collectable/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@frptools/config/tslint-base" 4 | ] 5 | } -------------------------------------------------------------------------------- /packages/red-black-tree/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@frptools/config/tslint-base" 4 | ] 5 | } -------------------------------------------------------------------------------- /packages/sorted-map/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@frptools/config/tslint-base" 4 | ] 5 | } -------------------------------------------------------------------------------- /packages/sorted-set/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@frptools/config/tslint-base" 4 | ] 5 | } -------------------------------------------------------------------------------- /lerna.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.7.1", 3 | "version": "0.0.0", 4 | "packages": ["packages/*"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/list/src/List.ts: -------------------------------------------------------------------------------- 1 | export { ListStructure as Instance } from './internals'; 2 | export * from './functions'; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .build/ 2 | .devnotes/ 3 | .assets/working-files/ 4 | .vscode/ 5 | node_modules/ 6 | lib/ 7 | .npmrc 8 | *.log -------------------------------------------------------------------------------- /packages/core/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .build/ 3 | node_modules/ 4 | src/ 5 | tests/ 6 | tsconfig.* 7 | tslint.json 8 | *.log -------------------------------------------------------------------------------- /packages/list/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .build/ 3 | node_modules/ 4 | src/ 5 | tests/ 6 | tsconfig.* 7 | tslint.json 8 | *.log -------------------------------------------------------------------------------- /packages/map/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .build/ 3 | node_modules/ 4 | src/ 5 | tests/ 6 | tsconfig.* 7 | tslint.json 8 | *.log -------------------------------------------------------------------------------- /packages/map/src/internals/nodes/LeafNode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LeafNode'; 2 | export * from './combineLeafNodes'; 3 | -------------------------------------------------------------------------------- /packages/set/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .build/ 3 | node_modules/ 4 | src/ 5 | tests/ 6 | tsconfig.* 7 | tslint.json 8 | *.log -------------------------------------------------------------------------------- /packages/set/src/HashSet.ts: -------------------------------------------------------------------------------- 1 | export { HashSetStructure as Instance } from './internals'; 2 | export * from './functions'; -------------------------------------------------------------------------------- /packages/map/src/HashMap.ts: -------------------------------------------------------------------------------- 1 | export { HashMapStructure as Instance } from './internals/HashMap'; 2 | export * from './functions'; -------------------------------------------------------------------------------- /packages/collectable/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .build/ 3 | node_modules/ 4 | src/ 5 | tests/ 6 | tsconfig.* 7 | tslint.json 8 | *.log -------------------------------------------------------------------------------- /packages/red-black-tree/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .build/ 3 | node_modules/ 4 | src/ 5 | tests/ 6 | tsconfig.* 7 | tslint.json 8 | *.log -------------------------------------------------------------------------------- /packages/sorted-map/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .build/ 3 | node_modules/ 4 | src/ 5 | tests/ 6 | tsconfig.* 7 | tslint.json 8 | *.log -------------------------------------------------------------------------------- /packages/sorted-set/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .build/ 3 | node_modules/ 4 | src/ 5 | tests/ 6 | tsconfig.* 7 | tslint.json 8 | *.log -------------------------------------------------------------------------------- /packages/sorted-set/src/SortedSet.ts: -------------------------------------------------------------------------------- 1 | export { SortedSetStructure as Instance } from './internals'; 2 | export * from './functions'; -------------------------------------------------------------------------------- /packages/map/src/internals/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bitwise-operations'; 2 | export * from './constants'; 3 | export * from './stringHash'; 4 | -------------------------------------------------------------------------------- /packages/list/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as List from './List'; 2 | export { List }; 3 | 4 | export * from './functions'; 5 | export { ListStructure } from './internals'; -------------------------------------------------------------------------------- /packages/sorted-map/src/internals/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SortedMap'; 2 | export * from './values'; 3 | export * from './iterate'; 4 | export * from './types'; 5 | -------------------------------------------------------------------------------- /packages/set/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as HashSet from './HashSet'; 2 | export { HashSet }; 3 | export { HashSetStructure } from './internals'; 4 | export * from './functions'; -------------------------------------------------------------------------------- /packages/sorted-map/src/SortedMap.ts: -------------------------------------------------------------------------------- 1 | export { 2 | SortedMapStructure as Instance, 3 | SortedMapEntry as Entry 4 | } from './internals'; 5 | export * from './functions'; -------------------------------------------------------------------------------- /packages/sorted-set/src/internals/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SortedSet'; 2 | export * from './assignment'; 3 | export * from './iterate'; 4 | export * from './types'; 5 | -------------------------------------------------------------------------------- /packages/collectable/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './from'; 2 | export * from './get'; 3 | export * from './has'; 4 | export * from './set'; 5 | export * from './update'; -------------------------------------------------------------------------------- /packages/list/src/functions/size.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | 3 | export function size (list: ListStructure): number { 4 | return list._size; 5 | } 6 | -------------------------------------------------------------------------------- /packages/map/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as HashMap from './HashMap'; 2 | export { HashMap }; 3 | 4 | export * from './functions'; 5 | export { HashMapStructure } from './internals/HashMap'; -------------------------------------------------------------------------------- /packages/sorted-set/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as SortedSet from './SortedSet'; 2 | export { SortedSet }; 3 | export { SortedSetStructure } from './internals'; 4 | export * from './functions'; -------------------------------------------------------------------------------- /packages/list/src/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | 3 | export function isEmpty (list: ListStructure): boolean { 4 | return list._size === 0; 5 | } 6 | -------------------------------------------------------------------------------- /packages/list/src/functions/toArray.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure, arrayFrom } from '../internals'; 2 | 3 | export function toArray (list: ListStructure): T[] { 4 | return arrayFrom(list); 5 | } 6 | -------------------------------------------------------------------------------- /packages/set/src/functions/toArray.ts: -------------------------------------------------------------------------------- 1 | import { HashSetStructure } from '../internals'; 2 | 3 | export function toArray (set: HashSetStructure): T[] { 4 | return Array.from(set); 5 | } 6 | -------------------------------------------------------------------------------- /packages/sorted-map/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as SortedMap from './SortedMap'; 2 | export { SortedMap }; 3 | export { SortedMapStructure, SortedMapEntry } from './internals'; 4 | export * from './functions'; -------------------------------------------------------------------------------- /packages/set/src/functions/isSet.ts: -------------------------------------------------------------------------------- 1 | import { HashSetStructure, isHashSet } from '../internals'; 2 | 3 | export function isSet (arg: any): arg is HashSetStructure { 4 | return isHashSet(arg); 5 | } -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/toArray.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure } from '../internals'; 2 | 3 | export function toArray (set: SortedSetStructure): T[] { 4 | return Array.from(set); 5 | } 6 | -------------------------------------------------------------------------------- /packages/list/src/functions/first.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure, getAtOrdinal } from '../internals'; 2 | 3 | export function first (list: ListStructure): T|undefined { 4 | return getAtOrdinal(list, 0); 5 | } 6 | -------------------------------------------------------------------------------- /packages/list/src/functions/last.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure, getAtOrdinal } from '../internals'; 2 | 3 | export function last (list: ListStructure): T|undefined { 4 | return getAtOrdinal(list, -1); 5 | } 6 | -------------------------------------------------------------------------------- /packages/set/src/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import { HashSetStructure, createSet } from '../internals'; 2 | 3 | export function fromArray (values: T[]): HashSetStructure { 4 | return createSet(values); 5 | } 6 | -------------------------------------------------------------------------------- /packages/set/src/functions/values.ts: -------------------------------------------------------------------------------- 1 | import { HashSetStructure, iterate } from '../internals'; 2 | 3 | export function values (set: HashSetStructure): IterableIterator { 4 | return iterate(set); 5 | } 6 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/toArray.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure } from '../internals'; 2 | 3 | export function toArray (map: SortedMapStructure): [K, V][] { 4 | return Array.from(map); 5 | } 6 | -------------------------------------------------------------------------------- /packages/set/src/functions/fromNativeSet.ts: -------------------------------------------------------------------------------- 1 | import { HashSetStructure, createSet } from '../internals'; 2 | 3 | export function fromNativeSet (values: Set): HashSetStructure { 4 | return createSet(values); 5 | } -------------------------------------------------------------------------------- /packages/map/src/functions/isMap.ts: -------------------------------------------------------------------------------- 1 | import { HashMapStructure, isHashMap } from '../internals/HashMap'; 2 | 3 | export function isMap (arg: any): arg is HashMapStructure { 4 | return isHashMap(arg); 5 | } -------------------------------------------------------------------------------- /packages/list/src/functions/get.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure, getAtOrdinal } from '../internals'; 2 | 3 | export function get (index: number, list: ListStructure): T|undefined { 4 | return getAtOrdinal(list, index); 5 | } 6 | -------------------------------------------------------------------------------- /packages/list/src/functions/iterate.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure, createIterator } from '../internals'; 2 | 3 | export function iterate (list: ListStructure): IterableIterator { 4 | return createIterator(list); 5 | } 6 | -------------------------------------------------------------------------------- /packages/list/src/functions/join.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure, arrayFrom } from '../internals'; 2 | 3 | export function join (separator: any, list: ListStructure): string { 4 | return arrayFrom(list).join(separator); 5 | } 6 | -------------------------------------------------------------------------------- /packages/set/src/functions/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import { HashSetStructure, createSet } from '../internals'; 2 | 3 | export function fromIterable (values: Iterable): HashSetStructure { 4 | return createSet(values); 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@frptools/corelib'; 2 | export * from '@frptools/structural'; 3 | 4 | export * from './collection'; 5 | export * from './common'; 6 | export * from './iterator'; 7 | export * from './ChangeFlag'; -------------------------------------------------------------------------------- /packages/map/src/internals/primitives/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getHash'; 2 | export * from './setKeyValue'; 3 | export * from './findHash'; 4 | export * from './iterateMap'; 5 | export * from './fold'; 6 | export * from './unwrap'; 7 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/keys.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure, iterateKeys } from '../internals'; 2 | 3 | export function keys (map: SortedMapStructure): IterableIterator { 4 | return iterateKeys(map); 5 | } 6 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/values.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure, iterateValues } from '../internals'; 2 | 3 | export function values (set: SortedSetStructure): IterableIterator { 4 | return iterateValues(set); 5 | } 6 | -------------------------------------------------------------------------------- /packages/list/src/functions/hasIndex.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure, verifyIndex } from '../internals'; 2 | 3 | export function hasIndex (index: number, list: ListStructure): boolean { 4 | return verifyIndex(list._size, index) !== -1; 5 | } 6 | -------------------------------------------------------------------------------- /packages/set/src/functions/size.ts: -------------------------------------------------------------------------------- 1 | import { size as _size } from '@collectable/map'; 2 | import { HashSetStructure } from '../internals'; 3 | 4 | export function size (set: HashSetStructure): number { 5 | return _size(set._map); 6 | } 7 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/last.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure, getLastItem } from '../internals'; 2 | 3 | export function last (map: SortedMapStructure): [K, V]|undefined { 4 | return getLastItem(map._sorted); 5 | } 6 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/isSortedSet.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure, isSortedSet as _isSortedSet } from '../internals'; 2 | 3 | export function isSortedSet (arg: any): arg is SortedSetStructure { 4 | return _isSortedSet(arg); 5 | } -------------------------------------------------------------------------------- /packages/set/src/functions/toNativeSet.ts: -------------------------------------------------------------------------------- 1 | import { HashSetStructure } from '../internals'; 2 | import { values } from './index'; 3 | 4 | export function toNativeSet (set: HashSetStructure): Set { 5 | return new Set(values(set)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/first.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure, getFirstItem } from '../internals'; 2 | 3 | export function first (map: SortedMapStructure): [K, V]|undefined { 4 | return getFirstItem(map._sorted); 5 | } 6 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/values.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure, iterateValues } from '../internals'; 2 | 3 | export function values (map: SortedMapStructure): IterableIterator { 4 | return iterateValues(map); 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./.build", 5 | "noEmit": false 6 | }, 7 | "include": [ 8 | "./src/**/*.ts", 9 | "./tests/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/set/src/functions/has.ts: -------------------------------------------------------------------------------- 1 | import { has as _has } from '@collectable/map'; 2 | import { HashSetStructure } from '../internals'; 3 | 4 | export function has (value: T, set: HashSetStructure): boolean { 5 | return _has(value, set._map); 6 | } -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/entries.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure, iteratePairs } from '../internals'; 2 | 3 | export function entries (map: SortedMapStructure): IterableIterator<[K, V]> { 4 | return iteratePairs(map); 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "outDir": "./lib/es2015", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/list/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "outDir": "./lib/es2015", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/map/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "outDir": "./lib/es2015", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/set/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "outDir": "./lib/es2015", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/isSortedMap.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure, isSortedMap as _isSortedMap } from '../internals'; 2 | 3 | export function isSortedMap (arg: any): arg is SortedMapStructure { 4 | return _isSortedMap(arg); 5 | } 6 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/toNativeMap.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure, iteratePairs } from '../internals'; 2 | 3 | export function toNativeMap (map: SortedMapStructure): Map { 4 | return new Map(iteratePairs(map)); 5 | } 6 | -------------------------------------------------------------------------------- /packages/collectable/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "outDir": "./lib/es2015", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/core/tsconfig.commonjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./lib/commonjs", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/list/tsconfig.commonjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./lib/commonjs", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/map/src/functions/size.ts: -------------------------------------------------------------------------------- 1 | import { HashMapStructure } from '../internals/HashMap'; 2 | 3 | export function size (map: HashMapStructure): number; 4 | export function size (map: HashMapStructure): number { 5 | return map._size; 6 | } 7 | -------------------------------------------------------------------------------- /packages/map/src/internals/common/constants.ts: -------------------------------------------------------------------------------- 1 | export const SIZE = 5; 2 | export const BUCKET_SIZE = Math.pow(2, SIZE); 3 | export const MASK = BUCKET_SIZE - 1; 4 | export const MAX_INDEX_NODE = BUCKET_SIZE / 2; 5 | export const MIN_ARRAY_NODE = BUCKET_SIZE / 4; 6 | -------------------------------------------------------------------------------- /packages/map/tsconfig.commonjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./lib/commonjs", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/set/src/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import { size as _size } from '@collectable/map'; 2 | import { HashSetStructure } from '../internals'; 3 | 4 | export function isEmpty (set: HashSetStructure): boolean { 5 | return _size(set._map) === 0; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /packages/set/tsconfig.commonjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./lib/commonjs", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/sorted-map/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "outDir": "./lib/es2015", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/has.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure } from '../internals'; 2 | import { has as _has } from '@collectable/map'; 3 | 4 | export function has (value: T, set: SortedSetStructure): boolean { 5 | return _has(value, set._map); 6 | } -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/toNativeSet.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure } from '../internals'; 2 | import { values } from './index'; 3 | 4 | export function toNativeSet (set: SortedSetStructure): Set { 5 | return new Set(values(set)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/sorted-set/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "outDir": "./lib/es2015", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/list/src/functions/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { fromArray } from './fromArray'; 3 | 4 | export function fromIterable (values: Iterable): ListStructure { 5 | return fromArray(Array.from(values)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/map/src/internals/nodes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './constants'; 3 | export * from './EmptyNode'; 4 | export * from './ArrayNode'; 5 | export * from './CollisionNode'; 6 | export * from './IndexedNode'; 7 | export * from './LeafNode'; 8 | -------------------------------------------------------------------------------- /packages/red-black-tree/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "outDir": "./lib/es2015", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/at.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure, getItemByIndex } from '../internals'; 2 | 3 | export function at (index: number, map: SortedMapStructure): [K, V]|undefined { 4 | return getItemByIndex(index, map._sorted); 5 | } 6 | -------------------------------------------------------------------------------- /packages/sorted-map/tsconfig.commonjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./lib/commonjs", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/size.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure } from '../internals'; 2 | import { size as _size } from '@collectable/red-black-tree'; 3 | 4 | export function size (set: SortedSetStructure): number { 5 | return _size(set._tree); 6 | } 7 | -------------------------------------------------------------------------------- /packages/sorted-set/tsconfig.commonjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./lib/commonjs", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/collectable/tsconfig.commonjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./lib/commonjs", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/list/src/functions/fromArgs.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { fromArray } from './fromArray'; 3 | 4 | export const fromArgs: (...values: T[]) => ListStructure = function () { 5 | return fromArray(Array.from(arguments)); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/red-black-tree/tsconfig.commonjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./lib/commonjs", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/list/src/functions/concatLeft.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { concat } from './concat'; 3 | 4 | export function concatLeft (right: ListStructure, left: ListStructure): ListStructure { 5 | return concat(left, right); 6 | } 7 | -------------------------------------------------------------------------------- /packages/map/src/functions/fromNativeMap.ts: -------------------------------------------------------------------------------- 1 | import { HashMapStructure } from '../internals/HashMap'; 2 | import { fromIterable } from './fromIterable'; 3 | 4 | export function fromNativeMap (map: Map): HashMapStructure { 5 | return fromIterable(map); 6 | } 7 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/internals/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RedBlackTree'; 2 | export * from './rebalance'; 3 | export * from './path'; 4 | export * from './node'; 5 | export * from './ops'; 6 | export * from './iterator'; 7 | export * from './find'; 8 | export * from './unwrap'; -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/size.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure } from '../internals'; 2 | import { size as _size } from '@collectable/red-black-tree'; 3 | 4 | export function size (map: SortedMapStructure): number { 5 | return _size(map._sorted); 6 | } 7 | -------------------------------------------------------------------------------- /packages/list/src/functions/remove.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { removeRange } from './removeRange'; 3 | 4 | export function remove (index: number, list: ListStructure): ListStructure { 5 | return removeRange(index, index + 1, list); 6 | } 7 | -------------------------------------------------------------------------------- /packages/list/tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./.build", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts", 10 | "./tests/**/*.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/map/src/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import { HashMapStructure } from '../internals/HashMap'; 2 | 3 | export function isEmpty (map: HashMapStructure): boolean; 4 | export function isEmpty (map: HashMapStructure): boolean { 5 | return map._size === 0; 6 | } 7 | -------------------------------------------------------------------------------- /packages/map/tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./.build", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts", 10 | "./tests/**/*.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/emptyWithNumericKeys.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, size } from '../../src'; 3 | 4 | test('returns a tree of size 0', t => { 5 | const tree = emptyWithNumericKeys(); 6 | t.is(size(tree), 0); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/set/src/functions/empty.ts: -------------------------------------------------------------------------------- 1 | import { MutationContext } from '@collectable/core'; 2 | import { HashSetStructure, emptySet } from '../internals'; 3 | 4 | export function empty (mutability?: MutationContext): HashSetStructure { 5 | return emptySet(mutability); 6 | } 7 | -------------------------------------------------------------------------------- /packages/set/tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./.build", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts", 10 | "./tests/**/*.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/has.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure } from '../internals'; 2 | import { has as _has } from '@collectable/map'; 3 | 4 | export function has (key: K, map: SortedMapStructure): boolean { 5 | return _has(key, map._indexed); 6 | } -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure } from '../internals'; 2 | import { size as _size } from '@collectable/red-black-tree'; 3 | 4 | export function isEmpty (set: SortedSetStructure): boolean { 5 | return _size(set._tree) === 0; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /packages/collectable/tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./.build", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts", 10 | "./tests/**/*.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/list/tests/functions/of.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { of } from '../../src'; 3 | import { getAtOrdinal } from '../../src/internals'; 4 | 5 | test('should return a list containing the value', t => { 6 | var list = of('A'); 7 | t.is(getAtOrdinal(list, 0), 'A'); 8 | }); -------------------------------------------------------------------------------- /packages/sorted-map/tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./.build", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts", 10 | "./tests/**/*.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/sorted-set/tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./.build", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts", 10 | "./tests/**/*.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/list/src/functions/insert.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { insertArray } from './insertArray'; 3 | 4 | export function insert (index: number, value: T, list: ListStructure): ListStructure { 5 | return insertArray(index, [value], list); 6 | } 7 | -------------------------------------------------------------------------------- /packages/red-black-tree/tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "./.build", 6 | "noEmit": false 7 | }, 8 | "include": [ 9 | "./src/**/*.ts", 10 | "./tests/**/*.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/set/src/functions/isEqual.ts: -------------------------------------------------------------------------------- 1 | import { isEqual as _isEqual } from '@collectable/map'; 2 | import { HashSetStructure } from '../internals'; 3 | 4 | export function isEqual (set: HashSetStructure, other: HashSetStructure): boolean { 5 | return _isEqual(set._map, other._map); 6 | } 7 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import { SortedMapStructure } from '../internals'; 2 | import { size as _size } from '@collectable/red-black-tree'; 3 | 4 | export function isEmpty (map: SortedMapStructure): boolean { 5 | return _size(map._sorted) === 0; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/clone.ts: -------------------------------------------------------------------------------- 1 | import { isMutable } from '@collectable/core'; 2 | import { SortedSetStructure, cloneSortedSet } from '../internals'; 3 | 4 | export function clone (set: SortedSetStructure): SortedSetStructure { 5 | return cloneSortedSet(isMutable(set), set); 6 | } -------------------------------------------------------------------------------- /packages/list/src/functions/prependIterable.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { prependArray } from './prependArray'; 3 | 4 | export function prependIterable (values: Iterable, list: ListStructure): ListStructure { 5 | return prependArray(Array.from(values), list); 6 | } 7 | -------------------------------------------------------------------------------- /packages/list/tests/functions/empty.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, zero } from '../../src'; 3 | 4 | test('should have size 0', t => { 5 | const list = empty(); 6 | t.is(list._size, 0); 7 | }); 8 | 9 | test('zero() is an alias of empty', t => { 10 | t.is(empty, zero); 11 | }); -------------------------------------------------------------------------------- /packages/list/src/functions/of.ts: -------------------------------------------------------------------------------- 1 | import { commit } from '@collectable/core'; 2 | import { ListStructure, appendValues, createList } from '../internals'; 3 | 4 | export function of (value: T): ListStructure { 5 | var state = createList(true); 6 | appendValues(state, [value]); 7 | return commit(state); 8 | } -------------------------------------------------------------------------------- /packages/red-black-tree/src/RedBlackTree.ts: -------------------------------------------------------------------------------- 1 | export { 2 | RedBlackTreeStructure as Instance, 3 | RedBlackTreeEntry as Entry, 4 | RedBlackTreeIterator as Iterator, 5 | RedBlackTreeKeyIterator as KeyIterator, 6 | RedBlackTreeValueIterator as ValueIterator 7 | } from './internals'; 8 | export * from './functions'; -------------------------------------------------------------------------------- /packages/set/src/functions/clone.ts: -------------------------------------------------------------------------------- 1 | import { PreferredContext } from '@collectable/core'; 2 | import { HashSetStructure, cloneHashSet } from '../internals'; 3 | 4 | export function clone (set: HashSetStructure, mutability?: PreferredContext): HashSetStructure { 5 | return cloneHashSet(set, mutability); 6 | } -------------------------------------------------------------------------------- /packages/list/src/functions/insertIterable.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { insertArray } from './insertArray'; 3 | 4 | export function insertIterable (index: number, values: Iterable, list: ListStructure): ListStructure { 5 | return insertArray(index, Array.from(values), list); 6 | } 7 | -------------------------------------------------------------------------------- /packages/list/src/functions/mapToArray.ts: -------------------------------------------------------------------------------- 1 | import { MapFn } from '@collectable/core'; 2 | import { ListStructure, mapArrayFrom } from '../internals'; 3 | 4 | export function mapToArray (mapper: MapFn, list: ListStructure): U[] { 5 | return mapArrayFrom(mapper, list, new Array(list._size)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/list/src/functions/empty.ts: -------------------------------------------------------------------------------- 1 | import { PreferredContext } from '@collectable/core'; 2 | import { ListStructure, createList } from '../internals'; 3 | 4 | export function empty (pctx?: PreferredContext): ListStructure { 5 | return createList(pctx); 6 | } 7 | 8 | export const zero: () => ListStructure = empty; -------------------------------------------------------------------------------- /packages/set/tests/functions/empty.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, size } from '../../src'; 3 | 4 | test('returns a set with size 0', t => { 5 | t.is(size(empty()), 0); 6 | }); 7 | 8 | test('always returns the same set instance', t => { 9 | const a = empty(), b = empty(); 10 | t.is(a, b); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/set/tests/functions/size.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, fromArray, size } from '../../src'; 3 | 4 | test('returns 0 for an empty set', t => { 5 | t.is(size(empty()), 0); 6 | }); 7 | 8 | test('returns the number of items in a set', t => { 9 | t.is(size(fromArray(['A', 'B', 'C'])), 3); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/clone.ts: -------------------------------------------------------------------------------- 1 | import { isMutable } from '@collectable/core'; 2 | import { SortedMapStructure, cloneSortedMap } from '../internals'; 3 | 4 | export function clone (map: SortedMapStructure): SortedMapStructure { 5 | return cloneSortedMap(map, false, isMutable(map)); 6 | } -------------------------------------------------------------------------------- /packages/map/src/internals/common/stringHash.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Generator of 32 bit hashes of given string 3 | */ 4 | export function stringHash (str: string): number { 5 | let hash = 0; 6 | 7 | for(let i = 0; i < str.length; ++i) { 8 | hash = (((hash << 5) - hash) + str.charCodeAt(i)) | 0; 9 | } 10 | 11 | return hash; 12 | } 13 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as RedBlackTree from './RedBlackTree'; 2 | export { RedBlackTree }; 3 | 4 | export * from './functions'; 5 | export { 6 | RedBlackTreeStructure, 7 | RedBlackTreeEntry, 8 | RedBlackTreeIterator, 9 | RedBlackTreeKeyIterator, 10 | RedBlackTreeValueIterator 11 | } from './internals'; 12 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/lastKey.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { SortedMapStructure, getLastItem } from '../internals'; 3 | 4 | export function lastKey (map: SortedMapStructure): K|undefined { 5 | const item = getLastItem(map._sorted); 6 | return isDefined(item) ? item[0] : void 0; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/firstKey.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { SortedMapStructure, getFirstItem } from '../internals'; 3 | 4 | export function firstKey (map: SortedMapStructure): K|undefined { 5 | const item = getFirstItem(map._sorted); 6 | return isDefined(item) ? item[0] : void 0; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/firstValue.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { SortedMapStructure, getFirstItem } from '../internals'; 3 | 4 | export function firstValue (map: SortedMapStructure): V|undefined { 5 | const item = getFirstItem(map._sorted); 6 | return isDefined(item) ? item[1] : void 0; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/lastValue.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { SortedMapStructure, getLastItem } from '../internals'; 3 | 4 | export function lastValue (map: SortedMapStructure): V|undefined { 5 | const item = getLastItem(map._sorted); 6 | return isDefined(item) ? item[1] : void 0; 7 | } 8 | -------------------------------------------------------------------------------- /packages/list/src/functions/set.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, setValueAtOrdinal } from '../internals'; 3 | 4 | export function set (index: number, value: T, list: ListStructure): ListStructure { 5 | list = modify(list); 6 | setValueAtOrdinal(list, index, value); 7 | return commit(list); 8 | } 9 | -------------------------------------------------------------------------------- /packages/list/tests/functions/unwrap.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { unwrap } from '@collectable/core'; 3 | import { fromArray } from '../../src'; 4 | 5 | test('unwraps embedded collections', t => { 6 | var list = fromArray(['X', 'Y', fromArray([fromArray(['A']), 'B']), 'C']); 7 | t.deepEqual(unwrap(list), ['X', 'Y', [['A'], 'B'], 'C']); 8 | }); 9 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/get.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { SortedMapStructure, getItemByKey } from '../internals'; 3 | 4 | export function get (key: K, map: SortedMapStructure): V|undefined { 5 | const item = getItemByKey(key, map._indexed); 6 | return isDefined(item) ? item.value : void 0; 7 | } 8 | -------------------------------------------------------------------------------- /packages/list/src/internals/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './capacity'; 3 | export * from './compact'; 4 | export * from './concat'; 5 | export * from './fold'; 6 | export * from './slice'; 7 | export * from './slot'; 8 | export * from './list'; 9 | export * from './traversal'; 10 | export * from './values'; 11 | export * from './view'; -------------------------------------------------------------------------------- /packages/map/src/internals/primitives/findHash.ts: -------------------------------------------------------------------------------- 1 | import { stringHash } from '../common'; 2 | 3 | export function findHash (key: any): number { 4 | const hash: number = typeof key === 'number' 5 | ? key 6 | : typeof key === 'string' 7 | ? stringHash(key) 8 | : Math.abs(stringHash(JSON.stringify(key))); 9 | 10 | return hash; 11 | } 12 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/empty.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, size } from '../../src'; 3 | 4 | test('returns a map with size 0', t => { 5 | t.is(size(empty()), 0); 6 | }); 7 | 8 | test('always returns the same set instance if called with no arguments', t => { 9 | const a = empty(), b = empty(); 10 | t.is(a, b); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/empty.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, size } from '../../src'; 3 | 4 | test('returns a set with size 0', t => { 5 | t.is(size(empty()), 0); 6 | }); 7 | 8 | test('always returns the same set instance if called with no arguments', t => { 9 | const a = empty(), b = empty(); 10 | t.is(a, b); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/list/src/functions/removeRange.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, deleteValues } from '../internals'; 3 | 4 | export function removeRange (start: number, end: number, list: ListStructure): ListStructure { 5 | list = modify(list); 6 | list = deleteValues(list, start, end); 7 | return commit(list); 8 | } 9 | -------------------------------------------------------------------------------- /packages/set/tests/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, fromArray, isEmpty } from '../../src'; 3 | 4 | test('returns true if the set contains no items', t => { 5 | t.true(isEmpty(empty())); 6 | }); 7 | 8 | test('returns false if the set contains one or more items', t => { 9 | t.false(isEmpty(fromArray(['A', 'B', 'C']))); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/keyAt.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { SortedMapStructure, getItemByIndex } from '../internals'; 3 | 4 | export function keyAt (index: number, map: SortedMapStructure): K|undefined { 5 | const item = getItemByIndex(index, map._sorted); 6 | return isDefined(item) ? item[0] : void 0; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/valueAt.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { SortedMapStructure, getItemByIndex } from '../internals'; 3 | 4 | export function valueAt (index: number, map: SortedMapStructure): V|undefined { 5 | const item = getItemByIndex(index, map._sorted); 6 | return isDefined(item) ? item[1] : void 0; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/last.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure } from '../internals'; 2 | import { isUndefined } from '@collectable/core'; 3 | import { lastKey } from '@collectable/red-black-tree'; 4 | 5 | export function last (set: SortedSetStructure): T|undefined { 6 | var entry = lastKey(set._tree); 7 | return isUndefined(entry) ? void 0 : entry.value; 8 | } 9 | -------------------------------------------------------------------------------- /packages/map/src/functions/get.ts: -------------------------------------------------------------------------------- 1 | import { hash as calculateHash } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { getHash } from '../internals/primitives'; 4 | 5 | export function get (key: K, map: HashMapStructure): V|undefined { 6 | const hash = calculateHash(key); 7 | return getHash(void 0, hash, key, map); 8 | } 9 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/first.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure } from '../internals'; 2 | import { isUndefined } from '@collectable/core'; 3 | import { firstKey } from '@collectable/red-black-tree'; 4 | 5 | export function first (set: SortedSetStructure): T|undefined { 6 | var entry = firstKey(set._tree); 7 | return isUndefined(entry) ? void 0 : entry.value; 8 | } 9 | -------------------------------------------------------------------------------- /packages/set/src/internals/iterate.ts: -------------------------------------------------------------------------------- 1 | import { keys } from '@collectable/map'; 2 | import { HashSetStructure } from './HashSet'; 3 | 4 | export function iterate (set: HashSetStructure): IterableIterator { 5 | return keys(set._map); 6 | } 7 | 8 | export function isIterable (arg: any): arg is Iterable { 9 | return !!arg && Symbol.iterator in arg; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/size.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, size } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | test('returns 0 for an empty map', t => { 6 | t.is(size(empty()), 0); 7 | }); 8 | 9 | test('returns the number of items in a map', t => { 10 | t.is(size(fromStringArray(['A', 'B', 'C'])), 3); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/get.ts: -------------------------------------------------------------------------------- 1 | import { SortedSetStructure } from '../internals'; 2 | import { isUndefined } from '@collectable/core'; 3 | import { keyAt } from '@collectable/red-black-tree'; 4 | 5 | export function get (index: number, set: SortedSetStructure): T|undefined { 6 | var entry = keyAt(index, set._tree); 7 | return isUndefined(entry) ? void 0 : entry.value; 8 | } -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/size.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, size } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | test('returns 0 for an empty set', t => { 6 | t.is(size(empty()), 0); 7 | }); 8 | 9 | test('returns the number of items in a set', t => { 10 | t.is(size(fromStringArray(['A', 'B', 'C'])), 3); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/internals/SortedSet.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { values } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | test('Symbol.iterator() emits the same values as the values() function', t => { 6 | const set = fromStringArray(['A', 'B', 'C', 'D', 'E']); 7 | t.deepEqual(Array.from(set[Symbol.iterator]()), Array.from(values(set))); 8 | }); 9 | -------------------------------------------------------------------------------- /packages/list/src/functions/prependArray.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, prependValues } from '../internals'; 3 | 4 | export function prependArray (values: T[], list: ListStructure): ListStructure { 5 | if(values.length === 0) return list; 6 | list = modify(list); 7 | prependValues(list, values); 8 | return commit(list); 9 | } 10 | -------------------------------------------------------------------------------- /packages/map/src/functions/clone.ts: -------------------------------------------------------------------------------- 1 | import { PreferredContext, selectContext } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | 4 | export function clone (map: HashMapStructure, pctx?: PreferredContext): HashMapStructure { 5 | return new HashMapStructure( 6 | selectContext(pctx), 7 | map._root, 8 | map._size, 9 | ); 10 | } -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/iterateKeysFromLast.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeKeyIterator, RedBlackTreeStructure } from '../internals'; 2 | import { iterateFromLast } from './iterateFromLast'; 3 | 4 | export function iterateKeysFromLast (tree: RedBlackTreeStructure): RedBlackTreeKeyIterator { 5 | return new RedBlackTreeKeyIterator(iterateFromLast(tree)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/iterateValuesFromLast.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeStructure, RedBlackTreeValueIterator } from '../internals'; 2 | import { iterateFromLast } from './iterateFromLast'; 3 | 4 | export function iterateValuesFromLast (tree: RedBlackTreeStructure): RedBlackTreeValueIterator { 5 | return new RedBlackTreeValueIterator(iterateFromLast(tree)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/internals/SortedMap.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { toArray } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | test('emits the same values as the toArray() function', t => { 6 | const values = ['A', 'B', 'C', 'D', 'E']; 7 | const map = fromStringArray(values); 8 | t.deepEqual(Array.from(map[Symbol.iterator]()), toArray(map)); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/collectable/src/functions/has.ts: -------------------------------------------------------------------------------- 1 | import { IndexedCollection, isIndexedCollection } from '@collectable/core'; 2 | 3 | export function hasIn (path: any[], collection: IndexedCollection): boolean { 4 | var i = 0, value: any = collection; 5 | while(i < path.length && isIndexedCollection(value)) { 6 | if(!IndexedCollection.has(path[i++], value)) return false; 7 | } 8 | return true; 9 | } 10 | -------------------------------------------------------------------------------- /packages/list/src/functions/insertArray.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, insertValues } from '../internals'; 3 | 4 | export function insertArray (index: number, values: T[], list: ListStructure): ListStructure { 5 | if(values.length === 0) return list; 6 | list = modify(list); 7 | insertValues(list, index, values); 8 | return commit(list); 9 | } 10 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/remove.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { SortedSetStructure, unsetItem } from '../internals'; 3 | 4 | export function remove (value: T, set: SortedSetStructure): SortedSetStructure { 5 | var nextSet = modify(set); 6 | const modified = unsetItem(value, nextSet._map, nextSet._tree); 7 | commit(nextSet); 8 | return modified ? nextSet : set; 9 | } -------------------------------------------------------------------------------- /packages/sorted-set/src/internals/types.ts: -------------------------------------------------------------------------------- 1 | import { HashMapStructure } from '@collectable/map'; 2 | import { RedBlackTreeStructure } from '@collectable/red-black-tree'; 3 | 4 | export interface SortedSetItem { 5 | index: number; 6 | view: any; 7 | value: T; 8 | } 9 | 10 | export type ValueMap = HashMapStructure>; 11 | export type Sorted = RedBlackTreeStructure, null>; -------------------------------------------------------------------------------- /packages/list/src/functions/updateList.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure } from '../internals'; 3 | 4 | export type UpdateListCallback = (value: T) => T|void; 5 | 6 | export function updateList (callback: UpdateListCallback>, list: ListStructure): ListStructure { 7 | list = modify(list); 8 | return commit(callback(list) || list); 9 | } 10 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/fromObject.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { fromObject, size } from '../../src'; 3 | import { unwrap } from '@collectable/core'; 4 | 5 | test('returns a tree that matches the keys in the source object', t => { 6 | const source = { a: 1, b: 2, c: 3 }; 7 | const tree = fromObject(source); 8 | t.is(size(tree), 3); 9 | t.deepEqual(unwrap(tree), source); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/set/src/functions/add.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import * as HashMap from '@collectable/map'; 3 | import { HashSetStructure } from '../internals'; 4 | 5 | export function add (value: T, set: HashSetStructure): HashSetStructure { 6 | if(HashMap.has(value, set._map)) return set; 7 | set = modify(set); 8 | HashMap.set(value, null, set._map); 9 | return commit(set); 10 | } -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, isEmpty } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | test('returns true if the map contains no items', t => { 6 | t.true(isEmpty(empty())); 7 | }); 8 | 9 | test('returns false if the map contains one or more items', t => { 10 | t.false(isEmpty(fromStringArray(['A', 'B', 'C']))); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/add.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { SortedSetStructure, setItem } from '../internals'; 3 | 4 | export function add (value: T, set: SortedSetStructure): SortedSetStructure { 5 | var nextSet = modify(set); 6 | const modified = setItem(value, nextSet._map, nextSet._tree, nextSet._select); 7 | commit(nextSet); 8 | return modified ? nextSet : set; 9 | } -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, isEmpty } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | test('returns true if the set contains no items', t => { 6 | t.true(isEmpty(empty())); 7 | }); 8 | 9 | test('returns false if the set contains one or more items', t => { 10 | t.false(isEmpty(fromStringArray(['A', 'B', 'C']))); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/collectable/src/functions/get.ts: -------------------------------------------------------------------------------- 1 | import { IndexedCollection, isIndexedCollection } from '@collectable/core'; 2 | 3 | export function getIn (path: any[], collection: IndexedCollection): R { 4 | var i = 0, value: any = collection; 5 | while(i < path.length && isIndexedCollection(value)) { 6 | value = IndexedCollection.get(path[i++], value); 7 | } 8 | return value; 9 | } 10 | -------------------------------------------------------------------------------- /packages/set/src/functions/remove.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { HashMap } from '@collectable/map'; 3 | import { HashSetStructure } from '../internals'; 4 | 5 | export function remove (value: T, set: HashSetStructure): HashSetStructure { 6 | if(!HashMap.has(value, set._map)) return set; 7 | set = modify(set); 8 | HashMap.remove(value, set._map); 9 | return commit(set); 10 | } -------------------------------------------------------------------------------- /packages/list/src/functions/appendArrayMapped.ts: -------------------------------------------------------------------------------- 1 | import { MapFn, commit, modify } from '@collectable/core'; 2 | import { ListStructure, appendValues } from '../internals'; 3 | 4 | export function appendArrayMapped (fn: MapFn, values: T[], list: ListStructure): ListStructure { 5 | if(values.length === 0) return list; 6 | list = modify(list); 7 | appendValues(list, values, fn); 8 | return commit(list); 9 | } 10 | -------------------------------------------------------------------------------- /packages/map/src/functions/forEach.ts: -------------------------------------------------------------------------------- 1 | import { KeyedForEachFn } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { fold } from '../internals/primitives'; 4 | 5 | export function forEach (f: KeyedForEachFn, map: HashMapStructure): HashMapStructure { 6 | fold((_, value, key, index) => f(value, key, index), null, >map, true); 7 | return map; 8 | } -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/fromKeys.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { fromStringKeys, size } from '../../src'; 3 | import { unwrap } from '@collectable/core'; 4 | 5 | test('returns a tree containing the keys in a source array', t => { 6 | const source = ['a', 'b', 'c']; 7 | const tree = fromStringKeys(source); 8 | t.is(size(tree), 3); 9 | t.deepEqual(unwrap(tree), { a: null, b: null, c: null }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/list/src/functions/prependArrayMapped.ts: -------------------------------------------------------------------------------- 1 | import { MapFn, commit, modify } from '@collectable/core'; 2 | import { ListStructure, prependValues } from '../internals'; 3 | 4 | export function prependArrayMapped (fn: MapFn, values: T[], list: ListStructure): ListStructure { 5 | if(values.length === 0) return list; 6 | list = modify(list); 7 | prependValues(list, values, fn); 8 | return commit(list); 9 | } 10 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/emptyWithStringKeys.ts: -------------------------------------------------------------------------------- 1 | import { PreferredContext } from '@collectable/core'; 2 | import { stringCompare } from '@collectable/core'; 3 | import { RedBlackTreeStructure } from '../internals'; 4 | import { empty } from './empty'; 5 | 6 | export function emptyWithStringKeys (mutability?: PreferredContext): RedBlackTreeStructure { 7 | return empty(stringCompare, mutability); 8 | } 9 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/remove.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { SortedMapStructure, unsetItem } from '../internals'; 3 | 4 | export function remove (key: K, map: SortedMapStructure): SortedMapStructure { 5 | var nextSet = modify(map); 6 | const modified = unsetItem(key, nextSet._indexed, nextSet._sorted); 7 | commit(nextSet); 8 | return modified ? nextSet : map; 9 | } -------------------------------------------------------------------------------- /packages/list/src/functions/take.ts: -------------------------------------------------------------------------------- 1 | import { isImmutable } from '@collectable/core'; 2 | import { empty } from './empty'; 3 | import { ListStructure } from '../internals'; 4 | import { slice } from './slice'; 5 | 6 | export function take (count: number, list: ListStructure): ListStructure { 7 | if(count === 0 && isImmutable(list)) return empty(); 8 | if(count >= list._size) return list; 9 | return slice(0, count, list); 10 | } 11 | -------------------------------------------------------------------------------- /packages/map/src/functions/reduce.ts: -------------------------------------------------------------------------------- 1 | import { KeyedReduceFn } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { fold } from '../internals/primitives'; 4 | 5 | export function reduce (f: KeyedReduceFn, seed: R, map: HashMapStructure): R; 6 | export function reduce (f: KeyedReduceFn, seed: R, map: HashMapStructure): R { 7 | return fold(f, seed, map); 8 | } 9 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/emptyWithNumericKeys.ts: -------------------------------------------------------------------------------- 1 | import { PreferredContext } from '@collectable/core'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { RedBlackTreeStructure } from '../internals'; 4 | import { empty } from './empty'; 5 | 6 | export function emptyWithNumericKeys (mutability?: PreferredContext): RedBlackTreeStructure { 7 | return empty(numericCompare, mutability); 8 | } 9 | -------------------------------------------------------------------------------- /packages/set/tests/functions/isSet.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty as emptyMap } from '@collectable/map'; 3 | import { empty, isSet } from '../../src'; 4 | 5 | test('returns true if the argument is an instance of a Collectable.js Set class', t => { 6 | t.true(isSet(empty())); 7 | }); 8 | 9 | test('returns false if the argument is not an instance of a Collectable.js Set class', t => { 10 | t.false(isSet(emptyMap())); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/list/src/functions/concatAll.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, concatLists } from '../internals'; 3 | 4 | export function concatAll (lists: ListStructure[]): ListStructure { 5 | var list: ListStructure = lists[0]; 6 | list = modify(list); 7 | for(var i = 1; i < lists.length; i++) { 8 | list = concatLists(list, modify(lists[i])); 9 | } 10 | return commit(list); 11 | } 12 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/iterateKeysFromIndex.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeKeyIterator, RedBlackTreeStructure } from '../internals'; 2 | import { iterateFromIndex } from './iterateFromIndex'; 3 | 4 | export function iterateKeysFromIndex (reverse: boolean, index: number, tree: RedBlackTreeStructure): RedBlackTreeKeyIterator { 5 | return new RedBlackTreeKeyIterator(iterateFromIndex(reverse, index, tree)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/list/src/functions/insertArrayMapped.ts: -------------------------------------------------------------------------------- 1 | import { MapFn, commit, modify } from '@collectable/core'; 2 | import { ListStructure, insertValues } from '../internals'; 3 | 4 | export function insertArrayMapped (fn: MapFn, index: number, values: T[], list: ListStructure): ListStructure { 5 | if(values.length === 0) return list; 6 | list = modify(list); 7 | insertValues(list, index, values, fn); 8 | return commit(list); 9 | } 10 | -------------------------------------------------------------------------------- /packages/list/src/functions/skip.ts: -------------------------------------------------------------------------------- 1 | import { isImmutable } from '@collectable/core'; 2 | import { empty } from './empty'; 3 | import { ListStructure } from '../internals'; 4 | import { slice } from './slice'; 5 | 6 | export function skip (count: number, list: ListStructure): ListStructure { 7 | if(count === 0) return list; 8 | if(count >= list._size && isImmutable(list)) return empty(); 9 | return slice(count, list._size, list); 10 | } 11 | -------------------------------------------------------------------------------- /packages/list/src/functions/skipLast.ts: -------------------------------------------------------------------------------- 1 | import { isImmutable } from '@collectable/core'; 2 | import { empty } from './empty'; 3 | import { ListStructure } from '../internals'; 4 | import { slice } from './slice'; 5 | 6 | export function skipLast (count: number, list: ListStructure): ListStructure { 7 | if(count === 0) return list; 8 | if(count >= list._size && isImmutable(list)) return empty(); 9 | return slice(0, -count, list); 10 | } 11 | -------------------------------------------------------------------------------- /packages/map/src/functions/entries.ts: -------------------------------------------------------------------------------- 1 | import { iterator } from '../internals/primitives'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { Leaf } from '../internals/nodes'; 4 | 5 | export function entries (map: HashMapStructure): IterableIterator<[K, V]> { 6 | return iterator(map._root, nodeEntries); 7 | } 8 | 9 | function nodeEntries (node: Leaf): [K, V] { 10 | return [node.key, node.value]; 11 | } 12 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/iterateKeysFrom.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeKeyIterator, RedBlackTreeStructure } from '../internals'; 2 | import { FindOp } from './find'; 3 | import { iterateFrom } from './iterateFrom'; 4 | 5 | export function iterateKeysFrom (op: FindOp, reverse: boolean, key: K, tree: RedBlackTreeStructure): RedBlackTreeKeyIterator { 6 | return new RedBlackTreeKeyIterator(iterateFrom(op, reverse, key, tree)); 7 | } 8 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/iterateValuesFromIndex.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeStructure, RedBlackTreeValueIterator } from '../internals'; 2 | import { iterateFromIndex } from './iterateFromIndex'; 3 | 4 | export function iterateValuesFromIndex (reverse: boolean, index: number, tree: RedBlackTreeStructure): RedBlackTreeValueIterator { 5 | return new RedBlackTreeValueIterator(iterateFromIndex(reverse, index, tree)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/set.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { SortedMapStructure, setItem } from '../internals'; 3 | 4 | export function set (key: K, value: V, map: SortedMapStructure): SortedMapStructure { 5 | var nextSet = modify(map); 6 | const modified = setItem(key, value, nextSet._indexed, nextSet._sorted, nextSet._select); 7 | commit(nextSet); 8 | return modified ? nextSet : map; 9 | } -------------------------------------------------------------------------------- /packages/list/src/functions/takeLast.ts: -------------------------------------------------------------------------------- 1 | import { isImmutable } from '@collectable/core'; 2 | import { empty } from './empty'; 3 | import { ListStructure } from '../internals'; 4 | import { slice } from './slice'; 5 | 6 | export function takeLast (count: number, list: ListStructure): ListStructure { 7 | if(count === 0 && isImmutable(list)) return empty(); 8 | if(count >= list._size) return list; 9 | return slice(-count, list._size, list); 10 | } 11 | -------------------------------------------------------------------------------- /packages/list/src/functions/slice.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, sliceList } from '../internals'; 3 | 4 | export function slice (start: number, end: number, list: ListStructure): ListStructure { 5 | if(list._size === 0) return list; 6 | var oldList = list; 7 | list = modify(list); 8 | sliceList(list, start, end); 9 | commit(list); 10 | return oldList._size === list._size ? oldList : list; 11 | } 12 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/iterateValuesFrom.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeStructure, RedBlackTreeValueIterator } from '../internals'; 2 | import { FindOp } from './find'; 3 | import { iterateFrom } from './iterateFrom'; 4 | 5 | export function iterateValuesFrom (op: FindOp, reverse: boolean, key: K, tree: RedBlackTreeStructure): RedBlackTreeValueIterator { 6 | return new RedBlackTreeValueIterator(iterateFrom(op, reverse, key, tree)); 7 | } 8 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/fromStringKeys.ts: -------------------------------------------------------------------------------- 1 | import * as C from '@collectable/core'; 2 | import { stringCompare } from '@collectable/core'; 3 | import { RedBlackTreeStructure } from '../internals'; 4 | import { fromKeys } from './fromKeys'; 5 | 6 | export function fromStringKeys (keys: string[]|RedBlackTreeStructure|Iterable, mutability?: C.PreferredContext): RedBlackTreeStructure { 7 | return fromKeys(stringCompare, keys, mutability); 8 | } 9 | -------------------------------------------------------------------------------- /packages/list/src/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import { commit } from '@collectable/core'; 2 | import { ListStructure, appendValues, createList } from '../internals'; 3 | 4 | export function fromArray (values: T[]): ListStructure { 5 | if(!Array.isArray(values)) { 6 | throw new Error('First argument must be an array of values'); 7 | } 8 | var list = createList(true); 9 | if(values.length > 0) { 10 | appendValues(list, values); 11 | } 12 | return commit(list); 13 | } 14 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/fromNumericKeys.ts: -------------------------------------------------------------------------------- 1 | import * as C from '@collectable/core'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { RedBlackTreeStructure } from '../internals'; 4 | import { fromKeys } from './fromKeys'; 5 | 6 | export function fromNumericKeys (keys: number[]|RedBlackTreeStructure|Iterable, mutability?: C.PreferredContext): RedBlackTreeStructure { 7 | return fromKeys(numericCompare, keys, mutability); 8 | } 9 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/fromPairsWithStringKeys.ts: -------------------------------------------------------------------------------- 1 | import * as C from '@collectable/core'; 2 | import { stringCompare } from '@collectable/core'; 3 | import { RedBlackTreeStructure } from '../internals'; 4 | import { fromPairs } from './fromPairs'; 5 | 6 | export function fromPairsWithStringKeys (pairs: [string, V][]|Iterable<[string, V]>, mutability?: C.PreferredContext): RedBlackTreeStructure { 7 | return fromPairs(stringCompare, pairs, mutability); 8 | } 9 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/fromPairs.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { fromPairsWithStringKeys, size } from '../../src'; 3 | import { unwrap } from '@collectable/core'; 4 | 5 | test('returns a tree that matches the pairs in the source array', t => { 6 | const source: [string, number][] = [['a', 1], ['b', 2], ['c', 3]]; 7 | const tree = fromPairsWithStringKeys(source); 8 | t.is(size(tree), 3); 9 | t.deepEqual(unwrap(tree), { a: 1, b: 2, c: 3 }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/isSortedMap.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, isSortedMap } from '../../src'; 3 | import { empty as emptyMap } from '@collectable/map'; 4 | 5 | test('returns true if the argument is an instance of a Collectable.js SortedMap class', t => { 6 | t.true(isSortedMap(empty())); 7 | }); 8 | 9 | test('returns false if the argument is not an instance of a Collectable.js SortedMap class', t => { 10 | t.false(isSortedMap(emptyMap())); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/fromPairsWithNumericKeys.ts: -------------------------------------------------------------------------------- 1 | import * as C from '@collectable/core'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { RedBlackTreeStructure } from '../internals'; 4 | import { fromPairs } from './fromPairs'; 5 | 6 | export function fromPairsWithNumericKeys (pairs: [number, V][]|Iterable<[number, V]>, mutability?: C.PreferredContext): RedBlackTreeStructure { 7 | return fromPairs(numericCompare, pairs, mutability); 8 | } 9 | -------------------------------------------------------------------------------- /packages/set/tests/functions/values.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, fromArray, values } from '../../src'; 3 | 4 | test('returns an empty iterable if the input list is empty', t => { 5 | const set = empty(); 6 | t.true(values(set).next().done); 7 | }); 8 | 9 | test('returns an iterable that emits each member of the input set and then completes', t => { 10 | const set = fromArray(['A', 'B', 'C']); 11 | t.deepEqual(Array.from(values(set)).sort(), ['A', 'B', 'C']); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/map/src/functions/keys.ts: -------------------------------------------------------------------------------- 1 | import { iterator } from '../internals/primitives'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { Leaf } from '../internals/nodes'; 4 | 5 | export function keys (map: HashMapStructure): IterableIterator; 6 | export function keys (map: HashMapStructure): IterableIterator { 7 | return iterator(map._root, nodeKeys); 8 | } 9 | 10 | function nodeKeys (node: Leaf): K { 11 | return node.key; 12 | } 13 | -------------------------------------------------------------------------------- /packages/set/src/functions/update.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { HashSetStructure, isHashSet } from '../internals'; 3 | 4 | export type UpdateSetCallback = (set: HashSetStructure) => HashSetStructure|void; 5 | 6 | export function update (callback: UpdateSetCallback, set: HashSetStructure): HashSetStructure { 7 | set = modify(set); 8 | var result = callback(set); 9 | if(isHashSet(result)) set = result; 10 | return commit(set); 11 | } 12 | -------------------------------------------------------------------------------- /packages/list/src/internals/fold.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure, createIterator } from '../internals'; 2 | 3 | export function fold (f: (accum: R, value: T, index: number) => R, seed: R, list: ListStructure, cancelOnFalse?: boolean): R { 4 | var it = createIterator(list); 5 | var current: IteratorResult; 6 | var index = 0; 7 | 8 | while((!cancelOnFalse || seed !== false) && !(current = it.next()).done) { 9 | seed = f(seed, current.value, index++); 10 | } 11 | 12 | return seed; 13 | } -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/isSet.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys } from '@collectable/red-black-tree'; 3 | import { empty, isSortedSet } from '../../src'; 4 | 5 | test('returns true if the argument is an instance of a Collectable.js SortedSet class', t => { 6 | t.true(isSortedSet(empty())); 7 | }); 8 | 9 | test('returns false if the argument is not an instance of a Collectable.js SortedSet class', t => { 10 | t.false(isSortedSet(emptyWithNumericKeys())); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/map/src/functions/has.ts: -------------------------------------------------------------------------------- 1 | import { hash as calculateHash } from '@collectable/core'; 2 | import { getHash } from '../internals/primitives'; 3 | import { HashMapStructure } from '../internals/HashMap'; 4 | import { NOTHING } from '../internals/nodes'; 5 | 6 | export function has (key: K, map: HashMapStructure): boolean; 7 | export function has (key: K, map: HashMapStructure): boolean { 8 | const hash = calculateHash(key); 9 | return getHash(NOTHING, hash, key, map) !== NOTHING; 10 | } -------------------------------------------------------------------------------- /packages/map/src/functions/values.ts: -------------------------------------------------------------------------------- 1 | import { iterator } from '../internals/primitives'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { Leaf } from '../internals/nodes'; 4 | 5 | export function values (map: HashMapStructure): IterableIterator; 6 | export function values (map: HashMapStructure): IterableIterator { 7 | return iterator(map._root, nodeValues); 8 | } 9 | 10 | function nodeValues (node: Leaf): V { 11 | return node.value; 12 | } 13 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/reduce.ts: -------------------------------------------------------------------------------- 1 | import { ReduceFn } from '@collectable/core'; 2 | import { SortedSetStructure } from '../internals'; 3 | import { iterateValues } from '../internals'; 4 | 5 | export function reduce (fn: ReduceFn, seed: R, set: SortedSetStructure): R { 6 | var it = iterateValues(set); 7 | var current: IteratorResult; 8 | var index = 0; 9 | while(!(current = it.next()).done) { 10 | seed = fn(seed, current.value, index++); 11 | } 12 | return seed; 13 | } 14 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/update.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { SortedSetStructure, isSortedSet } from '../internals'; 3 | 4 | export type UpdateSetCallback = (set: SortedSetStructure) => SortedSetStructure|void; 5 | 6 | export function update (callback: UpdateSetCallback, set: SortedSetStructure): SortedSetStructure { 7 | set = modify(set); 8 | var result = callback(set); 9 | if(isSortedSet(result)) set = result; 10 | return commit(set); 11 | } 12 | -------------------------------------------------------------------------------- /packages/list/src/functions/concat.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, concatLists } from '../internals'; 3 | 4 | export function concat (left: ListStructure, right: ListStructure): ListStructure { 5 | if(left._size === 0) return right; 6 | if(right._size === 0) return left; 7 | left = concatLists(modify(left), modify(right)); 8 | return commit(left); 9 | } 10 | 11 | export const alt: (left: ListStructure, right: ListStructure) => ListStructure = concat; -------------------------------------------------------------------------------- /packages/set/tests/functions/has.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { HashSetStructure, fromArray, has } from '../../src'; 3 | 4 | const values = ['A', 'B', 'C', 'D', 'E']; 5 | let set: HashSetStructure; 6 | test.before(() => { 7 | set = fromArray(values); 8 | }); 9 | 10 | test('returns true if the set contains the input item', t => { 11 | values.forEach(c => t.true(has(c, set))); 12 | }); 13 | 14 | test('returns false if the set does not contain the input item', t => { 15 | t.false(has('a', set)); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/list/src/functions/fromArrayMapped.ts: -------------------------------------------------------------------------------- 1 | import { MapFn, commit } from '@collectable/core'; 2 | import { ListStructure, appendValues, createList } from '../internals'; 3 | 4 | export function fromArrayMapped (fn: MapFn, values: T[]): ListStructure { 5 | if(!Array.isArray(values)) { 6 | throw new Error('First argument must be an array of values'); 7 | } 8 | var list = createList(true); 9 | if(values.length > 0) { 10 | appendValues(list, values, fn); 11 | } 12 | return commit(list); 13 | } 14 | -------------------------------------------------------------------------------- /packages/set/src/functions/forEach.ts: -------------------------------------------------------------------------------- 1 | import { ForEachFn } from '@collectable/core'; 2 | import { forEach as _forEach } from '@collectable/map'; 3 | import { HashSetStructure } from '../internals'; 4 | 5 | function forEachMap (pred: ForEachFn) { 6 | return function (value: null, key: T, index: number) { 7 | return pred(key, index); 8 | }; 9 | } 10 | 11 | export function forEach (f: ForEachFn, set: HashSetStructure): HashSetStructure { 12 | _forEach(forEachMap(f), set._map); 13 | return set; 14 | } 15 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/size.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeStructure } from '../internals'; 2 | 3 | /** 4 | * Returns the current number of entries in the tree 5 | * 6 | * @export 7 | * @template K The type of keys in the tree 8 | * @template V The type of values in the tree 9 | * @param {RedBlackTreeStructure} tree The input tree 10 | * @returns {number} The number of entries in the tree 11 | */ 12 | export function size (tree: RedBlackTreeStructure): number { 13 | return tree._size; 14 | } 15 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/keys.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, keys } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | test('returns an empty iterable if the input list is empty', t => { 6 | const map = empty(); 7 | t.true(keys(map).next().done); 8 | }); 9 | 10 | test('returns an iterable that emits each member of the input map and then completes', t => { 11 | const map = fromStringArray(['A', 'B', 'C']); 12 | t.deepEqual(Array.from(keys(map)), ['A', 'B', 'C']); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/list/src/functions/equality.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { iterate, size } from '../functions'; 3 | 4 | export function isEqual (list: ListStructure, other: ListStructure): boolean { 5 | if(list === other) return true; 6 | if(size(list) !== size(other)) return false; 7 | var ita = iterate(list), itb = iterate(other); 8 | do { 9 | var ca = ita.next(); 10 | var cb = itb.next(); 11 | if(ca.value !== cb.value) return false; 12 | } while(!ca.done); 13 | return true; 14 | } 15 | -------------------------------------------------------------------------------- /packages/map/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strictNullChecks": true, 7 | "target": "es6", 8 | "sourceMap": true, 9 | "preserveConstEnums": false, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "removeComments": false, 13 | "noUnusedLocals": true, 14 | "lib": ["es2015", "es2016", "es2017"], 15 | "skipLibCheck": true, 16 | "noEmit": true 17 | } 18 | } -------------------------------------------------------------------------------- /packages/set/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strictNullChecks": true, 7 | "target": "es6", 8 | "sourceMap": true, 9 | "preserveConstEnums": false, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "removeComments": false, 13 | "noUnusedLocals": true, 14 | "lib": ["es2015", "es2016", "es2017"], 15 | "skipLibCheck": true, 16 | "noEmit": true 17 | } 18 | } -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/values.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, values } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | test('returns an empty iterable if the input list is empty', t => { 6 | const set = empty(); 7 | t.true(values(set).next().done); 8 | }); 9 | 10 | test('returns an iterable that emits each member of the input set and then completes', t => { 11 | const set = fromStringArray(['A', 'B', 'C']); 12 | t.deepEqual(Array.from(values(set)), ['A', 'B', 'C']); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strictNullChecks": true, 7 | "target": "es6", 8 | "sourceMap": true, 9 | "preserveConstEnums": false, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "removeComments": false, 13 | "noUnusedLocals": true, 14 | "lib": ["es2015", "es2016", "es2017"], 15 | "skipLibCheck": true, 16 | "noEmit": true 17 | } 18 | } -------------------------------------------------------------------------------- /packages/list/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strictNullChecks": true, 7 | "target": "es6", 8 | "sourceMap": true, 9 | "preserveConstEnums": false, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "removeComments": false, 13 | "noUnusedLocals": true, 14 | "lib": ["es2015", "es2016", "es2017"], 15 | "skipLibCheck": true, 16 | "noEmit": true 17 | } 18 | } -------------------------------------------------------------------------------- /packages/set/tests/functions/toArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { HashSetStructure, empty, fromArray, toArray } from '../../src'; 3 | 4 | const values = ['A', 'B', 'C', 'D', 'E']; 5 | let set: HashSetStructure; 6 | test.before(() => { 7 | set = fromArray(values); 8 | }); 9 | 10 | test('returns an empty array if the set is empty', t => { 11 | t.is(toArray(empty()).length, 0); 12 | }); 13 | 14 | test('returns an array containing each member of the input set', t => { 15 | t.deepEqual(toArray(set).sort(), values); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/collectable/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strictNullChecks": true, 7 | "target": "es6", 8 | "sourceMap": true, 9 | "preserveConstEnums": false, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "removeComments": false, 13 | "noUnusedLocals": true, 14 | "lib": ["es2015", "es2016", "es2017"], 15 | "skipLibCheck": true, 16 | "noEmit": true 17 | } 18 | } -------------------------------------------------------------------------------- /packages/sorted-map/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strictNullChecks": true, 7 | "target": "es6", 8 | "sourceMap": true, 9 | "preserveConstEnums": false, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "removeComments": false, 13 | "noUnusedLocals": true, 14 | "lib": ["es2015", "es2016", "es2017"], 15 | "skipLibCheck": true, 16 | "noEmit": true 17 | } 18 | } -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/forEach.ts: -------------------------------------------------------------------------------- 1 | import { FilterFn } from '@collectable/core'; 2 | import { SortedSetStructure } from '../internals'; 3 | import { iterateValues } from '../internals'; 4 | 5 | export function forEach (fn: FilterFn, set: SortedSetStructure): SortedSetStructure { 6 | var it = iterateValues(set); 7 | var current: IteratorResult; 8 | var index = 0; 9 | while(!(current = it.next()).done) { 10 | var signal = fn(current.value, index++); 11 | if(signal === false) break; 12 | } 13 | return set; 14 | } -------------------------------------------------------------------------------- /packages/sorted-set/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strictNullChecks": true, 7 | "target": "es6", 8 | "sourceMap": true, 9 | "preserveConstEnums": false, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "removeComments": false, 13 | "noUnusedLocals": true, 14 | "lib": ["es2015", "es2016", "es2017"], 15 | "skipLibCheck": true, 16 | "noEmit": true 17 | } 18 | } -------------------------------------------------------------------------------- /packages/map/src/functions/empty.ts: -------------------------------------------------------------------------------- 1 | import { PreferredContext, immutable, isUndefined, withMutability } from '@collectable/core'; 2 | import { EMPTY } from '../internals/nodes'; 3 | import { HashMapStructure } from '../internals/HashMap'; 4 | 5 | var EMPTY_MAP: HashMapStructure; 6 | 7 | export function empty (pctx?: PreferredContext): HashMapStructure { 8 | if(isUndefined(EMPTY_MAP)) EMPTY_MAP = new HashMapStructure(immutable(), EMPTY, 0); 9 | return isUndefined(pctx) ? EMPTY_MAP : withMutability(pctx, EMPTY_MAP); 10 | } 11 | -------------------------------------------------------------------------------- /packages/red-black-tree/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strictNullChecks": true, 7 | "target": "es6", 8 | "sourceMap": true, 9 | "preserveConstEnums": false, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "removeComments": false, 13 | "noUnusedLocals": true, 14 | "lib": ["es2015", "es2016", "es2017"], 15 | "skipLibCheck": true, 16 | "noEmit": true 17 | } 18 | } -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/has.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { has } from '../../src'; 3 | import { SortedMap, fromStringArray } from '../test-utils'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | let map: SortedMap; 7 | test.before(() => { 8 | map = fromStringArray(values); 9 | }); 10 | 11 | test('returns true if the map contains the input item', t => { 12 | values.forEach(c => t.true(has(c, map))); 13 | }); 14 | 15 | test('returns false if the map does not contain the input item', t => { 16 | t.false(has('a', map)); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeStructure } from '../internals'; 2 | 3 | /** 4 | * Determines whether or not the tree currently has any entries 5 | * 6 | * @export 7 | * @template K The type of keys in the tree 8 | * @template V The type of values in the tree 9 | * @param {RedBlackTreeStructure} tree The input tree 10 | * @returns {boolean} True if the tree is empty, otherwise false 11 | */ 12 | export function isEmpty (tree: RedBlackTreeStructure): boolean { 13 | return tree._size === 0; 14 | } 15 | -------------------------------------------------------------------------------- /packages/list/src/functions/map.ts: -------------------------------------------------------------------------------- 1 | import { MapFn, commit, modify } from '@collectable/core'; 2 | import { ListStructure, createIterator, setValueAtOrdinal } from '../internals'; 3 | 4 | export function map (fn: MapFn, list: ListStructure): ListStructure { 5 | list = modify(list); 6 | var it = createIterator(list); 7 | var current: IteratorResult; 8 | var index = 0; 9 | while(!(current = it.next()).done) { 10 | setValueAtOrdinal(list, index, fn(current.value, index)); 11 | index++; 12 | } 13 | return commit(list); 14 | } 15 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/updateMap.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { SortedMapStructure } from '../internals/SortedMap'; 3 | 4 | export type UpdateMapCallback = (map: SortedMapStructure) => SortedMapStructure|void; 5 | 6 | export function updateMap (callback: UpdateMapCallback, map: SortedMapStructure): SortedMapStructure { 7 | var nextMap = modify(map); 8 | nextMap = >callback(nextMap) || nextMap; 9 | return commit(nextMap); 10 | } 11 | -------------------------------------------------------------------------------- /packages/map/src/functions/update.ts: -------------------------------------------------------------------------------- 1 | import { get, remove, set } from './index'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | 4 | export type UpdateEntryCallback = (value: V|undefined, map: HashMapStructure) => V|undefined; 5 | 6 | export function update (callback: UpdateEntryCallback, key: K, map: HashMapStructure): HashMapStructure { 7 | var oldv = get(key, map); 8 | var newv = callback(oldv, map); 9 | return newv === oldv ? map 10 | : newv === void 0 ? remove(key, map) 11 | : set(key, newv, map); 12 | } 13 | -------------------------------------------------------------------------------- /packages/set/src/functions/filter.ts: -------------------------------------------------------------------------------- 1 | import { FilterFn, commit, modify } from '@collectable/core'; 2 | import { filter as _filter } from '@collectable/map'; 3 | import { HashSetStructure } from '../internals'; 4 | 5 | function filterMap (pred: FilterFn) { 6 | return function (value: null, key: T, index: number): boolean { 7 | return pred(key, index); 8 | }; 9 | } 10 | 11 | export function filter (fn: FilterFn, set: HashSetStructure): HashSetStructure { 12 | set = modify(set); 13 | _filter(filterMap(fn), set._map); 14 | return commit(set); 15 | } 16 | -------------------------------------------------------------------------------- /packages/set/tests/functions/toNativeSet.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { HashSetStructure, empty, fromArray, toNativeSet } from '../../src'; 3 | 4 | const values = ['A', 'B', 'C', 'D', 'E']; 5 | let set: HashSetStructure; 6 | test.before(() => { 7 | set = fromArray(values); 8 | }); 9 | 10 | test('returns an empty set if the input set is empty', t => { 11 | t.is(toNativeSet(empty()).size, 0); 12 | }); 13 | 14 | test('returns a native set containing each member of the input set', t => { 15 | t.deepEqual(Array.from(toNativeSet(set)).sort(), values); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/values.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, values } from '../../src'; 3 | import { fromStringArray, pairsFrom } from '../test-utils'; 4 | 5 | test('returns an empty iterable if the input list is empty', t => { 6 | const map = empty(); 7 | t.true(values(map).next().done); 8 | }); 9 | 10 | test('returns an iterable that emits each member of the input map and then completes', t => { 11 | const map = fromStringArray(['A', 'B', 'C']); 12 | t.deepEqual(Array.from(values(map)), pairsFrom(['A', 'B', 'C']).map(p => p[1])); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/isRedBlackTree.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeStructure, isRedBlackTree as _isRedBlackTree } from '../internals'; 2 | 3 | /** 4 | * Determines whether the input argument is an instance of a Collectable.js RedBlackTree structure. 5 | * 6 | * @export 7 | * @param {RedBlackTreeStructure} arg The input value to check 8 | * @returns {boolean} True if the input value is a RedBlackTree, otherwise false 9 | */ 10 | export function isRedBlackTree (arg: any): arg is RedBlackTreeStructure { 11 | return _isRedBlackTree(arg); 12 | } -------------------------------------------------------------------------------- /packages/set/src/functions/reduce.ts: -------------------------------------------------------------------------------- 1 | import { reduce as _reduce } from '@collectable/map'; 2 | import { HashSetStructure } from '../internals'; 3 | 4 | export type ReducePredicate = (accum: R, value: K, index: number) => R; 5 | 6 | export function reduce (f: ReducePredicate, seed: R, set: HashSetStructure): R { 7 | return _reduce(reduceMap(f), seed, set._map); 8 | } 9 | 10 | function reduceMap (pred: ReducePredicate) { 11 | return function (accum: R, value: null, key: K, index: number) { 12 | return pred(accum, key, index); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/has.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { SortedSetStructure, has } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | let set: SortedSetStructure; 7 | test.before(() => { 8 | set = fromStringArray(values); 9 | }); 10 | 11 | test('returns true if the set contains the input item', t => { 12 | values.forEach(c => t.true(has(c, set))); 13 | }); 14 | 15 | test('returns false if the set does not contain the input item', t => { 16 | t.false(has('a', set)); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/list/tests/functions/last.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, fromArray, last } from '../../src'; 3 | 4 | test('should return undefined if the list is empty', t => { 5 | var list = empty(); 6 | t.is(last(list), void 0); 7 | }); 8 | 9 | test('should return the last element in a list with multiple elements', t => { 10 | var list = fromArray(['X', 'Y', 'Z']); 11 | t.is(last(list), 'Z'); 12 | }); 13 | 14 | test('should return the only element in a single-element list', t => { 15 | var list = fromArray(['X']); 16 | t.is(last(list), 'X'); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/updateTree.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { set, updateTree, values } from '../../src'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | test('treats the inner tree as mutable', t => { 7 | const tree = createTree(); 8 | const tree1 = updateTree(tree => { 9 | t.false(isImmutable(tree)); 10 | set(1, '#1', tree); 11 | }, tree); 12 | t.true(isImmutable(tree1)); 13 | t.deepEqual(Array.from(values(tree1)), [1].concat(sortedValues).map(n => `#${n}`)); 14 | }); 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "packages": true 5 | }, 6 | "files.watcherExclude": { 7 | "**/.git/**": true, 8 | "**/lib/**": true, 9 | "**/.build/**": true, 10 | "**/.archive": true, 11 | "packages": true 12 | }, 13 | "search.exclude": { 14 | "**/.git/**": true, 15 | "**/node_modules": true, 16 | "**/lib/**": true, 17 | "**/.build/**": true, 18 | "**/*.d.ts": true, 19 | "**/.archive": true, 20 | "packages": true 21 | } 22 | } -------------------------------------------------------------------------------- /packages/list/tests/functions/first.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, first, fromArray } from '../../src'; 3 | 4 | test('should return undefined if the list is empty', t => { 5 | var list = empty(); 6 | t.is(first(list), void 0); 7 | }); 8 | 9 | test('should return the first element in a list with multiple elements', t => { 10 | var list = fromArray(['X', 'Y', 'Z']); 11 | t.is(first(list), 'X'); 12 | }); 13 | 14 | test('should return the only element in a single-element list', t => { 15 | var list = fromArray(['K']); 16 | t.is(first(list), 'K'); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/iterateFromKey.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { iterateFromKey } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | tree = createTree(); 10 | }); 11 | 12 | test('returns an iterator starting from the specified key', t => { 13 | const it = iterateFromKey(false, sortedValues[5], tree); 14 | t.deepEqual(Array.from(it).map(n => n.key), sortedValues.slice(5)); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/map/src/functions/set.ts: -------------------------------------------------------------------------------- 1 | import { ChangeFlag, commit, modify } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { setKeyValue } from '../internals/primitives'; 4 | 5 | export function set (key: K, value: V, map: HashMapStructure): HashMapStructure; 6 | export function set (key: K, value: V, map: HashMapStructure): HashMapStructure { 7 | var nextMap = modify(map); 8 | const change = ChangeFlag.get(); 9 | setKeyValue(key, value, change, nextMap); 10 | return change.release(commit(nextMap), map); 11 | } 12 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/toArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, toArray } from '../../src'; 3 | import { SortedMap, fromStringArray, pairsFrom } from '../test-utils'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | let map: SortedMap; 7 | test.beforeEach(() => { 8 | map = fromStringArray(values); 9 | }); 10 | 11 | test('returns an empty array if the map is empty', t => { 12 | t.is(toArray(empty()).length, 0); 13 | }); 14 | 15 | test('returns an array containing each member of the input map', t => { 16 | t.deepEqual(toArray(map), pairsFrom(values)); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/toArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { SortedSetStructure as SortedSet, empty, toArray } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | let set: SortedSet; 7 | test.beforeEach(() => { 8 | set = fromStringArray(values); 9 | }); 10 | 11 | test('returns an empty array if the set is empty', t => { 12 | t.is(toArray(empty()).length, 0); 13 | }); 14 | 15 | test('returns an array containing each member of the input set', t => { 16 | t.deepEqual(toArray(set), values); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/update.ts: -------------------------------------------------------------------------------- 1 | import { get, remove, set } from './index'; 2 | import { SortedMapStructure } from '../internals/SortedMap'; 3 | 4 | export type UpdateEntryCallback = (value: V|undefined, map: SortedMapStructure) => V|undefined; 5 | 6 | export function update (callback: UpdateEntryCallback, key: K, map: SortedMapStructure): SortedMapStructure { 7 | var oldv = get(key, map); 8 | var newv = callback(oldv, map); 9 | return newv === oldv ? map 10 | : newv === void 0 ? remove(key, map) 11 | : set(key, newv, map); 12 | } 13 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import { ComparatorFn, SelectorFn } from '@collectable/core'; 2 | import { SortedSetStructure, createSet } from '../internals'; 3 | 4 | export function fromArray (values: T[], compare?: ComparatorFn): SortedSetStructure; 5 | export function fromArray (values: T[], compare: ComparatorFn, select: SelectorFn): SortedSetStructure; 6 | export function fromArray (values: T[], compare?: ComparatorFn, select?: SelectorFn): SortedSetStructure { 7 | return createSet(false, values, >compare, >select); 8 | } 9 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import { ComparatorFn, SelectorFn } from '@collectable/core'; 2 | import { SortedSetStructure, createSet } from '../internals'; 3 | 4 | export function fromIterable (values: Iterable, compare?: ComparatorFn): SortedSetStructure; 5 | export function fromIterable (values: Iterable, compare: ComparatorFn, select: SelectorFn): SortedSetStructure; 6 | export function fromIterable (values: Iterable, compare?: ComparatorFn, select?: SelectorFn): SortedSetStructure { 7 | return createSet(false, values, compare, select); 8 | } 9 | -------------------------------------------------------------------------------- /packages/list/src/functions/update.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, getAtOrdinal, setValueAtOrdinal } from '../internals'; 3 | 4 | export type UpdateIndexCallback = (value: T, list: ListStructure) => T; 5 | 6 | export function update (index: number, callback: UpdateIndexCallback, list: ListStructure): ListStructure { 7 | var oldv = getAtOrdinal(list, index); 8 | var newv = callback(oldv, list); 9 | if(newv === oldv) return list; 10 | list = modify(list); 11 | setValueAtOrdinal(list, index, newv); 12 | return commit(list); 13 | } 14 | -------------------------------------------------------------------------------- /packages/map/src/functions/filter.ts: -------------------------------------------------------------------------------- 1 | import { KeyedFilterFn, commit, modify } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { fold } from '../internals/primitives'; 4 | import { remove } from './remove'; 5 | 6 | export function filter (fn: KeyedFilterFn, map: HashMapStructure): HashMapStructure { 7 | map = modify(map); 8 | fold( 9 | function (map: HashMapStructure, value: V, key: K, index: number) { 10 | return fn(value, key, index) ? map : remove(key, map); 11 | }, 12 | map, map, true 13 | ); 14 | return commit(map); 15 | } 16 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/toNativeMap.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, toNativeMap } from '../../src'; 3 | import { SortedMap, fromStringArray, pairsFrom } from '../test-utils'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | let map: SortedMap; 7 | test.beforeEach(() => { 8 | map = fromStringArray(values); 9 | }); 10 | 11 | test('returns an empty map if the input map is empty', t => { 12 | t.is(toNativeMap(empty()).size, 0); 13 | }); 14 | 15 | test('returns a native map containing each member of the input map', t => { 16 | t.deepEqual(Array.from(toNativeMap(map)), pairsFrom(values)); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/list/tests/functions/size.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { appendArray, empty, fromArray, size } from '../../src'; 3 | import { BRANCH_FACTOR, makeValues } from '../helpers'; 4 | 5 | test('returns 0 if the list is empty', t => { 6 | t.is(size(empty()), 0); 7 | }); 8 | 9 | test('returns the size of a single-node list', t => { 10 | var list = fromArray(['X', 'Y']); 11 | t.is(size(list), 2); 12 | }); 13 | 14 | test('returns the correct size of a list with uncommitted changes', t => { 15 | var values = makeValues(BRANCH_FACTOR*4); 16 | t.is(size(appendArray(['X', 'Y'], fromArray(values))), values.length + 2); 17 | }); -------------------------------------------------------------------------------- /packages/set/tests/test-utils.ts: -------------------------------------------------------------------------------- 1 | import { isMutable, isUndefined } from '@collectable/core'; 2 | import { HashSet } from '../src'; 3 | 4 | let _id = 0; 5 | const CACHE = new WeakMap(); 6 | function ctxid (obj: object): number { 7 | var id = CACHE.get(obj); 8 | if(isUndefined(id)) { 9 | id = ++_id; 10 | CACHE.set(obj, id); 11 | } 12 | return id; 13 | } 14 | 15 | export function snapshot (set: HashSet.Instance): object { 16 | return { 17 | token: ctxid(set['@@mctx'].token), 18 | context: ctxid(set['@@mctx']), 19 | mutable: isMutable(set), 20 | values: Array.from(set) 21 | }; 22 | } -------------------------------------------------------------------------------- /packages/collectable/README.md: -------------------------------------------------------------------------------- 1 | # [![Collectable.js: Main Package](https://github.com/frptools/collectable/raw/master/.assets/logo.png)](https://github.com/frptools/collectable) 2 | 3 | This package includes references to all the individual data structure packages, and provides a general API containing methods to work with deeply-nested combinations of different Collectable.js data structures. 4 | 5 | *This documentation is under construction. The list of functions, descriptions and examples are pending.* 6 | 7 | ## Installation 8 | 9 | ``` 10 | # via NPM 11 | npm install collectable 12 | 13 | # or Yarn 14 | yarn add collectable 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/toNativeSet.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { SortedSetStructure as SortedSet, empty, toNativeSet } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | let set: SortedSet; 7 | test.beforeEach(() => { 8 | set = fromStringArray(values); 9 | }); 10 | 11 | test('returns an empty set if the input set is empty', t => { 12 | t.is(toNativeSet(empty()).size, 0); 13 | }); 14 | 15 | test('returns a native set containing each member of the input set', t => { 16 | t.deepEqual(Array.from(toNativeSet(set)), values); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/list/tests/functions/appendArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { appendArray, empty } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | 5 | test('should return the original list if called with an empty list', t => { 6 | const list = empty(); 7 | const appended = appendArray([], list); 8 | t.is(list._size, 0); 9 | t.is(list, appended); 10 | }); 11 | 12 | test('should append each element in the array', t => { 13 | var values = ['foo', 'bar', 'baz']; 14 | const list = appendArray(values, empty()); 15 | t.is(list._size, 3); 16 | t.deepEqual(arrayFrom(list), values); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/set/src/functions/map.ts: -------------------------------------------------------------------------------- 1 | import { MapFn, commit, modify } from '@collectable/core'; 2 | import { HashMap } from '@collectable/map'; 3 | import { HashSetStructure } from '../internals'; 4 | 5 | export function map (fn: MapFn, set: HashSetStructure): HashSetStructure { 6 | set = modify(set); 7 | var it = HashMap.keys(set._map); 8 | var current: IteratorResult; 9 | var map = HashMap.empty(set); 10 | var index = 0; 11 | while(!(current = it.next()).done) { 12 | HashMap.set(fn(current.value, index++), null, map); 13 | } 14 | set._map = map; 15 | return commit(set); 16 | } 17 | -------------------------------------------------------------------------------- /packages/map/src/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import { ChangeFlag, commit } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { setKeyValue } from '../internals/primitives'; 4 | import { empty } from './empty'; 5 | 6 | export function fromArray (array: Array<[K, V]>): HashMapStructure { 7 | let map = >empty(true); 8 | const change = ChangeFlag.get(); 9 | for(let i = 0; i < array.length; ++i) { 10 | var entry = array[i]; 11 | setKeyValue(entry[0], entry[1], change, map); 12 | change.reset(); 13 | } 14 | map = commit(map); 15 | return map; 16 | } 17 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/remove.notexists.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { has, remove, size } from '../../src'; 3 | import { SortedMap, fromStringArray } from '../test-utils'; 4 | 5 | let map0: SortedMap, map1: SortedMap; 6 | test.beforeEach(() => { 7 | map0 = fromStringArray(['A', 'B', 'C']); 8 | map1 = remove('D', map0); 9 | }); 10 | 11 | test('the map size does not change', t => { 12 | t.is(size(map1), 3); 13 | }); 14 | 15 | test('the input map is returned unmodified', t => { 16 | t.is(map0, map1); 17 | }); 18 | 19 | test('the item is still unretrievable from the map', t => { 20 | t.false(has('D', map1)); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/map/src/internals/common/bitwise-operations.ts: -------------------------------------------------------------------------------- 1 | import { MASK } from './constants'; 2 | 3 | export function hammingWeight (num: number): number { 4 | num = num - ((num >> 1) & 0x55555555); 5 | num = (num & 0x33333333) + ((num >> 2) & 0x33333333); 6 | return ((num + (num >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; 7 | } 8 | 9 | export function hashFragment (shift: number, hash: number) { 10 | return (hash >>> shift) & MASK; 11 | } 12 | 13 | export function toBitmap (num: number) { 14 | return 1 << num; 15 | } 16 | 17 | export function bitmapToIndex (shift: number, bitmap: number) { 18 | return hammingWeight(shift & (bitmap - 1)); 19 | } 20 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/indexOf.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { indexOf } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | let tree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | tree = createTree(); 10 | }); 11 | 12 | test('returns -1 if the key is not found', t => { 13 | t.is(indexOf(1, tree), -1); 14 | }); 15 | 16 | test('returns the correct index for any valid key', t => { 17 | for(var i = 0; i < sortedValues.length; i++) { 18 | t.is(indexOf(sortedValues[i], tree), i); 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /packages/map/src/functions/remove.ts: -------------------------------------------------------------------------------- 1 | import { ChangeFlag, commit, modify } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { setKeyValue } from '../internals/primitives'; 4 | import { NOTHING } from '../internals/nodes/constants'; 5 | 6 | export function remove (key: K, map: HashMapStructure): HashMapStructure; 7 | export function remove (key: K, map: HashMapStructure): HashMapStructure { 8 | var nextMap = modify(map); 9 | const change = ChangeFlag.get(); 10 | setKeyValue(key, NOTHING as V, change, nextMap); 11 | return change.release(commit(nextMap), map); 12 | } 13 | -------------------------------------------------------------------------------- /packages/sorted-map/src/internals/types.ts: -------------------------------------------------------------------------------- 1 | import { HashMap } from '@collectable/map'; 2 | import { RedBlackTree } from '@collectable/red-black-tree'; 3 | 4 | export interface Entry { 5 | index: number; 6 | view: U; 7 | key: K; 8 | value: V; 9 | } 10 | 11 | export interface SortingKey { 12 | index: number; 13 | view: U; 14 | key: K; 15 | } 16 | 17 | export type SortedMapEntry = { 18 | readonly [P in keyof Entry]: Entry[P]; 19 | }; 20 | 21 | export type KeyMap = HashMap.Instance>; 22 | export type SortedValues = RedBlackTree.Instance, V>; -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/get.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, get, set } from '../../src'; 3 | import { isMutable, unwrap } from '@collectable/core'; 4 | 5 | test('returns the value with the specified key', t => { 6 | var map = set('x', 3, empty()); 7 | 8 | t.is(get('x', map), 3); 9 | 10 | t.false(isMutable(map)); 11 | t.deepEqual(unwrap(map), { x: 3 }); 12 | }); 13 | 14 | test('returns undefined if the specified key is missing', t => { 15 | var map = set('x', 3, empty()); 16 | 17 | t.is(get('y', map), void 0); 18 | 19 | t.false(isMutable(map)); 20 | t.deepEqual(unwrap(map), { x: 3 }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/firstKey.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { empty, firstKey } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[]; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | }); 12 | 13 | test('returns the first key in the sorted index', t => { 14 | t.deepEqual(firstKey(map), values[0]); 15 | }); 16 | 17 | test('returns undefined if the collection is empty', t => { 18 | t.is(firstKey(empty()), void 0); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/set.exists.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { has, set, size } from '../../src'; 3 | import { SortedMap, fromStringArray } from '../test-utils'; 4 | 5 | let map0: SortedMap, map1: SortedMap; 6 | test.beforeEach(() => { 7 | map0 = fromStringArray(['D', 'A', 'B']); 8 | map1 = set('B', 'B'.charCodeAt(0), map0); 9 | }); 10 | 11 | test('the map size does not change', t => { 12 | t.is(size(map0), 3); 13 | t.is(size(map1), 3); 14 | }); 15 | 16 | test('the input map is returned', t => { 17 | t.is(map0, map1); 18 | }); 19 | 20 | test('the specified item can still be retrieved from the map', t => { 21 | t.true(has('B', map1)); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/list/tests/functions/prependArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, prependArray } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | 5 | test('should return the original list if called with an empty list', t => { 6 | const list = empty(); 7 | const prepended = prependArray([], list); 8 | t.is(list._size, 0); 9 | t.is(list, prepended); 10 | }); 11 | 12 | test('should append elements so that their order in the list matches the source array', t => { 13 | var values = ['foo', 'bar', 'baz']; 14 | const list = prependArray(values, empty()); 15 | t.is(list._size, 3); 16 | t.deepEqual(arrayFrom(list), values); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/map/src/internals/primitives/unwrap.ts: -------------------------------------------------------------------------------- 1 | import { Associative, isObject, unwrap, unwrapKey } from '@collectable/core'; 2 | import { HashMapStructure } from '../HashMap'; 3 | import { identity, iterator } from './index'; 4 | import { Leaf } from '../nodes'; 5 | 6 | export function unwrapInto (target: Associative, map: HashMapStructure): Associative { 7 | var it = iterator(map._root, identity); 8 | var current: IteratorResult>; 9 | while(!(current = it.next()).done) { 10 | var entry = current.value; 11 | var value = entry.value; 12 | target[unwrapKey(entry.key)] = isObject(value) ? unwrap(value) : value; 13 | } 14 | return target; 15 | } -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/first.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { empty, first } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[]; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | }); 12 | 13 | test('returns the first entry in the sorted index', t => { 14 | t.deepEqual(first(map), [values[0], `#${values[0]}`]); 15 | }); 16 | 17 | test('returns undefined if the collection is empty', t => { 18 | t.is(first(empty()), void 0); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/map/tests/get.ts: -------------------------------------------------------------------------------- 1 | import { isMutable } from '@collectable/core'; 2 | import { unwrap } from '@collectable/core'; 3 | import test from 'ava'; 4 | import { empty, get, set } from '../src'; 5 | 6 | test('returns the value with the specified key', t => { 7 | var map = set('x', 3, empty()); 8 | 9 | t.is(get('x', map), 3); 10 | 11 | t.false(isMutable(map)); 12 | t.deepEqual(unwrap(map), { x: 3 }); 13 | }); 14 | 15 | test('returns undefined if the specified key is missing', t => { 16 | var map = set('x', 3, empty()); 17 | 18 | t.is(get('y', map), void 0); 19 | 20 | t.false(isMutable(map)); 21 | t.deepEqual(unwrap(map), { x: 3 }); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/firstValue.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { empty, firstValue } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[]; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | }); 12 | 13 | test('returns the first value in the sorted index', t => { 14 | t.deepEqual(firstValue(map), `#${values[0]}`); 15 | }); 16 | 17 | test('returns undefined if the collection is empty', t => { 18 | t.is(firstValue(empty()), void 0); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/remove.notexists.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { SortedSetStructure, has, remove, size } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | let set0: SortedSetStructure, set1: SortedSetStructure; 6 | test.beforeEach(() => { 7 | set0 = fromStringArray(['A', 'B', 'C']); 8 | set1 = remove('D', set0); 9 | }); 10 | 11 | test('the set size does not change', t => { 12 | t.is(size(set1), 3); 13 | }); 14 | 15 | test('the input set is returned unmodified', t => { 16 | t.is(set0, set1); 17 | }); 18 | 19 | test('the item is still unretrievable from the set', t => { 20 | t.false(has('D', set1)); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/list/src/functions/appendIterable.ts: -------------------------------------------------------------------------------- 1 | import { ListStructure } from '../internals'; 2 | import { appendArray } from './appendArray'; 3 | 4 | /** 5 | * Appends a set of values to the end of a list, growing the size of the list by the number of 6 | * elements iterated over. 7 | * 8 | * @template T - The type of value contained by the list 9 | * @param value - The values to append to the list 10 | * @param list - The list to which the values should be appended 11 | * @returns A list containing the appended values 12 | */ 13 | export function appendIterable (values: Iterable, list: ListStructure): ListStructure { 14 | return appendArray(Array.from(values), list); 15 | } 16 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/isEmpty.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, isEmpty } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, 7 | emptyTree: RedBlackTreeStructure; 8 | 9 | test.before(() => { 10 | emptyTree = >emptyWithNumericKeys(); 11 | tree = createTree(); 12 | }); 13 | 14 | test('returns true if the tree is empty', t => { 15 | t.true(isEmpty(emptyTree)); 16 | }); 17 | 18 | test('returns false if the tree is not empty', t => { 19 | t.false(isEmpty(tree)); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/reduce.ts: -------------------------------------------------------------------------------- 1 | import { KeyedReduceFn } from '@collectable/core'; 2 | import { RedBlackTreeEntry } from '@collectable/red-black-tree'; 3 | import { SortedMapStructure, SortingKey } from '../internals'; 4 | import { iterate } from '../internals'; 5 | 6 | export function reduce (fn: KeyedReduceFn, seed: R, map: SortedMapStructure): R { 7 | var it = iterate(map); 8 | var current: IteratorResult, V>>; 9 | var index = 0; 10 | while(!(current = it.next()).done) { 11 | var entry = current.value; 12 | seed = fn(seed, entry.value, entry.key.key, index++); 13 | } 14 | return seed; 15 | } 16 | -------------------------------------------------------------------------------- /packages/list/tests/functions/prependIterable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, prependIterable } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | 5 | test('should return the original list if called with an empty iterable', t => { 6 | const list = empty(); 7 | const prepended = prependIterable(new Set(), list); 8 | t.is(list._size, 0); 9 | t.is(list, prepended); 10 | }); 11 | 12 | test('should prepend each value iterated over', t => { 13 | var values = new Set(['foo', 'bar', 'baz']); 14 | const list = prependIterable(values, empty()); 15 | t.is(list._size, 3); 16 | t.deepEqual(arrayFrom(list).sort(), Array.from(values).sort()); 17 | }); -------------------------------------------------------------------------------- /packages/core/src/common.ts: -------------------------------------------------------------------------------- 1 | import { Collection, CollectionEntry, IndexedCollection } from './collection'; 2 | 3 | export function isCollection (value: object): value is Collection { 4 | return '@@is-collection' in value; 5 | } 6 | 7 | export function isIndexedCollection, U = any> (value: object): value is IndexedCollection { 8 | return isCollection(value) && '@@verifyKey' in value; 9 | } 10 | 11 | export function normalizeIndex (index: number, size: number): number { 12 | return index < 0 13 | ? size + index < 0 14 | ? -1 15 | : size + index 16 | : index >= size 17 | ? -1 18 | : index; 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/iterator.ts: -------------------------------------------------------------------------------- 1 | export class MappableIterator implements IterableIterator { 2 | private it: IterableIterator; 3 | constructor ( 4 | private iterable: Iterable, 5 | private map: (value: T) => U 6 | ) { 7 | this.it = >this.iterable[Symbol.iterator](); 8 | } 9 | 10 | next (value?: any): IteratorResult { 11 | var result = >this.it.next(value); 12 | if(result.done) { 13 | result.value = void 0; 14 | } 15 | else { 16 | result.value = this.map(result.value); 17 | } 18 | return result; 19 | } 20 | 21 | [Symbol.iterator] (): IterableIterator { 22 | return this; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/firstKey.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, firstKey } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the tree is empty', t => { 14 | t.is(firstKey(emptyTree), void 0); 15 | }); 16 | 17 | test('returns the leftmost key', t => { 18 | const key = firstKey(tree); 19 | t.is(key, sortedValues[0]); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/size.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, size } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, 7 | emptyTree: RedBlackTreeStructure; 8 | 9 | test.before(() => { 10 | emptyTree = >emptyWithNumericKeys(); 11 | tree = createTree(); 12 | }); 13 | 14 | test('returns 0 if the tree is empty', t => { 15 | t.is(size(emptyTree), 0); 16 | }); 17 | 18 | test('returns the number of elements in the tree', t => { 19 | t.is(size(tree), sortedValues.length); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/map/src/functions/updateMap.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | 4 | export type UpdateMapCallback = (map: HashMapStructure) => HashMapStructure|void; 5 | 6 | export function updateMap (callback: UpdateMapCallback, map: HashMapStructure): HashMapStructure; 7 | export function updateMap (callback: UpdateMapCallback, map: HashMapStructure): HashMapStructure { 8 | var nextMap = modify(map); 9 | const oldRoot = nextMap._root; 10 | nextMap = >callback(nextMap) || nextMap; 11 | return commit(nextMap)._root === oldRoot ? map : nextMap; 12 | } 13 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/lastKey.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { RedBlackTreeStructure } from '../internals'; 3 | import { last } from './last'; 4 | 5 | /** 6 | * Retrieves the last key in the tree. 7 | * 8 | * @export 9 | * @template K The type of keys in the tree 10 | * @template V The type of values in the tree 11 | * @param {RedBlackTreeStructure} tree The input tree 12 | * @returns {([K, V]|undefined)} The key of the last entry in the tree, or undefined if the tree was empty 13 | */ 14 | export function lastKey (tree: RedBlackTreeStructure): K|undefined { 15 | var node = last(tree); 16 | return isDefined(node) ? node.key : void 0; 17 | } 18 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/isRedBlackTree.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, isRedBlackTree } from '../../src'; 3 | 4 | test('returns true if the argument is a valid RedBlackTree instance', t => { 5 | const tree = emptyWithNumericKeys(); 6 | t.true(isRedBlackTree(tree)); 7 | }); 8 | 9 | test('returns false if the argument is not a valid RedBlackTree instance', t => { 10 | t.false(isRedBlackTree(0)); 11 | t.false(isRedBlackTree(1)); 12 | t.false(isRedBlackTree('foo')); 13 | t.false(isRedBlackTree(null)); 14 | t.false(isRedBlackTree(void 0)); 15 | t.false(isRedBlackTree({})); 16 | t.false(isRedBlackTree(Symbol())); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/map/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clone'; 2 | export * from './empty'; 3 | export * from './entries'; 4 | export * from './filter'; 5 | export * from './forEach'; 6 | export * from './fromArray'; 7 | export * from './fromIterable'; 8 | export * from './fromNativeMap'; 9 | export * from './fromObject'; 10 | export * from './get'; 11 | export * from './has'; 12 | export * from './isEmpty'; 13 | export * from './isEqual'; 14 | export * from './isMap'; 15 | export * from './keys'; 16 | export * from './map'; 17 | export * from './reduce'; 18 | export * from './remove'; 19 | export * from './set'; 20 | export * from './size'; 21 | export * from './update'; 22 | export * from './updateMap'; 23 | export * from './values'; -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/lastKey.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, lastKey } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the tree is empty', t => { 14 | t.is(lastKey(emptyTree), void 0); 15 | }); 16 | 17 | test('returns the rightmost key', t => { 18 | const key = lastKey(tree); 19 | t.is(key, sortedValues[sortedValues.length - 1]); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/lastKey.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { empty, lastKey } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[], lastIndex; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | lastIndex = values.length - 1; 12 | }); 13 | 14 | test('returns the last key in the sorted index', t => { 15 | t.deepEqual(lastKey(map), values[lastIndex]); 16 | }); 17 | 18 | test('returns undefined if the collection is empty', t => { 19 | t.is(lastKey(empty()), void 0); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/map/src/functions/map.ts: -------------------------------------------------------------------------------- 1 | import { KeyedMapFn, commit, modify } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { reduce, set } from './index'; 4 | 5 | export function map (f: KeyedMapFn, map: HashMapStructure): HashMapStructure; 6 | export function map (f: KeyedMapFn, map: HashMapStructure): HashMapStructure { 7 | var nextMap = >modify(map); 8 | reduce( 9 | function (newMap: HashMapStructure, value: V, key: K, index: number) { 10 | return set(key, f(value, key, index), newMap); 11 | }, 12 | nextMap, 13 | map 14 | ); 15 | return commit(nextMap); 16 | } 17 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/clone.ts: -------------------------------------------------------------------------------- 1 | import { PreferredContext } from '@collectable/core'; 2 | import { RedBlackTreeStructure, cloneTree } from '../internals'; 3 | 4 | /** 5 | * Returns a copy of a tree, preserving the mutable/immutable status of the input tree. 6 | * 7 | * @export 8 | * @template K The type of keys in the tree 9 | * @template V The type of values in the tree 10 | * @param {RedBlackTreeStructure} tree The tree to be cloned 11 | * @returns {RedBlackTreeStructure} A cloned instance of the input tree 12 | */ 13 | export function clone (tree: RedBlackTreeStructure, mutability?: PreferredContext): RedBlackTreeStructure { 14 | return cloneTree(tree, mutability); 15 | } -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/firstValue.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, firstValue } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the tree is empty', t => { 14 | t.is(firstValue(emptyTree), void 0); 15 | }); 16 | 17 | test('returns the leftmost value', t => { 18 | const value = firstValue(tree); 19 | t.is(value, `#${sortedValues[0]}`); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/set/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add'; 2 | export * from './clone'; 3 | export * from './empty'; 4 | export * from './filter'; 5 | export * from './forEach'; 6 | export * from './fromArray'; 7 | export * from './fromIterable'; 8 | export * from './fromNativeSet'; 9 | export * from './has'; 10 | export * from './intersect'; 11 | export * from './isEmpty'; 12 | export * from './isEqual'; 13 | export * from './isSet'; 14 | export * from './map'; 15 | export * from './reduce'; 16 | export * from './remove'; 17 | export * from './size'; 18 | export * from './subtract'; 19 | export * from './toArray'; 20 | export * from './toNativeSet'; 21 | export * from './union'; 22 | export * from './update'; 23 | export * from './values'; -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/forEach.ts: -------------------------------------------------------------------------------- 1 | import { KeyedFilterFn } from '@collectable/core'; 2 | import { RedBlackTreeEntry } from '@collectable/red-black-tree'; 3 | import { SortedMapStructure, SortingKey } from '../internals'; 4 | import { iterate } from '../internals'; 5 | 6 | export function forEach (fn: KeyedFilterFn, map: SortedMapStructure): SortedMapStructure { 7 | var it = iterate(map); 8 | var current: IteratorResult, V>>; 9 | var index = 0; 10 | while(!(current = it.next()).done) { 11 | var entry = current.value; 12 | var signal = fn(entry.value, entry.key.key, index++); 13 | if(signal === false) break; 14 | } 15 | return map; 16 | } -------------------------------------------------------------------------------- /packages/list/tests/functions/appendIterable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { appendIterable, empty } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | 5 | test('should return the original list if called with an empty iterable', t => { 6 | const list = empty(); 7 | const appended = appendIterable(new Set(), list); 8 | t.is(list._size, 0); 9 | t.is(list, appended); 10 | }); 11 | 12 | test('should append each value iterated over', t => { 13 | var values = new Set(['foo', 'bar', 'baz']); 14 | const list = appendIterable(values, empty()); 15 | t.is(list._size, 3); 16 | const a = arrayFrom(list).sort(); 17 | const b = Array.from(values).sort(); 18 | t.deepEqual(a, b); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/map/src/internals/nodes/IndexedNode/toArrayNode.ts: -------------------------------------------------------------------------------- 1 | import { MutationContext } from '@collectable/core'; 2 | import { ChildNode, ChildrenNodes } from '../types'; 3 | import { ArrayNode } from '../ArrayNode'; 4 | 5 | export function toArrayNode ( 6 | mctx: MutationContext, 7 | fragment: number, 8 | child: ChildNode, 9 | bitmap: number, 10 | children: ChildrenNodes) { 11 | 12 | const array: ChildrenNodes = []; 13 | let bit = bitmap; 14 | let count = 0; 15 | 16 | for(let i = 0; bit; ++i) { 17 | if(bit & 1) { 18 | array[i] = children[count++]; 19 | } 20 | bit >>>= 1; 21 | } 22 | 23 | array[fragment] = child; 24 | 25 | return new ArrayNode(mctx, count + 1, array); 26 | } 27 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/keyAt.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { keyAt } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[]; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | }); 12 | 13 | test('returns the key at the specified index', t => { 14 | for (let i = 0; i < values.length; i++) { 15 | t.deepEqual(keyAt(i, map), values[i]); 16 | } 17 | }); 18 | 19 | test('returns undefined if the specified index is out of range', t => { 20 | t.is(keyAt(values.length, map), void 0); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/lastValue.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { empty, lastValue } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[], lastIndex; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | lastIndex = values.length - 1; 12 | }); 13 | 14 | test('returns the last value in the sorted index', t => { 15 | t.deepEqual(lastValue(map), `#${values[lastIndex]}`); 16 | }); 17 | 18 | test('returns undefined if the collection is empty', t => { 19 | t.is(lastValue(empty()), void 0); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/map/src/functions/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import { ChangeFlag, commit } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { setKeyValue } from '../internals/primitives'; 4 | import { empty } from './empty'; 5 | 6 | export function fromIterable (iterable: Iterable<[K, V]>): HashMapStructure { 7 | let map = >empty(true); 8 | let current: IteratorResult<[K, V]>; 9 | let it = iterable[Symbol.iterator](); 10 | 11 | while(!(current = it.next()).done) { 12 | var entry = current.value; 13 | const change = ChangeFlag.get(); 14 | setKeyValue(entry[0], entry[1], change, map); 15 | change.release(); 16 | } 17 | 18 | return commit(map); 19 | } 20 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/firstKey.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { RedBlackTreeStructure } from '../internals'; 3 | import { first } from './first'; 4 | 5 | /** 6 | * Retrieves the first key in the tree, or undefined if the tree is empty. 7 | * 8 | * @export 9 | * @template K The type of keys in the tree 10 | * @template V The type of values in the tree 11 | * @param {RedBlackTreeStructure} tree The input tree 12 | * @returns {(K|undefined)} The first key in the tree, or undefined if the tree is empty 13 | */ 14 | export function firstKey (tree: RedBlackTreeStructure): K|undefined { 15 | var node = first(tree); 16 | return isDefined(node) ? node.key : void 0; 17 | } 18 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/lastValue.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { RedBlackTreeStructure } from '../internals'; 3 | import { last } from './last'; 4 | 5 | /** 6 | * Retrieves the value of the last entry in the tree. 7 | * 8 | * @export 9 | * @template K The type of keys in the tree 10 | * @template V The type of values in the tree 11 | * @param {RedBlackTreeStructure} tree The input tree 12 | * @returns {([K, V]|undefined)} The value of the last entry in the tree, or undefined if the tree was empty 13 | */ 14 | export function lastValue (tree: RedBlackTreeStructure): V|undefined { 15 | var node = last(tree); 16 | return isDefined(node) ? node.value : void 0; 17 | } 18 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/lastValue.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, lastValue } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the tree is empty', t => { 14 | t.is(lastValue(emptyTree), void 0); 15 | }); 16 | 17 | test('returns the rightmost value', t => { 18 | const value = lastValue(tree); 19 | t.is(value, `#${sortedValues[sortedValues.length - 1]}`); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/set/tests/functions/remove.notexists.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { HashSetStructure, fromArray, has, remove, size } from '../../src'; 3 | 4 | let set0: HashSetStructure, set1: HashSetStructure; 5 | test.before(() => { 6 | set0 = fromArray(['A', 'B', 'C']); 7 | set1 = remove('D', set0); 8 | }); 9 | 10 | test('when the item does not exist in the set, the set size does not change', t => { 11 | t.is(size(set1), 3); 12 | }); 13 | 14 | test('when the item does not exist in the set, the input set is returned unmodified', t => { 15 | t.is(set0, set1); 16 | }); 17 | 18 | test('when the item does not exist in the set, the item is still unretrievable from the set', t => { 19 | t.false(has('D', set1)); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/at.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { at } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[]; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | }); 12 | 13 | test('returns the entry at the specified index', t => { 14 | for (let i = 0; i < values.length; i++) { 15 | t.deepEqual(at(i, map), [values[i], `#${values[i]}`]); 16 | } 17 | }); 18 | 19 | test('returns undefined if the specified index is out of range', t => { 20 | t.is(at(values.length, map), void 0); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/last.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { empty, last } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[], lastIndex; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | lastIndex = values.length - 1; 12 | }); 13 | 14 | test('returns the last entry in the sorted index', t => { 15 | t.deepEqual(last(map), [values[lastIndex], `#${values[lastIndex]}`]); 16 | }); 17 | 18 | test('returns undefined if the collection is empty', t => { 19 | t.is(last(empty()), void 0); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/set/tests/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromArray, isEmpty, size } from '../../src'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | 7 | test('returns an empty set if the array is empty', t => { 8 | t.true(isEmpty(fromArray([]))); 9 | }); 10 | 11 | test('returns a set containing each unique item in the array', t => { 12 | t.deepEqual(Array.from(fromArray(values)).sort(), values); 13 | }); 14 | 15 | test('the returned set has size equal to the number of unique items in the array', t => { 16 | t.is(size(fromArray(values)), values.length); 17 | }); 18 | 19 | test('the returned set is frozen', t => { 20 | t.true(isImmutable(fromArray(values))); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import { ComparatorFn, KeyedSelectorFn } from '@collectable/core'; 2 | import { Entry, SortedMapEntry, SortedMapStructure, createMap } from '../internals'; 3 | 4 | export function fromArray (pairs: [K, V][], compare?: ComparatorFn>): SortedMapStructure; 5 | export function fromArray (pairs: [K, V][], compare: ComparatorFn>, select: KeyedSelectorFn): SortedMapStructure; 6 | export function fromArray (pairs: [K, V][], compare?: ComparatorFn>, select?: KeyedSelectorFn): SortedMapStructure { 7 | return createMap(pairs, compare, >select, false); 8 | } 9 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/valueAt.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { numericCompare } from '@collectable/core'; 3 | import { valueAt } from '../../src'; 4 | import { SortedMap, fromNumericArray } from '../test-utils'; 5 | 6 | let map: SortedMap, values: number[]; 7 | test.before(() => { 8 | values = [13, 21, 34, 55, 1, 2, 3, 5, 8]; 9 | map = fromNumericArray(values); 10 | values.sort(numericCompare); 11 | }); 12 | 13 | test('returns the value at the specified index', t => { 14 | for (let i = 0; i < values.length; i++) { 15 | t.deepEqual(valueAt(i, map), `#${values[i]}`); 16 | } 17 | }); 18 | 19 | test('returns undefined if the specified index is out of range', t => { 20 | t.is(valueAt(values.length, map), void 0); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/set/tests/functions/add.exists.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { HashSetStructure, add, fromArray, has, size } from '../../src'; 3 | 4 | let set0: HashSetStructure, set1: HashSetStructure; 5 | test.before(() => { 6 | set0 = fromArray(['A', 'B', 'C']); 7 | set1 = add('B', set0); 8 | }); 9 | 10 | test('when the item already exists in the set, the set size does not change', t => { 11 | t.is(size(set0), 3); 12 | t.is(size(set1), 3); 13 | }); 14 | 15 | test('when the item already exists in the set, the input set is returned', t => { 16 | t.is(set0, set1); 17 | }); 18 | 19 | test('when the item already exists in the set, the specified item can still be retrieved from the set', t => { 20 | t.true(has('B', set1)); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import { ComparatorFn, KeyedSelectorFn } from '@collectable/core'; 2 | import { Entry, SortedMapEntry, SortedMapStructure, createMap } from '../internals'; 3 | 4 | export function fromIterable (pairs: Iterable<[K, V]>, compare?: ComparatorFn>): SortedMapStructure; 5 | export function fromIterable (pairs: Iterable<[K, V]>, compare: ComparatorFn>, select: KeyedSelectorFn): SortedMapStructure; 6 | export function fromIterable (pairs: Iterable<[K, V]>, compare?: ComparatorFn>, select?: KeyedSelectorFn): SortedMapStructure { 7 | return createMap(pairs, compare, select, false); 8 | } 9 | -------------------------------------------------------------------------------- /packages/map/tests/commit.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { commit, modify, unwrap } from '@collectable/core'; 3 | import { empty, set } from '../src'; 4 | 5 | test('returns the same map if already mutable', t => { 6 | var map = modify(set('x', 3, empty())); 7 | commit(map); 8 | var map1 = commit(map); 9 | 10 | t.is(map, map1); 11 | t.deepEqual(unwrap(map), { x: 3 }); 12 | }); 13 | 14 | test('operations performed on an immutable map return a new map', t => { 15 | var map = set('x', 3, empty(true)); 16 | set('y', 1, map); 17 | set('z', 2, map); 18 | commit(map); 19 | var map1 = set('z', 3, map); 20 | 21 | t.not(map, map1); 22 | t.deepEqual(unwrap(map), { x: 3, y: 1, z: 2 }); 23 | t.deepEqual(unwrap(map1), { x: 3, y: 1, z: 3 }); 24 | }); -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/indexOf.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeStructure, findIndex } from '../internals'; 2 | 3 | /** 4 | * Determines the index (ordinal) of the tree entry that has the specified key. If the key does not exist in the tree, -1 is returned. 5 | * 6 | * @export 7 | * @template K The type of keys in the tree 8 | * @template V The type of values in the tree 9 | * @param {K} key The key of the tree entry to find the index for 10 | * @param {RedBlackTreeStructure} tree The input tree 11 | * @returns {number} The index of the key in the tree, or -1 if the key was not found 12 | */ 13 | export function indexOf (key: K, tree: RedBlackTreeStructure): number { 14 | return findIndex(key, tree._root, tree._compare); 15 | } 16 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/last.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeEntry, RedBlackTreeStructure, isNone } from '../internals'; 2 | 3 | /** 4 | * Retrieves the last entry in the tree. 5 | * 6 | * @export 7 | * @template K The type of keys in the tree 8 | * @template V The type of values in the tree 9 | * @param {RedBlackTreeStructure} tree The input tree 10 | * @returns {([K, V]|undefined)} A key/value tuple for the last entry in the tree, or undefined if the tree was empty 11 | */ 12 | export function last (tree: RedBlackTreeStructure): RedBlackTreeEntry|undefined { 13 | if(tree._size === 0) return void 0; 14 | var node = tree._root; 15 | while(!isNone(node._right)) { 16 | node = node._right; 17 | } 18 | return node; 19 | } 20 | -------------------------------------------------------------------------------- /packages/map/tests/getSize.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, remove, set, size } from '../src'; 3 | 4 | test('returns 0 when the map empty', t => { 5 | t.is(size(empty()), 0); 6 | }); 7 | 8 | test('returns the correct size after adding entries', t => { 9 | var map1 = set('x', 1, empty()); 10 | var map2 = set('x', 2, map1); 11 | var map3 = set('y', 1, map1); 12 | t.is(size(map1), 1); 13 | t.is(size(map2), 1); 14 | t.is(size(map3), 2); 15 | }); 16 | 17 | test('returns the correct size after removing entries', t => { 18 | var map = set('x', 1, empty()); 19 | map = set('y', 3, map); 20 | map = set('z', 5, map); 21 | t.is(size(map = remove('x', map)), 2); 22 | t.is(size(map = remove('y', map)), 1); 23 | t.is(size(remove('z', map)), 0); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/firstValue.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from '@collectable/core'; 2 | import { RedBlackTreeStructure } from '../internals'; 3 | import { first } from './first'; 4 | 5 | /** 6 | * Retrieves the value of the first entry in the tree, or undefined if the tree is empty. 7 | * 8 | * @export 9 | * @template K The type of keys in the tree 10 | * @template V The type of values in the tree 11 | * @param {RedBlackTreeStructure} tree The input tree 12 | * @returns {(K|undefined)} The value of the first entry in the tree, or undefined if the tree is empty 13 | */ 14 | export function firstValue (tree: RedBlackTreeStructure): V|undefined { 15 | var node = first(tree); 16 | return isDefined(node) ? node.value : void 0; 17 | } 18 | -------------------------------------------------------------------------------- /packages/list/src/functions/appendArray.ts: -------------------------------------------------------------------------------- 1 | import { commit, modify } from '@collectable/core'; 2 | import { ListStructure, appendValues } from '../internals'; 3 | 4 | /** 5 | * Appends an array of values to the end of a list, growing the size of the list by the number of 6 | * elements in the array. 7 | * 8 | * @template T - The type of value contained by the list 9 | * @param value - The values to append to the list 10 | * @param list - The list to which the values should be appended 11 | * @returns A list containing the appended values 12 | */ 13 | export function appendArray (values: T[], list: ListStructure): ListStructure { 14 | if(values.length === 0) return list; 15 | list = modify(list); 16 | appendValues(list, values); 17 | return commit(list); 18 | } 19 | -------------------------------------------------------------------------------- /packages/map/src/internals/nodes/ArrayNode/toIndexNode.ts: -------------------------------------------------------------------------------- 1 | import { MutationContext } from '@collectable/core'; 2 | import { AnyNode, NodeType } from '../types'; 3 | import { IndexedNode } from '../IndexedNode'; 4 | 5 | export function toIndexNode (mctx: MutationContext, count: number, index: number, children: Array>): IndexedNode { 6 | const newChildren = new Array(count - 1); 7 | let g = 0; 8 | let bitmap = 0; 9 | for(let i = 0; i < children.length; ++i) { 10 | if(i !== index) { 11 | const child = children[i]; 12 | if(child && child.type > NodeType.EMPTY) { 13 | newChildren[g++] = child; 14 | bitmap |= 1 << i; 15 | } 16 | } 17 | } 18 | 19 | return new IndexedNode(mctx, bitmap, newChildren); 20 | } 21 | -------------------------------------------------------------------------------- /packages/list/tests/functions/appendArrayMapped.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { appendArrayMapped, empty } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | 5 | const fn = (s: string, i: number) => `[${s}, ${i}]`; 6 | 7 | test('should return the original list if called with an empty list', t => { 8 | const list = empty(); 9 | const appended = appendArrayMapped(fn, [], list); 10 | t.is(list._size, 0); 11 | t.is(list, appended); 12 | }); 13 | 14 | test('should append each element in the array', t => { 15 | const values = ['foo', 'bar', 'baz']; 16 | const mappedValues = values.map(fn); 17 | const list = appendArrayMapped(fn, values, empty()); 18 | t.is(list._size, 3); 19 | t.deepEqual(arrayFrom(list), mappedValues); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/map/tests/fromArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromArray, isEmpty, size } from '../src'; 4 | 5 | const pairs: [string, string][] = [['A', 'a'], ['B', 'b'], ['C', 'c'], ['D', 'd'], ['E', 'e']]; 6 | 7 | test('returns an empty set if the array is empty', t => { 8 | t.true(isEmpty(fromArray([]))); 9 | }); 10 | 11 | test('returns a set containing each unique item in the array', t => { 12 | t.deepEqual(Array.from(fromArray(pairs)).sort(), pairs); 13 | }); 14 | 15 | test('the returned set has size equal to the number of unique items in the array', t => { 16 | t.is(size(fromArray(pairs)), pairs.length); 17 | }); 18 | 19 | test('the returned set is frozen', t => { 20 | t.true(isImmutable(fromArray(pairs))); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/first.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { RedBlackTreeEntry, emptyWithNumericKeys, first } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the tree is empty', t => { 14 | t.is(first(emptyTree), void 0); 15 | }); 16 | 17 | test('returns a pointer to the first node', t => { 18 | const node = >first(tree); 19 | t.not(node, void 0); 20 | t.is(node.key, sortedValues[0]); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add'; 2 | export * from './clone'; 3 | export * from './empty'; 4 | export * from './filter'; 5 | export * from './first'; 6 | export * from './forEach'; 7 | export * from './fromArray'; 8 | export * from './fromIterable'; 9 | export * from './get'; 10 | export * from './has'; 11 | export * from './intersect'; 12 | export * from './isEmpty'; 13 | export * from './isEqual'; 14 | export * from './isSortedSet'; 15 | export * from './last'; 16 | export * from './map'; 17 | export * from './reduce'; 18 | export * from './remove'; 19 | export * from './size'; 20 | export * from './subtract'; 21 | export * from './toArray'; 22 | export * from './toNativeSet'; 23 | export * from './union'; 24 | export * from './update'; 25 | export * from './values'; -------------------------------------------------------------------------------- /packages/list/tests/functions/updateList.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { appendArray, empty, set, updateList } from '../../src'; 4 | import { arrayFrom } from '../../src/internals'; 5 | 6 | // test('returns the same list if no changes are made', t => { 7 | // const list = empty(); 8 | // const list1 = updateList(list => {}, list); 9 | // t.is(list1, list); 10 | // }); 11 | 12 | test('treats the inner list as mutable', t => { 13 | const list = empty(); 14 | const list1 = updateList(list => { 15 | t.false(isImmutable(list)); 16 | appendArray(['X', 'Y', 'Z'], list); 17 | set(1, 'K', list); 18 | }, list); 19 | t.true(isImmutable(list1)); 20 | t.deepEqual(arrayFrom(list1), ['X', 'K', 'Z']); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/get.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, get } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the key does not exist in the list', t => { 14 | t.is(get(1, emptyTree), void 0); 15 | }); 16 | 17 | test('returns the value associated with the specified key', t => { 18 | for(var i = 0; i < sortedValues.length; i++) { 19 | t.is(get(sortedValues[i], tree), `#${sortedValues[i]}`); 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/first.ts: -------------------------------------------------------------------------------- 1 | import { RedBlackTreeEntry, RedBlackTreeStructure, isNone } from '../internals'; 2 | 3 | /** 4 | * Retrieves the first entry in the tree, or undefined if the tree is empty. 5 | * 6 | * @export 7 | * @template K The type of keys in the tree 8 | * @template V The type of values in the tree 9 | * @param {RedBlackTreeStructure} tree The input tree 10 | * @returns {(RedBlackTreeEntry|undefined)} The first entry in the tree, or undefined if the tree is empty 11 | */ 12 | export function first (tree: RedBlackTreeStructure): RedBlackTreeEntry|undefined { 13 | if(tree._size === 0) return void 0; 14 | var node = tree._root; 15 | while(!isNone(node._left)) { 16 | node = node._left; 17 | } 18 | return node; 19 | } 20 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/last.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { RedBlackTreeEntry, emptyWithNumericKeys, last } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the tree is empty', t => { 14 | t.is(last(emptyTree), void 0); 15 | }); 16 | 17 | test('returns a pointer to the last node', t => { 18 | const node = >last(tree); 19 | t.not(node, void 0); 20 | t.is(node.key, sortedValues[sortedValues.length - 1]); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/collectable/src/internals/common.ts: -------------------------------------------------------------------------------- 1 | import { fromArray, fromIterable, fromMap, fromObject, fromSet } from '../functions'; 2 | 3 | export function convertValue (value: any): any { 4 | if(value && typeof value === 'object') { 5 | if(Array.isArray(value)) { 6 | return fromArray(value); 7 | } 8 | if(value.constructor === Object) { 9 | return fromObject(value); 10 | } 11 | if(value instanceof Map) { 12 | return fromMap(value); 13 | } 14 | if(value instanceof Set) { 15 | return fromSet(value); 16 | } 17 | if(Symbol.iterator in value) { 18 | return fromIterable(value); 19 | } 20 | } 21 | return value; 22 | } 23 | 24 | export function convertPair (entry: [K, V]): [K, any] { 25 | return [entry[0], convertValue(entry[1])]; 26 | } 27 | -------------------------------------------------------------------------------- /packages/sorted-set/src/internals/iterate.ts: -------------------------------------------------------------------------------- 1 | import { MappableIterator } from '@collectable/core'; 2 | import { keys } from '@collectable/red-black-tree'; 3 | import { SortedSetStructure } from './SortedSet'; 4 | import { SortedSetItem } from './types'; 5 | 6 | export function iterate (set: SortedSetStructure): IterableIterator> { 7 | return keys(set._tree); 8 | } 9 | 10 | function valueOf (item: SortedSetItem): T { 11 | return item.value; 12 | } 13 | 14 | export function iterateValues (set: SortedSetStructure): IterableIterator { 15 | return new MappableIterator, T>(keys(set._tree), valueOf); 16 | } 17 | 18 | export function isIterable (arg: any): arg is Iterable> { 19 | return !!arg && Symbol.iterator in arg; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "collectable-monorepo", 3 | "version": "0.0.0", 4 | "description": "An all-you-can-eat buffet of high-performance immutable/persistent data structures", 5 | "private": true, 6 | "scripts": { 7 | "ci-build": "mv lerna.default.json lerna.json && lerna bootstrap --hoist && lerna run lint && lerna run build && lerna run test" 8 | }, 9 | "contributors": [ 10 | "Nathan Ridley (https://github.com/axefrog)", 11 | "Tylor Steinberger (https://github.com/TylorS)" 12 | ], 13 | "license": "MIT", 14 | "bugs": "https://github.com/frptools/collectable/issues", 15 | "repository": "git@github.com:frptools/collectable.git", 16 | "devDependencies": { 17 | "@frptools/config": "^1.0.0", 18 | "lerna": "^2.7.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/set/tests/functions/fromNativeSet.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromNativeSet, isEmpty, size } from '../../src'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | 7 | const nativeSet = new Set(values); 8 | 9 | test('returns an empty set if the input set is empty', t => { 10 | t.true(isEmpty(fromNativeSet(new Set()))); 11 | }); 12 | 13 | test('returns a set containing the same items from the input set', t => { 14 | t.deepEqual(Array.from(fromNativeSet(nativeSet)).sort(), values); 15 | }); 16 | 17 | test('the returned set has the same size as the input set', t => { 18 | t.is(size(fromNativeSet(nativeSet)), values.length); 19 | }); 20 | 21 | test('the returned set is frozen', t => { 22 | t.true(isImmutable(fromNativeSet(nativeSet))); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/add.exists.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { SortedSetStructure, add, has, size } from '../../src'; 3 | import { fromStringArray } from '../test-utils'; 4 | 5 | let set0: SortedSetStructure, set1: SortedSetStructure; 6 | test.beforeEach(() => { 7 | set0 = fromStringArray(['D', 'A', 'B']); 8 | set1 = add('B', set0); 9 | }); 10 | 11 | test('when the item already exists in the set, the set size does not change', t => { 12 | t.is(size(set0), 3); 13 | t.is(size(set1), 3); 14 | }); 15 | 16 | test('when the item already exists in the set, the input set is returned', t => { 17 | t.is(set0, set1); 18 | }); 19 | 20 | test('when the item already exists in the set, the specified item can still be retrieved from the set', t => { 21 | t.true(has('B', set1)); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { isEmpty, size } from '../../src'; 4 | import { fromStringArray } from '../test-utils'; 5 | 6 | const values = ['A', 'B', 'C', 'D', 'E']; 7 | 8 | test('returns an empty set if the array is empty', t => { 9 | t.true(isEmpty(fromStringArray([]))); 10 | }); 11 | 12 | test('returns a set containing each unique item in the array', t => { 13 | t.deepEqual(Array.from(fromStringArray(values)), values); 14 | }); 15 | 16 | test('the returned set has size equal to the number of unique items in the array', t => { 17 | t.is(size(fromStringArray(values)), values.length); 18 | }); 19 | 20 | test('the returned set is frozen', t => { 21 | t.true(isImmutable(fromStringArray(values))); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/list/tests/functions/prependArrayMapped.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, prependArrayMapped } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | 5 | const fn = (s: string, i: number) => `[${s}, ${i}]`; 6 | 7 | test('should return the original list if called with an empty list', t => { 8 | const list = empty(); 9 | const prepended = prependArrayMapped(fn, [], list); 10 | t.is(list._size, 0); 11 | t.is(list, prepended); 12 | }); 13 | 14 | test('should append elements so that their order in the list matches the source array', t => { 15 | const values = ['foo', 'bar', 'baz']; 16 | const mappedValues = values.map(fn); 17 | const list = prependArrayMapped(fn, values, empty()); 18 | t.is(list._size, 3); 19 | t.deepEqual(arrayFrom(list), mappedValues); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/map/tests/fromNativeMap.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromNativeMap, isEmpty, size } from '../src'; 4 | 5 | const pairs: [string, string][] = [['A', 'a'], ['B', 'b'], ['C', 'c'], ['D', 'd'], ['E', 'e']]; 6 | 7 | test('returns an empty set if the input set is empty', t => { 8 | t.true(isEmpty(fromNativeMap(new Map()))); 9 | }); 10 | 11 | test('returns a set containing the same items from the input set', t => { 12 | t.deepEqual(Array.from(fromNativeMap(new Map(pairs))).sort(), pairs); 13 | }); 14 | 15 | test('the returned set has the same size as the input set', t => { 16 | t.is(size(fromNativeMap(new Map(pairs))), pairs.length); 17 | }); 18 | 19 | test('the returned set is frozen', t => { 20 | t.true(isImmutable(fromNativeMap(new Map(pairs)))); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/isEqual.ts: -------------------------------------------------------------------------------- 1 | import { isEqual as equals } from '@collectable/core'; 2 | import { iterateFromFirst } from '@collectable/red-black-tree'; 3 | import { SortedSetStructure } from '../internals'; 4 | import { size } from './size'; 5 | 6 | export function isEqual (set: SortedSetStructure, other: SortedSetStructure): boolean { 7 | if(set === other) return true; 8 | if(size(set) !== size(other) || 9 | set._select !== other._select || 10 | set._compare !== other._compare) return false; 11 | 12 | var a = set._tree, b = other._tree; 13 | var ita = iterateFromFirst(a), itb = iterateFromFirst(b); 14 | do { 15 | var ca = ita.next(); 16 | var cb = itb.next(); 17 | if(!equals(ca.value.value, cb.value.value)) return false; 18 | } while(!ca.done); 19 | 20 | return true; 21 | } 22 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/keyAt.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { keyAt } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, empty, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = empty(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the tree is empty', t => { 14 | t.is(keyAt(0, emptyTree), void 0); 15 | }); 16 | 17 | test('returns undefined if the index is out of range', t => { 18 | t.is(keyAt(sortedValues.length, tree), void 0); 19 | }); 20 | 21 | test('returns the key at the specified index (negative index offset from the right)', t => { 22 | t.is(keyAt(25, tree), sortedValues[25]); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { isEmpty, size } from '../../src'; 4 | import { fromStringArray, pairsFrom } from '../test-utils'; 5 | 6 | const values = ['A', 'B', 'C', 'D', 'E']; 7 | 8 | test('returns an empty map if the array is empty', t => { 9 | t.true(isEmpty(fromStringArray([]))); 10 | }); 11 | 12 | test('returns a map containing each unique item in the array', t => { 13 | t.deepEqual(Array.from(fromStringArray(values)), pairsFrom(values)); 14 | }); 15 | 16 | test('the returned set has size equal to the number of unique items in the array', t => { 17 | t.is(size(fromStringArray(values)), values.length); 18 | }); 19 | 20 | test('the returned set is frozen', t => { 21 | t.true(isImmutable(fromStringArray(values))); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/map/tests/fromObject.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromObject, isEmpty, size } from '../src'; 4 | 5 | const pairs: [string, string][] = [['A', 'a'], ['B', 'b'], ['C', 'c'], ['D', 'd'], ['E', 'e']]; 6 | const obj = pairs.reduce((o, [k, v]) => (o[k] = v, o), {}); 7 | 8 | test('returns an empty set if the input set is empty', t => { 9 | t.true(isEmpty(fromObject({}))); 10 | }); 11 | 12 | test('returns a set containing the same items from the input set', t => { 13 | t.deepEqual(Array.from(fromObject(obj)).sort(), pairs); 14 | }); 15 | 16 | test('the returned set has the same size as the input set', t => { 17 | t.is(size(fromObject(obj)), pairs.length); 18 | }); 19 | 20 | test('the returned set is frozen', t => { 21 | t.true(isImmutable(fromObject(obj))); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/iterateFromFirst.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, iterateFromFirst } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns a reverse iterator starting from the leftmost node', t => { 14 | const it = iterateFromFirst(tree); 15 | t.deepEqual(Array.from(it).map(n => n.key), sortedValues); 16 | }); 17 | 18 | test('the iterator should be in a completed state if the tree is empty', t => { 19 | const it = iterateFromFirst(emptyTree); 20 | t.true(it.next().done); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/isEqual.ts: -------------------------------------------------------------------------------- 1 | import { isEqual as equals } from '@collectable/core'; 2 | import { iterateFromFirst } from '@collectable/red-black-tree'; 3 | import { SortedMapStructure } from '../internals'; 4 | import { size } from './size'; 5 | 6 | export function isEqual (set: SortedMapStructure, other: SortedMapStructure): boolean { 7 | if(set === other) return true; 8 | if(size(set) !== size(other) || 9 | set._select !== other._select || 10 | set._compare !== other._compare) return false; 11 | 12 | var a = set._sorted, b = other._sorted; 13 | var ita = iterateFromFirst(a), itb = iterateFromFirst(b); 14 | do { 15 | var ca = ita.next(); 16 | var cb = itb.next(); 17 | if(!equals(ca.value.value, cb.value.value)) return false; 18 | } while(!ca.done); 19 | 20 | return true; 21 | } 22 | -------------------------------------------------------------------------------- /packages/list/tests/functions/append.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { append, empty } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | 5 | test('should not mutate the original List', t => { 6 | const list = empty(); 7 | const appended = append('foo', list); 8 | t.is(list._size, 0); 9 | t.is(list._left.slot.slots.length, 0); 10 | t.not(list, appended); 11 | t.notDeepEqual(list, appended); 12 | }); 13 | 14 | test('should have size:1 after adding the first element', t => { 15 | const list = append('foo', empty()); 16 | t.is(list._size, 1); 17 | t.deepEqual(arrayFrom(list), ['foo']); 18 | }); 19 | 20 | test('should have size:2 after adding the second element', t => { 21 | const list = append('bar', append('foo', empty())); 22 | t.is(list._size, 2); 23 | t.deepEqual(arrayFrom(list), ['foo', 'bar']); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/map/tests/has.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, has, remove, set } from '../src'; 3 | 4 | test('returns true if the specified property exists', t => { 5 | var map = set('x', 3, empty()); 6 | t.true(has('x', map)); 7 | }); 8 | 9 | test('returns false if the specified property is missing', t => { 10 | var map = set('x', 3, empty()); 11 | t.false(has('y', map)); 12 | }); 13 | 14 | test('returns true after assigning a property to a mutable map', t => { 15 | var map = empty(true); 16 | t.false(has('x', map)); 17 | set('x', 3, map); 18 | t.true(has('x', map)); 19 | }); 20 | 21 | test('return false after removing a property from a mutable map', t => { 22 | var map = set('x', 3, empty(true)); 23 | t.true(has('x', map)); 24 | remove('x', map); 25 | t.false(has('x', map)); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/list/tests/functions/prepend.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, prepend } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | 5 | test('should not mutate the original List', t => { 6 | const list = empty(); 7 | const prepended = prepend('foo', list); 8 | t.is(list._size, 0); 9 | t.is(list._left.slot.slots.length, 0); 10 | t.not(list, prepended); 11 | t.notDeepEqual(list, prepended); 12 | }); 13 | 14 | test('should have size:1 after adding the first element', t => { 15 | const list = prepend('foo', empty()); 16 | t.is(list._size, 1); 17 | t.deepEqual(arrayFrom(list), ['foo']); 18 | }); 19 | 20 | test('should have size:2 after adding the second element', t => { 21 | const list = prepend('bar', prepend('foo', empty())); 22 | t.is(list._size, 2); 23 | t.deepEqual(arrayFrom(list), ['bar', 'foo']); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/entries.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { empty, entries, set as setEntry } from '../../src'; 3 | import { fromStringArray, pairsFrom } from '../test-utils'; 4 | 5 | test('returns an empty iterable if the input list is empty', t => { 6 | const map = empty(); 7 | t.true(entries(map).next().done); 8 | }); 9 | 10 | test('returns an iterable that emits each member of the input map and then completes', t => { 11 | const map = fromStringArray(['A', 'B', 'C']); 12 | t.deepEqual(Array.from(entries(map)), pairsFrom(['A', 'B', 'C'])); 13 | }); 14 | 15 | test('items updated by key have up-to-date values when iterating', t => { 16 | let map = fromStringArray(['A', 'B', 'C']); 17 | map = setEntry('B', Math.PI, map); 18 | const pairs = pairsFrom(['A', 'B', 'C']); 19 | pairs[1][1] = Math.PI; 20 | t.deepEqual(Array.from(entries(map)), pairs); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/iterateFromLast.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { emptyWithNumericKeys, iterateFromLast } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = emptyWithNumericKeys(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns a reverse iterator starting from the rightmost node', t => { 14 | const it = iterateFromLast(tree); 15 | const expected = sortedValues.slice().reverse(); 16 | t.deepEqual(Array.from(it).map(n => n.key), expected); 17 | }); 18 | 19 | test('the iterator should be in a completed state if the tree is empty', t => { 20 | const it = iterateFromLast(emptyTree); 21 | t.true(it.next().done); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/set/tests/functions/forEach.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { HashSetStructure, forEach, fromArray } from '../../src'; 3 | 4 | let set: HashSetStructure, values: number[]; 5 | test.before(() => { 6 | values = [1, 2, 3, 5, 8, 13, 21, 34, 55]; 7 | set = fromArray(values); 8 | }); 9 | 10 | test('the predicate is called for each item in the set', t => { 11 | const array: number[] = []; 12 | forEach(n => array.push(n), set); 13 | t.deepEqual(array.sort((a, b) => a - b), values); 14 | }); 15 | 16 | test('iteration is terminated if `false` is explicitly returned from the predicate', t => { 17 | let count = 0; 18 | forEach((n, i) => { 19 | count++; 20 | if(i === 3) return false; 21 | }, set); 22 | t.is(count, 4); 23 | }); 24 | 25 | test('the input set is returned after iteration is complete', t => { 26 | const set1 = forEach(n => {}, set); 27 | t.is(set, set1); 28 | }); 29 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromIterable, isEmpty, size } from '../../src'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | let it: IterableIterator; 7 | test.beforeEach(() => { 8 | it = new Set(values).values(); 9 | }); 10 | 11 | test('returns an empty set if the iterable is empty', t => { 12 | t.true(isEmpty(fromIterable(new Set().values()))); 13 | }); 14 | 15 | test('returns a set containing each unique item emitted by the iterable', t => { 16 | t.deepEqual(Array.from(fromIterable(it)), values); 17 | }); 18 | 19 | test('the returned set has size equal to the number of unique items emitted by the iterable', t => { 20 | t.is(size(fromIterable(it)), values.length); 21 | }); 22 | 23 | test('the returned set is frozen', t => { 24 | t.true(isImmutable(fromIterable(it))); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/map/src/functions/fromObject.ts: -------------------------------------------------------------------------------- 1 | import { ChangeFlag, commit } from '@collectable/core'; 2 | import { HashMapStructure } from '../internals/HashMap'; 3 | import { setKeyValue } from '../internals/primitives'; 4 | import { empty } from './empty'; 5 | 6 | export function fromObject (object: { [key: number ]: V }): HashMapStructure; 7 | export function fromObject (object: { [key: string ]: V }): HashMapStructure; 8 | export function fromObject (object: any): HashMapStructure { 9 | const keys = Object.keys(object); 10 | 11 | let map = >empty(true); 12 | 13 | for(let i = 0; i < keys.length; ++i) { 14 | const key = keys[i]; 15 | const value = object[key]; 16 | 17 | const change = ChangeFlag.get(); 18 | setKeyValue(keys[i], value, change, map); 19 | change.release(); 20 | } 21 | 22 | return commit(map); 23 | } 24 | -------------------------------------------------------------------------------- /packages/set/tests/functions/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromIterable, isEmpty, size } from '../../src'; 4 | 5 | const values = ['A', 'B', 'C', 'D', 'E']; 6 | 7 | let it: IterableIterator; 8 | test.beforeEach(() => { 9 | it = new Set(values).values(); 10 | }); 11 | 12 | test('returns an empty set if the iterable is empty', t => { 13 | t.true(isEmpty(fromIterable(new Set().values()))); 14 | }); 15 | 16 | test('returns a set containing each unique item emitted by the iterable', t => { 17 | t.deepEqual(Array.from(fromIterable(it)).sort(), values); 18 | }); 19 | 20 | test('the returned set has size equal to the number of unique items emitted by the iterable', t => { 21 | t.is(size(fromIterable(it)), values.length); 22 | }); 23 | 24 | test('the returned set is frozen', t => { 25 | t.true(isImmutable(fromIterable(it))); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/red-black-tree/tests/functions/valueAt.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { valueAt } from '../../src'; 3 | import { RedBlackTreeStructure } from '../../src/internals'; 4 | import { createTree, empty, sortedValues } from '../test-utils'; 5 | 6 | var tree: RedBlackTreeStructure, emptyTree: RedBlackTreeStructure; 7 | 8 | test.beforeEach(() => { 9 | emptyTree = empty(); 10 | tree = createTree(); 11 | }); 12 | 13 | test('returns undefined if the tree is empty', t => { 14 | t.is(valueAt(0, emptyTree), void 0); 15 | }); 16 | 17 | test('returns undefined if the index is out of range', t => { 18 | t.is(valueAt(sortedValues.length, tree), void 0); 19 | }); 20 | 21 | test('returns the value at the specified index (negative index offset from the right)', t => { 22 | t.is(valueAt(25, tree), `#${sortedValues[25]}`); 23 | t.is(valueAt(-25, tree), `#${sortedValues[sortedValues.length - 25]}`); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/forEach.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { SortedSetStructure, forEach } from '../../src'; 3 | import { fromNumericArray } from '../test-utils'; 4 | 5 | let set: SortedSetStructure, values: number[]; 6 | test.before(() => { 7 | values = [1, 2, 3, 5, 8, 13, 21, 34, 55]; 8 | set = fromNumericArray(values); 9 | }); 10 | 11 | test('the predicate is called for each item in the set', t => { 12 | const array: number[] = []; 13 | forEach(n => array.push(n), set); 14 | t.deepEqual(array, values); 15 | }); 16 | 17 | test('iteration is terminated if `false` is explicitly returned from the predicate', t => { 18 | let count = 0; 19 | forEach((n, i) => { 20 | count++; 21 | if(i === 3) return false; 22 | }, set); 23 | t.is(count, 4); 24 | }); 25 | 26 | test('the input set is returned after iteration is complete', t => { 27 | const set1 = forEach(n => {}, set); 28 | t.is(set, set1); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/set/tests/internals/HashSet.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { HashSetStructure, fromArray, values } from '../../src'; 3 | 4 | let set: HashSetStructure; 5 | let set2: HashSetStructure; 6 | let set3: HashSetStructure; 7 | 8 | test.beforeEach(() => { 9 | set = fromArray(['A', 'B', 'C', 'D', 'E']); 10 | set3 = fromArray(['A', 'C', 'D', 'E', 'F']); 11 | set2 = fromArray(['B', 'E', 'C', 'A', 'D']); 12 | }); 13 | 14 | test('Symbol.iterator() emits the same values as the values() function', t => { 15 | t.deepEqual(Array.from(set[Symbol.iterator]()).sort(), Array.from(values(set)).sort()); 16 | }); 17 | 18 | test('@@equals() returns true if both sets have an equivalent set of members', t => { 19 | t.true(set['@@equals'](set2)); 20 | }); 21 | 22 | test('@@equals() returns false if the sets have differing members from each other', t => { 23 | t.false(set['@@equals'](set3)); 24 | t.false(set2['@@equals'](set3)); 25 | }); -------------------------------------------------------------------------------- /packages/map/tests/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromIterable, isEmpty, size } from '../src'; 4 | 5 | const pairs: [string, string][] = [['A', 'a'], ['B', 'b'], ['C', 'c'], ['D', 'd'], ['E', 'e']]; 6 | 7 | let it: IterableIterator<[string, string]>; 8 | test.beforeEach(() => { 9 | it = new Map(pairs).entries(); 10 | }); 11 | 12 | test('returns an empty set if the iterable is empty', t => { 13 | t.true(isEmpty(fromIterable(new Map().values()))); 14 | }); 15 | 16 | test('returns a set containing each unique item emitted by the iterable', t => { 17 | t.deepEqual(Array.from(fromIterable(it)).sort(), pairs); 18 | }); 19 | 20 | test('the returned set has size equal to the number of unique items emitted by the iterable', t => { 21 | t.is(size(fromIterable(it)), pairs.length); 22 | }); 23 | 24 | test('the returned set is frozen', t => { 25 | t.true(isImmutable(fromIterable(it))); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/forEach.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forEach } from '../../src'; 3 | import { SortedMap, fromNumericArray, pairsFrom } from '../test-utils'; 4 | 5 | let map: SortedMap, values: number[]; 6 | test.before(() => { 7 | values = [1, 2, 3, 5, 8, 13, 21, 34, 55]; 8 | map = fromNumericArray(values); 9 | }); 10 | 11 | test('the predicate is called for each item in the map', t => { 12 | const array: [number, string][] = []; 13 | forEach((v, k) => array.push([k, v]), map); 14 | t.deepEqual(array, pairsFrom(values)); 15 | }); 16 | 17 | test('iteration is terminated if `false` is explicitly returned from the predicate', t => { 18 | let count = 0; 19 | forEach((v, k, i) => { 20 | count++; 21 | if(i === 3) return false; 22 | }, map); 23 | t.is(count, 4); 24 | }); 25 | 26 | test('the input map is returned after iteration is complete', t => { 27 | const map1 = forEach(n => {}, map); 28 | t.is(map, map1); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/map.ts: -------------------------------------------------------------------------------- 1 | import { MapFn, commit, isImmutable } from '@collectable/core'; 2 | import { SortedSetStructure, cloneSortedSet } from '../internals'; 3 | import { iterateValues, setItem } from '../internals'; 4 | 5 | export function map (fn: MapFn, set: SortedSetStructure): SortedSetStructure; 6 | export function map (fn: MapFn, set: SortedSetStructure): SortedSetStructure { 7 | var immutable = isImmutable(set); 8 | var nextSet = cloneSortedSet(true, set, true); 9 | var map = nextSet._map; 10 | var tree = nextSet._tree; 11 | var select = nextSet._select; 12 | 13 | var it = iterateValues(set); 14 | var current: IteratorResult; 15 | var index = 0; 16 | while(!(current = it.next()).done) { 17 | setItem(fn(current.value, index++), map, tree, select); 18 | } 19 | 20 | if(immutable) { 21 | return commit(nextSet); 22 | } 23 | 24 | set._map = map; 25 | set._tree = tree; 26 | return set; 27 | } -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/add.notexists.mutable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isMutable, modify } from '@collectable/core'; 3 | import { SortedSetStructure, add, has, size } from '../../src'; 4 | import { fromStringArray } from '../test-utils'; 5 | 6 | let set0: SortedSetStructure, set1: SortedSetStructure; 7 | test.before(() => { 8 | set0 = modify(fromStringArray(['A', 'B', 'D'])); 9 | set1 = add('C', set0); 10 | }); 11 | 12 | test('the input set is returned', t => { 13 | t.is(set0, set1); 14 | }); 15 | 16 | test('the input set is still mutable', t => { 17 | t.true(isMutable(set1)); 18 | }); 19 | 20 | test('the set size is incremented', t => { 21 | t.is(size(set1), 4); 22 | }); 23 | 24 | test('the added item can be retrieved from the set', t => { 25 | t.true(has('C', set1)); 26 | }); 27 | 28 | test('all expected members exist in the set in the correct order', t => { 29 | t.deepEqual(Array.from(set1), ['A', 'B', 'C', 'D']); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/set.notexists.mutable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isMutable, modify } from '@collectable/core'; 3 | import { has, set, size } from '../../src'; 4 | import { SortedMap, fromStringArray, pairsFrom } from '../test-utils'; 5 | 6 | let map0: SortedMap, map1: SortedMap; 7 | 8 | test.before(() => { 9 | map0 = modify(fromStringArray(['A', 'B', 'D'])); 10 | map1 = set('C', 'C'.charCodeAt(0), map0); 11 | }); 12 | 13 | test('the input map is returned', t => { 14 | t.is(map0, map1); 15 | }); 16 | 17 | test('the input map is still mutable', t => { 18 | t.true(isMutable(map1)); 19 | }); 20 | 21 | test('the map size is incremented', t => { 22 | t.is(size(map1), 4); 23 | }); 24 | 25 | test('the seted item can be retrieved from the map', t => { 26 | t.true(has('C', map1)); 27 | }); 28 | 29 | test('all expected members exist in the map in the correct order', t => { 30 | t.deepEqual(Array.from(map1), pairsFrom(['A', 'B', 'C', 'D'])); 31 | }); 32 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/fromIterable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isImmutable } from '@collectable/core'; 3 | import { fromIterable, isEmpty, size } from '../../src'; 4 | import { pairsFrom } from '../test-utils'; 5 | 6 | const values = ['A', 'B', 'C', 'D', 'E']; 7 | let it: IterableIterator<[string, number]>; 8 | test.beforeEach(() => { 9 | it = new Map(pairsFrom(values)).entries(); 10 | }); 11 | 12 | test('returns an empty map if the iterable is empty', t => { 13 | t.true(isEmpty(fromIterable(new Set().values()))); 14 | }); 15 | 16 | test('returns a map containing each unique item emitted by the iterable', t => { 17 | t.deepEqual(Array.from(fromIterable(it)), pairsFrom(values)); 18 | }); 19 | 20 | test('the returned set has size equal to the number of unique items emitted by the iterable', t => { 21 | t.is(size(fromIterable(it)), values.length); 22 | }); 23 | 24 | test('the returned set is frozen', t => { 25 | t.true(isImmutable(fromIterable(it))); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/red-black-tree/src/functions/fromKeys.ts: -------------------------------------------------------------------------------- 1 | import * as C from '@collectable/core'; 2 | import { ComparatorFn } from '@collectable/core'; 3 | import { RedBlackTreeStructure, createTree, isRedBlackTree } from '../internals'; 4 | import { iterateKeysFromFirst } from './iterateKeysFromFirst'; 5 | import { set } from './set'; 6 | 7 | export function fromKeys (compare: ComparatorFn, keys: K[]|RedBlackTreeStructure|Iterable, mutability?: C.PreferredContext): RedBlackTreeStructure { 8 | const tree = C.modify(createTree(compare, mutability)); 9 | if(Array.isArray(keys)) { 10 | for(var i = 0; i < keys.length; i++) { 11 | set(keys[i], null, tree); 12 | } 13 | } 14 | else { 15 | const it = isRedBlackTree(keys) ? iterateKeysFromFirst(keys) : keys[Symbol.iterator](); 16 | var current: IteratorResult; 17 | while(!(current = it.next()).done) { 18 | set(current.value, null, tree); 19 | } 20 | } 21 | return C.commit(tree); 22 | } 23 | -------------------------------------------------------------------------------- /packages/sorted-set/tests/functions/filter.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { filter } from '../../src'; 3 | import { fromNumericArray } from '../test-utils'; 4 | 5 | let values0: number[], 6 | values1: number[], 7 | values2: number[]; 8 | const predicate1 = (n: number) => ((n >>> 1) << 1) !== n; 9 | const predicate2 = (n: number) => ((n >>> 1) << 1) === n; 10 | test.before(() => { 11 | values0 = [1, 2, 3, 5, 8, 13, 21, 34, 55]; 12 | values1 = [1, 3, 5, 13, 21, 55]; 13 | values2 = [2, 8, 34]; 14 | }); 15 | 16 | test('items are considered excluded if the predicate returns a falsey value', t => { 17 | const set0 = fromNumericArray(values0); 18 | const set1 = filter(predicate1, set0); 19 | t.deepEqual(Array.from(set1), values1); 20 | }); 21 | 22 | test('items are considered included if the predicate returns a truthy value', t => { 23 | const set0 = fromNumericArray(values0); 24 | const set1 = filter(predicate2, set0); 25 | t.deepEqual(Array.from(set1), values2); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/map/tests/forEach.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { HashMapStructure, forEach, fromArray } from '../src'; 3 | 4 | type Pair = [number, string]; 5 | let map: HashMapStructure, values: Pair[]; 6 | test.beforeEach(() => { 7 | values = [1, 2, 3, 5, 8, 13, 21, 34, 55].map(n => [n, `#${n}`]); 8 | map = fromArray(values); 9 | }); 10 | 11 | test('the predicate is called for each item in the map', t => { 12 | const array: Pair[] = []; 13 | forEach((v, k) => array.push([k, v]), map); 14 | array.sort((a, b) => a[0] - b[0]); 15 | t.deepEqual(array, values); 16 | }); 17 | 18 | test('iteration is terminated if `false` is explicitly returned from the predicate', t => { 19 | let count = 0; 20 | forEach((v, k, i) => { 21 | count++; 22 | if(i === 3) return false; 23 | }, map); 24 | t.is(count, 4); 25 | }); 26 | 27 | test('the input map is returned after iteration is complete', t => { 28 | const set1 = forEach(n => {}, map); 29 | t.is(map, set1); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/sorted-set/src/functions/filter.ts: -------------------------------------------------------------------------------- 1 | import { FilterFn, commit, isImmutable, modify } from '@collectable/core'; 2 | import { SortedSetStructure } from '../internals'; 3 | import { iterateValues, unsetItem } from '../internals'; 4 | import { size } from './size'; 5 | 6 | export function filter (fn: FilterFn, set: SortedSetStructure): SortedSetStructure { 7 | var nextSet = modify(set); 8 | var map = nextSet._map; 9 | var tree = nextSet._tree; 10 | 11 | var it = iterateValues(set); 12 | var current: IteratorResult; 13 | var index = 0, remaining = size(set); 14 | while(!(current = it.next()).done) { 15 | if(!fn(current.value, index++)) { 16 | remaining--; 17 | unsetItem(current.value, map, tree); 18 | } 19 | } 20 | 21 | if(remaining <= 0) { 22 | return set; 23 | } 24 | 25 | commit(nextSet); 26 | 27 | if(isImmutable(set)) { 28 | return nextSet; 29 | } 30 | 31 | set._map = map; 32 | set._tree = tree; 33 | return set; 34 | } 35 | -------------------------------------------------------------------------------- /packages/sorted-map/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './at'; 2 | export * from './clone'; 3 | export * from './empty'; 4 | export * from './entries'; 5 | export * from './filter'; 6 | export * from './first'; 7 | export * from './firstKey'; 8 | export * from './firstValue'; 9 | export * from './forEach'; 10 | export * from './fromArray'; 11 | export * from './fromIterable'; 12 | export * from './get'; 13 | export * from './has'; 14 | export * from './isEmpty'; 15 | export * from './isEqual'; 16 | export * from './isSortedMap'; 17 | export * from './keyAt'; 18 | export * from './keys'; 19 | export * from './last'; 20 | export * from './lastKey'; 21 | export * from './lastValue'; 22 | export * from './map'; 23 | export * from './reduce'; 24 | export * from './remove'; 25 | export * from './set'; 26 | export * from './size'; 27 | export * from './toArray'; 28 | export * from './toNativeMap'; 29 | export * from './update'; 30 | export * from './updateMap'; 31 | export * from './valueAt'; 32 | export * from './values'; -------------------------------------------------------------------------------- /packages/map/src/functions/isEqual.ts: -------------------------------------------------------------------------------- 1 | import { isEqual as eq } from '@collectable/core'; 2 | import { identity, iterator } from '../internals/primitives'; 3 | import { HashMapStructure } from '../internals/HashMap'; 4 | import { Leaf } from '../internals/nodes'; 5 | 6 | export function isEqual (map: HashMapStructure, other: HashMapStructure): boolean; 7 | export function isEqual (map: HashMapStructure, other: HashMapStructure): boolean { 8 | if(map === other) return true; 9 | if(map._size !== other._size) return false; 10 | 11 | const ita = iterator(map._root, identity), 12 | itb = iterator(other._root, identity); 13 | 14 | let ca: IteratorResult>, 15 | cb: IteratorResult>, 16 | a: Leaf, 17 | b: Leaf; 18 | 19 | while(!(ca = ita.next(), cb = itb.next()).done) { 20 | a = ca.value; 21 | b = cb.value; 22 | if(!eq(a.key, b.key) || !eq(a.value, b.value)) return false; 23 | } 24 | return true; 25 | } 26 | -------------------------------------------------------------------------------- /packages/set/tests/functions/union.Iterable.mutable.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { isMutable, modify } from '@collectable/core'; 3 | import { HashSetStructure, fromArray, size, union } from '../../src'; 4 | 5 | const mainValues = ['A', 'B', 'C', 'D', 'E']; 6 | const otherValues = ['D', 'E', 'F', 'G']; 7 | const expectedValues = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; 8 | 9 | let main: HashSetStructure, result: HashSetStructure; 10 | let other: Iterable; 11 | 12 | test.before(() => { 13 | other = new Set(otherValues).values(); 14 | main = modify(fromArray(mainValues)); 15 | result = union(other, main); 16 | }); 17 | 18 | test('the input set is returned', t => { 19 | t.is(result, main); 20 | }); 21 | 22 | test('the input set is still mutable', t => { 23 | t.true(isMutable(result)); 24 | }); 25 | 26 | test('the main set includes all items from both inputs', t => { 27 | t.deepEqual(Array.from(result).sort(), expectedValues); 28 | t.is(size(result), expectedValues.length); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/list/tests/functions/fromArray.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { fromArray } from '../../src'; 3 | import { arrayFrom } from '../../src/internals'; 4 | import { BRANCH_FACTOR, makeValues } from '../helpers'; 5 | 6 | test('should return an empty list if passed an empty array', t => { 7 | const list = fromArray([]); 8 | t.is(list._size, 0); 9 | t.true(list._left.isDefaultEmpty()); 10 | t.true(list._right.isDefaultEmpty()); 11 | }); 12 | 13 | test('should return a list containing all the values in the array', t => { 14 | var values = makeValues(BRANCH_FACTOR >>> 1); 15 | t.deepEqual(arrayFrom(fromArray(values)), values); 16 | 17 | values = makeValues(BRANCH_FACTOR); 18 | t.deepEqual(arrayFrom(fromArray(values)), values); 19 | 20 | values = makeValues(BRANCH_FACTOR + 1); 21 | var list = fromArray(values); 22 | t.deepEqual(arrayFrom(list), values); 23 | 24 | values = makeValues(BRANCH_FACTOR*BRANCH_FACTOR); 25 | list = fromArray(values); 26 | t.deepEqual(arrayFrom(list), values); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/map/src/internals/primitives/setKeyValue.ts: -------------------------------------------------------------------------------- 1 | import { ChangeFlag, hash as _hash, isUndefined } from '@collectable/core'; 2 | import { AnyNode } from '../nodes'; 3 | import { HashMapStructure } from '../HashMap'; 4 | import { NOTHING } from '../nodes/constants'; 5 | 6 | const constant = (x: T) => () => x; 7 | 8 | export function setKeyValue ( 9 | key: K, 10 | value: V, 11 | change: ChangeFlag, 12 | map: HashMapStructure): HashMapStructure { 13 | 14 | if(isUndefined(value)) { 15 | value = NOTHING as V; 16 | } 17 | 18 | const hash: number = _hash(key); 19 | const newNode: AnyNode = map._root.modify(map, change, 0, constant(value), hash, key); 20 | 21 | // ## DEV [[ 22 | if(newNode !== map._root && !change.confirmed) { 23 | throw new Error('Investigate how the root managed to change without the change flag being set'); 24 | } 25 | // ]] ## 26 | 27 | if(change.confirmed) { 28 | map._root = newNode; 29 | map._size += change.delta; 30 | } 31 | 32 | return map; 33 | } 34 | -------------------------------------------------------------------------------- /packages/sorted-map/tests/functions/filter.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { filter } from '../../src'; 3 | import { fromNumericArray, pairsFrom } from '../test-utils'; 4 | 5 | let values0: number[], 6 | values1: number[], 7 | values2: number[]; 8 | const predicate1 = (_: any, n: number) => ((n >>> 1) << 1) !== n; 9 | const predicate2 = (_: any, n: number) => ((n >>> 1) << 1) === n; 10 | test.before(() => { 11 | values0 = [1, 2, 3, 5, 8, 13, 21, 34, 55]; 12 | values1 = [1, 3, 5, 13, 21, 55]; 13 | values2 = [2, 8, 34]; 14 | }); 15 | 16 | test('items are considered excluded if the predicate returns a falsey value', t => { 17 | const map0 = fromNumericArray(values0); 18 | const map1 = filter(predicate1, map0); 19 | t.deepEqual(Array.from(map1), pairsFrom(values1)); 20 | }); 21 | 22 | test('items are considered included if the predicate returns a truthy value', t => { 23 | const map0 = fromNumericArray(values0); 24 | const map1 = filter(predicate2, map0); 25 | t.deepEqual(Array.from(map1), pairsFrom(values2)); 26 | }); 27 | --------------------------------------------------------------------------------