number ranges

Ali Çehreli acehreli at yahoo.com
Tue Jan 18 23:13:14 UTC 2022


On 1/18/22 14:08, forkit wrote:

 > never use number ranges.. not ever!  ;-)
 >
 > (except in combination with iota)

Indeed, the following is an elegant but slow (tested with dmd) 
implementation with Phobos:

auto range(T)(T a, T b)
in (a <= b) {
   import std.range : chain, iota, only;
   return chain(iota(a, b), only(b));
}

But I like the following one better because it is fast and I think it 
works correctly. However, I am reminded of one of the reasons why 
exclusive ranges are better: It is not possible to represent an empty 
range with the same syntax. For example, range(42, 42) includes 42. 
Hmmm. Should range(42, 41) mean empty? Looks weird.

struct InclusiveRange(T) {
   T front;
   T last;
   bool empty;

   this(U)(in U front, in U last)
   in (front <= last) {
     this.front = front;
     this.last = last;
     this.empty = false;
   }

   void popFront() {
     if (front == last) {
       empty = true;

     } else {
       ++front;
     }
   }
}

auto inclusiveRange(T)(T first, T last) {
   return InclusiveRange!T(first, last);
}

unittest {
   // Impossible to be empty
   import std.algorithm : equal;

   auto r = inclusiveRange(42, 42);
   assert(!r.empty);
   assert(r.equal([42]));
}

unittest {
   // Can represent all values of a type
   import std.range : ElementType;
   import std.algorithm : sum;

   auto r = inclusiveRange(ubyte.min, ubyte.max);
   static assert(is(ElementType!(typeof(r)) == ubyte));

   assert(r.sum == (ubyte.max * (ubyte.max + 1)) / 2);
}

unittest {
   // Really inclusive
   import std.algorithm : sum;

   assert(inclusiveRange(1, 10).sum == 55);
}

unittest {
   // Works with negative values
   import std.algorithm : equal;

   assert(inclusiveRange(-3, 3).equal([-3, -2, -1, 0, 1, 2, 3]));
   assert(inclusiveRange(-30, -27).equal([-30, -29, -28, -27]));
}

import std.stdio;

void main() {
}

Ali



More information about the Digitalmars-d-learn mailing list