class Gogyou::Model::BasicCreator

Public Instance Methods

addfield(type, packexp, args) click to toggle source
# File lib/gogyou/model.rb, line 395
def addfield(type, packexp, args)
  typeobj = typemap[type.intern]
  unless typeobj
    raise NoMethodError, "typename or method is missing (#{type})"
  end

  addfield!(typeobj, packexp, args)
end
addfield!(typeobj, packexp, args) click to toggle source
# File lib/gogyou/model.rb, line 404
def addfield!(typeobj, packexp, args)
  typesize = typealign = nil # 自己参照構造体を実現するために必要な時に取得する

  tmpfields = []

  parse!(args) do |name, vect|
    if name.kind_of?(Model::Pointer::Creator)
      (name, ptrtype) = name.create(typeobj)
      self.offset = offset.align_ceil(Primitives::SIZE_T.bytealign) unless kind_of?(Model::Union::Creator)
      fields << f = Field[offset, name, vect, ptrtype, 0 | packexp]
      tmpfields << f
      unless kind_of?(Model::Union::Creator)
        elements = vect ? vect.inject(1, &:*) : 1
        self.offset += Primitives::SIZE_T.bytesize * elements
      end
    else
      typesize ||= typeobj.bytesize
      typealign ||= [typeobj.bytealign, 1 << packexp].min

      self.offset = offset.align_ceil(typealign) unless kind_of?(Model::Union::Creator)
      fields << f = Field[offset, name, vect, typeobj, 0 | packexp]
      tmpfields << f
      unless kind_of?(Model::Union::Creator)
        elements = vect ? vect.inject(1, &:*) : 1
        self.offset += typesize * elements
      end
    end
  end

  tmpfields
end
const(fields) click to toggle source
# File lib/gogyou/model.rb, line 330
def const(fields)
  fields.each { |f| f.set_const }
end
define_container(args, packexp, anonymblock, container) click to toggle source
# File lib/gogyou/model.rb, line 309
def define_container(args, packexp, anonymblock, container)
  if anonymblock
    raise ArgumentError, "given block and arguments" unless args.empty?
    model = container.(typemap.dup, packexp, &anonymblock)
    raise "BUG - object is not a Model (#{model.class})" unless model.kind_of?(Model)
    #p model: model, superclass: model.superclass
    self.offset = offset.align_ceil(model.bytealign) unless kind_of?(Model::Union::Creator)
    fields << f = Field[offset, nil, nil, model, packexp]
    self.offset += model.bytesize unless kind_of?(Model::Union::Creator)
    [f]
  else
    type = args.shift
    type = container.(typemap.dup, packexp, &type) if type.kind_of?(::Proc)
    addfield!(type, packexp, args)
  end
end
flatten_field(fields = self.fields) click to toggle source
# File lib/gogyou/model.rb, line 236
def flatten_field(fields = self.fields)
  #pp fields
  fields2 = []
  fields.each do |f|
    #p f
    #p f.class
    if f.name
      fields2 << f
    else
      raise "BUG? : field.type is not a Model (%p)" % f.type unless f.type.kind_of?(Model)
      fs = flatten_field(f.type.fields)
      fs.each { |ff| ff.offset += f.offset; ff.set_const if f.const? }
      fields2.concat fs
    end
  end
  fields2
end
maxalign(fields = self.fields) click to toggle source
# File lib/gogyou/model.rb, line 228
def maxalign(fields = self.fields)
  fields.map { |f| f.packed? ? f.packsize : f.type.bytealign }.max
end
maxsize(fields = self.fields) click to toggle source
# File lib/gogyou/model.rb, line 232
def maxsize(fields = self.fields)
  fields.map { |f| f.bytesize }.max
end
packed { ... } → nil click to toggle source
packed(bytealign) { ... } → nil

ブロック内部のフィールドのバイトアライメントを調節します。

packed を直接の入れ子にして呼び出すことは出来ません。struct や union を挟んで呼び出すことは出来ます。

引数無しで呼び出した場合は、bytealign に 1 を与えて呼び出すものと同義となります。

bytealign

1 以上で2の冪乗となる整数値を指定します。

nil を与えた場合、上位階層で指定したパックサイズを無効化して本来のバイトアライメントに配置するようにします。

# File lib/gogyou/model.rb, line 350
def packed(bytealign = 1)
  raise "This method is defined for documentaion. Real implemented is in Gogyou::Model::BasicCreator::Proxy#initialize"
  yield
  nil
end
parse!(args) { |name, vector| ... } click to toggle source

フィールド名の解析

# File lib/gogyou/model.rb, line 359
def parse!(args)
  raise ArgumentError, "nothing argument" if args.empty?
  name = nil
  vector = nil
  args.each do |arg|
    case arg
    when ::Array  # pointer field
      yield(name, vector) if name
      name = nil
      vector = nil
      parse!(arg) do |name1, elements|
        raise ArgumentError, "wrong pointer definision" if name
        name = Model::Pointer.create(name1, elements)
      end
    when Symbol, String
      yield(name, vector) if name
      raise ArgumentError, "informal field name (#{arg.to_s})" unless arg =~ FIELDNAME_PATTERN
      name = arg.intern
      vector = nil
    when Integer
      raise ArgumentError, "first argument is field name only (#{arg})" unless name
      raise ArgumentError, "can't internal extensible in multi-dimentional array" if vector && vector[-1] < 1
      v = arg.to_i
      raise ArgumentError, "given negative number (#{arg})" unless v >= 0
      vector ||= []
      vector << v
    else
      raise ArgumentError, "given any object (#{arg.inspect})"
    end
  end

  yield(name, vector)

  nil
end
struct type, name, *vector click to toggle source
struct proc, name, *vector
struct { ... }

最初と二番目の呼び出し方法は、既存の (typedef していない) 型情報を用いる、または構造体をその場で定義するために利用できます。

三番目の呼び出し方法は、無名構造体を定義するために利用できます。

example (型情報を用いる)

Type1 = struct {
  struct UserType, :a, :b, 2, 3, 4
}

example (構造体をその場で定義して、構造体へのアクセッサを定義する)

Type2 = struct {
  struct -> {
    int :x, y, z
  }, :a, :b, 2, 3, 4
}

example (無名構造体)

Type3 = struct {
  struct {
    int :a, :b, 2, 3, 4
  }
}
# File lib/gogyou/model.rb, line 286
def struct(args, packexp, &block)
  define_container(args, packexp, block, Model.method(:struct))
end
typedef(args) click to toggle source
# File lib/gogyou/model.rb, line 326
def typedef(args)
  raise NotImplementedError
end
union type, name, *vector click to toggle source
union proc, name, *vector
union { ... }

共用体を定義します。

呼び出し方は struct と変わりません。

ただ、union type, ... の場合は、struct type, ... と同じ結果となります。 これは type がどのような構造になっているのかを gogyou が管理も把握もしないためです。 この記述ができる唯一の理由は、人間が見てわかりやすくすることを意図しています (ただし、ミスリードを誘う手口にも利用されてしまうのが最大の欠点です)。

# File lib/gogyou/model.rb, line 305
def union(args, packexp, &block)
  define_container(args, packexp, block, Model.method(:union))
end