diff --git a/ranges/typedranges.nim b/ranges/typedranges.nim index fbe6d14..7e109ac 100644 --- a/ranges/typedranges.nim +++ b/ranges/typedranges.nim @@ -9,7 +9,7 @@ type when rangesGCHoldEnabled: gcHold: seq[T] start: ptr T - mLen: int32 + mLen: int # A view into mutable array MutRange*[T] = distinct Range[T] @@ -22,13 +22,13 @@ proc toImmutableRange[T](a: seq[T]): Range[T] = when rangesGCHoldEnabled: result.gcHold = a result.start = addr result.gcHold[0] - result.mLen = int32(a.len) + result.mLen = a.len when unsafeAPIEnabled: proc toImmutableRangeNoGCHold[T](a: openarray[T]): Range[T] = if a.len != 0: result.start = unsafeAddr a[0] - result.mLen = int32(a.len) + result.mLen = a.len proc toImmutableRange[T](a: openarray[T]): Range[T] {.inline.} = toImmutableRangeNoGCHold(a) @@ -122,7 +122,7 @@ proc sliceNormalized[T](r: Range[T], ibegin, iend: int): Range[T] = when rangesGCHoldEnabled: result.gcHold = r.gcHold result.start = r.start.shift(ibegin) - result.mLen = int32(iend - ibegin + 1) + result.mLen = iend - ibegin + 1 proc slice*[T](r: Range[T], ibegin = 0, iend = -1): Range[T] = let e = if iend < 0: r.len + iend @@ -192,3 +192,43 @@ proc `&`*[T](a, b: Range[T]): seq[T] = proc hash*(x: Range): Hash = result = hash(toOpenArray(x)) + +template advanceImpl(a, b: untyped): bool = + var res = false + if b == 0: + res = true + elif b > 0: + if isNil(a.start) or a.mLen <= 0: + res = false + else: + if a.mLen - b < 0: + res = false + else: + a.start = a.start.shift(b) + a.mLen -= b + res = true + res + +proc tryAdvance*[T](x: var Range[T], idx: int): bool = + ## Move internal start offset of range ``x`` by ``idx`` elements forward. + ## + ## Returns ``true`` if operation got completed successfully, or + ## ``false`` if you are trying to overrun range ``x``. + result = x.advanceImpl(idx) + +proc tryAdvance*[T](x: var MutRange[T], idx: int): bool = + ## Move internal start offset of range ``x`` by ``idx`` elements forward. + ## + ## Returns ``true`` if operation got completed successfully, or + ## ``false`` if you are trying to overrun range ``x``. + result = x.advanceImpl(idx) + +proc advance*[T](x: var Range[T], idx: int) = + ## Move internal start offset of range ``x`` by ``idx`` elements forward. + let res = x.advanceImpl(idx) + if not res: raise newException(IndexError, "Advance Error") + +proc advance*[T](x: var MutRange[T], idx: int) = + ## Move internal start offset of range ``x`` by ``idx`` elements forward. + let res = x.advanceImpl(idx) + if not res: raise newException(IndexError, "Advance Error") diff --git a/tests/ttypedranges.nim b/tests/ttypedranges.nim index 5d99a06..1f682ff 100644 --- a/tests/ttypedranges.nim +++ b/tests/ttypedranges.nim @@ -102,3 +102,54 @@ suite "Typed ranges": test "toOpenArray": var a = toRange(@[1,2,3]) check $a.toOpenArray == "[1, 2, 3]" + + test "tryAdvance": + var a: Range[int] + check: + a.tryAdvance(1) == false + a.tryAdvance(-1) == false + a.tryAdvance(0) == true + var b = toRange(@[1, 2, 3]) + check: + b.tryAdvance(-1) == false + $b.toOpenArray == "[1, 2, 3]" + b.tryAdvance(0) == true + $b.toOpenArray == "[1, 2, 3]" + b.tryAdvance(1) == true + $b.toOpenArray == "[2, 3]" + b.tryAdvance(1) == true + $b.toOpenArray == "[3]" + b.tryAdvance(1) == true + $b.toOpenArray == "[]" + b.tryAdvance(1) == false + $b.toOpenArray == "[]" + + test "advance": + template aecheck(a, b): int = + var res = 0 + try: + a.advance(b) + res = 1 + except IndexError: + res = 2 + res + + var a: Range[int] + check: + a.aecheck(1) == 2 + a.aecheck(-1) == 2 + a.aecheck(0) == 1 + var b = toRange(@[1, 2, 3]) + check: + b.aecheck(-1) == 2 + $b.toOpenArray == "[1, 2, 3]" + b.aecheck(0) == 1 + $b.toOpenArray == "[1, 2, 3]" + b.aecheck(1) == 1 + $b.toOpenArray == "[2, 3]" + b.aecheck(1) == 1 + $b.toOpenArray == "[3]" + b.aecheck(1) == 1 + $b.toOpenArray == "[]" + b.aecheck(1) == 2 + $b.toOpenArray == "[]"