Comparing version 0.1.4 to 0.2.0
{ | ||
"name": "qintervals", | ||
"version": "0.1.4", | ||
"version": "0.2.0", | ||
@@ -5,0 +5,0 @@ "description": "A JavaScript library allowing to store and manipulate lists of intervals.", |
@@ -8,2 +8,6 @@ // QIntervals <https://github.com/jshq/qintervals> | ||
describe("IntervalOps", function() { | ||
var kTestNone = qintervals.kTestNone; | ||
var kTestFull = qintervals.kTestFull; | ||
var kTestPart = qintervals.kTestPart; | ||
it("should wrap packed values if they are well-formed.", function() { | ||
@@ -13,9 +17,9 @@ var packed; | ||
packed = []; | ||
assert(qintervals.wrap(packed).data === packed); | ||
assert(qintervals.wrap(packed).getData() === packed); | ||
packed = [1, 2]; | ||
assert(qintervals.wrap(packed).data === packed); | ||
assert(qintervals.wrap(packed).getData() === packed); | ||
packed = [1, 2, 4, 5, 10, 19, 20, 24]; | ||
assert(qintervals.wrap(packed).data === packed); | ||
assert(qintervals.wrap(packed).getData() === packed); | ||
}); | ||
@@ -63,6 +67,2 @@ | ||
it("should test `test` functionality.", function() { | ||
var kTestNone = qintervals.kTestNone; | ||
var kTestFull = qintervals.kTestFull; | ||
var kTestPart = qintervals.kTestPart; | ||
var a = [0, 1]; | ||
@@ -87,4 +87,4 @@ var b = [0, 1, 5, 6, 10, 11]; | ||
assert(qintervals.test(b, [0, 1] ) === kTestPart); | ||
assert(qintervals.test(b, [0, 1, 5, 6]) === kTestPart); | ||
assert(qintervals.test(b, [0, 1] ) === kTestFull); | ||
assert(qintervals.test(b, [0, 1, 5, 6]) === kTestFull); | ||
assert(qintervals.test(b, [5, 6, 9,10]) === kTestPart); | ||
@@ -94,2 +94,21 @@ assert(qintervals.test(b, [0, 11] ) === kTestPart); | ||
it("should test `test` functionality with more data.", function() { | ||
var a = []; | ||
var i; | ||
for (i = 0; i < 1000; i += 2) | ||
a.push(i, i + 1); | ||
for (i = 0; i < 1000; i += 2) | ||
assert(qintervals.test(a, i + 0.5) === kTestFull); | ||
for (i = 0; i < 1000; i += 2) | ||
assert(qintervals.test(a, i + 1.0) === kTestNone); | ||
for (i = 0; i < 1000; i += 2) | ||
assert(qintervals.test(a, i - 0.1) === kTestNone); | ||
assert(qintervals.test(a, a.slice(2, a.length - 2)) === kTestFull); | ||
}); | ||
it("should test shift functionality.", function() { | ||
@@ -96,0 +115,0 @@ var a = [0, 1]; |
@@ -37,2 +37,9 @@ // QIntervals <https://github.com/jshq/qintervals> | ||
/** | ||
* qintervals.VERSION | ||
* | ||
* Version string of `qintervals` library as "major.minor.patch". | ||
*/ | ||
qintervals.VERSION = "0.2.0"; | ||
/** | ||
* qintervals.kTestNone | ||
@@ -348,17 +355,33 @@ * | ||
/** | ||
* Find an index that is closest to `b`. | ||
* Find an index that is closest to `value`. | ||
*/ | ||
function closestIndex(data, value) { | ||
// Should always be 2 or greater. | ||
var len = data.length; | ||
var cur = 0; | ||
if (value <= data[1]) | ||
return 0; | ||
if (value >= data[len - 2]) | ||
return len - 2; | ||
var base = 0; | ||
var i = 0; | ||
for (var lim = len; lim !== 0; lim >>>= 1) { | ||
cur = base + (lim >> 1); | ||
if (data[cur] > value) | ||
base = cur; | ||
for (var lim = len >>> 1; lim !== 0; lim >>>= 1) { | ||
i = base + (lim & ~1); | ||
var a = data[i]; | ||
var b = data[i + 1]; | ||
if (b <= value) { | ||
base = i + 2; | ||
lim--; | ||
} | ||
else if (a <= value) { | ||
return i; | ||
} | ||
} | ||
return cur & ~1; | ||
return i; | ||
} | ||
@@ -369,3 +392,2 @@ | ||
*/ | ||
function testOp(a, value) { | ||
@@ -405,7 +427,10 @@ var aLen = a.length; | ||
// Boundary check. | ||
if (b1 <= a[0] || b0 >= a[aLen - 1]) | ||
if (b1 <= a[0] || b0 >= a[aLen - 1]) { | ||
return kTestNone; | ||
} | ||
// This is very similar to intersection, however, there is no output array. | ||
var full = 0; | ||
b1 = b[1]; | ||
for (;;) { | ||
@@ -779,3 +804,3 @@ // Skip leading, non-intersecting intervals. | ||
/** | ||
* Get well-formed data of `input`. | ||
* Get well-formed data of `arg`. | ||
*/ | ||
@@ -933,5 +958,15 @@ function dataFromArg(arg, aKey, bKey) { | ||
/** | ||
* Get a reference to the internal packed data. | ||
* | ||
* NOTE: You shouldn't not change the data unless you are not gonna use the | ||
* `qintervals` object anymore. | ||
*/ | ||
qintervals.prototype.getData = function() { | ||
return this.data; | ||
}; | ||
/** | ||
* Return a copy of `qintervals` data in a packed format. | ||
*/ | ||
qintervals.prototype.asPacked = function() { | ||
qintervals.prototype.toPacked = function() { | ||
var data = this.data; | ||
@@ -949,3 +984,3 @@ return data.slice(0, data.length); | ||
*/ | ||
qintervals.prototype.asArrays = function() { | ||
qintervals.prototype.toArrays = function() { | ||
var output = []; | ||
@@ -970,3 +1005,3 @@ | ||
*/ | ||
qintervals.prototype.asObjects = function(aKey, bKey) { | ||
qintervals.prototype.toObjects = function(aKey, bKey) { | ||
if (!aKey) aKey = "from"; | ||
@@ -1053,12 +1088,41 @@ if (!bKey) bKey = "to"; | ||
qintervals.test = function(a, value) { | ||
var data = dataFromArg(a); | ||
if (typeof value === "number") { | ||
// It's a `qintervals` instance, proceed with `testOp()`. | ||
if (a instanceof qintervals) | ||
return testOp(a.data, value); | ||
if (typeof value === "number") | ||
return testOp(data, value); | ||
if (!isArray(a)) | ||
throw new TypeError("Expected an array or qintervals, got " + typeof a + "."); | ||
var b = dataFromArg(value); | ||
if (data === b) | ||
return data.length ? kTestFull : kTestNone; | ||
else | ||
return testOp(data, b); | ||
var array = a; | ||
var i, len = array.length; | ||
if (!len) | ||
return kTestNone; | ||
// If the value is scalar we don't really need to do any conversion to just | ||
// test if it's within all the intervals. Constructing a binary searchable | ||
// list takes much longer than just one traversal. This is handled only in | ||
// static method as prototype method guarantees binary searchable data. | ||
var first = array[0]; | ||
if (typeof first === "number") { | ||
for (i = 0; i < len; i += 2) { | ||
if (value >= array[i] && value < array[i + 1]) | ||
return kTestFull; | ||
} | ||
return kTestNone; | ||
} | ||
return testOp(dataFromArg(a), b); | ||
} | ||
else { | ||
var data = dataFromArg(a); | ||
var b = dataFromArg(value); | ||
if (data === b) | ||
return data.length ? kTestFull : kTestNone; | ||
else | ||
return testOp(data, b); | ||
} | ||
}; | ||
@@ -1065,0 +1129,0 @@ |
@@ -34,3 +34,3 @@ QIntervals | ||
var a = qintervals([ | ||
{ from: 0, to: 1}, | ||
{ from: 0, to: 1 }, | ||
{ from: 2, to: 3 } | ||
@@ -41,3 +41,3 @@ ]); | ||
var a = qintervals([ | ||
{ start: 0, end: 1}, | ||
{ start: 0, end: 1 }, | ||
{ start: 2, end: 3 } | ||
@@ -48,3 +48,3 @@ ]); | ||
var a = qintervals([ | ||
{ a: 0, b: 1}, | ||
{ a: 0, b: 1 }, | ||
{ a: 2, b: 3 } | ||
@@ -55,3 +55,3 @@ ]); | ||
var a = qintervals([ | ||
{ x: 0, y: 1}, | ||
{ x: 0, y: 1 }, | ||
{ x: 2, y: 3 } | ||
@@ -77,6 +77,6 @@ ], "x", "y"); | ||
```JS | ||
qintervals([1, 2, 5, 6]).data; // [1, 2, 5, 6] (weak). | ||
qintervals([1, 2, 5, 6]).asPacked(); // [1, 2, 5, 6] (copy). | ||
qintervals([1, 2, 5, 6]).asArrays(); // [[1, 2], [5, 6]]. | ||
qintervals([1, 2, 5, 6]).asObjects(); // [{ from: 1, to: 2}, { from: 5, to: 6}]. | ||
qintervals([1, 2, 5, 6]).getData(); // [1, 2, 5, 6] (weak). | ||
qintervals([1, 2, 5, 6]).toPacked(); // [1, 2, 5, 6] (copy). | ||
qintervals([1, 2, 5, 6]).toArrays(); // [[1, 2], [5, 6]]. | ||
qintervals([1, 2, 5, 6]).toObjects(); // [{ from: 1, to: 2}, { from: 5, to: 6}]. | ||
``` | ||
@@ -83,0 +83,0 @@ |
40326
1175