summaryrefslogtreecommitdiff
path: root/src/logoot.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/logoot.js')
-rw-r--r--src/logoot.js153
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,
+}