From e0287b9efeac90338f017188fe69e84cd261e8d8 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 29 Mar 2017 17:40:19 +0200 Subject: [PATCH] add `CCInt.range{,',by}` for iterating on integer ranges --- src/core/CCInt.ml | 73 ++++++++++++++++++++++++++++++++++++++++++++++ src/core/CCInt.mli | 26 +++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/core/CCInt.ml b/src/core/CCInt.ml index d4a3bae4..6efcc11f 100644 --- a/src/core/CCInt.ml +++ b/src/core/CCInt.ml @@ -39,6 +39,7 @@ let pow a b = type 'a printer = Format.formatter -> 'a -> unit type 'a random_gen = Random.State.t -> 'a +type 'a sequence = ('a -> unit) -> unit let random n st = Random.State.int st n let random_small = random 100 @@ -96,6 +97,76 @@ let to_string_binary n = Q.int (fun n -> n = int_of_string (to_string_binary n)) *) +let range_by ~step i j yield = + let rec range i j yield = + if i=j then yield i + else ( + yield i; + range (i+step) j yield + ) + in + if step = 0 then + raise (Invalid_argument "CCList.range_by") + else if (if step > 0 then i>j else i Sequence.to_list) + [] (range_by ~step:1 5 0 |> Sequence.to_list) + [] (range_by ~step:2 1 0 |> Sequence.to_list) + [0;2;4] (range_by ~step:2 0 4 |> Sequence.to_list) + [0;2;4] (range_by ~step:2 0 5 |> Sequence.to_list) + [0] (range_by ~step:~-1 0 0 |> Sequence.to_list) + [] (range_by ~step:~-1 0 5 |> Sequence.to_list) + [] (range_by ~step:~-2 0 1 |> Sequence.to_list) + [5;3;1] (range_by ~step:~-2 5 1 |> Sequence.to_list) + [5;3;1] (range_by ~step:~-2 5 0 |> Sequence.to_list) + [0] (range_by ~step:max_int 0 2 |> Sequence.to_list) +*) + +(*$Q + Q.(pair small_int small_int) (fun (i,j) -> \ + let i = min i j and j = max i j in \ + CCList.equal CCInt.equal \ + (CCInt.range_by ~step:1 i j |> Sequence.to_list) \ + (CCInt.range i j |> Sequence.to_list) ) +*) + +let range i j yield = + let rec up i j yield = + if i=j then yield i + else ( + yield i; + up (i+1) j yield + ) + and down i j yield = + if i=j then yield i + else ( + yield i; + down (i-1) j yield + ) + in + if i<=j then up i j yield else down i j yield + +(*$= & ~printer:Q.Print.(list int) + [0;1;2;3;4;5] (range 0 5 |> Sequence.to_list) + [0] (range 0 0 |> Sequence.to_list) + [5;4;3;2] (range 5 2 |> Sequence.to_list) +*) + +let range' i j yield = + if i Sequence.to_list) + [0;1;2;3;4] (range' 0 5 |> Sequence.to_list) + [5;4;3] (range' 5 2 |> Sequence.to_list) +*) + + module Infix = struct let (=) = Pervasives.(=) let (<>) = Pervasives.(<>) @@ -103,6 +174,8 @@ module Infix = struct let (>) = Pervasives.(>) let (<=) = Pervasives.(<=) let (>=) = Pervasives.(>=) + let (--) = range + let (--^) = range' end include Infix let min = min diff --git a/src/core/CCInt.mli b/src/core/CCInt.mli index 88d4abd7..c38b8818 100644 --- a/src/core/CCInt.mli +++ b/src/core/CCInt.mli @@ -25,6 +25,7 @@ val pow : t -> t -> t type 'a printer = Format.formatter -> 'a -> unit type 'a random_gen = Random.State.t -> 'a +type 'a sequence = ('a -> unit) -> unit val random : int -> t random_gen val random_small : t random_gen @@ -51,6 +52,23 @@ val min : t -> t -> t val max : t -> t -> t (** @since 0.17 *) +val range_by : step:t -> t -> t -> t sequence +(** [range_by ~step i j] iterates on integers from [i] to [j] included, + where the difference between successive elements is [step]. + use a negative [step] for a decreasing list. + @raise Invalid_argument if [step=0] + @since NEXT_RELEASE *) + +val range : t -> t -> t sequence +(** [range i j] iterates on integers from [i] to [j] included . It works + both for decreasing and increasing ranges + @since NEXT_RELEASE *) + +val range' : t -> t -> t sequence +(** Same as {!range} but the second bound is excluded. + For instance [range' 0 5 = Sequence.of_list [0;1;2;3;4]] + @since NEXT_RELEASE *) + (** {2 Infix Operators} @since 0.17 *) @@ -72,6 +90,14 @@ module Infix : sig val (>=) : t -> t -> bool (** @since 0.17 *) + + val (--) : t -> t -> t sequence + (** Alias to {!range} + @since NEXT_RELEASE *) + + val (--^) : t -> t -> t sequence + (** Alias to {!range'} + @since NEXT_RELEASE *) end include module type of Infix