// This file mainly just holds range interface definition
/** Interface that all Range objects must implement
* @interface Range
*/
/** Start of range
* @name Range#start
* @type {any}
*/
/** End of range
* @name Range#end
* @type {any}
*/
/** Whether {@link Range#start} is exclusive; if undefined or null, it defaults to inclusive
* @name Range#startExcl
* @type {?boolean}
*/
/** Whether {@link Range#end} is exclusive; if undefined or null, it defaults to inclusive
* @name Range#endExcl
* @type {?boolean}
*/
/** Indicates the index into {@link RangeGroup#ranges}, for which this range was sourced from during
* a boolean set operation. This is set from {@link RangeGroup#diff} if the `track_sources` option
* is enabled. A value of `null` indicates the range was not present in group `a`.
* @name Range#a
* @type {?number}
*/
/** Indicates the index into {@link RangeGroup#ranges}, for which this range was sourced from during
* a boolean set operation. This is set from {@link RangeGroup#diff} if the `track_sources` option
* is enabled. A value of `null` indicates the range was not present in group `b`.
* @name Range#b
* @type {?number}
*/
/** Generic range type interface for use with {@link RangeGroup}. This provides all the definitions
* for creating and manipulating a {@link Range}. An important design choice was to allow ranges to
* be defined with plain JSON objects. Because of this, {@link RangeType} provide a C-like interface
* for performing operations on those objects, rather than forcing a class based design. You can
* still use a class to implement a particular type of {@link Range}; if going that route, you'll
* supply a supplementary {@link RangeType} to {@link RangeGroup}, where you are simply calling the
* class methods.
* @interface RangeType
*/
// TODO: maybe have create perform this.copy(args[0]) if only one argument?
/** Create a new {@link Range} object. If no arguments are passed, an empty/default range should
* be created. Otherwise, a new range should be initialized using the arguments passed. The form
* of these arguments is up to the {@link RangeType}.
* @function
* @static
* @name RangeType.create
* @param {...any} args arguments to initialize the range
* @returns {Range} the newly created range
*/
/** Copy a {@link Range} of this {@link RangeType}
* @function
* @static
* @name RangeType.copy
* @param {Range} range the range to be copied
* @returns {Range} copied range
*/
/** Return the size, or cardinality of this range. This is called by {@link RangeGroup#size}
* @function
* @static
* @name RangeType.size
* @param {Range} range the range to retrieve the size of
* @returns {number} the range size
*/
/** Result of {@link RangeType.compare}
* @typedef {object} RangeType~CompareResult
* @prop {number} distance The signed distance between `a` and `b`. For continuous domains, this is
* a traditional distance measure, e.g. `a - b` for numbers. For discrete domains, it should
* measure the number of elements **in between** `a` and `b`; e.g. for integers, the distance
* between 3 and 5 is 1, since only one integer, 4, is between.
*
* The `distance` is used for several things:
* 1. To merge adjacent ranges if the distance (or gap) between them is zero. For example, the
* integer ranges `[0,2] [3,5]` or floating point ranges `[0,3) [3,5]` could be merged as
* `[0,5]`. Another case might be, `[-2,-0] [+0,3]` which can be merged as `[-2,3]`.
* 2. To perform interpolation search in {@link RangeGroup#search}. You can opt-out of interpolation
* search by returning the sign of distance (-1, 0, or +1); this causes the search to reduce
* to binary search instead. See {@link CommonType.compareBinarySearch} for a decorator which
* does this.
* @prop {number} side One of the following:
* - `-1`: `a` comes before `b`
* - `0`: `a` equals `b` exactly; signed zero `-0` is also fine here
* - `1`: `a` comes after `b`
*/
/** Compares two start/end boundaries.
*
* The comparison function should return a tuple, which is a little different than what you might
* use with `Array.prototype.sort`. This is to allow proper handling of exclusive bounds. As an
* example, consider the gap between ranges `[0,5) [5,10]`: the distance between the ranges is
* infinitely small, but not quite equal. So in this case, the compare function returns
* `{distance:0, side:-1}`, to indicate zero gap approaching from the left. See
* {@link RangeType~CompareResult} for more details.
* @function
* @static
* @name RangeType.compare
* @param {ComparisonModes} mode What combination of range starts/ends is being compared. See
* documentation for {@link ComparisonModes} for the specific enumeration values, or for details
* on using it as a bitmask instead. This allows you to properly handle exclusive bounds for start
* vs end.
* @param {any} a The {@link Range#start} or {@link Range#end} to be compared
* @param {any} b The {@link Range#start} or {@link Range#end} to compare with
* @param {?boolean} aExcl Whether `a` is an exclusive bound
* @param {?boolean} bExcl Whether `b` is an exclusive bound
* @returns {RangeType~CompareResult}
*/
/** Iterate values inside the range. This is called by {@link RangeGroup#iterate}, and should be
* implemented if the type wishes to support that method.
* @function
* @name RangeType.iterate
* @param {?boolean} reverse Whether values should be iterated forward or backward. The ordering is
* up to the {@link RangeType}, but in general *forward* should correspond to *ascending* order.
* @param {...any} args Arbitrary arguments used to customize the iteration. These are forwarded
* from {@link RangeGroup#iterate}
* @returns {iterable} Can return a generator, or some other object implementing the iterable
* interface
*/
/** Set the starting bound of a {@link Range}. Range starts are always modified using this method,
* so that a {@link RangeType} can implement *auto-normalization*: normalizing the bound to be
* inclusive.
* @function
* @name RangeType.setStart
* @param {Range} range the range to modify
* @param {any} start the starting bound
* @param {?boolean} startExcl whether the start is exclusive
* @returns {Range} the modified range
*/
/** Set the ending bound of a {@link Range}. Range ends are always modified using this method,
* so that a {@link RangeType} can implement *auto-normalization*: normalizing the bound to be
* inclusive.
* @function
* @name RangeType.setEnd
* @param {Range} range the range to modify
* @param {any} end the new ending bound
* @param {?boolean} endExcl whether the end is exclusive
* @returns {Range} the modified range
*/
/** Draw a sample from a {@link Range}. This is used by {@link Sampler}
* @function
* @name RangeType.sample
* @param {Range} range the range to sample from
* @param {number} i a float between [0,1) indicating what sample to return
* @returns {Range} a sample drawn from `range`
*/