UNPKG

mute-structs

Version:

NodeJS module providing an implementation of the LogootSplit CRDT algorithm

109 lines (105 loc) 3.8 kB
/* This file is part of MUTE-structs. Copyright (C) 2017 Matthieu Nicolas, Victorien Elvinger This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ import { isArrayFromMap, isObject } from "../data-validation"; import { Epoch } from "./epoch"; export function compareEpochFullIds(id1, id2) { const minLength = id1.length < id2.length ? id1.length : id2.length; for (let i = 0; i < minLength; i++) { const value1 = id1[i]; const value2 = id2[i]; if (value1 < value2) { return -1 /* Less */; } else if (value1 > value2) { return 1 /* Greater */; } } if (id1.length < id2.length) { return -1 /* Less */; } else if (id1.length > id2.length) { return 1 /* Greater */; } else { return 0 /* Equal */; } } export class EpochStore { constructor(origin) { this.epochs = new Map(); this.addEpoch(origin); } static fromPlain(o) { if (isObject(o) && Array.isArray(o.epochs) && o.epochs.length > 0) { const epochs = o.epochs .filter(isArrayFromMap) .map(([_, v]) => { return Epoch.fromPlain(v); }) .filter((epoch) => epoch !== null); if (o.epochs.length === epochs.length) { const [origin, ...rest] = epochs; const epochStore = new EpochStore(origin); rest.forEach((epoch) => { epochStore.addEpoch(epoch); }); return epochStore; } } return null; } addEpoch(epoch) { this.epochs.set(epoch.id.asStr, epoch); } hasEpoch(epoch) { return this.epochs.has(epoch.id.asStr); } getEpoch(epochId) { return this.epochs.get(epochId.asStr); } getEpochFullId(epoch) { console.assert(this.hasEpoch(epoch), "The epoch should have been added to the store previously"); let parentEpochFullId = []; if (epoch.parentId !== undefined) { const parentEpoch = this.getEpoch(epoch.parentId); if (parentEpoch !== undefined) { parentEpochFullId = this.getEpochFullId(parentEpoch); } } return parentEpochFullId.concat(epoch.id.replicaNumber, epoch.id.epochNumber); } getEpochPath(epoch) { const pathEpoch = []; let currentEpoch = epoch; while (currentEpoch !== undefined) { pathEpoch.push(currentEpoch); currentEpoch = currentEpoch.parentId !== undefined ? this.getEpoch(currentEpoch.parentId) : undefined; } return pathEpoch.reverse(); } getPathBetweenEpochs(from, to) { const fromPath = this.getEpochPath(from); const toPath = this.getEpochPath(to); let i = 0; while (i < fromPath.length && i < toPath.length && fromPath[i].equals(toPath[i])) { i++; } return [fromPath.slice(i).reverse(), toPath.slice(i)]; } toJSON() { return { epochs: Array.from(this.epochs) }; } } //# sourceMappingURL=epochstore.js.map