Jump to page: 1 2
Thread overview
Universal Type
Feb 19, 2013
Salih Dinçer
Feb 19, 2013
Salih Dinçer
Feb 20, 2013
Salih Dinçer
Feb 20, 2013
Salih Dinçer
Feb 21, 2013
Salih Dinçer
Mar 03, 2013
Salih Dinçer
Mar 04, 2013
Salih Dinçer
Mar 04, 2013
Salih Dinçer
Mar 04, 2013
Salih Dinçer
February 19, 2013

Yakında örneklere değineceğim...

struct Tx(T) {
 auto türAdı = typeid(T);  // auto = TypeInfo

 private:
   union parçala {
     T data;
     ubyte[T.sizeof] part;
   }

   size_t index;
   auto veri = parçala(T.min);

   alias front this;  /* <-- DMD 2.6x'den öncesi
   alias this = front; //*     için satırı açın */

 public:
   this(T değeri)
   {
    this.veri.data = değeri;
   }

   void popFront()
   {
     index = empty() ? 0 : index + 1;
   }

   //enum empty = false; /*
   //@disable
   bool empty() const @property
   {
     return (index > T.sizeof);
   }//*/

   T front() const @property
   {
     return index ? part(index) : veri.data;
   }

   T part(size_t i) const @property
   // in { assert(i < T.sizeof); } body
   {
     return i > T.sizeof ? 0 : veri.part[i - 1];
   }

} unittest {

 auto int16Türü =
      Tx!ushort(0b0000_0010_0000_0001);

 assert(int16Türü == 513);
 assert(int16Türü.part(1) == 1);
 assert(int16Türü.part(2) == 2);
 assert(int16Türü.türAdı is typeid(ushort));
}

void main()
{

}

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2013

Ali hocam, bunun çok eksiği var ve ayak üstü yazılmış kadar basit bir deneme oldu...

Tabii ki oturarak yazdım ve hatta çok düşündüm...:)

Muhtemelen kimse benim ne yapmak istediğimi anlamamıştır. Gerçi anlaşılsa bile omayacak gibi çünkü şablon kullanıyorum. Amacım herhangi bir türü, taşıyıcı yapı (container) ile taşımak. Taşırken kendisi ve türün ismi (string bile olabilir) gelecek. Elbette yanında union ile parçalara bölmek ve aralıklar ile kullanmak da BONUS'u olacak...

İşte asıl sorun:

Bir tür, işleve girerken, hangi isimde olduğunun bilinmesi gerekmekte. Yani T veya auto gibi şeyler, derleme zamanında yerlerine yerleştirmekte. Oysa yapmak istediğim çalışma zamanında türleri serbestçe kullanabilmek. Evet, ütopik görünüyor!

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2013

Gözüme çarpanlar:

  • Daha önce de öyle yazmıştın ama dmd'nin sürümü 2.6x değil de 2.06x olmalı, değil mi? :)

  • Tam amacını bilmiyorum ama boş olan bir topluluğa popFront() yapmak hata kabul edilmeli. Kullanıcılara bir yararı olsun diye index'i 0 yapmak istiyorsun ama ileride kendini bile yanıltabilirsin. empty() true döndürdüğü halde popFront()'u çağıran kod hata yapmış demek olmalıdır. En iyisi hemen o an bu hatayı bildirmek olmalı.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2013

Parametrenin hangi tür olduğu bilinmeyince kod derlenemiyor tabii. Örneğin yerel bir değişken olsa, program yığıtında ne kadar yer tutacağının derleme zamanında bilinmesi ve kodun ona göre derlenmesi gerekiyor.

Anladığım kadarıyla ona en yakın kavram std.variant modülünde var:

http://dlang.org/phobos/std_variant.html

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 20, 2013

Merhaba Ali hocam,

Variant modülünü şuradaki bağlantıda (https://github.com/D-Programming-Language/phobos/blob/master/std/variant.d) inceledim ama sanki tam olarak yapmak istediğimi karşılamıyor. Bit'lere erişim konusunda da başka bir modüle ihtiyaç bırakıyor. Belki de ütopik bir şey istiyorumdur diye düşünürken....:)

İşte 1-2 düzenleme ile son bulduğum çözüm:

module sdb.utype;

struct Tx {
   union parçala {
     ulong data;
     ubyte[8] part;
   }

   parçala veri;
   size_t dizin;

   TypeInfo tür;

   this(T)(T değeri) {
     this.dizin = 1;  // artık ilk eleman 1...:)
     this.veri = parçala(
             cast(ulong)değeri);
     this.tür = typeid(T);
   }

   void popFront() {
     dizin = empty() ? 0 : dizin + 1;
   }

   @property
   bool empty() const {
     return (dizin > tür.tsize());
   }

   @property
   ulong front() const {
     return dizin ? part(dizin) : veri.data;
   }

   @property
   ubyte part(size_t i) const
   in { assert(i, "0 alamaz!"); } body {
     return i > tür.tsize() ? 0 : veri.part[i - 1];
   }
}

Bu yapıda tek yaptığım, veri uzunluğunu olabilecek en büyük veri türüne (parçala.data: ulong) kayıt ediyorum ve uzunluğunu bayt cinsinden dizin'e kayıt ediyorum. Dilersem part() işlevi ile 1 ila 8. parçaları (0 ilktir geleneğinden uzaklaşarak) talep edebiliyorum. İstersem bunu, aralıklar ile sıralı bir şekilde gelmesini sağlayabiliyorum.

Ancak önemli bir sorun var ve belki de bit'ler ile uğraşacağımdan gerekmiyor ama yapılabilirliğini sorgulamalıyım. Gelen veri türünün ismini ve boyutunu öğrenebildiğime göre o türde bir değişkene aktarabilir miyim?

import std.stdio;

void main() {
  uint data = 513;
  auto test = Tx(data);
       test.veri.part.writeln(": ", test.tür);

  writefln("%-(%s, %)", test);

 /* Bu:
  * uint veri = cast(test.tür)test.veri.data;
  * olmuyor çünkü türü toString ile döndürüyor...
  */

  /* TypeInfo veri; türünde bir şey oluyor herhalde */
  typeof(test.tür) veri;
  writeln(typeid(veri)); /*<-- bu satırda
  Parçalama arızası (core dumped) hatası veriyor... */

}/*
[1, 2, 0, 0, 0, 0, 0, 0]: uint
1, 2, 0, 0
Parçalama arızası (core dumped)
*/

Sorunları çözmek için TypeInfo yapısını incelemeye karar verdim ama bulabildiğim yer, sanki sadece object modünün eski bir kopyasıydı, anlayamadım: https://github.com/D-Programming-Language/druntime/blob/master/src/object_.d

Yine de iyi bir başlangıç yaptığımı ve/veya başarılı bir adım attığımı zannediyorum...:D

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 20, 2013

Bu da çok leziz görünüyor, teşekkürler. Ancak dikkat edersen şablon kullanımından vazgeçtim. Çünkü farklı türleri aynı anda taşıyamıyorum. Bilemiyorum, belki de çokuz olaylarına girmenin vakti gelmiştir. Peki çokuzlar, derleme anındaki şablon olanaklarından değil mi? Sanki bir ara yapmaya (kırmaya) çalıştığımız, dizi içinde dizi (farklı tür) çıkmazına girdim yine...:)

Yine de son yapıyı her halükarda denemeliydim. Şu kodların bir ekran görüntüsünü aldım:

void main() {
   auto t = Tx(0x12345678);
   writefln("%(0x%02x %)", t.parçalar);

   t.Tür değişken;

   "Yapının gerçekteki aldığı ismi: ".writeln(typeid(t));
   "Yeniden oluşturulan değişken  : ".writeln(typeid(değişken));

   auto başkaBirTür = Tx('A');
   "Aynı yapının başka türü: ".writeln(typeid(başkaBirTür));
}

Alıntı (ÇIKTISI):

>

0x78 0x56 0x34 0x12
Yapının gerçekteki aldığı ismi: rasgeleveri.Tx!(int).Tx
Yeniden oluşturulan değişken : int
Aynı yapının başka türü: rasgeleveri.Tx!(char).Tx

Yukarıda görüldüğü gibi, şablon ile birlikte gelen tür isminden dolayı; aynı kapta durması tehlikeli gazlar gibi (yanıcı/yakıcı) illegal bir durum oluşturuyor. Zaten bu başlıkta işlemeye/aşmaya çalıştığım sorun da bu. Sanki aştım gibi!

Şöyle bir test kodumuz olsun:

import std.stdio, std.random, sdb.utype; /* <-- utype modülü bulunmayanlar,
yukarıda son naklettiğim Tx yapısını aynı dosyada kullanabilirler... */

char rasgeleSeç(string seçenekler) {
 auto rasgeleSayı = uniform(0, size_t.max);
 auto aralıkOranı = size_t.max / seçenekler.length;
 size_t biriniSeç = rasgeleSayı / aralıkOranı;

 return seçenekler[biriniSeç];
}

auto rasgeleTür(size_t adedi) {
 Tx[] sonuç;

 while(adedi--) {
   final switch(rasgeleSeç("LISB")) {
     case 'L': ulong s7 = uniform(ulong.min, ulong.max);
               sonuç ~= Tx(s7); break;
     case 'I': uint s5 = uniform(uint.min, uint.max);
               sonuç ~= Tx(s5); break;
     case 'S': ushort s3 = uniform(ushort.min, ushort.max);
               sonuç ~= Tx(s3); break;
     case 'B': ubyte s1 = uniform(ubyte.min, ubyte.max);
               sonuç ~= Tx(s1); break;
   }
 }
 return sonuç;
}


void main() {
   foreach(r; rasgeleTür(3)) {
     r.veri.data.writeln(": ", r.tür);
   }
}

Alıntı (ÇIKTISI):

>

1539812105: uint
17258: ushort
1025021539: uint

Anlaşılacağı üzere, artık Tx'in taşıcılığında farklı türden verileri bir işleve sokabilir veya çıkarabilirim. Ancak bu türün içindeki veriyi basit bir eşitleme ile uyumlu olduğu türe aktaramıyorum. Her ne kadar TypeInfo sınıfını kullanmış olsam da, döndürdüğü türün ismi aslında bir dizge ya da ben bir şeyleri yanlış yapıyorum... :scared:

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 20, 2013

Eğer asıl türü şablon olarak yazarsan bir alias ile çok kolay:

import std.stdio;

struct Tx(T)
{
   union
   {
       T veri;
       ubyte[T.sizeof] parçalar;
   }

   alias Tür = T;
}

Tx!T tx(T)(T veri)
{
   return Tx!T(veri);
}

void main()
{
   auto t = tx(0x12345678);
   writefln("%(0x%02x %)", t.parçalar);

   t.Tür değişken;
}

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 21, 2013

std.variant, bana sanki tür dönüşümlerini güvenli bir şekilde otomatikleştiren bir modül gibi geldi. Doğru mu anlamışım?

Bunu düşünürken, benim de artık bir to(T) üyesine ihtiyacım olduğun farkettim ve önce union'ı şu hale getirdim:

   union parçala {
     ulong data;
     ubyte[8] b8x;
     ushort[4] s4x;
     uint[2] i2x;
   }

Sonra bu basit çözüm için şu işlevi patırdanak bir şekilde yazmak kaldı...:)

   T to(T)() {
     switch(T.sizeof) {
       case 1: return cast(T)veri.b8x[0];
       case 2: return cast(T)veri.s4x[0];
       case 4: return cast(T)veri.i2x[0];
       default:
     }
     return cast(T)veri.data;
   }

Aşağıdak kod ile denemek istediğimde başarılı sonuç elde ettim:

  uint data = 153;
  auto test = Tx(data);
       test.veri.b8x.writeln(": ", test.tür);

  data = 0;
  data.writeln;

  data = test.to!uint();
  data.writeln(": uint");

  ubyte veri = test.to!ubyte();
  veri.writeln(": ubyte");

Alıntı (ÇIKTISI):

>

0
153: uint
153: ubyte

Şimdi sıra, olası illegal durumları tespit edip invirant, in/out kümelerini icra etmeye geldi. Ancak işaretli türlerde ciddi bir başarısızlık içerisindeyim. Sanırım şu Big-Endian/Little-Endian olaylarına takıldım. Bu eksiğimi gidermek için biraz okuma yapmam gerekecek...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 20, 2013

Bir yapı tanımlamak istiyorsun. Bu yapının öyle bir üyesi olsun ki, her türe dönüşebilsin istiyorsun:

r0.tür değişken0;    // belki int
// daha sonra ...
r1.tür değişken1;    // belki başka bir şey

Derleyici bu satırlar için kod üretebilmek için r0.tür'ün ve r1.tür'ün ne oldukalrını bilmek zorundadır. Hangi genişlikte yazmaç kullansın? Yığıttan kaç bayt ayırsın? vs. Derlemeli bir dilde olanaksızdır.

Her ne kadar Variant'ın doğru çözüm olmadığını düşünsen de bence onların bu sorunu nasıl çözdüklerine bakmalısın. Aynı yöntemler senin yapıda da kullanılabilir.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 21, 2013

Alıntı (Salih Dinçer):

>

std.variant, bana sanki tür dönüşümlerini güvenli bir şekilde otomatikleştiren bir modül gibi geldi. Doğru mu anlamışım?

Değil. Variant, içinde her türü barındırabilen bir türdür. Her Variant'ın içinde farklı bir tür bile olsa dışarıdan bakıldığında hep Variant göründüğü için Variant dizileri oluşturarak farklı türden değerleri bir arada tutabiliriz:

import std.variant;

void main()
{
   Variant[] değerler;
   değerler ~= Variant(42);
   değerler ~= Variant("merhaba");

   assert(değerler[0] == 42);
   assert(değerler[1] == "merhaba");
}

Sonuçta tek dizi içine int ve string yerleştirebilmiş olduk. Tabii kullanım aşamasında her elemanın asıl türünü bilerek ona göre davranma gibi bir sorun ortaya çıkıyor. "merhaba"ya bir int ekleyemeyiz.

Böyle sorunların bir çözümü ziyaretçi örüntüsüdür (visitor pattern). Variant bunu destekler ve bizden her veriyi işleyecek olan işlevler (veya temsilciler, vs.) alır:

import std.variant;
import std.stdio;

alias KısıtlıTür = Algebraic!(int, string);

void foo(KısıtlıTür[] değerler)
{
   // Bunlar visit'e lambda olarak da verilebilir

   void stringİşlevi(string s)
   {
       writeln(s ~ " dünya");
   }

   void intİşlevi(int i)
   {
       writeln(i + 7);
   }

   foreach (değer; değerler) {
       değer.visit!(stringİşlevi, intİşlevi);
   }
}

void main()
{
   KısıtlıTür[] değerler;
   değerler ~= KısıtlıTür(42);
   değerler ~= KısıtlıTür("merhaba");

   assert(değerler[0] == 42);
   assert(değerler[1] == "merhaba");

   foo(değerler);
}

int' ve string'e uygun olan işlev otomatik olarak seçilir:

'49
merhaba dünya'

std.variant çok daha kapsamlı; bakmanı öneririm. Senin burada yapmaya çalıştığın Variant ile ilgili.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

« First   ‹ Prev
1 2