0.1.14 • Published 1 year ago

btreemap v0.1.14

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

btreemap

Version Coverage Dependencies License

A BTreeMap is an indexed, sorted, type-aware, and persistable data store with a Map-like API and extensions for range-based methods. At its core is a Map object, used to store key/value pairs, and a B+ Tree for managing keys. This "best of both worlds" approach leverages the strengths of each: the efficient data access of a Map, and the sorting and range benefits of a B+ Tree. In benchmark tests, BTreeMap significantly outperforms the B+ Tree libraries sorted-btree and bplus-index when retrieving and updating existing values, and performs comparably on insertion and deletion tasks (see Benchmarks for details).

There is one important way in which a BTreeMap is different from a Map. The design inspiration comes from database indexes that can enforce unique keys constraints or allow keys to have multiple related values. A BTreeMap can be similarly configured either way. When keys are unique, a BTreeMap effectively functions the same as a Map, with the added benefit of key sorting and range-based access. When keys are non-unique, each key can have an array of associated values, and this has several implications:

  • The get method returns an array of values for a key, as opposed to returning a single value.
  • The delete method removes the entire array of values associated with a key, as opposed to deleting just a single value.
  • The values iterator yields a result for each individual element of a key's array of associated values.
  • The entries iterator yields a key/value pair for each individual element of a key's array of associated values, as opposed to a single key/value pair per key.
  • The forEach method, being based on the entries iterator, applies the supplied function to each individual element of a key's array of associated values.

By default, a BTreeMap is configured for unique keys.

Examples

Unique keys

const { BTreeMap } = require("btreemap");

const btm = new BTreeMap();
btm.set(1, "one");
btm.get(1); // returns "one"
btm.set(1, "two"); // overwrites "one" with "two"
btm.get(1); // returns "two"
btm.delete(1) // deletes key 1 and value "two"

Non-unique keys

const { BTreeMap } = require("btreemap");

const btm = new BTreeMap({unique: false});
btm.set(1, "one");
btm.get(1); // returns ["one"]
btm.set(1, "two"); // adds "two" for key 1
btm.get(1); // returns ["one", "two"]
btm.delete(1); // deletes key 1 and values "one" and "two"

There are two other important factors to be aware of: the use of BSON to serialize and deserialize data with persistent storage; and the default comparator used to determine the sort order of keys.

While a Map key or value can be any primitive or object, BSON cannot effectively serialize all of them, so if you attempt to save a BTreeMap that contains certain types of keys or values it may result in an error. In particular, the following primitives and object types are "safe": null, boolean, number, Date, string, RegExp, Array, and Object (that is, [object Object]). The BSON library will convert any undefined keys or values to null, will fail on bigint, and may not serialize other types of objects as you'd expect. When using BTreeMap completely in-memory, none of theses restrictions apply.

By default, BTreeMap uses a type-aware comparator function to compare and determine the sort order of keys. If two keys being compared are of the same type (null keys have their type converted from object to null), they are compared using the "less than" (<) operator and the Abstract Relational Comparison algorithm. If the keys are of different types, they are compared lexicographically using their type name. This results in a somewhat arbitrary ordering of differing types, but any ordering of types is bound to be somewhat arbitrary. If desired, a custom comparator function can be supplied when creating a BTreeMap instance.

Table of contents

Constructor

Syntax

new BTreeMap([options]);

Parameters

options

An object containing configuration options for the BTreeMap.

OptionTypeDescriptionDefault
uniquebooleanWhether keys are uniquetrue
ordernumberThe order of the B+ Tree3
comparatorfunctionThe function used to compare keysDescribed above.

If a custom comparator is provided, it must take two values as input and return a value less than zero if the first value should be sorted before the second, greater than zero if the second value should be sorted before the first, or zero to keep the existing order.

Examples

const btm = new BTreeMap({
	unique: false,
	order: 5,
	comparator: (a, b) => {
		return (a < b) ? -1 : ((a > b) ? 1 : 0);
	}
});

Properties

BTreeMap.lowest

Returns the lowest key in the BTreeMap.

BTreeMap.highest

Returns the highest key in the BTreeMap.

BTreeMap.order

Returns the order of the BTreeMap object's B+ Tree.

BTreeMap.size

Returns the number of keys in a BTreeMap object. If configured for unique keys, this will be equal to the number of values; otherwise, the number of values may be greater.

BTreeMap.stats

Returns an object with statistics for a BTreeMap object's B+ Tree:

PropertyDescription
depthThe depth of the tree
nodesThe number of nodes in the tree
leavesThe number of leaves in the tree
keysThe number of keys in the tree
valuesThe number of values in the tree

The number of keys in the tree will be equal to the size of the BTreeMap, but the number of values could be greater if configured for non-unique keys.

Data manipulation methods

BTreeMap.has()

Returns a boolean indicating whether the specified key exists.

Syntax

has(key)

Parameters

key

The key to test for presence in the BTreeMap object.

Return value

true if the specified key exists in the BTreeMap object; otherwise, false.

BTreeMap.set()

Adds a value for a specified key to a BTreeMap object. If configured for unique keys, overwrites the value if the key exits; otherwise, adds the value to the array of values for the key.

Syntax

set(key, value)

Parameters

key

The key to add to the BTreeMap object.

value

The associated value to add to the BTreeMap object.

Return value

The BTreeMap object.

BTreeMap.get()

Returns a value associated with a specified key from a BTreeMap object or an iterator object for the values associated with a range of keys.

Syntax

get(key [, endKey, inclusive])

Parameters

key

The key for the associated value to return from the BTreeMap object.

endKey

If an endKey is provided, get() returns a new iterator object for values in the BTreeMap object, from key to endKey, in sorted order.

inclusive

A boolean indicating whether to include the associated value for the endKey. Default is true.

Return value

The value associated with the specified key, or values associated with a range of keys, or undefined if the key, or keys in the range, can't be found in the BTreeMap object.

Examples

// Returns the value associated with key 1
btm.get(1);

// Returns an iterator for the values associated with keys 1 through 10
btm.get(1, 10);

// Returns an iterator for the values associated with keys 1 up to but not including 10
btm.get(1, 10, false);

BTreeMap.delete()

Removes the specified key and its associated value, or range of keys and associated values, from a BTreeMap object.

Syntax

delete(key [, endKey, inclusive])

Parameters

key

The key to remove from the BTreeMap object.

endKey

If an endKey is provided, delete() removes keys in the range from key to endKey from the BTreeMap object.

inclusive

A boolean indicating whether to include the endKey. Default is true.

See get for examples of how endKey and inclusive can be used.

Return value

true if a key, or range of keys, in the BTreeMap object existed and have been removed, or false if the key does not exist, or there are no keys in the range.

BTreeMap.clear()

Removes all elements from a BTreeMap object.

Syntax

clear()

Return value

undefined

Iterators

BTreeMap[@@iterator]()

Returns the same iterator object as the entries method. If configured for non-unique keys, a key, value pair will be yielded for each value in a key's array of associated values.

Examples

for (const entry of btm) {
	console.log(entry); // [key, value]
}

BTreeMap.keys()

Returns a new iterator object that contains the keys in the BTreeMap object in sorted order.

Syntax

keys([start, end, inclusive])

If start or end are provided, returns keys within the range from start to end.

Parameters

start

The lowest key that should be included in the iterator. Default is the lowest key in the BTreeMap object.

end

The highest key that should be included in the iterator. Default is the highest key in the BTreeMap object.

inclusive

A boolean indicating whether to include the end element. Default is true.

Return value

A new BTreeMap iterator object.

Examples

// Returns an iterator for all keys
btm.keys();

// Returns an iterator for keys 1 through 10
btm.keys(1, 10);

// Returns an iterator for keys from the lowest key to 10
btm.keys(undefined, 10)

// Returns an iterator for keys 10 up through the highest key
btm.keys(10, undefined);

// Returns an iterator for keys 1 up to but not including 10
btm.keys(1, 10, false)

BTreeMap.values()

Returns a new iterator object that contains the values in the BTreeMap object sorted by key order.

Syntax

values([start, end, inclusive])

If start or end are provided, returns values for keys within the range from start to end. Note that if configured for non-unique keys, each value yielded will be one of an array of values.

Parameters

start

The lowest key that should be included in the iterator. Default is the lowest key in the BTreeMap object.

end

The highest key that should be included in the iterator. Default is the highest key in the BTreeMap object.

inclusive

A boolean indicating whether to include the end element. Default is true.

See keys for examples of how start, end, and inclusive can be used.

Return value

A new BTreeMap iterator object.

BTreeMap.entries()

Returns a new iterator object that contains the key, value pairs in the BTreeMap object sorted by key order. If configured for non-unique keys, a key, value pair will be yielded for each value in a key's array of associated values; that is, more than one key, value pair may be yielded for a given key.

Syntax

entries([start, end, inclusive])

If start or end are provided, returns key, value pairs for keys within the range from start to end.

Parameters

start

The lowest key that should be included in the iterator. Default is the lowest key in the BTreeMap object.

end

The highest key that should be included in the iterator. Default is the highest key in the BTreeMap object.

inclusive

A boolean indicating whether to include the end element. Default is true.

See keys for examples of how start, end, and inclusive can be used.

Return value

A new BTreeMap iterator object.

Functional methods

BTreeMap.forEach()

Executes a provided function once per each key/value pair in the BTreeMap object in sorted order. If configured for non-unique keys, applies the supplied function to each individual element of a key's array of associated values.

Syntax

forEach(function, [start, end, inclusive])

If start or end are provided, executes the function for keys within the range from start to end.

Parameters

function

The function to be executed, invoked with three arguments: the value, the key, and the BTreeMap object.

start

The lowest key for which the function should be executed. Default is the lowest key in the BTreeMap object.

end

The highest key for which the function should be executed. Default is the highest key in the BTreeMap object.

inclusive

A boolean indicating whether to execute the function for the end element. Default is true.

See keys for examples of how start, end, and inclusive can be used.

Return value

undefined

Input/Output methods

BTreeMap.load()

Creates a new BTreeMap object using data from a file.

Syntax

load(path)

Parameters

path

The path to a file containing BTreeMap data.

Return value

undefined

BTreeMap.save()

Saves a BTreeMap map object's data to a file.

Syntax

save(path)

Parameters

path

The path to a file where the BTreeMap object's data should be saved. The file is created if it doesn't exist, and overwritten if it does.

Return value

undefined

BTreeMap.toString()

Returns a string representing the BTreeMap object.

Syntax

toString()

Return value

A string representing the BTreeMap object.

Benchmarks

Twenty rounds of benchmark tests were conducted to compare btreemap with sorted-btree and bplus-index. Each test involved the following for ascending and descending integer keys, and a randomly generated mix of integer and character keys:

  • Inserting key/value pairs in batches of 1000, 10000, 100000, and 1000000
  • Retrieving values for a random 20% of the keys
  • Updating values for a random 10% of the keys
  • Deleting a random 1% of the keys

Times were captured at nanosecond scale using process.hrtime.bigint() and the results were converted into measures of operations per millisecond. The benchmark script, raw data output, and an Excel spreadsheet with a pivot chart, are all available in the "benchmarks" folder.

Benchmark results

0.1.12

1 year ago

0.1.13

1 year ago

0.1.14

1 year ago

0.1.11

2 years ago

0.1.10

2 years ago

0.1.9

2 years ago

0.1.8

2 years ago

0.1.7

2 years ago

0.1.6

2 years ago

0.1.5

2 years ago

0.1.4

2 years ago

0.1.3

2 years ago

0.1.2

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago