Thread overview
Inclusive Range for D v3
Nov 24, 2022
Salih Dincer
Nov 24, 2022
Salih Dincer
Nov 24, 2022
Salih Dincer
November 24, 2022

Merhaba,

Yaklaşık 1 senelik süre içerisinde, aralıklı geliştirilen iota() alternatifi için gönül rahatlıyla v3 diyebiliriz. Şurada başlayan ve Türkçe forumlarda devam eden InclusiveRange için kısaca ir veya iras takma adlarını yaygınlaştıralım lütfen. Belki bir gün kısa olan bu sürüm Phobos'da yerini alır.

Kullanmak için şu derleme parametrelerine ihtiyaç duyabilirsiniz:

>

dmd -w "inclusiveRange3.d" -preview=shortenedMethods -release

auto inclusiveRange(T)(T oneValue)
  => inclusiveRange!T(T(0), oneValue);

template inclusiveRange(Type)
{
  enum typeTest = () => !is(Type == bool);
  static assert(typeTest(), "\nBoolean type cannot be used!");

  auto inclusiveRange(Type f, Type l, Type s = Type(1))
    => InclusiveRange(f, l, s);

  struct InclusiveRange {
    mixin Value!Type;
    Type s, l, term;

    import std.format;
    this(Type first, Type last, Type step)
    in (first <= last, format!"Invalid range: [%s-%s]"(first, last))
    {
      f = Value(first);
      l = term = last;
      s = step;
      if(diff % s) {
        const t = cast(Type)(diff / s);
        term = cast(Type)(t * s + first);
      }
    }
    private auto diff() => term - front;

    bool empty() => f.empty || front > l;
    Type front() => f.value;
    auto popFront() => f += s;
    auto save() => this;
    auto length() => empty ? cast(size_t)0
         : cast(size_t)(diff / s) + 1;
  }
}

template Value(Type) {
  Value f;
  struct Value
  {
    Type value;
    bool empty;

    auto ref opAssign(Type first) => value = first;
    auto ref opOpAssign(string op)(Type first)
    if(op == "+")
    {
      const prev = value;
      value += first;
      if(value < prev)
      {
        empty = true;
        value = prev;
      }
    }
  }
}
November 24, 2022

On Thursday, 24 November 2022 at 11:19:54 UTC, Salih Dincer wrote:

>

iota() alternatifi için gönül rahatlıyla v3 diyebiliriz.

Aslında alternatifin bir de başlangıç alternatifi var! İsteyen seq(sequence'ın kısaltması) ile step'i şablon parametresi olarak kullanabilir. Tür çıkarsama konusunda bazı kısıtlamalar olsa da (şablon içindeki enum'u kapatmayı deneyebilirsiniz) kayda değer buluyorum...

Test kodları ile birlikte bütün set veriyorum. Lütfen birim tesleri için derlerken -release yerine -unittest parametresi verin:

>

dmd -w "inclusiveRange3.d" -unittest -preview=shortenedMethods


import std.stdio;
import std.range;
import std.algorithm;

unittest {
  assert(iras(10).equal(iota(11)));
}

unittest {
  import std.exception : assertThrown;
  assertThrown!Error(iras(2, 1));
}

unittest {
  auto r1 = iras(42, 42);
  assert(!r1.empty);
  assert(r1.equal([42]));
}

unittest {
  auto r2 = iras(ubyte.min, ubyte.max);
  static assert(is(ElementType!(typeof(r2)) == ubyte));
  assert(r2.sum == (ubyte.max * (ubyte.max + 1)) / 2);
  assert(iras(1, 10).sum == 55);
}

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

unittest {
  auto GregorySeries = iras(1, 0x1.0p+27, 2);
  assert(GregorySeries.length == 67_108_864);

  double piNumber = 0;
  foreach(e, n; GregorySeries.enumerate) {
    if(e & 1) piNumber -= 1/n;
    else piNumber += 1/n;
  }
  import std.math;
  assert(PI.isClose(piNumber * 4,  1e-8));/*
  writefln("%.21f (calculated)", piNumber * 4);
  writefln("%.21f (constant)", PI);//*/
}

void main()
{ /* Test-ok...
  auto r1 = iras(5, 0);
  r1.writeln; //* AssertError, Invalid range: [5-0] */

	auto r2a = iras(ubyte.min, ubyte.max, 15);
	assert(r2a.length == 18);
	r2a.writeln("<-- Version 2");

	auto r2b = iras(0, .51, 0.1);
	assert(r2b.length == 6);
	r2b.writeln("<-- Version 2");
	
	auto r2c = ir!(double, 0.1)(0, .51);
	assert(r2c.length == 6);
	r2c.writeln("<-- Version 1");
	
	auto r3 = ir!(double, 0.11)(0.1, 2.09);
	r3.writeln("<-- Version 1");
	
	enum x = 2022;
	auto r4 = iras(x, 10110, x);
	r4.writeln("<-- Version 2");
	assert(r4.length == 5);

	iras(0.1, 2.09, 0.11).writeln("<-- Version 2");
	iras(0, 1.5, 0.1).writeln("<-- Version 2");
 	ir!(char, 2)(65, 70).writeln("<-- Version 1"); // ACE;
 	iras('A', 'Z').writeln("<-- Version 2");
}

alias ir = seq; // Version 1
alias iras = inclusiveRange;

template seq(Type = int, Type s = 1)
{
  enum typeTest = () => !is(Type == bool);
  static assert(typeTest(), "\nBoolean type cannot be used!");

  enum seq = (Type f, Type l) => Seq(f, l); /*
     auto seq(Type f, Type l) => Seq(f, l);//*/

  struct Seq
  {
    mixin Value!Type;
    Type l, term;

    this(Type first, Type last)
    {
      f = Value(first);
      l = term = last;
      if(diff % s) {
        const t = cast(Type)(diff / s);
        term = cast(Type)(t * s + first);
      }
    }

    private auto diff() {
      return term - front;
    }

    bool empty() {
      return f.empty || front > l;
    }

    Type front() {
      return f.value;
    }

    void popFront() {
      f += s;
    }

    auto save() {
      return this;
    }

    auto length() {
      return empty ? cast(size_t)0
             : cast(size_t)(diff / s) + 1;
    }
  }
}

Başarılar...

November 24, 2022

On Thursday, 24 November 2022 at 11:33:09 UTC, Salih Dincer wrote:

>

Test kodları ile birlikte bütün set veriyorum...

Haydi biraz maytap geçelim 😃

MyType isminde kendi türümüz olsun ve onu belirlediğimiz sınırların dışına çıkmayacak bir aralığa emanet edelim:

struct MyType(int limit)
{
  int n;
  alias n this;
  
  this(int f) {
    n = f % limit;
  }
  alias opOpAssign = opUnary;

  auto opUnary(string op)(int i = 1)
  if(op=="++") {
    n = (n + i) % limit;
  }
}

import std.stdio;
void main()
{
  enum {
      first = 10,
      last = 15,
      limit = last * 2
  } // sınırlar belirlendi.
  
  assert(imported!"std.algorithm".equal(
      first.iras(last), [10, 11, 12, 13, 14, 15])
  ); // standart aralık ve:
  
  auto start = MyType!limit(first);
  auto end = MyType!limit(last);
  
  // başlıyoruz...
  
  size_t loop = last;
  while (loop--) {
    start.iras(end).writeln;
    start++;
    end++;
  }
  assert(start > end);
}
/* ÇIKTISI:
[10, 11, 12, 13, 14, 15]
[11, 12, 13, 14, 15, 16]
[12, 13, 14, 15, 16, 17]
[13, 14, 15, 16, 17, 18]
[14, 15, 16, 17, 18, 19]
[15, 16, 17, 18, 19, 20]
[16, 17, 18, 19, 20, 21]
[17, 18, 19, 20, 21, 22]
[18, 19, 20, 21, 22, 23]
[19, 20, 21, 22, 23, 24]
[20, 21, 22, 23, 24, 25]
[21, 22, 23, 24, 25, 26]
[22, 23, 24, 25, 26, 27]
[23, 24, 25, 26, 27, 28]
[24, 25, 26, 27, 28, 29]
*/

Aslında kendi türümüz (MyType) sınırlarını kendi belirliyor. Kısmen, yani limit'e göre mod (kalanı) bulma ve dolaylı geri döndürme (alias n this ile) yapıyoruz. Tabi start > end durumuna döndüğünden, InclusiveRange bize sonsuza giden bir aralık sunamaz. (-bknz. Sözleşmeli Programlama)

Sevgiler, saygılar...