collection-abstraction/set

View on GitHub
src/_Set.js

Summary

Maintainability
D
2 days
Test Coverage
import {KeyError} from '@failure-abstraction/error';

export default function _Set(BaseSet) {
    /* eslint-disable no-use-extend-native/no-use-extend-native */
    const Set = function (iterable = null) {
        this.container = new BaseSet(iterable);
    };

    Set.wrap = function (A) {
        if (A instanceof Set) return A;

        return new Set(A);
    };

    Set._operator = function (method) {
        return function (...args) {
            return method.apply(this, Array.from(args, Set.wrap));
        };
    };

    Set._inclusion = function (A, B) {
        return A._ispropersubset(B) ? -1 : B._ispropersubset(A) ? 1 : 0;
    };

    Set.inclusion = Set._operator(Set._inclusion);

    // eslint-disable-next-line no-multi-assign
    Set.prototype[Symbol.iterator] = Set.prototype.keys = function* () {
        yield* this.container;
    };

    Set.prototype.len = function () {
        return this.container.size;
    };

    Set.prototype.has = function (key) {
        return this.container.has(key);
    };

    Set.prototype._isdisjoint = function (other) {
        return this._commonkeys(other).next().done;
    };

    Set.prototype.isdisjoint = Set._operator(Set.prototype._isdisjoint);

    Set.prototype._isequal = function (other) {
        return this._issubset(other) && other._issubset(this);
    };

    Set.prototype.isequal = Set._operator(Set.prototype._isequal);

    Set.prototype._issubset = function (other) {
        if (this.len() > other.len()) return false;

        for (const key of this) if (!other.has(key)) return false;

        return true;
    };

    Set.prototype.issubset = Set._operator(Set.prototype._issubset);

    Set.prototype._ispropersubset = function (other) {
        return this._issubset(other) && !this._issuperset(other);
    };

    Set.prototype.ispropersubset = Set._operator(Set.prototype._ispropersubset);

    Set.prototype._issuperset = function (other) {
        return other._issubset(this);
    };

    Set.prototype.issuperset = Set._operator(Set.prototype._issuperset);

    Set.prototype._ispropersuperset = function (other) {
        return this._issuperset(other) && !this._issubset(other);
    };

    Set.prototype.ispropersuperset = Set._operator(
        Set.prototype._ispropersuperset,
    );

    // eslint-disable-next-line no-multi-assign
    Set.prototype.union = Set.prototype._union = function (...others) {
        return this.copy()._update(...others);
    };

    Set.prototype._commonkeys = function* (...others) {
        // eslint-disable-next-line no-labels
        keys: for (const key of this) {
            for (const other of others) {
                // eslint-disable-next-line no-labels
                if (!other.has(key)) continue keys;
            }

            yield key;
        }
    };

    Set.prototype._intersection = function (...others) {
        return new Set(this._commonkeys(...others));
    };

    Set.prototype.intersection = Set._operator(Set.prototype._intersection);

    // eslint-disable-next-line no-multi-assign
    Set.prototype.difference = Set.prototype._difference = function (...others) {
        return this.copy()._difference_update(...others);
    };

    // eslint-disable-next-line no-multi-assign
    Set.prototype.symmetric_difference = Set.prototype._symmetric_difference =
        function (other) {
            return this.copy()._symmetric_difference_update(other);
        };

    Set.prototype.copy = function () {
        return new Set(this);
    };

    // eslint-disable-next-line no-multi-assign
    Set.prototype.update = Set.prototype._update = function (...others) {
        for (const other of others) {
            for (const key of other) this.add(key);
        }

        return this;
    };

    Set.prototype._intersection_update = function (...others) {
        const intersection = this._intersection(...others);

        this.clear().update(intersection);

        return this;
    };

    Set.prototype.intersection_update = Set._operator(
        Set.prototype._intersection_update,
    );

    // eslint-disable-next-line no-multi-assign
    Set.prototype.difference_update = Set.prototype._difference_update =
        function (...others) {
            for (const other of others) {
                for (const key of other) this.discard(key);
            }

            return this;
        };

    Set.prototype.symmetric_difference_update =
        // eslint-disable-next-line no-multi-assign
        Set.prototype._symmetric_difference_update = function (other) {
            for (const key of other) {
                if (this.has(key)) this.discard(key);
                else this.add(key);
            }

            return this;
        };

    Set.prototype.add = function (key) {
        this.container.add(key);

        return this;
    };

    Set.prototype.remove = function (key) {
        if (!this.container.delete(key)) throw new KeyError();

        return this;
    };

    Set.prototype.discard = function (key) {
        this.container.delete(key);

        return this;
    };

    Set.prototype.pop = function () {
        if (this.len() === 0) throw new KeyError();

        const key = this.keys().next().value;

        this.discard(key);

        return key;
    };

    Set.prototype.clear = function () {
        this.container.clear();

        return this;
    };

    return Set;
    /* eslint-enable no-use-extend-native/no-use-extend-native */
}