Thread overview
GBS-2: Şablon ve Yükleme özellikli yapı (Çitring)
Jan 10, 2022
Salih Dincer
Jan 10, 2022
Ali Cehreli
Jan 10, 2022
Salih Dincer
January 10, 2022

Tekrar Merhaba,

Gereksiz Bilgiler Serisi'nin bu 2. bölümünde aşağıdaki uyduruk yapımızı yaptık. Hani "deveye hendek atlatmak şeklinde bir deyiş vardır! İşte string'e çit atlatınca Çitring oldu :)

Biliyorsunuz string türü çok akıllı! İçinde hem dar string (ASCII) hem dchar barındırarak UTF8'den itibaren her türlü karakteri taşıyor. Ancak daha kişilleştirilmiş deli bir şeye ihtiyacınız var diyelim...

Evet, aşağıdaki Çitring (!) biraz kafa karıştırıcı olabilir ama alias ile her şey daha basit oluyor. Elbette daha da basit yazılabilirdi. Sadece birçok olanağı kullanmak istedim:

struct Çitring (T, size_t boyut) {
  private T[boyut] harfler;
  private size_t indeks;

  this(S) (S str) {
    foreach(s; str.stride(1)) {
      harfler[indeks++]= cast(T)s;
    }
  }

  @property length () { return indeks; }
  @property capacity () { return boyut; }
  @property usefulCapacity () {
    return boyut - indeks;
  }

  ref opIndex (size_t harf) {
    return harfler[harf];
  }

  auto opSlice (size_t x, size_t y) {
     return harfler[x..y];
  }
}

NOT: mısralar[11] dizisi ilk bölümümüzde. Kodu denemek isterseniz buradan kopyalamalısınız ya da 37 karakteri aşmayan kendi cümleleriniz ile deneyin...

void main() {
  alias MISRA = Çitring!(dchar, 37);
  MISRA[] çitring = [ MISRA(mısralar[0]),
                       MISRA(mısralar[1])
                     ];
  mısralar[2].length.writeln; // 40!
  /* Aslında yapı kurucusunda boyut
   * kontrolü olmalı! (-bknz:
   * Sözleşmeli Programlama)
   */
  çitring[0][0..6].writeln;  // korkma
  çitring[1][8..16].writeln; // yurdumun

  çitring ~= MISRA(mısralar[2]);

  çitring[$-1][16..23].writeln("!");   // yıldızı
  çitring[$-1].usefulCapacity.writeln; // Kalan: 1
}

Çıktısı basit, alt alta "korkma yurdumun yıldızı!" yazıyor. Elbette bunu string dizisi ile de yapabilirdik ama mesela bu dizinin 3. elemanı (mısrası) kaç harften oluşuyor dediğimde bana 36 yerine 40 sayısını veriyor. İşte o yüzden elemanlarına stride() ile erişiyoruz ya!

Neyse, fazla lafa gerek yok. Gereksiz bir container yapıda zaten pekçok şey var. Siz de belki pratik yapmak için opDollar(), opAssign() gibi yüklemeleri de yapabilirsiniz.

Kolay gelsin...

January 10, 2022
On 1/10/22 04:13, Salih Dincer wrote:

> Biliyorsunuz string türü çok akıllı! İçinde hem dar string (ASCII) hem
> dchar barındırarak UTF8'den itibaren her türlü karakteri taşıyor.

Ben de gereksizce tam doğrucu davranacağım. Aşağıdaki T'den anlaşıldığı gibi, sen "string" derken bütün dizgi türleri kastediyorsun ama yine de...

Aslında string immutable(char)[]'dan başka bir şey değil. Yani, bir dizi değiştirilemeyen char... char da UTF-8 code birimidir. Sonuçta, string UTF-8 code biriminden başka bir şey taşımaz. Özellikle, eleman türü dchar değildir.

O UTF-8 kod birimlerini Unicode karakterleri olarak kullanmak, string'i kullanan işlevlerin becerisidir.

UTF-8 de ASCII'yi doğrudan destekleyecek biçimde tasarlanmış olduğundan, string ASCII karakter barındırabilmesi de Unicode'un marifetidir; string'in değil.

> Ancak
> daha kişilleştirilmiş deli bir şeye ihtiyacınız var diyelim...
>
> Evet, aşağıdaki Çitring (!) biraz kafa karıştırıcı olabilir ama alias
> ile her şey daha basit oluyor. Elbette daha da basit yazılabilirdi.
> Sadece birçok olanağı kullanmak istedim:
> ```d
> struct Çitring (T, size_t boyut) {
>    private T[boyut] harfler;
>    private size_t indeks;

İndeks başka şey çağrıştırdığından ben olsam ona 'uzunluk' derdim.

>    this(S) (S str) {
>      foreach(s; str.stride(1)) {
>        harfler[indeks++]= cast(T)s;

O cast hatalı olmalı: main içinde Çitring'i dchar yerine char ile kullanınca çıktı yanlış oluyor ama şaşırtıcı biçimde de "okunur" olmaya devar ediyor.

   alias MISRA = Çitring!(char, 37);

40
korkma
yurdumun
y1ld1z1!   <-- 1'ler güzel durdu.
1

>    @property length () { return indeks; }
>    @property capacity () { return boyut; }
>    @property usefulCapacity () {
>      return boyut - indeks;
>    }
>
>    ref opIndex (size_t harf) {
>      return harfler[harf];
>    }

Benim yaptığım gibi T, char (veya wchar) seçildiğinde harfler[harf]'in bir "harf" olmadığını akılda tutmak gerek. Örneğin, ö gibi iki UTF-8 kod biriminden oluşan harflerin yarısını döndürebilir.

>    mısralar[2].length.writeln; // 40!
>    /* Aslında yapı kurucusunda boyut
>     * kontrolü olmalı! (-bknz:
>     * Sözleşmeli Programlama)
>     */

Tabii ki iyi fikir. Akla şunları getiriyor: Uzunluğu derleme zamanında belirlemiş olmak, dizgi için dinamik bellekten yer ayrılmasını önlemiş olur ama bazen de gereğinden fazla yer tutar.

Tesadüf, tam da bugün seninki gibi bir "fixed string" bildirildi:

  https://forum.dlang.org/post/pbwgwfkyflqlfmymsrda@forum.dlang.org

> Çıktısı basit, alt alta "korkma yurdumun yıldızı!" yazıyor. Elbette bunu
> string dizisi ile de yapabilirdik ama mesela bu dizinin 3. elemanı
> (mısrası) kaç harften oluşuyor dediğimde bana 36 yerine 40 sayısını
> veriyor. İşte o yüzden elemanlarına stride() ile erişiyoruz ya!

Kurucuda stride kullanıyorsun ama yukarıda gösterdiğim gibi, 'char' seçince senin tür de aynı durumdan muzdarip.

Ali
January 10, 2022

On Monday, 10 January 2022 at 18:51:52 UTC, Ali Cehreli wrote:

>

Kurucuda stride kullanıyorsun ama yukarıda gösterdiğim gibi, 'char'
seçince senin tür de aynı durumdan .
muzdarip.

Ali

Değerlendirmeniz için teşekkürler. Şu an yüklemeleri tek tek öğrenmeye çalıştığımdan aslında string'e özel bir şey yapmaya çalışmıyorum. Dün gece deneyebileceğim örnek olarak bu geldi ve aynı zamanda, serinin ilk kodunun üzerine yapabildiğim için kolay da...

https://github.com/Moth-Tolias/fixedstring/blob/main/source/fixedstring.d

Bunu yeni görüyorum, mutlaka deneyeceğim. Ama önce opEquals var. Bugün sınıflardaki bir sorun için Adam'ın Pull Request'inde şöyle bir öneri var ve gayet şık gözüküyor:

import std.stdio;

/// Overrides opEquals by calling into custom method accepting typeof(this)
mixin template forwardingOpEquals()
{
    // TODO: Check that another opEquals exists
    override bool opEquals(const Object o) const
    {
        auto a = cast(typeof(this)) o;
        return a && this.opEquals(a);
    }
}

class Foo {
    int i;

    this(int i)
    {
        this.i = i;
    }

    mixin forwardingOpEquals!();

    final bool opEquals(const Foo f) const /* applicable attributes */
    {
        f.i.writeln(" == ?");
        return this.i == f.i;
    }
}


void main()
{
  int birSayı = 41;

  auto foo = new Foo(birSayı);
  auto bar = new Foo(++birSayı);
  foo.i.writeln(": ", foo == bar);
}

Gerçi şu an tartışılıyor ve belki sorun kökünden düzeltilecek sanırım.

Sevgiler, saygılar...