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