UNPKG

itclocks

Version:

An implementation of Interval Tree Clocks in TypeScript

150 lines (149 loc) 5.72 kB
"use strict"; /** * Copyright (C) 2017 Gabriel Batista Galli * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ Object.defineProperty(exports, "__esModule", { value: true }); /** * Reasons about the order of two events. */ class Causality { static lift(e) { return e.isLeaf() ? 0 : e.value; } static tryLeft(e) { return e.isLeaf() ? e : e.left; } static tryRight(e) { return e.isLeaf() ? e : e.right; } /** * Less than-equal operator for causality: either e1 happens before e2 or e1 * equals e2. * * @param offset1 The accumulated lifted value for occurrence e1. * @param e1 The first occurrence being compared. * @param offset2 The accumulated lifted value for occurrence e2 * @param e2 The second occurrence being compared. * @return Returns if e1 is precedes or equals e2. */ static lessThanEquals(offset1, e1, offset2, e2) { let new_a = offset1 + e1.value; if (e1.isLeaf()) return new_a <= offset2 + e2.value; let new_b = Causality.lift(e2) + offset2; if (!Causality.lessThanEquals(new_a, e1.left, new_b, Causality.tryLeft(e2))) return false; return Causality.lessThanEquals(new_a, e1.right, new_b, Causality.tryRight(e2)); } static isUnordered(o) { return o === Order.EQUALS || o === Order.UNCOMPARABLE; } /** * Compose two causality events. */ static compose(c1, c2) { switch (c1) { case Order.EQUALS: return c2; case Order.UNCOMPARABLE: return Order.UNCOMPARABLE; case Order.HAPPENS_BEFORE: { switch (c2) { case Order.HAPPENS_BEFORE: case Order.EQUALS: return Order.HAPPENS_BEFORE; default: return Order.UNCOMPARABLE; } } default: { switch (c2) { case Order.HAPPENS_AFTER: case Order.EQUALS: return Order.HAPPENS_AFTER; default: return Order.UNCOMPARABLE; } } } } /** * Base case of comparison. */ static compare0(offset, e1, e2) { if (e1.value < e2.value) return Causality.lessThanEquals(offset, e1, offset, e2) ? Order.HAPPENS_BEFORE : Order.UNCOMPARABLE; if (e1.value > e2.value) return Causality.lessThanEquals(offset, e2, offset, e1) ? Order.HAPPENS_AFTER : Order.UNCOMPARABLE; // Since one of the events is a leaf occurrence, then only one leq is called. if (Causality.lessThanEquals(offset, e1, offset, e2)) { if (Causality.lessThanEquals(offset, e2, offset, e1)) return Order.EQUALS; return Order.HAPPENS_BEFORE; } if (Causality.lessThanEquals(offset, e2, offset, e1)) return Order.HAPPENS_AFTER; return Order.UNCOMPARABLE; } /** * Checks if a given occurrence happens-before (LT), happens-after (GT), equals, * or is undefined */ static compare(offset, e1, e2) { if (e1.value != e2.value || e1.isLeaf() || e2.isLeaf()) return Causality.compare0(offset, e1, e2); let newOffset = offset + e1.value; return Causality.compose(Causality.compare(newOffset, e1.left, e2.left), Causality.compare(newOffset, e1.right, e2.right)); } /** * Check if timestamp {@code s1} happens before or equals to timestamp {@code s2} */ static stampLessThanEquals(s1, s2) { return Causality.occurrenceLessThanEquals(s1.occurrence, s2.occurrence); } /** * Check if occurrence {@code e1} precedes or equals occurrence {@code e2} */ static occurrenceLessThanEquals(e1, e2) { return Causality.lessThanEquals(0, e1, 0, e2); } /** * Checks if this occurrence is concurrent with {@code e}. If * {@code e1.isConcurrent(e2)}, then {@code e2.isConcurrent(e1)}. * * @param other The occurrence this object is being compared against. * @return */ static isConcurrent(e1, e2) { return Causality.isUnordered(Causality.compare(0, e1, e2)); } /** * Checks if this occurrence happened before the other. If neither occurrence happened * before the other, we say that they are concurrent. */ static stampHappensBefore(s1, s2) { return Causality.happensBefore(s1.occurrence, s2.occurrence); } /** * Checks if this occurrence happened before the other. If neither occurrence happened * before the other, we say that they are concurrent. */ static happensBefore(e1, e2) { return Causality.compare(0, e1, e2) == Order.HAPPENS_BEFORE; } }