immutable-aatree
Version:
Persistent AAtree datastructure
243 lines (170 loc) • 6.89 kB
Markdown
Immutable/ Persistent AATree Datastructure
==========================================
[![npm version]][npm-url] ![size] ![gzip size]
An implementation of [Persistent][1] ordered dictionaries via [AA trees][2],
with a Cursor API for stepping through and manipulating entries.
![AATree Image][3]
**Note**: The AATree datastructure is an implementation of a dictionary that is ordered
by a given _comparison function_ on keys. This is different from ES6 Map objects,
and it has other use cases.
[1]: https://en.wikipedia.org/wiki/Persistent_data_structure
[2]: https://en.wikipedia.org/wiki/AA_tree
[3]: svg/sample.svg
Example
-------
```javascript
import AATree from 'immutable-aatree'
const log = console.log.bind (console)
const empty = new AATree (AATree.defaultCompare)
var tree1 = empty.insert (1, 'Hello', 2, 'World', 3, '!!')
function logp (value, key) {
log (key+':', value)
}
tree1.forEach (logp)
// 1: Hello
// 2: World
// 3: !!
var cursor = tree1.select (3)
log (cursor.found)
// true
var tree2 = cursor.set ('!')
tree2.forEach (logp)
// 1: Hello
// 2: World
// 3: !
var cursor = tree2.select (5)
log (cursor.found)
// false
var tree4 = cursor.set ('Welcome!')
tree4.forEach (logp)
// 1: Hello
// 2: World
// 3: !
// 5: Welcome!
var tree5 = tree4.remove (2)
for (let p of tree5) log (p)
// [ 1, 'Hello' ]
// [ 3, '!' ]
// [ 5, 'Welcome!' ]
```
API
---
### Comparison functions
Since AATrees implement _ordered_ keyed dictionaries,
they are parameterized by the order on keys.
This order is specified by a comparison function, a function
`compare (k1, k2)` that returns:
- `-1` if `k1` is to be considered smaller than `k2`,
- `0` if `k1` and `k2` are to be considered equivalent, and
- `1` if `k1` is to be considered larger than `k2`.
This is the same kind of comparison functions that JavaScript's built-in `Array.sort`
method expects. The static method `AATree.defaultCompare` is a comparison function
that compares values on their type first and uses javascripts built-in
comparison operators if the type is equal.
```javascript
const defaultCompare = function (a, b) {
const ta = typeof a, tb = typeof b
return ta < tb ? -1 : ta > tb ? 1 : a < b ? -1 : a > b ? 1 : 0 }
```
### AATree constructor
Given a comparison function `cmp` for keys,
`new AATree (cmp)` returns an empty AATree object, an object with a single property
`size`, reflecting the number of key-value pairs stored in the tree; and the following methods:
- `has (key)`
- `get (key)`
- `lookup (key)`
- `select (key)`
- `insert (key, value)`
- `remove (key)`
- `entries ()`
- `keys ()`
- `values ()`
- `[Symbol.iterator] ()`
- `forEach (fn)`
**Note** that none of these methods mutate their owner object.
The methods `insert` and `remove` return new AATree objects instead.
### Has, Get
These methods were added to align the API with the built-in Map object of ES6.
`has (k)` searches for a key `k` and returns `true` if found and `false` otherwise.
`get (k)` searches for a key `k` and returns its value if found, and `undefined` otherwise.
If for some reason you store `undefined` values under certain keys you can use
the `lookup` method instead to disambiguate.
### Lookup, Search
`lookup (k)` searches for a key `k` and returns an object
`{ found:true, key:k, value }` if found,
or `{ found:false }` otherwise. `search` is an alias for `lookup`.
### Select
`select (k)` searches for a key `k` and returns a `Cursor` object.
Cursor objects have methods to step through key-value pairs and to create new AATree
objects by setting, and/ or remove key-value pairs from their associated AATree.
Cursor objects have members `found:boolean`, `key`, `value`
and methods `previous`, `next`, `set` and `unset`.
### Insert
`insert (k1, v1, ... kn, vn)` inserts an arbitrary number of
key value pairs at once and returns a new AATree object.
Note that for a single pair, `t.insert (k1, v1)` is equivalent to
`t.select (k1) .set (v1)`.
### Remove, Delete
`remove (k1, ... kn)` returns a new AATree object by removing the
key-value pairs with the specified keys. Note that `t.remove (k1)` is
equivalent to `t.select (k1) .unset ()`.
### ForEach
`forEach (fn)` calls a function `fn (v, k)` for each of the
key-value pairs `(k, v)` in the AATree in ascending key order.
### Entries, [Symbol.iterator]
`entries ()` returns a javascript ES6 style iterator object.
The key value pairs are iterated as tuples, e.g. arrays `[key, value]`
in ascending order by key.
### Keys
`keys ()` returns a javascript ES6 style iterator object for the
keys in the AATree in ascending order.
### Values
`values ()` returns a javascript ES6 style iterator object for the
_values_ in the AATree in ascending order of the key under which they are stored.
## Cursor constructor
The Cursor constructor is private.
Cursor objects can be obtained via the public method `select`
on an AATree object. However, cursors do have public members
`found:boolean`, `key`, `value` and methods
`previous`, `next`, `set` and `unset`.
### Previous, Prev
`previous ()` returns a new Cursor object by moving the cursor
to the previous key-value pair in its associated AATree, or
`null` if no such pair exists. `prev` is an alias for `previous`.
### Next
`next ()` returns a new Cursor object by moving the cursor
to the next key-value pair in its associated AATree, or
`null` if no such pair exists.
### Unset
`unset()` returns a new AATree object by removing the key-value pair
that the cursor is pointed at from its associated AATree.
If `cursor.found` is `false` the original associated AATree is returned.
### Set
`set (value)` returns a new AATree object by inserting or updating the
the key-value pair that the cursor is pointing at in its associated AATree.
Changelog
---------
- Version 2.0.0:
- Converted the project to an ES Module.
- Touch-ups.
- Version 1.0.0:
- Some touch-ups.
- Added a nicer visualisation for the test/ examples.
- Version 1.0.0-alpha:
- Switched to ES6.
- Changed the default compare function to compare on the type first, the value next.
- Added a `size` property.
- Added methods `has` and `get` to align with the ES6 `Map` API.
- Removed the `delete` alias to avoid confusion with the ES6 API, where it is a mutating method.
- Version 0.10.0, changes since 0.9.0:
- Added `AATree` methods `keys` and `values`
- Made the iterator objects returned from `entries`, `keys` and `values` iterable themselves.
- Added an alias `prev` for the `previous` method on `Cursor`.
License
-------
MIT License.
Enjoy!
[NPM version]: https://img.shields.io/npm/v/immutable-aatree.svg
[npm-url]: https://npmjs.org/package/immutable-aatree
[size]: http://img.badgesize.io/alwinb/immutable-aatree/master/lib/aatree.js
[gzip size]: http://img.badgesize.io/alwinb/immutable-aatree/master/lib/aatree.js?compression=gzip