Thread overview
Literal HexaDecimal Kullanırken
Oct 27, 2022
Salih Dincer
Oct 27, 2022
Salih Dincer
Oct 27, 2022
Ali Çehreli
Oct 30, 2022
Salih Dincer
Oct 30, 2022
Salih Dincer
October 27, 2022

Merhaba,

Gerçi kişiselleştirilmiş birkaç şablon var ama eskiden (yani Tango zamanları) sanırım x isminde bir şablon varmış. Yani şu şekilde bir hexadecimal veriyi pekala çevirebiliyorduk değil mi?

// D1:
  writeln(x!"e697a5 e69cac e8aa9e"); // 日本語

// D2:
  auto data = hexString!"e697a5 e69cac e8aa9e";

Adım adım gidersek, hata verdiğine göre bu kalktı ve yerine std.conv.hexString gelmiş olmalı. Hatta belki o zamanlar kısaca literal word olarak kullanıyorduk belki de: x!0x01_ff_7f.

Günümüzde ise bütün bu dönüşüm olayları std.conv.parse marifetiyle tek modülde toplandı. Örneğin bizim .map!(c => uint(c).toChars!(16, char, LetterCase.upper)) şeklinde çok güzel olaylarımız (acaba benim keşfetmediği başkaları?) da var. Ama nedense std.ascii.isHexDigit ismindeki olanak başka modülde.

Dolambaçlı oldu farkındayım; asıl soruma gelince: Ben şu çokuzlu döndüren kodu, .array kullanmadan örneğin .tupleof kullanarak bir ubyte[] dizisine aktaramıyorum. Neden bilmiyorum ama her şeyi denedim çözemedim 😞

//...

  ubyte[size] data;

  this(const(char)[] str) {
    auto demet = str.chunks(2)
                    .map!(bin => bin
                    .to!ubyte(16))
                    .array;//.tupleof;
    size_t i;
    foreach_reverse(c; demet) {
      this.data[i++] = c;
      assert(i < size, text(i));
    }
  }
//...

Bu konuda başka çözüm araçlarına girdim. Bir gelişme olana kadar öneri yazarsanız sevinirim. Eğer Phobos'da yoksa böyle şeyler kendi göbek bağımızı kendimiz kesecez!

Teşekkürler...

October 27, 2022

On Thursday, 27 October 2022 at 18:02:29 UTC, Salih Dincer wrote:

>

Bir gelişme olana kadar öneri yazarsanız sevinirim.

Bende küçük bir gelişme var, fena sayılmaz. En azından foreach'den kurtardım :)

import std;

auto hex(const(char)[] str = "BADEDEDE".dup) {
    auto range = str.chunks(2)
                    .map!(bin => bin
                    .to!ubyte(16))
                    .array;//tupleof;

    auto size = range.length;
    ubyte[100] data;
    auto buffer = data[];
         buffer.put(range);

    return data.idup[0..size];
}
unittest {
  assert(hex == [186, 222, 222, 222]);
}
October 27, 2022
On 10/27/22 11:02, Salih Dincer wrote:

> Ben şu çokuzlu
> döndüren kodu,

Çokuzlu yerine aralık demek istediğini varsayıyorum.

> `.array` kullanmadan örneğin `.tupleof` kullanarak bir
> ubyte[] dizisine aktaramıyorum.

.tupleof, bir nesnenin üye değerlerini çokuzlu olarak üretir. Burada kullansak .map'in döndürdüğü nesnenin üyeleri olurdu. Biz ise onun üyelerini değil, üreteceği elemanları istiyoruz.

İkinci mesajındaki koda bakıyorum:

>     auto size = range.length;
>     ubyte[100] data;

Buradaki asıl sorun, 100 büyüklüğündeki bir dizinin içine yazmak mı? 'size' daha az mı olmak zorunda? Yoksa gerektikçe 100'ü arttırmak mı istiyoruz?

>     return data.idup[0..size];

Zaten idup ile kopyalayacaksak neden ayrıca 100'lük dizi var?

Burada benim aklıma gelen bir eniyileştirme, 100'lük diziyi static yapmak ve doğrudan onun elemanlarına dilim döndürmektir:

void foo() {
    static ubyte[100] data;
    // ...
    return data[0..size];
}

Ama dikkat edilmesi gereken konu: Döndürülen değer foo'nun bir sonraki çağrılmasında geçersiz olacaktır.

(D'nin thread-local-by-default özelliği nedeniyle multithread konusunda güvendeyiz.)

Buna ek olarak, ben data'yı dinamik de yapıyorum:

void foo() {
    static ubyte[] data;
    // ...
    if (size > data.length) {
        data.length = size;
    }
    // ...
    return data[0..size];
}

Böylece data, şimdiye kadar gereken en uzun durumunda bulunuyor ve bir noktadan sonra bir daha bellek ayırmıyoruz.

Asıl soruya dönersek, ben olsam hex işlevinden doğrudan aralık döndürürdüm ve diziye kopyalama işini kullanıcılara bırakırdım. Dizi gerekmediği zaman bellek ayrılmaz. Gerektiği zaman da ayrılır.

Ve asıl sorunun tam cevabı, copy'yi kullanmak:

import std;

auto hex(const(char)[] str = "BADEDEDE".dup) {
    auto range = str.chunks(2)
                    .map!(bin => bin
                    .to!ubyte(16));

    ubyte[100] data;

    auto kalan = copy(range, data[]);
    writeln(kalan.length);

    return data[0..$ - kalan.length].dup;
}

Ali

October 30, 2022

On Thursday, 27 October 2022 at 20:41:28 UTC, Ali Çehreli wrote:

>

On 10/27/22 11:02, Salih Dincer wrote:

>

Ben şu çokuzlu
döndüren kodu,

Çokuzlu yerine aralık demek istediğini varsayıyorum.

Aslında .array kullanmak istemediğimi ve .tupleof ile çokuzlu kullanmak istediğimi belirtmiştim. Ama evet dağınık bir anlatım tarzı olduğunu kabul ediyorum.

On Thursday, 27 October 2022 at 20:41:28 UTC, Ali Çehreli wrote:

>

İkinci mesajındaki koda bakıyorum:

>     auto size = range.length;
>     ubyte[100] data;

Buradaki asıl sorun, 100 büyüklüğündeki bir dizinin içine yazmak mı? 'size' daha az mı olmak zorunda? Yoksa gerektikçe 100'ü arttırmak mı istiyoruz?

100 değeri varsayımsal, yani hiçbir zaman çıkmayacak değer. İşin ilginci yapı kurulurken size değerini biliyoruz. Sorun kopyalama işlemini tersine yapmam gerektiği ve put() bize bunu veriyor ama .array'den kurtaramıyor...

On Thursday, 27 October 2022 at 20:41:28 UTC, Ali Çehreli wrote:

>

Burada benim aklıma gelen bir eniyileştirme, 100'lük diziyi static yapmak ve doğrudan onun elemanlarına dilim döndürmektir:

void foo() {
    static ubyte[100] data;
    // ...
    return data[0..size];
}

Ama dikkat edilmesi gereken konu: Döndürülen değer foo'nun bir sonraki çağrılmasında geçersiz olacaktır.

(D'nin thread-local-by-default özelliği nedeniyle multithread konusunda güvendeyiz.)

Evet hocam, bu dediğiniz ile çok karşılaşıyorum ve static kullanmak hiç aklıma gelmemişti. Escape hatası ile karşılaşmamak için genelde dilimi .dup ile kullanarak kolaya kaçıyordum. Bilgi için teşekkür ederim.

On Thursday, 27 October 2022 at 20:41:28 UTC, Ali Çehreli wrote:

>

Buna ek olarak, ben data'yı dinamik de yapıyorum:

void foo() {
    static ubyte[] data;
    // ...
    if (size > data.length) {
        data.length = size;
    }
    // ...
    return data[0..size];
}

Böylece data, şimdiye kadar gereken en uzun durumunda bulunuyor ve bir noktadan sonra bir daha bellek ayırmıyoruz.

Bu güzel aslında, ama aralık ile kullanıp kullanmayacağımdan emin değilim. Aslında aralık kullanmak benim için kolaylık ama uzun vadeli kullanıcıya hizmet eden (empty, front, popFront'u olan) bir şey değil. Sadece kurulurken değeri kendi türüme insancıl olarak eşitliyor, hepsi bu...

On Thursday, 27 October 2022 at 20:41:28 UTC, Ali Çehreli wrote:

>

Asıl soruya dönersek, ben olsam hex işlevinden doğrudan aralık döndürürdüm ve diziye kopyalama işini kullanıcılara bırakırdım. Dizi gerekmediği zaman bellek ayrılmaz. Gerektiği zaman da ayrılır.

Ve asıl sorunun tam cevabı, copy'yi kullanmak:

Maalesef .retro gibi bir şey (o da map ile çalışmadı!) olmadan tersi sonuç veriyor. Yapıyı aşağıdaki test koduyla denedim, yapının ve 2 adet kurucusu vardır. Eğer çıktının 2. ve 3. satırlara bakarsanız .copy ile insan algısının tersine kayıt ettiğini göreceksiniz:

alias Hex4 = HexString!int;
enum sample = 123456789; //0x075bcd15
void main()
{
  Hex4 n = sample;
  n.writeln; // "075bcd15"

  auto hex = Hex4.fromString("075bcd15");
  hex.writeln(": ", typeof(hex).stringof);

  Hex4 hexStr = "075bcd15";
  hexStr.writeln;
} /* ÇIKTISI:

0x075bcd15
0x15cd5b07: HexString!int
0x15cd5b07

*/

Özetle, defalarca bellek tahsisinden kurtulup kurulum sırasında gerek int¤, gerekse stringolarak hexadecimal sayılar ile çalışmak istiyorum. An itibariyle yaptıklarım CTFE değil ama tersine veriyi kayıt etme zorluğu beni durdurdu. Bunun.retro¤ ile çalışamaması beni klasik yöntemlere yakınlaştırdı.

D'nin modernliğini şu şekilde kullanabilmek güzel olurdu ama şu an bir ayağı (kurucusu) topallıyor!i 😀

struct HexString(T)
{
  union
  {
    T veri;
    ubyte[T.sizeof] data;
  }

  this(T veri)
  {
     this.veri = veri;
  }

  this(const(char)[] str)
  {
    str.chunks(2)
       .map!(bin => bin
       .to!ubyte(16))
       .copy(data[]);
  }
//...

Teşekkürler...

October 30, 2022

On Sunday, 30 October 2022 at 16:20:37 UTC, Salih Dincer wrote:

>

Bunun .retro ile çalışamaması beni klasik yöntemlere yakınlaştırdı.

Meğer şuradaki son örnekteki gibi algoritmanun sonuna değil de şu şekilde parantez içinde kullanınca oluyormuş:

  this(const(char)[] str)
  {
    str.chunks(2)
       .map!(bin => bin
       .to!ubyte(16))
       .copy(data[].retro);
  }

Şaşırtıcı ve tuhaf! Ben .retro'yu orada kullanmayı beklemezdim!

April 06

On Thursday, 27 October 2022 at 18:02:29 UTC, Salih Dincer wrote:

>

Merhaba,

Gerçi kişiselleştirilmiş birkaç şablon var ama eskiden (yani Tango zamanları) sanırım x isminde bir şablon varmış. Yani şu şekilde bir hexadecimal veriyi pekala çevirebiliyorduk değil mi?

// D1:
  writeln(x!"e697a5 e69cac e8aa9e"); // 日本語

// D2:
  auto data = hexString!"e697a5 e69cac e8aa9e";

Adım adım gidersek, hata verdiğine göre bu kalktı ve yerine std.conv.hexString gelmiş olmalı. Hatta belki o zamanlar kısaca literal word olarak kullanıyorduk belki de: x!0x01_ff_7f.

D 2.108.0'dan itibaren artık var:
https://dlang.org/changelog/2.108.0.html#dmd.hexstring-cast

SDB@79