Skip to content

Instantly share code, notes, and snippets.

@FireNeslo
Last active May 14, 2017 17:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FireNeslo/f045db7b8897bfebd364efd29af2f9da to your computer and use it in GitHub Desktop.
Save FireNeslo/f045db7b8897bfebd364efd29af2f9da to your computer and use it in GitHub Desktop.
Immutable thingy
var {ARRAY, NUMBER, STRING, BOOLEAN, OBJECT} = {
ARRAY: Symbol('array'),
OBJECT: Symbol('object'),
NUMBER: Symbol('number'),
STRING: Symbol('string'),
BOOLEAN: Symbol('boolean'),
}
function flatMap(list, callback) {
const result = []
for(const [key, value] of Object.entries(list)) {
result.push(...callback(value, key))
}
return result
}
function hash(value) {
switch(typeof value) {
case 'number': return [NUMBER, ...value.toString(5)]
case 'string': return [STRING, ...value]
case 'boolean': return [BOOLEAN, value]
}
if(Array.isArray(value)) {
return [ARRAY, ...flatMap(value, hash)]
}
return [OBJECT, ...flatMap(value, (value, key)=>flatMap([key, value], hash))]
}
var Node = class Node {
constructor(values, nodes=null) {
this.nodes = Object.assign({}, nodes)
this.value = null
this.key = null
if(values) {
for(var [key, value] of Object.entries(values)) {
this.mutateSet(key, value)
}
}
}
*[Symbol.iterator]() {
for(let index of Reflect.ownKeys(this.nodes)) {
const node = this.nodes[index]
if(node.key !== null) {
yield [node.key, node.value]
} else {
yield* node
}
}
}
mutateSet(key, value) {
const path = hash(key)
let node = this
for(var index of path) {
node = node.nodes[index] || (node.nodes[index] = new Node())
}
node.key = key
node.value = value
return this
}
delete(key) {
const path = hash(key)
const root = new Node(null, this.nodes)
const last = path.length - 1
let node = root
let from = this
for(var i = 0; i <= last; i++) {
const index = path[i]
if(!(from = from && from.nodes[index])) return this
node = node.nodes[index] = new Node(null, from.nodes)
}
delete node.nodes[path[last]]
return root
}
set(key, value) {
const path = hash(key)
const root = new Node(null, this.nodes)
let node = root
let from = this
for(var index of path) {
from = from && from.nodes[index]
node = node.nodes[index] = new Node(null, from && from.nodes)
}
node.value = value
node.key = key
return root
}
get(key) {
const path = hash(key)
let node = this
for(var index of path) {
if(!node.nodes[index]) break
node = node.nodes[index]
}
return node.value
}
}
function Map(values) {
return new Node(values)
}
var node = Map({a: 6, b: {}})
var before = node.set({a: 1}, 5)
var after = before.delete({a: 1})
console.log('nonexistent: ', before.get({a: 2}))
console.log('before: ', before.get({a: 1}))
console.log('after: ', after.get({a: 1}))
for(let [key, value] of node) {
console.log({key, value})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment