Module: Gogyou

Includes:
TypeSpec
Defined in:
lib/gogyou.rb,
lib/gogyou/mixin.rb,
lib/gogyou/model.rb,
lib/gogyou/accessor.rb,
lib/gogyou/typespec.rb,
lib/gogyou/primitives.rb

Overview

gogyou は構造体や共用体、多次元配列 (もどき) を扱うためのライブラリです。

原始的な型情報は Gogyou::Primitives で定義してあり、struct や union メソッド内で利用できる型を次の表に示します:

                            符号あり    符号なし
                            ----        ----
8ビット整数型               char        uchar
                                        unsigned_char
16ビット整数型              short       ushort
                                        unsigned_short
32ビット整数型              int         uint
                                        unsigned_int
環境依存32/64ビット整数型   long        ulong
                                        unsigned_long
64ビット整数型              longlong    ulonglong
                            long_long   unsigned_long_long
32ビット浮動少数型          float
64ビット浮動少数型          double
sizeof 表現型               ssize_t     size_t
ポインタ整数型              intptr_t    uintptr_t

  *** ビット数環境非依存 ***

                バイトオーダー環境依存  バイトオーダー反転
                符号あり  符号なし      符号あり    符号なし
                ----      ----          ----        ----
8ビット整数型   int8_t    uint8_t       //          //
16ビット整数型  int16_t   uint16_t      int16_swap  uint16_swap
24ビット整数型  int24_t   uint24_t      int24_swap  uint24_swap
32ビット整数型  int32_t   uint32_t      int32_swap  uint32_swap
48ビット整数型  int48_t   uint48_t      int48_swap  uint48_swap
64ビット整数型  int64_t   uint64_t      int64_swap  uint64_swap

                ビッグエンディアン    リトルエンディアン
                符号あり  符号なし    符号あり  符号なし
                ----      ----        ----      ----
16ビット整数型  int16_be  uint16_be   int16_le  uint16_le
24ビット整数型  int24_be  uint24_be   int24_le  uint24_le
32ビット整数型  int32_be  uint32_be   int32_le  uint32_le
48ビット整数型  int48_be  uint48_be   int48_le  uint48_le
64ビット整数型  int64_be  uint64_be   int64_le  uint64_le

                    ビッグエンディアン  リトルエンディアン  バイトオーダー反転
32ビット浮動少数型  float_be            float_le            float_swap
64ビット浮動少数型  double_be           double_le           double_swap

利用者定義の型情報

型情報を利用者が定義して利用することが出来ます。

型情報オブジェクトは、次のメソッドを必要とします:

  • bytesize - 型のバイト数です。拡張要素を含んでいる場合は、最小となるバイト数です。

  • bytealign - 型のバイト位置境界です。uint32_t であれば、通常は 4バイトです。

  • aset(buffer, offset, value) - バッファに値を埋め込みます。

  • aref(buffer, offset) - バッファから値を取り出します。

  • extensible? - 型自身が拡張要素、または拡張要素が含まれているかの有無です。int a[0] のような可変個配列などの場合が当てはまります。

利用者定義の型情報は、struct / union / typedef メソッドの引数として与えることが出来ます。

example (ruby.h から struct RBasic と struct RString を模倣した場合)

ポインタ型は実現できていないため、intptr_t で代用しています。

module MyRuby
  extend Gogyou

  typedef :uintptr_t, :VALUE

  RBasic = struct {
    VALUE :flags
    VALUE :klass
  }

  RString = struct {
    RBasic :basic
    union -> {
      struct -> {
        long :len
        intptr_t :ptr
        union -> {
          long :capa
          VALUE :shared
        }, :aux
      }, :heap
      char :ary, RSTRING_EMBED_LEN_MAX + 1
    }, :as
  }
end

“gogyou” の処理の分類とクラスの役割

  • 原始的な型情報の管理と登録

    • Primitives - 原始的な型情報

    • Model::TYPEMAP (hash) - 構造体構築時に利用できる、型名の登録

    • 型情報オブジェクト - 型の情報を保持するオブジェクト

      Primitives 内の定数として定義されているオブジェクトや、Accessor のサブクラスなどが当てはまります。

      利用者定義の任意のオブジェクト (クラスやモジュールも含まれる) も、利用できます。

      利用者定義の型情報オブジェクトについては、README を参照してください。

  • 構造体構築

    • Model - 構造体・共用体の定義時にフィールド並びを管理するためのクラス

      利用者が直接扱う必要はありません。

  • 構造体の実体の管理と参照・操作手段の提供

    • Accessor - 構造体・共用体・配列を定義したあとの各クラスの親クラス

      次のインスタンスメソッドが定義されます。

      • #size - フィールドの要素数。配列の場合はその要素数。

      • #bytesize - バイトサイズを返す。可変長配列を含んでいる場合は、現在の buffer と offset から計算された最大値を返す。

      • #<field> / #<field>= - 構造体・共用体のフィールドへの参照・代入メソッド。配列の場合は定義されない。

      • #[] / []= - 配列の要素への参照・代入メソッド。構造体・共用体の場合は定義されない。

Defined Under Namespace

Modules: Extensions, Primitives, TypeSpec Classes: Accessor, Model

Constant Summary collapse

Gogyou =
self
VERSION =
Gem::Version.new("0.2.2")

Constants included from TypeSpec

TypeSpec::SIZEOF_CHAR, TypeSpec::SIZEOF_DOUBLE, TypeSpec::SIZEOF_FLOAT, TypeSpec::SIZEOF_INT, TypeSpec::SIZEOF_INTPTR_T, TypeSpec::SIZEOF_LONG, TypeSpec::SIZEOF_LONGLONG, TypeSpec::SIZEOF_SHORT, TypeSpec::SIZEOF_SIZE_T

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.define_typeinfo(type, bytesize, bytealign, extensible, aref, aset) ⇒ Object

call-seq:

define_typeinfo(type, bytesize, bytealign, extensible, aref, aset) -> type

“type“ に対して、型情報子とするための特異メソッドである “#bytesize“ “#bytealign“ “#extensible?“ “#aref“ “#aset“ を定義します。

“bytesize“ と “bytealign“ には整数値、文字列、nil を与えます。

“extensible“ には真偽値、文字列、nil を与えます。

“aref“ には、引数として “(buffer, offset)“ を受け取る Proc オブジェクト、文字列、nil を与えます。

“aset“ には、引数として “(buffer, offset, value)“ を受け取る Proc オブジェクト、文字列、nil を与えます。

これらの引数に文字列を与えた場合、メソッド定義コードとして直接埋め込まれます。

“bytesize“ と “bytealign“、“extensible“ の引数はありません。

“aref“ の文字列内部で利用できる引数は “buffer“ “offset“ です。

“aset“ の文字列内部で利用できる引数は “buffer“ “offset“ “value“ です。

また nil を与えた場合は、対応するメソッドの定義を省略します。

常に “type“ を返します。



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/gogyou.rb', line 225

def self.define_typeinfo(type, bytesize, bytealign, extensible, aref, aset)
  type.instance_eval do
    unless bytesize.nil?
      bytesize = bytesize.to_i unless bytesize.kind_of?(String)
      eval <<-EOM
        def bytesize
          #{bytesize}
        end
      EOM
    end

    unless bytealign.nil?
      bytealign = bytealign.to_i unless bytealign.kind_of?(String)
      eval <<-EOM
        def bytealign
          #{bytealign}
        end
      EOM
    end

    unless extensible.nil?
      extensible = (!!extensible).inspect unless extensible.kind_of?(String)
      eval <<-EOM
        def extensible?
          #{extensible}
        end
      EOM
    end

    unless aref.nil?
      if aref.kind_of?(String)
        eval <<-EOM
          def aref(buffer, offset)
            #{aref}
          end
        EOM
      else
        define_singleton_method(:aref, aref)
      end
    end

    unless aset.nil?
      if aset.kind_of?(String)
        eval <<-EOM
          def aset(buffer, offset, value)
            #{aset}
          end
        EOM
      else
        define_singleton_method(:aset, aset)
      end
    end
  end

  type
end

.struct(&block) ⇒ Object

call-seq:

struct { ... } -> accessor class

構造体を定義します。モジュールやクラス内で extend Gogyou しない(したくない)場合に利用することが出来ます。

example

class MyClass
  Type1 = Gogyou.struct {
    ...
  }
end


166
167
168
# File 'lib/gogyou.rb', line 166

def self.struct(&block)
  Model.struct(Model::TYPEMAP.dup, &block).create_accessor
end

.typeinfo(type) ⇒ Object

call-seq:

typeinfo(typename) -> typeinfo
typeinfo(typeobj) -> typeinfo

型名に対する型情報子を取得します。

型情報子を渡した場合は、それをそのまま返り値とします。

型名が存在しないか、型情報子でない場合は nil を返します。



185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/gogyou.rb', line 185

def self.typeinfo(type)
  case type
  when Symbol, String
    return nil unless type =~ /\A[_A-Za-z][_0-9A-Za-z]*\Z/
    Model::TYPEMAP[type.intern]
  else
    if Model.check_typeinfo(type)
      type
    else
      nil
    end
  end
end

.union(&block) ⇒ Object



170
171
172
# File 'lib/gogyou.rb', line 170

def self.union(&block)
  Model.union(Model::TYPEMAP.dup, &block).create_accessor
end

Instance Method Details

#struct(&block) ⇒ Object

構造体 (もどき) を定義します。

入れ子の構造体や共用体を定義するのはもちろん、無名構造体に無名共用体、多次元配列を定義することが出来ます。

extend Gogyou したモジュール・クラス内で定義された構造体(もどき)のクラスは自動的に型情報を取り込みます。 サンプルコードの MyType3 の定義する際に使われる MyType1 と MyType2 に注目して下さい。

example

class MyClass
  extend Gogyou

  MyType1 = struct {        # struct MyType1 {
    uint32_t :a             #   uint32_t a;
    uint32_t :b             #   uint32_t b;
    uint32_t :c, 8, 4       #   uint32_t c[8][4];
  }                         # };

  MyType2 = struct {        # struct MyType2 {
    float :a, :b, :c, 8, 4  #   float a, b, c[8][4];
  }                         # };

  MyType3 = union {         # union MyType3 {
    MyType1 :a              #   MyType1 a;
    MyType2 :b              #   MyType2 b;
  }                         # };
end

t1 = MyClass::MyType1.new
t2 = MyClass::MyType2.bind(String.alloc(MyClass::MyType2::BYTESIZE))
t3 = MyClass::MyType3.bind(File.read("sample.bin", MyClass::MyType3::BYTESIZE, mode: "rb"))


315
316
317
# File 'lib/gogyou.rb', line 315

def struct(&block)
  Model.struct(update_typemap__GOGYOU__, &block).create_accessor
end

#typedef(type, aliasname, *elements) ⇒ Object

call-seq:

typedef type, aliasname -> self
typedef type, aliasname, *elements -> self
type

This parameter can given a symbol or an object.

シンボル (または文字列) を与える場合、すでに定義されている型名である必要があります。

クラスオブジェクト (またはモジュールオブジェクト) を与える場合、‘.aset` と `.aref` `.bytesize` `.bytealign` メソッドを持つ必要があります。

aliasname

定義する型名としてのシンボル (または文字列) を与えます。

elements

配列型の要素数を与えます。要素数は複数をとることが出来、最後の要素数として ‘0` を与えると任意個の要素数として定義されます。



366
367
368
# File 'lib/gogyou.rb', line 366

def typedef(type, aliasname, *elements)
  Model.typedef(update_typemap__GOGYOU__, type, aliasname, *elements)
end

#typeinfo(type) ⇒ Object

call-seq:

typeinfo(typename) -> typeinfo
typeinfo(typeobj) -> typeinfo

型名に対する型情報子を取得します。

型情報子を渡した場合は、それをそのまま返り値とします。

型名が存在しないか、型情報子でない場合は nil を返します。



334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/gogyou.rb', line 334

def typeinfo(type)
  case type
  when Symbol, String
    return nil unless type =~ /\A[_A-Za-z][_0-9A-Za-z]*\Z/
    update_typemap__GOGYOU__[type.intern]
  else
    if Model.check_typeinfo(type)
      type
    else
      nil
    end
  end
end

#union(&block) ⇒ Object



319
320
321
# File 'lib/gogyou.rb', line 319

def union(&block)
  Model.union(update_typemap__GOGYOU__, &block).create_accessor
end