QIntervals
A JavaScript library allowing to store and manipulate lists of intervals.
Introduction
QIntervals is a library that can store and manipulate lists of intervals. It implements a data structure that can store an array of intervals in normalized form (sorted, non-intersecting, and non-ambiguous) and utility methods that can manipulate it. The library allows to perform a boolean algebra (and, or, xor, and subtraction) and various other operations like testing whether a value or an interval is in lists of intervals, and basic manipulation like shifting.
QIntervals has been designed to be friendly for JavaScript engines, especially V8, which powers Node. The list of intervals is stored as an array of numbers giving JS engine a chance to store the whole data in an unboxed continuous array to minimize the memory footprint. Utility functions to convert to/from internal representation are provided.
Documentation
QIntervals provides member-function based functionality and static-function based functionality. Member functions can be called on objects created by qintervals
and static functions are available through qintervals
itself. The design follows a rule that each member function should have a static function counterpart.
Creating a list of intervals
To create an interval representation of a list of intervals use qintervals()
or qintervals.wrap()
functions.
var a = qintervals([
0, 1,
2, 3
]);
var a = qintervals([
{ from: 0, to: 1 },
{ from: 2, to: 3 }
]);
var a = qintervals([
{ start: 0, end: 1 },
{ start: 2, end: 3 }
]);
var a = qintervals([
{ a: 0, b: 1 },
{ a: 2, b: 3 }
]);
var a = qintervals([
{ x: 0, y: 1 },
{ x: 2, y: 3 }
], "x", "y");
To wrap an existing data into the qintervals
object, consider using qintervals.fromData()
:
var a = qintervals.fromData([0, 1, 2, 3]);
NOTE: QIntervals is designed in a way that all arguments always accept qintervals
object or plain JavaScript array that is implicitly converted to qintervals
for a given operation. You don't need to wrap all data you are using by qintervals
, however, it's much faster to wrap each array that is used more than once as the library will normalize it only once and can omit normalization checks during processing.
Data conversion
If you are done with qintervals
it's possible to convert the data back to a preferred data format:
qintervals([1, 2, 5, 6]).getData();
qintervals([1, 2, 5, 6]).toPacked();
qintervals([1, 2, 5, 6]).toArrays();
qintervals([1, 2, 5, 6]).toObjects();
Algebraic Operations
QIntervals library implements the following algebraic operations:
- AND - Use
qintervals.and
or qintervals.intersect
. - OR - Use
qintervals.or
or qintervals.union
. - XOR - Use
qintervals.xor
. - SUB - Use
qintervals.sub
or qintervals.subtract
.
Examples:
var a = qintervals.or([1, 2], [5, 6]);
var a = qintervals([1, 2]).or([5, 6]);
var a = qintervals.and([1, 6], [4, 8]);
var a = qintervals([1, 6]).and([4, 8]);
var a = qintervals.xor([1, 6], [4, 8]);
var a = qintervals([1, 6]).xor([4, 8]);
var a = qintervals.sub([1, 6], [4, 8]);
var a = qintervals([1, 6]).sub([4, 8]);
The number of intervals in a list is not limited:
var a = qintervals([1, 2, 10, 100, 1000, 5000]);
var b = qintervals([5, 6, 15, 200, 4000, 9999]);
qintervals.or(a, b);
qintervals.and(a, b);
qintervals.xor(a, b);
qintervals.sub(a, b);
Other Operations
Shifting allows to shift a list of intervals by a scalar value:
var a = qintervals([1, 2, 5, 6, 11, 12]);
a.shift(-5);
a.shift( 5);
Testing Operations
Testing enables to check whether a scalar value, an interval, or a list of intervals is contained in qintervals
object. There are 3 possible results defined:
qintervals.kTestNone
- No match - the tested value, interval, or intervals are not part of the qintervals
object.qintervals.kTestFull
- Full match - the tested value, interval, or list of intervals are fully contained in qintervals
object.qintervals.kTestPart
- Partial match - part of an interval or list of intervals are contained in qintervals
object.
var a = qintervals([1, 5, 10, 20, 50, 99]);
var b = qintervals([8, 20, 80, 100]);
a.test(0);
a.test(4);
a.test(5);
a.test([1, 5]);
a.test([1, 99]);
a.test([0, 1, 6, 7);
a.test(a);
a.test(b);
a.test([]);