mute-structs
Version:
NodeJS module providing an implementation of the LogootSplit CRDT algorithm
178 lines (174 loc) • 6.79 kB
JavaScript
/*
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 { isObject } from "./data-validation";
import { isSorted } from "./helpers";
import { Identifier } from "./identifier";
import { isInt32 } from "./int32";
/**
* Define an interval between two identifiers sharing the same base
*/
var IdentifierInterval = /** @class */ (function () {
// Creation
function IdentifierInterval(idBegin, end) {
console.assert(isInt32(end), "end ∈ int32");
console.assert(idBegin.lastOffset <= end, "idBegin must be less than or equal to idEnd");
this.idBegin = idBegin;
this.end = end;
}
IdentifierInterval.fromPlain = function (o) {
if (isObject(o) && isInt32(o.end)) {
var idBegin = Identifier.fromPlain(o.idBegin);
if (idBegin !== null && idBegin.lastOffset <= o.end) {
return new IdentifierInterval(idBegin, o.end);
}
}
return null;
};
/**
* Merge as much as possible Identifiers contained into an array into IdentifierIntervals
*
* @param {Identifier[]} ids The array of Identifiers
* @return {IdentifierInterval[]} The corresponding array of IdentifierIntervals
*/
IdentifierInterval.mergeIdsIntoIntervals = function (ids) {
var compareIdsFn = function (id, other) { return id.compareTo(other); };
console.assert(isSorted(ids, compareIdsFn), "The array should be sorted");
var res = [];
if (ids.length > 0) {
var idBegin = ids[0];
for (var i = 1; i < ids.length; i++) {
var prevId = ids[i - 1];
var id = ids[i];
if (!prevId.equalsBase(id) || prevId.lastOffset + 1 !== id.lastOffset) {
var idInterval = new IdentifierInterval(idBegin, prevId.lastOffset);
res.push(idInterval);
idBegin = id;
}
}
var lastId = ids[ids.length - 1];
var lastIdInterval = new IdentifierInterval(idBegin, lastId.lastOffset);
res.push(lastIdInterval);
}
return res;
};
Object.defineProperty(IdentifierInterval.prototype, "begin", {
/**
* Shortcut to retrieve the offset of the last tuple of idBegin
* This offset also corresponds to the beginning of the interval
*
* @return {number} The offset
*/
get: function () {
return this.idBegin.lastOffset;
},
enumerable: true,
configurable: true
});
Object.defineProperty(IdentifierInterval.prototype, "idEnd", {
/**
* Shortcut to retrieve the last identifier of the interval
*
* @return {Identifier} The last identifier of the interval
*/
get: function () {
return this.getBaseId(this.end);
},
enumerable: true,
configurable: true
});
Object.defineProperty(IdentifierInterval.prototype, "length", {
/**
* Shortcut to compute the length of the interval
*
* @return {number} The length
*/
get: function () {
return this.end - this.begin + 1;
},
enumerable: true,
configurable: true
});
Object.defineProperty(IdentifierInterval.prototype, "base", {
get: function () {
return this.idBegin.base;
},
enumerable: true,
configurable: true
});
Object.defineProperty(IdentifierInterval.prototype, "dot", {
get: function () {
return this.idBegin.dot;
},
enumerable: true,
configurable: true
});
IdentifierInterval.prototype.equals = function (aOther) {
return this.idBegin.equals(aOther.idBegin) &&
this.begin === aOther.begin && this.end === aOther.end;
};
/**
* Compute the union between this interval and [aBegin, aEnd]
*
* @param {number} aBegin
* @param {number} aEnd
* @return {IdentifierInterval} this U [aBegin, aEnd]
*/
IdentifierInterval.prototype.union = function (aBegin, aEnd) {
console.assert(isInt32(aBegin), "aBegin ∈ int32");
console.assert(isInt32(aEnd), "aEnd ∈ int32");
var minBegin = Math.min(this.begin, aBegin);
var maxEnd = Math.max(this.end, aEnd);
var newIdBegin = Identifier.fromBase(this.idBegin, minBegin);
return new IdentifierInterval(newIdBegin, maxEnd);
};
/**
* Check if the provided identifier belongs to this interval
*
* @param {Identifier} id
* @return {boolean} Does the identifier belongs to this interval
*/
IdentifierInterval.prototype.containsId = function (id) {
return this.idBegin.compareTo(id) === -1 /* Less */ &&
this.idEnd.compareTo(id) === 1 /* Greater */;
};
/**
* Retrieve a identifier from the interval from its offset
*
* @param {number} offset The offset of the identifier
* @return {Identifier} The identifier
*/
IdentifierInterval.prototype.getBaseId = function (offset) {
console.assert(isInt32(offset), "offset ∈ int32");
console.assert(this.begin <= offset && offset <= this.end, "offset must be included in the interval");
return Identifier.fromBase(this.idBegin, offset);
};
IdentifierInterval.prototype.digest = function () {
// '| 0' converts to 32bits integer
return (this.idBegin.digest() * 17 + this.end) | 0;
};
IdentifierInterval.prototype.toIds = function () {
var res = [];
for (var i = this.begin; i <= this.end; i++) {
res.push(Identifier.fromBase(this.idBegin, i));
}
return res;
};
IdentifierInterval.prototype.toString = function () {
return "IdInterval[" + this.idBegin.tuples.join(",") + " .. " + this.end + "]";
};
return IdentifierInterval;
}());
export { IdentifierInterval };
//# sourceMappingURL=identifierinterval.js.map