From 4306b2220cdb94d14deef83cad66530f48c14b36 Mon Sep 17 00:00:00 2001 From: ge Date: Tue, 30 Dec 2025 12:19:35 +0300 Subject: [PATCH] breaking,fix: remove range exclusivity support The usefulness of this feature is questionable, and its correct implementation is difficult due to the use of generics. The implementation worked incorrectly in cases where the iterator step is not equal to one and is not a multiple of the end element. For example, for `range(0, 7, 4)`, the result is `[0]` instead of `[0, 4]`. After this commit range end value is always included. To check for multiples, a user-defined type must also implement an overload of the remainder operator (`%`), even if the exclusivity function is not needed. Another correct implementation requires subtracting one from the end element for integers and the minimum fractional part supported by the type for floats. This cannot be done correctly for generics, as it requires casting the literal to a specific type, and we cannot cast number to any type. --- ranges.v | 23 +++++------------------ ranges_test.v | 24 ------------------------ 2 files changed, 5 insertions(+), 42 deletions(-) diff --git a/ranges.v b/ranges.v index af2a04e..6d81ef7 100644 --- a/ranges.v +++ b/ranges.v @@ -22,30 +22,18 @@ pub fn (mut r Range[T]) next() ?T { return r.cur } -@[params] -pub struct RangeConfig { -pub: - // If true exclude the end value from range. - exclusive bool -} - // range creates new Range iterator with given start, end and step values. // // Generally numbers are expected. If type is a struct the following operators // must be overloaded to perform comparisons and arithmetics: `+`, `-`, `<`, `==`. // See https://docs.vlang.io/limited-operator-overloading.html for details. // -// By default, the range includes the end value. This behavior can be changed -// by enabling the 'exclusive' option. +// The range includes the end value. // // Note: Zero step value will cause an infitite loop! -pub fn range[T](start T, end T, step T, config RangeConfig) Range[T] { - mut limit := end - if config.exclusive { - limit -= step - } +pub fn range[T](start T, end T, step T) Range[T] { return Range[T]{ - limit: limit + limit: end step: step cur: start is_neg: start > end @@ -54,7 +42,6 @@ pub fn range[T](start T, end T, step T, config RangeConfig) Range[T] { @[params] pub struct RangeFromStringConfig { - RangeConfig pub: sep string = '-' group_sep string = ',' @@ -92,7 +79,7 @@ pub fn from_string[T](s string, config RangeFromStringConfig) ![]Range[T] { convert_string[T](range_str[0])!, convert_string[T](range_str[1])!, convert_string[T](range_str[2])!, - config.RangeConfig) + ) // vfmt on } return result @@ -133,7 +120,7 @@ pub fn from_string_custom[T](s string, conv StringConvertFn[T], config RangeFrom start := conv[T](range_str[0])! end := conv[T](range_str[1])! step := conv[T](range_str[2])! - result << range(start, end, step, config.RangeConfig) + result << range(start, end, step) } return result } diff --git a/ranges_test.v b/ranges_test.v index 03ccc58..4f6efe1 100644 --- a/ranges_test.v +++ b/ranges_test.v @@ -9,14 +9,6 @@ fn test_range() { assert result == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } -fn test_range_exclusive() { - mut result := []int{} - for i in ranges.range[int](0, 10, 1, exclusive: true) { - result << i - } - assert result == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] -} - fn test_range_negative() { mut result := []int{} for i in ranges.range[int](10, 0, -1) { @@ -25,14 +17,6 @@ fn test_range_negative() { assert result == [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] } -fn test_range_negative_exclusive() { - mut result := []int{} - for i in ranges.range[int](10, 0, -1, exclusive: true) { - result << i - } - assert result == [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] -} - fn test_range_with_step() { mut result := []int{} for i in ranges.range[int](0, 10, 2) { @@ -65,14 +49,6 @@ fn test_range_single_item() { assert result == [0] } -fn test_range_single_item_exclusive() { - mut result := []int{} - for i in ranges.range(0, 1, 1, exclusive: true) { - result << i - } - assert result == [0] -} - fn test_range_bigint() { start := big.zero_int end := big.integer_from_int(5)