diff options
Diffstat (limited to 'src/logoot.js')
-rw-r--r-- | src/logoot.js | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/logoot.js b/src/logoot.js new file mode 100644 index 0000000..c8c7c02 --- /dev/null +++ b/src/logoot.js @@ -0,0 +1,153 @@ +export default { + + query(property) { + return { + [property]: { + $type: 'array', + $type: ['int', 'long'], + }, + $nor: [ + { [property]: { $gt: this.maxInt } }, + { [property]: { $lt: 0 } }, + ] + } + }, + + get before() { + return [] + }, + + get after() { + return [this.maxInt+1] + }, + + between(a, b, scale=100) { + // Strip zeros and find common length + const aLength = this.lengthWithoutZeros(a) + const bLength = this.lengthWithoutZeros(b) + const minLength = Math.min(aLength, bLength) + + // Initialize output + const out = [] + + // Find the break point where a[i] != b[i] + let i = 0 + while (i < minLength && a[i] == b[i]) { + out.push(a[i]) + i++ + } + + // Initialize upper and lower bounds for + // sampling the last digit + let lowerBound = 1 + let upperBound = this.maxInt + + if (i < minLength) { + // If the break happened before we hit + // the end of one of the arrays + + if (Math.abs(a[i] - b[i]) > 1) { + // If a[i] and b[i] are more than one + // away from each other, just sample + // between them + lowerBound = Math.min(a[i], b[i]) + 1 + upperBound = Math.max(a[i], b[i]) - 1 + } else { + // If they are one away no integers + // will fit in between, so add new layer + const lesser = (a[i] < b[i])? a : b + out.push(lesser[i]) + i++ + + while (i < lesser.length && lesser[i] >= this.maxInt) { + // If the lesser is at it's limit, + // we will need to add even more layers + out.push(lesser[i]) + i++ + } + + if (i < lesser.length) { + // Sample something greater than + // the lesser digit + lowerBound = lesser[i] + 1 + } + } + } else { + // The break happened because we hit + // the end of one of the arrays. + + if (aLength == bLength) { + // If they are entirely equal, + // there is nothing in between + // just return what we have + return out + } + + const longerLength = Math.max(aLength, bLength) + const longer = (a.length == longerLength)? a : b + while (i < longerLength && longer[i] == 0) { + // Skip past the zeros because we can't sample + // for digits less than zero + out.push(0) + i++ + } + + if (i < longerLength) { + if (longer[i] == 1) { + // If longer is at it's limit, + // we still need to add another layer + out.push(0) + } else { + upperBound = longer[i] - 1 + } + } + } + + // Create a random number in [0,1] but bias it to be small, + // so that numbers tend to increase by a small amount. + let random = Math.random() + random = -Math.log(1-random)/scale + random = Math.min(random, 1) + + // Finally, sample between the upper and lower bounds + out.push(Math.floor(random * (upperBound + 1 - lowerBound)) + lowerBound) + return out + }, + + compare(a, b) { + // Strip zeros and find common length + const aLength = this.lengthWithoutZeros(a) + const bLength = this.lengthWithoutZeros(b) + const minLength = Math.min(aLength, bLength) + + // See if there are any differences + for (let i = 0; i < minLength; i++) { + if (a[i] > b[i]) { + return 1 + } else if (a[i] < b[i]) { + return -1 + } + } + + // If they are all the same up til now, + // the longer one is bigger + if (aLength > bLength) { + return 1 + } else if (aLength < bLength) { + return -1 + } else { + return 0 + } + }, + + + lengthWithoutZeros(a) { + let length = a.length + while (length > 0 && a[length - 1] == 0) { + length-- + } + return length + }, + + maxInt: 9007199254740991, +} |