types_Int.mjs

import { create, copy, setStart, setEnd } from "./helpers/common.mjs";
import { compare, size as size_base } from "./IntNorm.mjs";

function size(r){
	let s = size_base(r);	
	if (r.startExcl) s--;
	if (r.endExcl) s--;
	return s;
}

/** Implementation of {@link RangeType} for integer values. You can use this to implement
 * any discrete {@link RangeType}, so long as you can map the values to the domain of integers.
 * 
 * Inputs for this type are [coerced to
 * numbers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_coercion)
 * prior to calculations.
 * @implements {RangeType}
 */
const IntType = {
	create,
	copy,
	setStart,
	setEnd,
	size,
	/** Exclusion is implemented by an increment or decrement to a neighboring integer: e.g. `[0,5)`
 	 * is equivalent to `[0,4]`. The distance between two integers is the signed count of integers
 	 * that lie between them: e.g. the distance from start-to-end of `[0,5]` is 4, and end-to-start
 	 * is -4.
	 */
	compare(mode, a, b, aExcl, bExcl){
		// normalize a/b to be inclusive first; exclusive start = +1, exclusive end = -1;
		// note we do (v = +v + ...) instead of (v += ...) to do explicit cast to number
		if (aExcl)
			a = +a + 1 - ((mode & 0b1) << 1);
		if (bExcl)
			b = +b + 1 - (mode & 0b10);
		return compare(mode, a, b);
	},
	*iterate(r, reverse){
		// using xor to possibly invert, and convert to number in single op;
		// it handles conversion of `undefined` values, where alternative is to cast to boolean first, then number
		if (reverse){
			let i = +r.end - (r.endExcl^0);
			const end = +r.start - (r.startExcl^1);
			for (; i > end; i--)
				yield i;
		}
		else{
			let i = +r.start + (r.startExcl^0);
			const end = +r.end + (r.endExcl^1);
			for (; i < end; i++)
				yield i;
		}
	},
	sample(r, i){
		// floor in inner portion for numerical stability;
		// can't use IntNorm.sample since we need to use Int.size
		return +r.start + (r.startExcl^0) + Math.floor(size(r)*i);
	}
};

const DateType = IntType;

export { IntType as default, DateType };