Skip to content
This repository has been archived by the owner on Jul 30, 2018. It is now read-only.

Improve shims #101

Merged
merged 28 commits into from
Jul 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 130 additions & 107 deletions src/Map.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,131 @@
import { ArrayLike } from './interfaces';
import { hasClass } from './support/decorators';
import global from './global';
import { forOf, Iterable, IterableIterator, ShimIterator } from './iterator';
import global from './global';
import { is as objectIs } from './object';
import has from './support/has';
import './Symbol';

export namespace Shim {
export interface Map<K, V> {
/**
* Deletes all keys and their associated values.
*/
clear(): void;

/**
* Deletes a given key and its associated value.
*
* @param key The key to delete
* @return true if the key exists, false if it does not
*/
delete(key: K): boolean;

/**
* Returns an iterator that yields each key/value pair as an array.
*
* @return An iterator for each key/value pair in the instance.
*/
entries(): IterableIterator<[K, V]>;

/**
* Executes a given function for each map entry. The function
* is invoked with three arguments: the element value, the
* element key, and the associated Map instance.
*
* @param callbackfn The function to execute for each map entry,
* @param thisArg The value to use for `this` for each execution of the calback
*/
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;

/**
* Returns the value associated with a given key.
*
* @param key The key to look up
* @return The value if one exists or undefined
*/
get(key: K): V | undefined;

/**
* Returns an iterator that yields each key in the map.
*
* @return An iterator containing the instance's keys.
*/
keys(): IterableIterator<K>;

/**
* Checks for the presence of a given key.
*
* @param key The key to check for
* @return true if the key exists, false if it does not
*/
has(key: K): boolean;

/**
* Sets the value associated with a given key.
*
* @param key The key to define a value to
* @param value The value to assign
* @return The Map instance
*/
set(key: K, value: V): this;

/**
* Returns the number of key / value pairs in the Map.
*/
readonly size: number;

/**
* Returns an iterator that yields each value in the map.
*
* @return An iterator containing the instance's values.
*/
values(): IterableIterator<V>;

/** Returns an iterable of entries in the map. */
[Symbol.iterator](): IterableIterator<[K, V]>;

readonly [Symbol.toStringTag]: string;
}

export interface MapConstructor {
/**
* An implementation analogous to the Map specification in ES2015.
* Creates a new Map
*
* @constructor
*/
export class Map<K, V> {
new (): Map<any, any>;

/**
* Creates a new Map
*
* @constructor
*
* @param iterator
* Array or iterator containing two-item tuples used to initially populate the map.
* The first item in each tuple corresponds to the key of the map entry.
* The second item corresponds to the value of the map entry.
*/
new <K, V>(iterator?: [K, V][]): Map<K, V>;

/**
* Creates a new Map
*
* @constructor
*
* @param iterator
* Array or iterator containing two-item tuples used to initially populate the map.
* The first item in each tuple corresponds to the key of the map entry.
* The second item corresponds to the value of the map entry.
*/
new <K, V>(iterator: Iterable<[K, V]>): Map<K, V>;

readonly prototype: Map<any, any>;

readonly [Symbol.species]: MapConstructor;
}

export let Map: MapConstructor = global.Map;

if (!has('es6-map')) {
Map = class Map<K, V> {
protected readonly _keys: K[] = [];
protected readonly _values: V[] = [];

Expand All @@ -26,16 +142,8 @@ export namespace Shim {
return -1;
}

/**
* Creates a new Map
*
* @constructor
*
* @param iterator
* Array or iterator containing two-item tuples used to initially populate the map.
* The first item in each tuple corresponds to the key of the map entry.
* The second item corresponds to the value of the map entry.
*/
static [Symbol.species] = Map;

constructor(iterable?: ArrayLike<[K, V]> | Iterable<[K, V]>) {
if (iterable) {
forOf(iterable, (value: [K, V]) => {
Expand All @@ -44,28 +152,14 @@ export namespace Shim {
}
}

/**
* Returns the number of key / value pairs in the Map.
*
* @return the number of key / value pairs in the Map
*/
get size(): number {
return this._keys.length;
}

/**
* Deletes all keys and their associated values.
*/
clear(): void {
this._keys.length = this._values.length = 0;
}

/**
* Deletes a given key and its associated value.
*
* @param key The key to delete
* @return true if the key exists, false if it does not
*/
delete(key: K): boolean {
const index = this._indexOfKey(this._keys, key);
if (index < 0) {
Expand All @@ -76,27 +170,14 @@ export namespace Shim {
return true;
}

/**
* Returns an iterator that yields each key/value pair as an array.
*
* @return An iterator for each key/value pair in the instance.
*/
entries(): IterableIterator<[K, V]> {
const values = this._keys.map((key: K, i: number): [K, V] => {
return [ key, this._values[i] ];
});

return new ShimIterator<[K, V]>(values);
return new ShimIterator(values);
}

/**
* Executes a given function for each map entry. The function
* is invoked with three arguments: the element value, the
* element key, and the associated Map instance.
*
* @param callback The function to execute for each map entry,
* @param context The value to use for `this` for each execution of the calback
*/
forEach(callback: (value: V, key: K, mapInstance: Map<K, V>) => any, context?: {}) {
const keys = this._keys;
const values = this._values;
Expand All @@ -105,43 +186,19 @@ export namespace Shim {
}
}

/**
* Returns the value associated with a given key.
*
* @param key The key to look up
* @return The value if one exists or undefined
*/
get(key: K): V | undefined {
const index = this._indexOfKey(this._keys, key);
return index < 0 ? undefined : this._values[index];
}

/**
* Checks for the presence of a given key.
*
* @param key The key to check for
* @return true if the key exists, false if it does not
*/
has(key: K): boolean {
return this._indexOfKey(this._keys, key) > -1;
}

/**
* Returns an iterator that yields each key in the map.
*
* @return An iterator containing the instance's keys.
*/
keys(): IterableIterator<K> {
return new ShimIterator<K>(this._keys);
return new ShimIterator(this._keys);
}

/**
* Sets the value associated with a given key.
*
* @param key The key to define a value to
* @param value The value to assign
* @return The Map instance
*/
set(key: K, value: V): Map<K, V> {
let index = this._indexOfKey(this._keys, key);
index = index < 0 ? this._keys.length : index;
Expand All @@ -150,50 +207,16 @@ export namespace Shim {
return this;
}

/**
* Returns an iterator that yields each value in the map.
*
* @return An iterator containing the instance's values.
*/
values(): IterableIterator<V> {
return new ShimIterator<V>(this._values);
return new ShimIterator(this._values);
}

[Symbol.iterator](): IterableIterator<[K, V]> {
return this.entries();
}

[Symbol.toStringTag] = 'Map';
}
[Symbol.toStringTag]: 'Map' = 'Map';
};
}

@hasClass('es6-map', global.Map, Shim.Map)
export default class Map<K, V> {
/* istanbul ignore next */
constructor(iterable?: ArrayLike<[K, V]> | Iterable<[K, V]>) { };

/* istanbul ignore next */
get size(): number { throw new Error('Abstract method'); };
/* istanbul ignore next */
clear(): void { throw new Error('Abstract method'); };
/* istanbul ignore next */
delete(key: K): boolean { throw new Error('Abstract method'); };
/* istanbul ignore next */
entries(): IterableIterator<[K, V]> { throw new Error('Abstract method'); };
/* istanbul ignore next */
forEach(callback: (value: V, key: K, mapInstance: Map<K, V>) => any, context?: {}): void { throw new Error('Abstract method'); };
/* istanbul ignore next */
get(key: K): V | undefined { throw new Error('Abstract method'); };
/* istanbul ignore next */
has(key: K): boolean { throw new Error('Abstract method'); };
/* istanbul ignore next */
keys(): IterableIterator<K> { throw new Error('Abstract method'); };
/* istanbul ignore next */
set(key: K, value: V): Map<K, V> { throw new Error('Abstract method'); };
/* istanbul ignore next */
values(): IterableIterator<V> { throw new Error('Abstract method'); };
/* istanbul ignore next */
[Symbol.iterator](): IterableIterator<[K, V]> { throw new Error('Abstract method'); };
/* istanbul ignore next */
[Symbol.toStringTag] = 'Map';
}
export default Map;
Loading