"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.SortedSegmentSet = void 0;
/**
 * Stores a unique and sorted set of segments, or objects with segments
 *
 * This differs from a normal sorted set in that the keys are not fixed.
 * The segments are sorted via their ordinals which can change as the merge tree is modified.
 * Even though the values of the ordinals can change their ordering and uniqueness cannot, so the order of a set of
 * segments ordered by their ordinals will always have the same order even if the ordinal values on
 * the segments changes. This invariant allows ensure the segments stay ordered and unique, and that new segments
 * can be inserted into that order.
 */
class SortedSegmentSet {
    constructor() {
        this.ordinalSortedItems = [];
    }
    get size() {
        return this.ordinalSortedItems.length;
    }
    get items() {
        return this.ordinalSortedItems;
    }
    addOrUpdate(newItem, update) {
        const position = this.findOrdinalPosition(this.getOrdinal(newItem));
        if (position.exists) {
            if (update) {
                update(this.ordinalSortedItems[position.index], newItem);
            }
        }
        else {
            this.ordinalSortedItems.splice(position.index, 0, newItem);
        }
    }
    remove(item) {
        const position = this.findOrdinalPosition(this.getOrdinal(item));
        if (position.exists) {
            this.ordinalSortedItems.splice(position.index, 1);
            return true;
        }
        return false;
    }
    has(item) {
        const position = this.findOrdinalPosition(this.getOrdinal(item));
        return position.exists;
    }
    getOrdinal(item) {
        const maybeObject = item;
        if (maybeObject === null || maybeObject === void 0 ? void 0 : maybeObject.segment) {
            return maybeObject.segment.ordinal;
        }
        const maybeSegment = item;
        return maybeSegment.ordinal;
    }
    findOrdinalPosition(ordinal, start, end) {
        if (this.ordinalSortedItems.length === 0) {
            return { exists: false, index: 0 };
        }
        if (start === undefined || end === undefined) {
            return this.findOrdinalPosition(ordinal, 0, this.ordinalSortedItems.length - 1);
        }
        const index = start + Math.floor((end - start) / 2);
        if (this.getOrdinal(this.ordinalSortedItems[index]) > ordinal) {
            if (start === index) {
                return { exists: false, index };
            }
            return this.findOrdinalPosition(ordinal, start, index - 1);
        }
        else if (this.getOrdinal(this.ordinalSortedItems[index]) < ordinal) {
            if (index === end) {
                return { exists: false, index: index + 1 };
            }
            return this.findOrdinalPosition(ordinal, index + 1, end);
        }
        return { exists: true, index };
    }
}
exports.SortedSegmentSet = SortedSegmentSet;
//# sourceMappingURL=sortedSegmentSet.js.map