Created
February 22, 2013 19:54
-
-
Save madbook/5016099 to your computer and use it in GitHub Desktop.
my own implementation of the es6 map spec, written in coffeescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
toObject = (val) -> | |
if !val? | |
throw new TypeError() | |
return Object(val) | |
class MapIterator | |
next: -> | |
if !@__Map__? or !@__MapNextIndex__? or !@__MapIterationKind__? | |
return new TypeError('MapIterator not initialised') | |
if !@__Map__.__MapData__? | |
return new TypeError('Invalid Map object') | |
index = @__MapNextIndex__ | |
entries = @__Map__.__MapData__ | |
itemKind = @__MapIterationKind__ | |
if index < entries.length | |
e = entries[index] | |
@__MapNextIndex__++ | |
if e.key? | |
if itemKind == "key" then return e.key | |
if itemKind == "value" then return e.value | |
if itemKind == "key+value" then return [e.key, e.value] | |
return undefined # throw 'StopIteration' # need to do more than this? | |
# __iterator__: -> @ | |
# __toStringTag__ : -> "Map Iterator" | |
IteratorComplete = (itr, value) -> | |
if value == undefined and itr.__MapNextIndex__ >= itr.__map__.__MapData__.length | |
return true | |
return false | |
CreateMapIterator = (map, kind) -> | |
map = toObject(map) | |
if !map.__MapData__ then throw new TypeError() | |
itr = new MapIterator() | |
itr.__Map__ = map | |
itr.__MapNextIndex__ = 0 | |
itr.__MapIterationKind__ = kind | |
return itr | |
class Record | |
constructor: (@key, @value) -> | |
MapInitialisation = (obj, iterable) -> | |
if typeof obj != 'object' | |
throw new TypeError() | |
if obj.__MapData__? | |
throw new TypeError() | |
if !(Object.isExtensible(obj)) | |
throw new TypeError() | |
if iterable? | |
iterable = toObject(iterable) | |
# iterable = @@iterable (wat?) | |
itr = obj.iterable() | |
adder = obj.set | |
if !(adder instanceof Function) | |
throw new TypeError() | |
obj.__MapData__ = [] | |
if !iterable? | |
return obj | |
while true | |
next = itr.next() | |
if IteratorComplete(itr, next) | |
return obj | |
k = next["0"] | |
v = next["1"] | |
status = adder.call(obj, k, v) | |
class Map | |
constructor: (iterable) -> | |
status = MapInitialisation(@, iterable) | |
clear: -> | |
if !@__MapData__ | |
throw new TypeError() | |
@__MapData__ = [] | |
return undefined | |
delete: (key) -> | |
if !@__MapData__ | |
throw new TypeError() | |
for p in @__MapData__ | |
if p.key == key | |
p.key = undefined | |
p.value = undefined | |
# splice entry object out of list | |
return true | |
return false | |
forEach: (callbackfn, thisArg=undefined) -> | |
if !callbackfn? then return | |
if !@__MapData__ then throw new TypeError() | |
if !(callbackfn instanceof Function) then throw new TypeError() | |
for e in @__MapData__ | |
if e.key? | |
callbackfn.call(thisArg, e.value, e.key, @) | |
return undefined | |
get: (key) -> | |
if !@__MapData__ then throw new TypeError() | |
for p in @__MapData__ | |
if p.key == key | |
return p.value | |
return undefined | |
has: (key) -> | |
if !@__MapData__ then throw new TypeError() | |
for p in @__MapData__ | |
if p.key == key | |
return true | |
return false | |
items: -> | |
CreateMapIterator(@, "key+value") | |
keys: -> | |
CreateMapIterator(@, "key") | |
set: (key, value) -> | |
if !@__MapData__ then throw new TypeError() | |
for p in @__MapData__ | |
if p.key == key | |
p.value = value | |
return undefined | |
@__MapData__.push( new Record(key, value) ) | |
return undefined | |
values: -> | |
CreateMapIterator(@, "value") | |
Object.defineProperty(Map::, 'size', { | |
get: -> | |
if !@__MapData__ then throw new TypeError() | |
count = 0 | |
for p in @__MapData__ | |
if p.key? | |
count++ | |
return count | |
}) | |
# __iterator__: ::items | |
# __toStringTag__: "Map" | |
window.Map = Map |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment