gogyou 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9633436e949f5045c684dde26894ed49cb30630e
4
- data.tar.gz: 86d4d3037ebbbf38f66757aa1735cdb4430f684b
3
+ metadata.gz: 163f1b2f74bea2dc136f06beb499aaf9904db858
4
+ data.tar.gz: b7d8d846d1dfa2ee4747ab51d5dabdf29bdc63f4
5
5
  SHA512:
6
- metadata.gz: 014588ae16a1e4def6fb346f49f8102e268d7035e0b0a7174430c3a1e31dccc085dc5c5045f9fcba7f3c7fe738892ff34e26d7503eb8d0b4c0e90447f0655c93
7
- data.tar.gz: dc82211d768d36370a59b67b03e3715cde0cea1c351f0914ec6f6948cfeac50b0c8bdc21e306684fe7e1e3e517b949cf848067592a1adcde0a823fdeb6e2c0ea
6
+ metadata.gz: e0ab33b2ed9a6758fdd4d784839138aa78f1ef17ba18def71a46063bf8a95ed7e5b52241635abfd247c117056457bf526c25e6701425d9fc010dfb3c72a17f0d
7
+ data.tar.gz: 44db392c49b2afe2649b1815ea12e3770499ae0697eb848bb0744953990d25b760000c3bcf905d62fdc62bf2159c63909686c490482e2e40d2fd54fd5ef1cdea
@@ -1,5 +1,19 @@
1
1
  # gogyou の更新履歴
2
2
 
3
+ ## gogyou-0.2.5 (2015-10-20)
4
+
5
+ * 可変長要素に続く要素の定義
6
+
7
+ 構造体定義中に可変長要素を置いた場合、続く要素を定義出来ませんでしたがこの制限を撤廃しています。
8
+
9
+ この場合、可変長要素の可変長領域と、続く要素の領域以降が重なるため、部分的に union を用いたような動作となります。
10
+
11
+ * ポインタ要素の実現 (実験的)
12
+
13
+ 非常に限定的ながらポインタ要素の定義を可能としました。
14
+ 詳細は pointer.ja.md を参照して下さい。
15
+
16
+
3
17
  ## gogyou-0.2.4 (2015-10-16)
4
18
 
5
19
  * 環境依存の型に対する結果の正確性を修正
data/README.md CHANGED
@@ -23,7 +23,7 @@ ruby 構文による、C 言語の構造体・共用体・多次元配列 (も
23
23
  * Distribute License (頒布ライセンス): 2-clause BSD License (二条項 BSD ライセンス)
24
24
  * Software Quarity (ソフトウェア品質): EXPERIMENTAL
25
25
  * User (想定利用者): Rubyist
26
- * Release Number (リリースナンバー): 0.2.4
26
+ * Release Number (リリースナンバー): 0.2.5
27
27
  * Memory Usage (使用メモリ量): 2 MB +
28
28
  * Installed Size (インストール容量): under 1 MB
29
29
  * Project Page: <https://osdn.jp/projects/rutsubo/>
@@ -32,7 +32,7 @@ ruby 構文による、C 言語の構造体・共用体・多次元配列 (も
32
32
  ## Example
33
33
 
34
34
  ruby/ruby.h の ``struct RBasic`` と ``struct RObject`` を gogyou を用いて次のように記述出来ます
35
- (ポインタの定義はできていないため、``uintptr_t`` で置き換えています):
35
+ (ポインタの定義は ``uintptr_t`` で置き換えています):
36
36
 
37
37
  ``` ruby:ruby
38
38
  require "gogyou"
@@ -54,8 +54,8 @@ module MyRuby
54
54
  union -> {
55
55
  struct -> {
56
56
  long :numiv
57
- uintptr_t :ivptr
58
- uintptr_t :iv_index_tbl
57
+ uintptr_t :ivptr # VALUE *ivptr
58
+ uintptr_t :iv_index_tbl # struct st_table *iv_index_tbl
59
59
  }, :heap
60
60
  VALUE :ary, ROBJECT_EMBED_LEN_MAX
61
61
  }, :as
@@ -632,9 +632,6 @@ data = YourStruct.bind(ptr)
632
632
 
633
633
  ## Demerit (短所)
634
634
 
635
- * Can't be handled pointer
636
- (ポインタが扱えない)
637
-
638
635
  * The cost is high for reference/asignment from/to fields
639
636
  (フィールドに対する参照・代入のコストが高い)
640
637
 
data/Rakefile CHANGED
@@ -24,7 +24,8 @@ GEMSTUB.extensions += EXTCONF
24
24
  GEMSTUB.executables += FileList["bin/*"].map { |n| File.basename n }
25
25
  GEMSTUB.executables.sort!
26
26
 
27
- GEMFILE = "#{GEMSTUB.name}-#{GEMSTUB.version}.gem"
27
+ PACKAGENAME = "#{GEMSTUB.name}-#{GEMSTUB.version}"
28
+ GEMFILE = "#{PACKAGENAME}.gem"
28
29
  GEMSPEC = "#{GEMSTUB.name}.gemspec"
29
30
 
30
31
  GEMSTUB.files += DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + EXTRA
@@ -143,6 +144,11 @@ task gem: GEMFILE
143
144
  desc "generate gemspec"
144
145
  task gemspec: GEMSPEC
145
146
 
147
+ desc "print package name"
148
+ task "package-name" do
149
+ puts PACKAGENAME
150
+ end
151
+
146
152
  file GEMFILE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + [GEMSPEC] do
147
153
  sh "gem build #{GEMSPEC}"
148
154
  end
data/gemstub.rb CHANGED
@@ -10,11 +10,15 @@ The gogyou is a library written at pure ruby that provides auxiliary features of
10
10
 
11
11
  The C-liked struct, union and multidimensional array definition are posible in ruby syntax.
12
12
 
13
- * Available nested struct and union with anonymous field.
14
- * Available multidimensional array.
15
- * Available const field.
16
- * Available packed field.
17
- * Available user definition types.
13
+ Available features:
14
+
15
+ (1) nested struct and union with anonymous field
16
+ (2) multidimensional array
17
+ (3) field of variable array
18
+ (4) const field
19
+ (5) packed field
20
+ (6) user definition types
21
+ (7) (EXPERIMENTAL AND LIMITATION FEATURE) pointer
18
22
  EOS
19
23
  s.license = "2-clause BSD License"
20
24
  s.author = "dearblue"
@@ -26,6 +30,8 @@ EOS
26
30
  s.add_development_dependency "rake", "~> 10.0"
27
31
  end
28
32
 
33
+ DOC << "pointer.ja.md"
34
+
29
35
  primitives = "lib/gogyou/primitives.rb"
30
36
  mkprims = "mkprims.rb"
31
37
  LIB << primitives
@@ -163,6 +163,12 @@
163
163
  module Gogyou
164
164
  Gogyou = self
165
165
 
166
+ class PointerError < ::RuntimeError
167
+ end
168
+
169
+ class NullPointerError < PointerError
170
+ end
171
+
166
172
  require_relative "gogyou/version"
167
173
  require_relative "gogyou/typespec"
168
174
  require_relative "gogyou/extensions"
@@ -424,6 +430,8 @@ module Gogyou
424
430
  # typedef type, aliasname -> self
425
431
  # typedef type, aliasname, *elements -> self
426
432
  #
433
+ # ***limitation***: not usable the pointer.
434
+ #
427
435
  # [type]
428
436
  # This parameter can given a symbol or an object.
429
437
  #
@@ -177,6 +177,12 @@ module Gogyou
177
177
  subarray
178
178
  end
179
179
 
180
+ def self.define_subpointer(typeobj, constant = false)
181
+ newtype = Accessor::Pointer.define(typeobj)
182
+ Accessor.const_set("AnonymousPointer_%08X" % newtype.__id__, newtype)
183
+ newtype
184
+ end
185
+
180
186
  def self.define_accessors(accessorclass, model)
181
187
  accessorclass.class_eval do
182
188
  namecheck = {}
@@ -252,6 +258,114 @@ module Gogyou
252
258
  self::EXTENSIBLE
253
259
  end
254
260
 
261
+ class Pointer < Accessor
262
+ BYTESIZE = Primitives::SIZE_T.bytesize
263
+ BYTEALIGN = Primitives::SIZE_T.bytealign
264
+ EXTENSIBLE = false
265
+
266
+ def self.aref(buf, off)
267
+ new(buf, off)
268
+ end
269
+
270
+ def self.aset(buf, off, val)
271
+ if val.kind_of?(Fixnum)
272
+ buf.store_sizet(off, val)
273
+ else
274
+ raise PointerError, "wrong address (#{val.class} for Fixnum)"
275
+ end
276
+
277
+ buf
278
+ end
279
+
280
+ def self.define(type)
281
+ require_relative "fiddle" # for Fiddle::Pointer and extend
282
+
283
+ Class.new(Pointer) do |t|
284
+ define_singleton_method(:aset, ->(buf, off, val) {
285
+ if val.kind_of?(self)
286
+ addr = val.buffer.load_sizet(val.offset)
287
+ buf.store_sizet(off, addr)
288
+ else
289
+ super
290
+ end
291
+
292
+ buf
293
+ })
294
+
295
+ define_method(:pointer_address, -> {
296
+ @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__)
297
+ })
298
+
299
+ define_method(:[], ->(*args) {
300
+ case args.size
301
+ when 0
302
+ elem = 0
303
+ when 1
304
+ elem = args[0].to_i
305
+ else
306
+ raise ArgumentError, "wrong argument size (#{args.size} for 0 .. 1)"
307
+ end
308
+ addr = @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__)
309
+ if addr == 0
310
+ raise NullPointerError, "nullpo - #<%s:0x%08X>" % [self.class, __id__ << 1]
311
+ end
312
+ buf = ::Fiddle::Pointer.new(addr + elem * type.bytesize, type.bytesize)
313
+ type.aref(buf, 0)
314
+ })
315
+
316
+ define_method(:[]=, ->(*args) {
317
+ case args.size
318
+ when 1
319
+ elem = 0
320
+ v = args[0]
321
+ when 2
322
+ elem = args[0].to_i
323
+ v = args[1]
324
+ else
325
+ raise ArgumentError, "wrong argument size (#{args.size} for 1 .. 2)"
326
+ end
327
+
328
+ addr = @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__)
329
+ if addr == 0
330
+ raise NullPointerError, "nullpo - #<%s:0x%08X>" % [self.class, __id__ << 1]
331
+ end
332
+ buf = ::Fiddle::Pointer.new(addr + elem * type.bytesize, type.bytesize)
333
+ type.aset(buf, 0, v)
334
+ v
335
+ })
336
+
337
+ define_method(:+, ->(elem) {
338
+ addr = @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__)
339
+ buf = String.alloc(Primitives::SIZE_T.bytesize)
340
+ buf.store_sizet(0, addr + elem * type.bytesize)
341
+ self.class.new(buf, 0)
342
+ })
343
+
344
+ typename = String(type.respond_to?(:name) ? type.name : type) rescue String(type)
345
+ define_method(:inspect, -> {
346
+ addr = @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__)
347
+ "#<*%s:0x%08X>" % [typename, addr]
348
+ })
349
+ end
350
+ end
351
+
352
+ #
353
+ # call-seq:
354
+ # self + elem_num -> new pointer object
355
+ #
356
+ def +(elem_num)
357
+ raise NotImplementedError, "this method is shall be defined in sub-class"
358
+ end
359
+
360
+ def -(off)
361
+ send(:+, -off.to_i)
362
+ end
363
+
364
+ def pretty_print(q)
365
+ q.text inspect
366
+ end
367
+ end
368
+
255
369
  class BasicStruct < Accessor
256
370
  end
257
371
 
@@ -360,8 +360,16 @@ module Gogyou
360
360
  raise ArgumentError, "nothing argument" if args.empty?
361
361
  name = nil
362
362
  vector = nil
363
- while arg = args.shift
363
+ args.each do |arg|
364
364
  case arg
365
+ when ::Array # pointer field
366
+ yield(name, vector) if name
367
+ name = nil
368
+ vector = nil
369
+ parse!(arg) do |name1, elements|
370
+ raise ArgumentError, "wrong pointer definision" if name
371
+ name = Model::Pointer.create(name1, elements)
372
+ end
365
373
  when Symbol, String
366
374
  yield(name, vector) if name
367
375
  raise ArgumentError, "informal field name (#{arg.to_s})" unless arg =~ FIELDNAME_PATTERN
@@ -369,16 +377,11 @@ module Gogyou
369
377
  vector = nil
370
378
  when Integer
371
379
  raise ArgumentError, "first argument is field name only (#{arg})" unless name
372
- raise ArgumentError, "given negative number (#{arg})" unless arg >= 0
380
+ raise ArgumentError, "can't internal extensible in multi-dimentional array" if vector && vector[-1] < 1
381
+ v = arg.to_i
382
+ raise ArgumentError, "given negative number (#{arg})" unless v >= 0
373
383
  vector ||= []
374
- vector << arg.to_i
375
- if vector[-1] == 0
376
- yield(name, vector)
377
- unless args.empty?
378
- raise ArgumentError, "given fields after extensible vector"
379
- end
380
- return nil
381
- end
384
+ vector << v
382
385
  else
383
386
  raise ArgumentError, "given any object (#{arg.inspect})"
384
387
  end
@@ -399,24 +402,31 @@ module Gogyou
399
402
  end
400
403
 
401
404
  def addfield!(typeobj, packexp, args)
402
- #p typeobj
403
- # check extensible field >>> creator.fields[-1].vector[-1]
404
- if (x = fields[-1]) && (x = x.vector) && x[-1] == 0
405
- raise ArgumentError, "not given fields after extensible vector"
406
- end
407
-
408
- typesize = typeobj.bytesize
409
- typealign = [typeobj.bytealign, 1 << packexp].min
405
+ typesize = typealign = nil # 自己参照構造体を実現するために必要な時に取得する
410
406
 
411
407
  tmpfields = []
412
408
 
413
409
  parse!(args) do |name, vect|
414
- self.offset = offset.align_ceil(typealign) unless kind_of?(Model::Union::Creator)
415
- fields << f = Field[offset, name, vect, typeobj, 0 | packexp]
416
- tmpfields << f
417
- unless kind_of?(Model::Union::Creator)
418
- elements = vect ? vect.inject(1, &:*) : 1
419
- self.offset += typesize * elements
410
+ if name.kind_of?(Model::Pointer::Creator)
411
+ (name, ptrtype) = name.create(typeobj)
412
+ self.offset = offset.align_ceil(Primitives::SIZE_T.bytealign) unless kind_of?(Model::Union::Creator)
413
+ fields << f = Field[offset, name, vect, ptrtype, 0 | packexp]
414
+ tmpfields << f
415
+ unless kind_of?(Model::Union::Creator)
416
+ elements = vect ? vect.inject(1, &:*) : 1
417
+ self.offset += Primitives::SIZE_T.bytesize * elements
418
+ end
419
+ else
420
+ typesize ||= typeobj.bytesize
421
+ typealign ||= [typeobj.bytealign, 1 << packexp].min
422
+
423
+ self.offset = offset.align_ceil(typealign) unless kind_of?(Model::Union::Creator)
424
+ fields << f = Field[offset, name, vect, typeobj, 0 | packexp]
425
+ tmpfields << f
426
+ unless kind_of?(Model::Union::Creator)
427
+ elements = vect ? vect.inject(1, &:*) : 1
428
+ self.offset += typesize * elements
429
+ end
420
430
  end
421
431
  end
422
432
 
@@ -471,6 +481,27 @@ module Gogyou
471
481
  end
472
482
  end
473
483
 
484
+ class Pointer < Model
485
+ class Creator < ::Struct.new(:token, :elements)
486
+ def create(typeobj)
487
+ name = token
488
+ if name.kind_of?(Creator)
489
+ # multiple pointer
490
+ (name, typeobj) = name.create(typeobj)
491
+ end
492
+ if elements && !elements.empty?
493
+ typeobj = Accessor.define_subarray(Model::Field[0, nil, elements, typeobj, 0])
494
+ end
495
+ model = Accessor.define_subpointer(typeobj)
496
+ [name, model]
497
+ end
498
+ end
499
+
500
+ def self.create(token, elements)
501
+ Creator.new(token, elements)
502
+ end
503
+ end
504
+
474
505
  class Struct < Model
475
506
  class Creator < Model::BasicCreator
476
507
  def bytealign(bytesize)
@@ -1,3 +1,3 @@
1
1
  module Gogyou
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  end
@@ -0,0 +1,104 @@
1
+
2
+ # About pointer (ポインタについて) (***EXPERIMENTAL FEATURE***)
3
+
4
+ 非常に限定的ながらポインタを扱うことが出来るようになりました (0.2.5 にて追加)。
5
+
6
+ 構造体を作成する時に、ポインタとしたい要素を配列としてくくることで定義できます。
7
+
8
+ C と ruby を並べて記述しています (左側が ruby、右側が C):
9
+
10
+ ``` ruby:ruby
11
+ int [:a] # => int *a
12
+
13
+ int [[[[:a]]]] # => int ****a
14
+
15
+ int [:a, 4] # => (NOW) int (*a)[4]
16
+ # (FEATURE) int *a[4] : "a" is a 4 elements pointer of int
17
+
18
+ int [:a], 4 # => (NOW) int *a[4]
19
+ # (FEATURE) int (*a)[4] : "a" is a pointer of 4 elements int
20
+
21
+ int [:a, 4], 8 # => (NOW) int (*a[8])[4]
22
+ # (FEATURE) int (*a[4])[8] : "a" is a 4 elements pointer of 8 elements int
23
+
24
+ const int [:a] # => (NOW) int *const a
25
+ # (FEATURE) const int *a : "a" is a pointer of constant int
26
+
27
+ int [const(:a)] # => (NOW) NOT WORK
28
+ # (FEATURE) int *const a : "a" is a constant pointer of int
29
+
30
+ a[] # => *a , a[0]
31
+ a[1] # => a[1]
32
+ a[][1] # => (*a)[1] , a[0][1]
33
+ ```
34
+
35
+ 実際に利用した例 (***ruby の規律から逸脱しているため、実用しないで下さい***):
36
+
37
+ ``` ruby:ruby
38
+ X = Gogyou.struct {
39
+ int [:a]
40
+ }
41
+
42
+ frozen_str = "abcdefghijklmn"
43
+ x = X.new([frozen_str].pack("p"))
44
+ frozen_str.freeze
45
+
46
+ x.a[] = 0x44434241 # *x.a = 0x44434241
47
+ p frozen_str # => "ABCDefghijklmn"
48
+ # ^^^^
49
+
50
+ x.a[2] ^= 0x20202020 # same as C code
51
+ p frozen_str # => "ABCDefghIJKLmn"
52
+ # ^^^^
53
+
54
+ x.a += 1 # address + sizeof(int[1])
55
+ x.a[] = 0x24232221 # *x.a = 0x24232221
56
+ p frozen_str # => "ABCD!\"\#$IJKLmn"
57
+ # ^^^^^^
58
+ ```
59
+
60
+ 実験的な機能のため、以下の制限(出来無いこと)があります:
61
+
62
+ * const 修飾子が機能しない (又は挙動がおかしい)
63
+ * typedef 出来ない
64
+ * ポインタと配列の定義を混ぜると挙動がおかしい
65
+ * そもそも C に見えない!
66
+
67
+
68
+ ## 自己参照構造体、相互参照構造体について
69
+
70
+ ポインタによる自己参照構造体、相互参照構造体を定義する場合、Gogyou::Struct クラスを継承したクラスを定義することで可能です。
71
+
72
+ ``` C:C
73
+ struct TypeA;
74
+
75
+ struct TypeB
76
+ {
77
+ struct TypeA *a;
78
+ struct TypeB *b;
79
+ };
80
+
81
+ struct TypeA
82
+ {
83
+ struct TypeB *b;
84
+ };
85
+ ```
86
+
87
+ ``` ruby:ruby
88
+ class TypeA < Gogyou::Struct
89
+ # class definition only!
90
+ end
91
+
92
+ class TypeB < Gogyou::Struct
93
+ struct {
94
+ struct TypeA, [:a]
95
+ struct TypeB, [:b]
96
+ }
97
+ end
98
+
99
+ class TypeA
100
+ struct {
101
+ struct TypeB, [:b]
102
+ }
103
+ end
104
+ ```
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gogyou
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - dearblue
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-16 00:00:00.000000000 Z
11
+ date: 2015-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -43,11 +43,15 @@ description: |
43
43
 
44
44
  The C-liked struct, union and multidimensional array definition are posible in ruby syntax.
45
45
 
46
- * Available nested struct and union with anonymous field.
47
- * Available multidimensional array.
48
- * Available const field.
49
- * Available packed field.
50
- * Available user definition types.
46
+ Available features:
47
+
48
+ (1) nested struct and union with anonymous field
49
+ (2) multidimensional array
50
+ (3) field of variable array
51
+ (4) const field
52
+ (5) packed field
53
+ (6) user definition types
54
+ (7) (EXPERIMENTAL AND LIMITATION FEATURE) pointer
51
55
  email: dearblue@users.osdn.me
52
56
  executables: []
53
57
  extensions: []
@@ -65,6 +69,7 @@ extra_rdoc_files:
65
69
  - lib/gogyou/primitives.rb
66
70
  - lib/gogyou/typespec.rb
67
71
  - lib/gogyou/version.rb
72
+ - pointer.ja.md
68
73
  files:
69
74
  - HISTORY.ja.md
70
75
  - LICENSE
@@ -82,6 +87,7 @@ files:
82
87
  - lib/gogyou/typespec.rb
83
88
  - lib/gogyou/version.rb
84
89
  - mkprims.rb
90
+ - pointer.ja.md
85
91
  - spec/gogyou_spec.rb
86
92
  - test/test_loadstore.rb
87
93
  - test/test_packbin.rb