All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Unsigned backward-inclusive to zero no longer underflows.
NewNumberRange[uint](0, StartAt[uint](5), Inclusive[uint]())previously computedend - 1on unsigned zero, wrapped toMaxUint, flipped direction, and produced a 10M-element forward garbage slice. It now returns[5 4 3 2 1 0]. Regression locked in byTest_UnsignedInclusiveBackwardToZero. - Signed inclusive ranges at the type's extrema no longer wrap.
NewNumberRange[int8](127, StartAt[int8](125), Inclusive[int8]())previously computedend + 1onint8(127), wrapped to-128, and produced backward garbage. The mirror case atint8(-128)had the same bug. Both now produce the expected terminal-inclusive result. Theuint8(255)forward case is also covered. Regressions locked in byTest_SignedInclusiveForwardAtMaxT,Test_SignedInclusiveBackwardAtMinT, andTest_UnsignedInclusiveForwardAtMaxT. - Negative step is now coerced to
abs(step)instead of silently returning[0]. Direction is derived fromstartvsend, never from the sign ofstep. Consistent with the existing zero-step coercion. Regression locked in byTest_NegativeStepCoercedToAbs.
calculateActualEndis gone. The inclusive flag now flows directly intogenerateForwardRange/generateBackwardRange, which decide continuation via!(i <= end)/!(i >= end). The!(...)form is deliberate — it preserves NaN-safe termination because every comparison with NaN evaluates to false, whereas the De Morgan rewritei > endwould not terminate. Astaticcheck -QF1001exclusion in.golangci.ymldocuments this.- NaN step is now rejected at the top of
NewNumberRange, before any arithmetic. The package doc previously claimed this but the check lived inside the generators. Doc and behavior now agree. - Every empty-result path returns a non-nil
[]T{}. Previously some paths returnedniland others returned[]T{}, makingreflect.DeepEqualcomparisons flaky depending on which branch fired. Regression locked in byTest_EmptyPathsAreNonNiland an updatedTest_ProgressGuard_NaN. - Result slices are now preallocated to a capacity estimate computed in
float64space and clamped toMaxElements. Benchmarks show allocs/op dropped to 2 across all range sizes (one config pointer, one slice) with no intermediate grow-reallocs. isDegenerateStepis renamed toisNaN— the old name implied defenses against a broader class of degenerate values than it actually provided.
MaxElements(exported constant, value10_000_000). Callers who need to distinguish natural termination from cap truncation can now pre-check their bounds against this constant. The constant's contract is verified directly byTest_MaxElementsCapFires, which fires the cap on a well-formed finite input rather than relying on a+Infside effect.- Regression / coverage tests for the unsigned path,
float32,~-aliased integer types (type Port uint16), and repeated-option last-wins semantics. The unsigned andfloat32paths had no direct coverage before. - Float benchmark, progress-guard benchmark, and
b.ReportAllocson every benchmark. A refactor that reintroduces per-iteration allocation now shows up in the diff as an allocs/op change.
.golangci.ymldepguard rule now allows the package under test to be imported from_test.gofiles. Previously the black-boxnum_testpackage tripped depguard; this was pre-existing but never blocked anything because the failure was on a path CI was not yet running strictly.
NewNumberRange[T Numeric](end T, opts ...RangeOption[T]) []T— generate a slice of numbers with ergonomic options.StartAt[T](start T) RangeOption[T]— set the starting value of the range.StepBy[T](step T) RangeOption[T]— set the step size. A zero step is silently replaced with 1 to prevent infinite loops.Inclusive[T]() RangeOption[T]— include the end value in the range.Numerictype constraint — local union of all integer and floating-point types (and their~-underlying type aliases), replacing a previous dependency ongolang.org/x/exp/constraints.- Forward, backward, inclusive, exclusive, float-step, and negative-range coverage.
- DoS guards on
NewNumberRange: 10-million element iteration cap, NaN step rejection, and per-iteration progress check. These bound worst-case memory and runtime even for hostile float inputs (NaN, Inf, precision-exhausted step). Regression tests lock each guard in place. - Zero external dependencies; benchmarks for every path.
- Go 1.21 or later