mapam
A bidirectional Map/WeakMap implementation with the same API as an ES6 Map/WeakMap!
Features
- Tiny: less than 720 bytes minzipped including dependencies!
- Familiar: uses the same API as an ES6 Map/WeakMap
- Compliant: maintains all the invariants of Map/WeakMap including method
return values and even iteration order!
- Correct: handles edge cases correctly
Install
$ npm i mapam
Huh?
A bidirectional map is like a regular map except it preserves uniqueness of its
values (in addition to its keys) and supports an inverse view, which is another
bidirectional map containing and backed by the same entries, but with reversed
keys and values.
For a weak bidirectional map specifically, its values (in addition to its keys)
must be objects.
Usage
The API of one side/view of the bidirectional map is identical to the
Map
/WeakMap
API. Just use like a normal Map
or WeakMap
and call the
inverse
map to get the other side of the bidirectional map!
import { BiMap, WeakBiMap } from 'mapam'
const biMap = new BiMap()
biMap.set(1, `one`)
biMap.set(2, `two`)
biMap.inverse().set(`three`, 3)
console.log([...biMap])
console.log([...biMap.inverse()])
console.log(biMap.get(2))
console.log(biMap.inverse().get(`two`))
biMap.inverse().delete(`two`)
console.log(biMap.has(2))
console.log([...biMap])
try {
biMap.set(10, `three`)
} catch (error) {
console.log(error.message)
}
biMap.inverse().set(`three`, 10)
biMap.set(10, `three`, { force: true })
const weakBiMap = new WeakBiMap()
const a = {}
const b = {}
weakBiMap.set(a, b)
console.log(weakBiMap.get(a) === b)
console.log(weakBiMap.inverse().get(b) === a)
See the
type definitions
for more documentation.
Correctness
Iteration order | :heavy_check_mark: | :x: | :x: | :x: | :x: |
Negative zero | :heavy_check_mark: | :x: | :x: | :x: | :x: |
Iteration order
Map
(and many other "unordered" data structures) allow iteration in insertion
order so it's only logical for a bidirectional map to support iteration in a
logical order like insertion order.
const biMap = new BiMap()
biMap.set(1, `one`)
biMap.set(2, `two`)
biMap.set(3, `three`)
biMap.set(4, `four`)
biMap.inverse().set(`two`, -2)
biMap.delete(3)
console.log([...biMap])
Negative zero
A key in a Map
can only occur once. But how is the key's uniqueness
determined? JavaScript's Map
uses the
sameValueZero
algorithm
when checking if two keys are equal. The algorithm considers +0 and -0 to be
equal, but they are actually two different values due to how
IEEE floating point numbers
work.
This means that Map
coerces -0 to +0 for its keys, but not for its values. So
if a bidirectional map implementation uses Map
internally, then it must either
coerce -0 to +0 for its values as well or
somehow broaden its keys to support
both -0 and +0.
const biMap = new BiMap()
biMap.set(`negative-zero`, -0)
biMap.set(`zero`, 0)
console.log(
biMap.get(`negative-zero`),
biMap.get(`zero`),
biMap.inverse().get(-0),
biMap.inverse().get(0),
)
Contributing
Stars are always welcome!
For bugs and feature requests,
please create an issue.
License
MIT ©
Tomer Aberbach