Thread overview
Read Buffer
Feb 27, 2022
Salih Dincer
Feb 27, 2022
Ali Çehreli
February 27, 2022

Merhaba,

Meğer bu sabah, çok leziz bir kod ile karşılaşacakmışım! Yabancı forumda denk geldiğim ve Ali hocanın sarmaladığı bu yöntemi çok beğendim...

Ufkumu açtı, teşekkür ederim.

import std.system;

void main() {
  auto read(T, Endian E = Endian.bigEndian, R)
           (R range) {
    import bop = std.bitmanip;
    return bop.read!(T, E)(range);
  }
//               MSB:  0,    1,    2,    3,
  ubyte[8] buffer = [ 0xFF, 0xFF, 0xFF, 0xFF,
                      0xAA, 0xAA, 0xFF, 0xFF ];
//               LSB:  4,    5,    6,    7
  ushort us;
         us = read!(typeof(us))(buffer[4..6]);
  assert(us == 0xAAAA);
} /* ŞURDA BAŞLADI:

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

   */

Aslında kullanımı şöyle daha kısa ve belki daha güzel!

ushort us = buffer[4..6].read!ushort;

Ama bu şekilde çalışması için (CTFE olayları) işlevin main() dışında olması lazım nedense?

Başarılar...

February 27, 2022
> Ama bu şekilde çalışması için (CTFE olayları)

Aslında lvalue-rvalue olayları... :) (sol değer - sağ değer) data[4..6] bir sağ değerdir:

  http://ddili.org/ders/d/deger_sol_sag.html

> işlevin main() dışında
> olması lazım nedense?

read(), dilimi 'ref' olarak alıyor çünkü onda değişiklik yapmak istiyor. D'de rvalue ifadeler 'ref' olarak geçirilemezler[1]. O yüzden ben 'ref' olarak almayan bir işlev yazarak rvalue'yu lvalue'ya dönüştürmüş oldum. (Yani, rvalue'yu kopyaladım; dilim kopyalamak da çok ucuz bir işlemdir.) Sonuçta read() mutlu, biz mutlu...

Ali

[1] C++'ta ise rvalue'lar 'const &' olarak geçirilebilirler ve bunun D'de de olması istenir. Onun yerine, artık daha mantıklı işleyen 'in' parametrelerimiz var. Eğer işlevlerin giriş parametrelerini 'in' olarak tanımlarsak ve programı (şimdilik) -preview=in olarak derlersek, rvalue'lar da referans olarak geçirilirler:


http://ddili.org/ders/d/islev_parametreleri.html#ix_islev_parametreleri.in,%20parametre

'in' parametreler çok anlamlı. Daha çok kullanmak gerek.

October 17

On Sunday, 27 February 2022 at 11:25:27 UTC, Salih Dincer wrote:

>

Aslında kullanımı şöyle daha kısa ve belki daha güzel!

ushort us = buffer[4..6].read!ushort;

Eski bir başlığı hortlatmak zorundaydım! Sebebi basit:

Konumuz olan std.bitmanip.read aralıklarla çalışma kabiliyetine sahip olsa da sadece byte türünü okuyor. Oysa basit şekilde readUnits() kullanılabilir de!

Bir süredir readBytes() şablonunu kullanıyordum. Bu bana big/littleEndian geçişini (sadece true/false ile) kolaylaştırıyordu. Üstelik kütüphanedeki read() çakışmasını önlüyordu. İşte bu yüzden aslında isminin readBytes() olması gerektiğini iddia ediyorum; verdiği hata kodu bunu destekliyor. Neyse ki artık alternatifimiz var:

import std.range;
alias TestType = ushort;

void main()
{
  TestType[] data1 = [ 0, 1, 2, 3, 4, 5 ];
  auto data12 = iota(cast(TestType)data1.length);

  while(!data12.empty)
  {
    data12.testRange!uint;
  }
}/* readBytes() Results:

  (ubyte -> ushort): [1, 515, 1029]
  (ushort -> uint): fail
  Error: dlang/dmd/linux/bin64/../../src/phobos/std/bitmanip.d(3721):        Candidate is: `read(T, Endian endianness = Endian.bigEndian, R)(ref R range)`
  with `T = uint,
       endianness = E,
       R = Result`
  must satisfy the following constraint:
`       is(ElementType!R : const(ubyte))`
  HATANIN NEDENİ ------------------^
  
  readUnits() Results:

  (ubyte -> ushort): [1, 515, 1029]
  (ushort -> uint): [1, 131075, 262149]
//*/

template readUnits(T, R)
{
  enum ES = ElementType!R.sizeof;
  enum size = T.sizeof / ES;

  auto readUnits(ref R data)
  {
    T result;
    auto len = size;
    while(len--)
    {
      result <<= ES * 8;
      result |= data.front;
      data.popFront;
    }
    return result;
  }
}

template readBytes(T, bool big = true, R)
{        // pair endian version 2.0
  import bop = std.bitmanip;

  static if(big)
    enum E = bop.Endian.bigEndian;
  else
    enum E = bop.Endian.littleEndian;

  auto readBytes(ref R dat)
   => bop.read!(T, E)(dat);
}

void testRange(T, R)(ref R r)
{
  import std.stdio : writefln;

  //r.readBytes!T.writefln!"%s";/*
  r.readUnits!T.writefln!"%s";//*/
  writefln("Data: %s, Length: %s", r, r.length);
}

Play Ground Link: https://run.dlang.io/is/iFth1w

Sorunu yukardaki kodun testRange() işlevini değiştirip derleyerek veya kod içine işaret ettiğim hata koduna bakarak anlayabilirsiniz.

Kolay gelsin...