mirror of
https://github.com/gechandesu/ranges.git
synced 2026-01-23 23:04:14 +03:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 39314b474b | |||
| 06f85c48d3 | |||
| 74e92c77ab | |||
| b51f74a877 | |||
| b1eaeee6f0 | |||
| 899dacba7a | |||
| 4306b2220c |
@@ -3,7 +3,7 @@
|
|||||||
The `ranges` module provides tools for creating ranges of numbers.
|
The `ranges` module provides tools for creating ranges of numbers.
|
||||||
|
|
||||||
Ranges are represented by the generic `Range` iterator, which has start and
|
Ranges are represented by the generic `Range` iterator, which has start and
|
||||||
end points, a step size, and an inclusive/exclusive flag.
|
end points and a step size.
|
||||||
|
|
||||||
```v
|
```v
|
||||||
import ranges
|
import ranges
|
||||||
|
|||||||
42
ranges.v
42
ranges.v
@@ -4,7 +4,8 @@ import strconv
|
|||||||
import math.big
|
import math.big
|
||||||
|
|
||||||
struct Range[T] {
|
struct Range[T] {
|
||||||
limit T
|
start T
|
||||||
|
end T
|
||||||
step T
|
step T
|
||||||
is_neg bool
|
is_neg bool
|
||||||
mut:
|
mut:
|
||||||
@@ -13,7 +14,7 @@ mut:
|
|||||||
|
|
||||||
// next returns the new element from range or none if range end is reached.
|
// next returns the new element from range or none if range end is reached.
|
||||||
pub fn (mut r Range[T]) next() ?T {
|
pub fn (mut r Range[T]) next() ?T {
|
||||||
if (r.is_neg && r.cur < r.limit) || (!r.is_neg && r.cur > r.limit) {
|
if (r.is_neg && r.cur < r.end) || (!r.is_neg && r.cur > r.end) {
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
defer {
|
defer {
|
||||||
@@ -22,11 +23,19 @@ pub fn (mut r Range[T]) next() ?T {
|
|||||||
return r.cur
|
return r.cur
|
||||||
}
|
}
|
||||||
|
|
||||||
@[params]
|
// reset resets the internal iterator state to its initial value, after which the iterator can be reused.
|
||||||
pub struct RangeConfig {
|
// Note: `for i in iter {` does not modify the internal iterator state, but direct `next()` call does.
|
||||||
pub:
|
pub fn (mut r Range[T]) reset() {
|
||||||
// If true exclude the end value from range.
|
r.cur = r.start
|
||||||
exclusive bool
|
}
|
||||||
|
|
||||||
|
// with_step returns copy of the range with new step value.
|
||||||
|
pub fn (r Range[T]) with_step[T](step T) Range[T] {
|
||||||
|
return Range[T]{
|
||||||
|
...r
|
||||||
|
step: step
|
||||||
|
cur: r.start
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// range creates new Range iterator with given start, end and step values.
|
// range creates new Range iterator with given start, end and step values.
|
||||||
@@ -35,17 +44,13 @@ pub:
|
|||||||
// must be overloaded to perform comparisons and arithmetics: `+`, `-`, `<`, `==`.
|
// must be overloaded to perform comparisons and arithmetics: `+`, `-`, `<`, `==`.
|
||||||
// See https://docs.vlang.io/limited-operator-overloading.html for details.
|
// See https://docs.vlang.io/limited-operator-overloading.html for details.
|
||||||
//
|
//
|
||||||
// By default, the range includes the end value. This behavior can be changed
|
// The range includes the end value.
|
||||||
// by enabling the 'exclusive' option.
|
|
||||||
//
|
//
|
||||||
// Note: Zero step value will cause an infitite loop!
|
// Note: Zero step value will cause an infitite loop!
|
||||||
pub fn range[T](start T, end T, step T, config RangeConfig) Range[T] {
|
pub fn range[T](start T, end T, step T) Range[T] {
|
||||||
mut limit := end
|
|
||||||
if config.exclusive {
|
|
||||||
limit -= step
|
|
||||||
}
|
|
||||||
return Range[T]{
|
return Range[T]{
|
||||||
limit: limit
|
start: start
|
||||||
|
end: end
|
||||||
step: step
|
step: step
|
||||||
cur: start
|
cur: start
|
||||||
is_neg: start > end
|
is_neg: start > end
|
||||||
@@ -54,7 +59,6 @@ pub fn range[T](start T, end T, step T, config RangeConfig) Range[T] {
|
|||||||
|
|
||||||
@[params]
|
@[params]
|
||||||
pub struct RangeFromStringConfig {
|
pub struct RangeFromStringConfig {
|
||||||
RangeConfig
|
|
||||||
pub:
|
pub:
|
||||||
sep string = '-'
|
sep string = '-'
|
||||||
group_sep string = ','
|
group_sep string = ','
|
||||||
@@ -65,7 +69,7 @@ pub:
|
|||||||
// Use from_string_custom if you want to use custom type with special string
|
// Use from_string_custom if you want to use custom type with special string
|
||||||
// convertion rules.
|
// convertion rules.
|
||||||
//
|
//
|
||||||
// Supported string formats are `start-end`, `start[:step]end`. start and end
|
// Supported string formats are `start-end` and `start[:step]end`. start and end
|
||||||
// values are sepatared by 'sep' which is hypen (`-`) by default. Single number
|
// values are sepatared by 'sep' which is hypen (`-`) by default. Single number
|
||||||
// will be interpreted as range of one element. Several ranges can be specified
|
// will be interpreted as range of one element. Several ranges can be specified
|
||||||
// in a line, separated by 'group_sep' (comma by default). 'sep' and 'group_sep'
|
// in a line, separated by 'group_sep' (comma by default). 'sep' and 'group_sep'
|
||||||
@@ -92,7 +96,7 @@ pub fn from_string[T](s string, config RangeFromStringConfig) ![]Range[T] {
|
|||||||
convert_string[T](range_str[0])!,
|
convert_string[T](range_str[0])!,
|
||||||
convert_string[T](range_str[1])!,
|
convert_string[T](range_str[1])!,
|
||||||
convert_string[T](range_str[2])!,
|
convert_string[T](range_str[2])!,
|
||||||
config.RangeConfig)
|
)
|
||||||
// vfmt on
|
// vfmt on
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@@ -133,7 +137,7 @@ pub fn from_string_custom[T](s string, conv StringConvertFn[T], config RangeFrom
|
|||||||
start := conv[T](range_str[0])!
|
start := conv[T](range_str[0])!
|
||||||
end := conv[T](range_str[1])!
|
end := conv[T](range_str[1])!
|
||||||
step := conv[T](range_str[2])!
|
step := conv[T](range_str[2])!
|
||||||
result << range(start, end, step, config.RangeConfig)
|
result << range(start, end, step)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,6 @@ fn test_range() {
|
|||||||
assert result == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
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() {
|
fn test_range_negative() {
|
||||||
mut result := []int{}
|
mut result := []int{}
|
||||||
for i in ranges.range[int](10, 0, -1) {
|
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]
|
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() {
|
fn test_range_with_step() {
|
||||||
mut result := []int{}
|
mut result := []int{}
|
||||||
for i in ranges.range[int](0, 10, 2) {
|
for i in ranges.range[int](0, 10, 2) {
|
||||||
@@ -65,14 +49,6 @@ fn test_range_single_item() {
|
|||||||
assert result == [0]
|
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() {
|
fn test_range_bigint() {
|
||||||
start := big.zero_int
|
start := big.zero_int
|
||||||
end := big.integer_from_int(5)
|
end := big.integer_from_int(5)
|
||||||
@@ -169,3 +145,36 @@ fn test_range_from_string_custom_type() {
|
|||||||
sep: '..'
|
sep: '..'
|
||||||
)! == [ranges.range[Int](Int{0}, Int{10}, Int{1})]
|
)! == [ranges.range[Int](Int{0}, Int{10}, Int{1})]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_range_reset() {
|
||||||
|
mut result := []int{}
|
||||||
|
mut iter := ranges.range(0, 5, 1)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if elem := iter.next() {
|
||||||
|
result << elem
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert result == [0, 1, 2, 3, 4, 5]
|
||||||
|
|
||||||
|
iter.reset()
|
||||||
|
|
||||||
|
result = []int{}
|
||||||
|
|
||||||
|
for i in iter {
|
||||||
|
result << i
|
||||||
|
}
|
||||||
|
assert result == [0, 1, 2, 3, 4, 5]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_range_new_with_step() {
|
||||||
|
mut result := []int{}
|
||||||
|
mut iter := ranges.range(0, 5, 1)
|
||||||
|
|
||||||
|
for i in iter.with_step(2) {
|
||||||
|
result << i
|
||||||
|
}
|
||||||
|
assert result == [0, 2, 4]
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user