carray 1.1.4 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (231) hide show
  1. checksums.yaml +4 -4
  2. data/COPYING +56 -0
  3. data/GPL +340 -0
  4. data/Gemfile +9 -0
  5. data/Gemfile.lock +33 -0
  6. data/LEGAL +50 -0
  7. data/NOTE +73 -0
  8. data/Rakefile +20 -0
  9. data/TODO +5 -0
  10. data/ca_iter_block.c +242 -0
  11. data/ca_iter_dimension.c +287 -0
  12. data/ca_iter_window.c +202 -0
  13. data/ca_obj_array.c +1189 -0
  14. data/ca_obj_bitarray.c +523 -0
  15. data/ca_obj_bitfield.c +636 -0
  16. data/ca_obj_block.c +885 -0
  17. data/ca_obj_fake.c +405 -0
  18. data/ca_obj_farray.c +482 -0
  19. data/ca_obj_field.c +625 -0
  20. data/ca_obj_grid.c +738 -0
  21. data/ca_obj_mapping.c +614 -0
  22. data/ca_obj_object.c +777 -0
  23. data/ca_obj_reduce.c +299 -0
  24. data/ca_obj_refer.c +627 -0
  25. data/ca_obj_repeat.c +640 -0
  26. data/ca_obj_select.c +558 -0
  27. data/ca_obj_shift.c +952 -0
  28. data/ca_obj_transpose.c +582 -0
  29. data/ca_obj_unbound_repeat.c +557 -0
  30. data/ca_obj_window.c +1023 -0
  31. data/carray.h +1381 -0
  32. data/carray_access.c +1798 -0
  33. data/carray_attribute.c +903 -0
  34. data/carray_call_cfunc.c +1107 -0
  35. data/carray_cast.c +1155 -0
  36. data/carray_cast_func.rb +498 -0
  37. data/carray_class.c +132 -0
  38. data/carray_conversion.c +518 -0
  39. data/carray_copy.c +453 -0
  40. data/carray_core.c +1307 -0
  41. data/carray_element.c +572 -0
  42. data/carray_generate.c +681 -0
  43. data/carray_iterator.c +630 -0
  44. data/carray_loop.c +462 -0
  45. data/carray_mask.c +1174 -0
  46. data/carray_math.rb +834 -0
  47. data/carray_numeric.c +257 -0
  48. data/carray_operator.c +582 -0
  49. data/carray_order.c +1040 -0
  50. data/carray_random.c +529 -0
  51. data/carray_sort_addr.c +261 -0
  52. data/carray_stat.c +2102 -0
  53. data/carray_stat_proc.rb +1990 -0
  54. data/carray_test.c +602 -0
  55. data/carray_undef.c +69 -0
  56. data/carray_utils.c +740 -0
  57. data/ext/calculus/carray_calculus.c +792 -0
  58. data/ext/calculus/carray_interp.c +355 -0
  59. data/ext/calculus/extconf.rb +12 -0
  60. data/ext/calculus/lib/autoload/autoload_math_calculus.rb +2 -0
  61. data/ext/calculus/lib/math/calculus.rb +119 -0
  62. data/ext/calculus/lib/math/interp/adapter_interp1d.rb +31 -0
  63. data/ext/dataframe/API.txt +11 -0
  64. data/ext/dataframe/extconf.rb +3 -0
  65. data/ext/dataframe/lib/carray/autoload/autoload_dataframe_dataframe.rb +14 -0
  66. data/ext/dataframe/lib/carray/dataframe/dataframe.rb +1104 -0
  67. data/ext/dataframe/sample/test_uniq_sort.rb +5 -0
  68. data/ext/fortio/extconf.rb +3 -0
  69. data/ext/fortio/lib/carray/autoload/autoload_fortran_format.rb +5 -0
  70. data/ext/fortio/lib/carray/io/fortran_format.rb +43 -0
  71. data/ext/fortio/lib/fortio.rb +3 -0
  72. data/ext/fortio/lib/fortio/fortran_format.rb +603 -0
  73. data/ext/fortio/lib/fortio/fortran_format.tab.rb +536 -0
  74. data/ext/fortio/lib/fortio/fortran_format.y +215 -0
  75. data/ext/fortio/lib/fortio/fortran_namelist.rb +151 -0
  76. data/ext/fortio/lib/fortio/fortran_namelist.tab.rb +470 -0
  77. data/ext/fortio/lib/fortio/fortran_namelist.y +213 -0
  78. data/ext/fortio/lib/fortio/fortran_sequential.rb +345 -0
  79. data/ext/fortio/ruby_fortio.c +182 -0
  80. data/ext/fortio/test/test_H.rb +5 -0
  81. data/ext/fortio/test/test_T.rb +7 -0
  82. data/ext/fortio/test/test_fortran_format.rb +86 -0
  83. data/ext/fortio/test/test_namelist.rb +25 -0
  84. data/ext/fortio/test/test_sequential.rb +13 -0
  85. data/ext/fortio/test/test_sequential2.rb +13 -0
  86. data/ext/fortio/work/test.rb +10 -0
  87. data/ext/fortio/work/test_e.rb +19 -0
  88. data/ext/fortio/work/test_ep.rb +10 -0
  89. data/ext/fortio/work/test_parse.rb +12 -0
  90. data/ext/imagemap/carray_imagemap.c +495 -0
  91. data/ext/imagemap/doc/call_graph.dot +28 -0
  92. data/ext/imagemap/draw.c +567 -0
  93. data/ext/imagemap/extconf.rb +13 -0
  94. data/ext/imagemap/lib/autoload/autoload_graphics_imagemap.rb +1 -0
  95. data/ext/imagemap/lib/graphics/imagemap.rb +273 -0
  96. data/ext/imagemap/lib/image_map.rb +4 -0
  97. data/ext/imagemap/test/swath_index.rb +83 -0
  98. data/ext/imagemap/test/swath_warp.rb +99 -0
  99. data/ext/imagemap/test/test.rb +23 -0
  100. data/ext/imagemap/test/test_image.rb +42 -0
  101. data/ext/imagemap/test/test_line.rb +14 -0
  102. data/ext/imagemap/test/test_rotate.rb +17 -0
  103. data/ext/imagemap/test/test_triangle.rb +20 -0
  104. data/ext/imagemap/test/test_warp.rb +26 -0
  105. data/ext/mathfunc/carray_mathfunc.c +321 -0
  106. data/ext/mathfunc/extconf.rb +18 -0
  107. data/ext/mathfunc/lib/autoload/autoload_math_mathfunc.rb +1 -0
  108. data/ext/mathfunc/lib/math/mathfunc.rb +15 -0
  109. data/ext/mathfunc/test/test_hypot.rb +5 -0
  110. data/ext/mathfunc/test/test_j0.rb +22 -0
  111. data/ext/mathfunc/test/test_jn.rb +8 -0
  112. data/ext/mathfunc/test/test_sph.rb +9 -0
  113. data/ext/narray/README +22 -0
  114. data/ext/narray/ca_wrap_narray.c +491 -0
  115. data/ext/narray/carray_narray.c +21 -0
  116. data/ext/narray/extconf.rb +57 -0
  117. data/ext/narray/lib/autoload/autoload_math_narray.rb +1 -0
  118. data/ext/narray/lib/autoload/autoload_math_narray_miss.rb +11 -0
  119. data/ext/narray/lib/math/narray.rb +17 -0
  120. data/ext/narray/lib/math/narray_miss.rb +45 -0
  121. data/extconf.rb +3 -25
  122. data/lib/carray.rb +28 -0
  123. data/lib/carray/autoload/autoload_base.rb +23 -0
  124. data/lib/carray/autoload/autoload_graphics_gnuplot.rb +2 -0
  125. data/lib/carray/autoload/autoload_io_csv.rb +14 -0
  126. data/lib/carray/autoload/autoload_io_excel.rb +5 -0
  127. data/lib/carray/autoload/autoload_io_imagemagick.rb +6 -0
  128. data/lib/carray/autoload/autoload_io_pg.rb +6 -0
  129. data/lib/carray/autoload/autoload_io_sqlite3.rb +12 -0
  130. data/lib/carray/autoload/autoload_io_table.rb +1 -0
  131. data/lib/carray/autoload/autoload_math_histogram.rb +5 -0
  132. data/lib/carray/autoload/autoload_math_interp.rb +4 -0
  133. data/lib/carray/autoload/autoload_math_recurrence.rb +6 -0
  134. data/lib/carray/autoload/autoload_object_iterator.rb +1 -0
  135. data/lib/carray/autoload/autoload_object_link.rb +1 -0
  136. data/lib/carray/autoload/autoload_object_pack.rb +2 -0
  137. data/lib/carray/base/autoload.rb +94 -0
  138. data/lib/carray/base/basic.rb +1051 -0
  139. data/lib/carray/base/inspect.rb +252 -0
  140. data/lib/carray/base/iterator.rb +367 -0
  141. data/lib/carray/base/math.rb +403 -0
  142. data/lib/carray/base/obsolete.rb +93 -0
  143. data/lib/carray/base/serialize.rb +260 -0
  144. data/lib/carray/base/struct.rb +634 -0
  145. data/lib/carray/graphics/gnuplot.rb +2116 -0
  146. data/lib/carray/info.rb +112 -0
  147. data/lib/carray/io/csv.rb +560 -0
  148. data/lib/carray/io/excel.rb +26 -0
  149. data/lib/carray/io/imagemagick.rb +231 -0
  150. data/lib/carray/io/pg.rb +101 -0
  151. data/lib/carray/io/sqlite3.rb +202 -0
  152. data/lib/carray/io/table.rb +77 -0
  153. data/lib/carray/math/histogram.rb +179 -0
  154. data/lib/carray/math/interp.rb +57 -0
  155. data/lib/carray/math/interp/adapter_gsl_spline.rb +47 -0
  156. data/lib/carray/math/recurrence.rb +95 -0
  157. data/lib/carray/mkmf.rb +145 -0
  158. data/lib/carray/object/ca_obj_iterator.rb +52 -0
  159. data/lib/carray/object/ca_obj_link.rb +52 -0
  160. data/lib/carray/object/ca_obj_pack.rb +101 -0
  161. data/mkmath.rb +731 -0
  162. data/mt19937ar.c +182 -0
  163. data/mt19937ar.h +86 -0
  164. data/rdoc_main.rb +27 -0
  165. data/rdoc_math.rb +5 -0
  166. data/rdoc_stat.rb +31 -0
  167. data/ruby_carray.c +242 -0
  168. data/ruby_ccomplex.c +497 -0
  169. data/ruby_float_func.c +83 -0
  170. data/spec/CABlockIterator/CABlockIterator_spec.rb +113 -0
  171. data/spec/CArray/bug/store_spec.rb +27 -0
  172. data/spec/CArray/index/repeat_spec.rb +10 -0
  173. data/spec/CArray/method/eq_spec.rb +80 -0
  174. data/spec/CArray/method/is_nan_spec.rb +12 -0
  175. data/spec/CArray/method/ne_spec.rb +18 -0
  176. data/spec/CArray/method/round_spec.rb +11 -0
  177. data/spec/CArray/object/_attribute_spec.rb +32 -0
  178. data/spec/CArray/object/s_new_spec.rb +31 -0
  179. data/spec/CArray/serialize/Serialization_spec.rb +89 -0
  180. data/spec/spec_all.rb +11 -0
  181. data/test/test_ALL.rb +50 -0
  182. data/test/test_CABitfield.rb +59 -0
  183. data/test/test_CABlock.rb +208 -0
  184. data/test/test_CAField.rb +40 -0
  185. data/test/test_CAGrid.rb +76 -0
  186. data/test/test_CAMapping.rb +106 -0
  187. data/test/test_CAMmap.rb +11 -0
  188. data/test/test_CARefer.rb +94 -0
  189. data/test/test_CARepeat.rb +66 -0
  190. data/test/test_CASelect.rb +23 -0
  191. data/test/test_CAShift.rb +17 -0
  192. data/test/test_CATranspose.rb +61 -0
  193. data/test/test_CAVirtual.rb +214 -0
  194. data/test/test_CAWindow.rb +55 -0
  195. data/test/test_CAWrap.rb +9 -0
  196. data/test/test_CArray.rb +228 -0
  197. data/test/test_CComplex.rb +83 -0
  198. data/test/test_CScalar.rb +91 -0
  199. data/test/test_attribute.rb +281 -0
  200. data/test/test_block_iterator.rb +17 -0
  201. data/test/test_boolean.rb +99 -0
  202. data/test/test_cast.rb +33 -0
  203. data/test/test_class.rb +85 -0
  204. data/test/test_complex.rb +43 -0
  205. data/test/test_composite.rb +125 -0
  206. data/test/test_convert.rb +79 -0
  207. data/test/test_copy.rb +141 -0
  208. data/test/test_creation.rb +85 -0
  209. data/test/test_element.rb +146 -0
  210. data/test/test_extream.rb +55 -0
  211. data/test/test_generate.rb +75 -0
  212. data/test/test_index.rb +71 -0
  213. data/test/test_mask.rb +578 -0
  214. data/test/test_math.rb +98 -0
  215. data/test/test_narray.rb +64 -0
  216. data/test/test_order.rb +147 -0
  217. data/test/test_random.rb +15 -0
  218. data/test/test_ref_store.rb +211 -0
  219. data/test/test_stat.rb +414 -0
  220. data/test/test_struct.rb +72 -0
  221. data/test/test_virtual.rb +49 -0
  222. data/utils/ca_ase.rb +21 -0
  223. data/utils/ca_methods.rb +15 -0
  224. data/utils/cast_checker.rb +30 -0
  225. data/utils/create_rdoc.sh +9 -0
  226. data/utils/diff_method.rb +52 -0
  227. data/utils/extract_rdoc.rb +27 -0
  228. data/utils/make_tgz.sh +3 -0
  229. data/utils/remove_resource_fork.sh +5 -0
  230. data/version.h +3 -3
  231. metadata +266 -1
@@ -0,0 +1,260 @@
1
+ # ----------------------------------------------------------------------------
2
+ #
3
+ # carray/base/serialize.rb
4
+ #
5
+ # This file is part of Ruby/CArray extension library.
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Ruby Licence.
8
+ #
9
+ # Copyright (C) 2005 Hiroki Motoyoshi
10
+ #
11
+ # ----------------------------------------------------------------------------
12
+ #
13
+ #
14
+ # CArray.save(ca, filename, {:endian=>CArray.endian})
15
+ # CArray.save(ca, io, {:endian=>CArray.endian})
16
+ #
17
+ # CArray.load(filename)
18
+ # CArray.load(io)
19
+ #
20
+ # CArray.dump(filename, {:endian=>CArray.endian})
21
+ #
22
+ # CArray#marshal_dump
23
+ # CArray#marshal_load(data)
24
+ #
25
+
26
+ #
27
+ # CArray's Binary Format
28
+ #
29
+ # offset 0 bytes
30
+ # magic_string : char*8 : "_CARRAY_"
31
+ # data_type_name : char*8 : e.g. "int8", "cmplx256" ...
32
+ # endian : char*4 : "_LE_":LITTLE_ENIDAN or "_BE_":BIG_ENDIAN
33
+ # offset 20 bytes
34
+ # data_type : int32 : data type specifier
35
+ # bytes : int32 : byte size of each data
36
+ # rank : int32 : rank of array
37
+ # elements : int32 : number of all elements
38
+ # has_mask : int32 : 0 (not masked) or 1 (masked)
39
+ # offset 40 bytes
40
+ # dim[CA_RANK_MAX] : int32 : size for 0-th dimension
41
+ # has_attribute : int32
42
+ #
43
+ # offset 256 bytes
44
+ # data : bytes*elements : value data
45
+ # mask : int8*elements : mask data if has_mask == 1
46
+
47
+ require "stringio"
48
+
49
+ class CArray::Serializer # :nodoc:
50
+
51
+ Header = CA.struct(:pack=>1, :size=>256) {
52
+ char_p :magic_string, :bytes=>8
53
+ char_p :data_type_name, :bytes=>8
54
+ char_p :endian, :bytes=>4
55
+ int32 :data_type
56
+ int32 :bytes
57
+ int32 :rank
58
+ int32 :elements
59
+ int32 :has_mask
60
+ array :dim, :type => CArray.int32(CA_RANK_MAX)
61
+ int32 :has_attr
62
+ }
63
+
64
+ def initialize (io)
65
+ case io
66
+ when String
67
+ @io = StringIO.new(io)
68
+ else
69
+ @io = io
70
+ end
71
+ end
72
+
73
+ def save (ca, opt = {})
74
+ endian = opt[:endian] || CArray.endian
75
+ # ---
76
+ header = Header.new()
77
+ header[:magic_string] = "_CARRAY_"
78
+ header[:data_type_name] = ca.data_type_name.ljust(8)
79
+ header[:endian] = ( endian == CA_LITTLE_ENDIAN ) ? "_LE_" : "_BE_"
80
+ header[:data_type] = ca.data_type
81
+ header[:bytes] = ca.bytes
82
+ header[:rank] = ca.rank
83
+ header[:elements] = ca.elements
84
+ header[:has_mask] = ca.has_mask? ? 1 : 0
85
+ header[:dim][[0,ca.rank]] = ca.dim
86
+ attr = nil
87
+ if ca.attribute
88
+ attr = ca.attribute.clone
89
+ end
90
+ if opt[:attribute]
91
+ (attr ||= {}).update(opt[:attribute])
92
+ end
93
+ header[:has_attr] = attr.empty? ? 0 : 1
94
+ unless CArray.endian == endian
95
+ header.swap_bytes!
96
+ end
97
+ @io.write(header.encode)
98
+ # ---
99
+ if ca.data_type == CA_OBJECT
100
+ Marshal.dump(ca.value.to_a, @io)
101
+ else
102
+ unless CArray.endian == endian
103
+ ca = ca.swap_bytes
104
+ end
105
+ ca.dump_binary(@io)
106
+ end
107
+ # ---
108
+ if ca.has_mask?
109
+ ca.mask.dump_binary(@io)
110
+ end
111
+ if attr
112
+ Marshal.dump(attr, @io)
113
+ end
114
+ return ca
115
+ end
116
+
117
+ def load (opt = {})
118
+ header = Header.decode(@io.read(256))
119
+ if header[:magic_string] != "_CARRAY_"
120
+ raise "not a CArray binary data"
121
+ end
122
+ case header[:endian]
123
+ when "_LE_"
124
+ endian = CA_LITTLE_ENDIAN
125
+ when "_BE_"
126
+ endian = CA_BIG_ENDIAN
127
+ end
128
+ unless CArray.endian == endian
129
+ header.swap_bytes!
130
+ end
131
+ data_type = header[:data_type]
132
+ bytes = header[:bytes]
133
+ rank = header[:rank]
134
+ elements = header[:elements]
135
+ has_mask = header[:has_mask] != 0 ? true : false
136
+ dim = header[:dim][[0, rank]].to_a
137
+ has_attr = header[:has_attr]
138
+ if data_type == 255
139
+ data_type = header[:data_type_name].strip.to_sym
140
+ end
141
+ data_type, bytes = CArray.guess_type_and_bytes(data_type, bytes)
142
+ if opt[:data_type] and data_type == CA_FIXLEN
143
+ data_type = opt[:data_type]
144
+ end
145
+ ca = CArray.new(data_type, dim, :bytes=>bytes)
146
+ if data_type == CA_OBJECT
147
+ ca.value[] = Marshal.load(@io)
148
+ else
149
+ ca.load_binary(@io)
150
+ unless CArray.endian == endian
151
+ ca.swap_bytes!
152
+ end
153
+ end
154
+ if has_mask
155
+ ca.mask = 0
156
+ ca.mask.load_binary(@io)
157
+ end
158
+ if has_attr == 1
159
+ ca.attribute = Marshal.load(@io)
160
+ end
161
+ return ca
162
+ end
163
+
164
+ end
165
+
166
+ class CArray
167
+
168
+ def self.save(ca, output, opt={})
169
+ case output
170
+ when String
171
+ open(output, "wb:ASCII-8BIT") { |io|
172
+ return Serializer.new(io).save(ca, opt)
173
+ }
174
+ else
175
+ return Serializer.new(output).save(ca, opt)
176
+ end
177
+ end
178
+
179
+ def self.load (input, opt={})
180
+ case input
181
+ when String
182
+ if input.length >= 256 and input =~ /\A_CARRAY_.{8}_(LE|BE)_/
183
+ io = StringIO.new(input)
184
+ return Serializer.new(io).load(opt)
185
+ else
186
+ open(input, "rb:ASCII-8BIT") { |io|
187
+ return Serializer.new(io).load(opt)
188
+ }
189
+ end
190
+ else
191
+ return Serializer.new(input).load(opt)
192
+ end
193
+ end
194
+
195
+ def self.dump (ca, opt={})
196
+ io = StringIO.new("")
197
+ Serializer.new(io).save(ca, opt)
198
+ return io.string
199
+ end
200
+
201
+ # for Marshal
202
+
203
+ def marshal_dump ()
204
+ if self.class != CArray and self.class != CScalar
205
+ raise TypeError, "can't dump a virtual or wrapped array."
206
+ end
207
+ return CArray.dump(self)
208
+ end
209
+
210
+ def marshal_load (data)
211
+ io = StringIO.new(data)
212
+ ca = CArray.load(io)
213
+ initialize_copy(ca)
214
+ end
215
+
216
+ ### obsolete methods
217
+
218
+ def save_binary (filename, opt={}) # :nodoc:
219
+ warn "CArray#save_binary will be obsolete, use CArray.save"
220
+ open(filename, "w") { |io|
221
+ return Serializer.new(io).save(self, opt)
222
+ }
223
+ end
224
+
225
+ def self.load_binary (filename, opt={}) # :nodoc:
226
+ warn "CArray.load_binary will be obsolete, use CArray.load"
227
+ open(filename) { |io|
228
+ return Serializer.new(io).load(opt)
229
+ }
230
+ end
231
+
232
+ def save_binary_io (io, opt={}) # :nodoc:
233
+ warn "CArray#save_binary_io will be obsolete, use CArray.save"
234
+ return Serializer.new(io).save(self, opt)
235
+ end
236
+
237
+ def self.load_binary_io (io, opt={}) # :nodoc:
238
+ warn "CArray#load_binary_io will be obsolete, use CArray.load"
239
+ return Serializer.new(io).load(opt)
240
+ end
241
+
242
+ def to_binary (io="", opt={}) # :nodoc:
243
+ warn "CArray#to_binary will be obsolete, use CArray.dump"
244
+ Serializer.new(io).save(self, opt)
245
+ return io
246
+ end
247
+
248
+ def self.from_binary (io, opt={}) # :nodoc:
249
+ warn "CArray.from_binary will be obsolete, use CArray.load"
250
+ return Serializer.new(io).load(opt)
251
+ end
252
+
253
+ # depleted methods
254
+
255
+ def self.load_from_file (filename, data_type, dim, opt={}) # :nodoc:
256
+ raise "Sorry, CArray.load_from_file is depleted"
257
+ end
258
+
259
+ end
260
+
@@ -0,0 +1,634 @@
1
+ # ----------------------------------------------------------------------------
2
+ #
3
+ # carray/base/struct.rb
4
+ #
5
+ # This file is part of Ruby/CArray extension library.
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Ruby Licence.
8
+ #
9
+ # Copyright (C) 2005 Hiroki Motoyoshi
10
+ #
11
+ # ----------------------------------------------------------------------------
12
+ #
13
+ # The data class for fixed length carray are required to satisfy only
14
+ # four conditions.
15
+ #
16
+ # * constant data_class::DATA_SIZE -> integer
17
+ # * constant data_class::MEMBERS -> array of string
18
+ # * constant data_class::MEMBER_TABLE -> hash
19
+ # * method data_class.decode(data) -> new data_class object
20
+ # * method data_class#encode() -> string
21
+ #
22
+ # The implementation of other properties (cf. initialization, instance,
23
+ # methods ...) are left free.
24
+ #
25
+ # CA::Struct and CA::Union are examples of such data class.
26
+ #
27
+ # option = {
28
+ # :pack => 1, # nil for alignment, int for pack(n)
29
+ # :size => 1024 # user defined size (with padding)
30
+ # }
31
+ #
32
+ # CA.struct(option) { |s|
33
+ #
34
+ # # numeric types
35
+ #
36
+ # int8 :a, :b, :c
37
+ #
38
+ # float32 :f1, :f2
39
+ # float :f5, :f6
40
+ #
41
+ # float64 :d1, :d2
42
+ # double :d5, :d6
43
+ #
44
+ # # fixed length or string
45
+ #
46
+ # fixlen :str1, :str2, :bytes => 3
47
+ # char_p :str3, :str4, :bytes => 3
48
+ #
49
+ # # array type
50
+ # array :ary1, :ary2, :type => CArray.int(3)
51
+ #
52
+ # # struct type
53
+ # struct(:st1, :st2) { uint8 :a, :b, :c }
54
+ # struct :st3, :st4, :type => CA.struct { uint8 :a, :b, :c }
55
+ #
56
+ # # union type
57
+ # union(:un1, :un2) { uint8 :a; int16 :b; float32 :c }
58
+ # union :un3, :un4, :type => CA.union { uint8 :a, :b, :c }
59
+ #
60
+ # # anonymous
61
+ #
62
+ # int8_t nil, nil, nil
63
+ # fixlen nil, :bytes=>3 ### padding
64
+ #
65
+ # # low level definition
66
+ # member CA_INT8, :x0
67
+ # member :int8, :mem0, :mem1
68
+ # member "int8", :mem0, :mem1
69
+ # member :uint8, nil ### anonymous
70
+ # member CArray.int(3), :ary3
71
+ # member struct{ int8 :a, :b, :c }, :st5, :st6
72
+ # member union{ int8 :a; int16 :b; float :c }, :st5, :st6
73
+ #
74
+ # }
75
+ #
76
+
77
+ class CArray
78
+
79
+ def st
80
+ unless has_data_class?
81
+ raise "should have data_class"
82
+ end
83
+ unless @struct
84
+ struct_class = Struct.new(nil, *data_class::MEMBERS)
85
+ members = data_class::MEMBERS.map{|name| self[name]}
86
+ @struct = struct_class.new(*members)
87
+ end
88
+ return @struct
89
+ end
90
+
91
+ end
92
+
93
+ class CA::Struct
94
+
95
+ include Enumerable
96
+
97
+ class << self
98
+
99
+ def inspect
100
+ return name.empty? ? "AnonStruct" : name
101
+ end
102
+
103
+ def [] (*argv)
104
+ obj = new()
105
+ members.each do |name|
106
+ obj[name] = argv.shift
107
+ end
108
+ return obj
109
+ end
110
+
111
+ def members
112
+ return self::MEMBERS.clone
113
+ end
114
+
115
+ def decode (data) ### required element as data class
116
+ return new.decode(data)
117
+ end
118
+
119
+ def size
120
+ return self::DATA_SIZE
121
+ end
122
+
123
+ end
124
+
125
+ def initialize (*argv)
126
+ @data = CScalar.new(self.class)
127
+ mems = members
128
+ if argv.size == 1 and argv.first.is_a?(Hash)
129
+ argv.first.each do |k,v|
130
+ self[k] = v
131
+ end
132
+ elsif argv.size <= mems.size
133
+ argv.each_with_index do |v, i|
134
+ self[mems[i]] = v
135
+ end
136
+ else
137
+ raise ArgumentError,
138
+ format("too many arguments for %s.new (<%i> for <%i>)",
139
+ self.class.inspect, argv.size, members.size)
140
+ end
141
+ end
142
+
143
+ protected
144
+
145
+ def __data__
146
+ @data
147
+ end
148
+
149
+ public
150
+
151
+ def [] (name)
152
+ if name.kind_of?(Integer)
153
+ name = members[name]
154
+ end
155
+ offset, type, opts = *self.class::MEMBER_TABLE[name.to_s]
156
+ case type
157
+ when nil
158
+ return send(name)
159
+ when Class
160
+ return type.decode(@data.field(offset, type))
161
+ when CArray
162
+ return @data.field(offset,type)[0,false]
163
+ else
164
+ return @data.field(offset,type,opts)[0]
165
+ end
166
+ end
167
+
168
+ def []= (name, val)
169
+ if name.kind_of?(Integer)
170
+ name = members[name]
171
+ end
172
+ offset, type, opts = *self.class::MEMBER_TABLE[name.to_s]
173
+ case type
174
+ when nil
175
+ send(name.to_s + "=", val)
176
+ when Class
177
+ @data.field(offset, type)[0] = val
178
+ when CArray
179
+ @data.field(offset, type)[0,false] = val
180
+ else
181
+ @data.field(offset,type,opts)[0] = val
182
+ end
183
+ end
184
+
185
+ def each
186
+ members.each do |name|
187
+ yield(self[name])
188
+ end
189
+ end
190
+
191
+ def each_pair
192
+ members.each do |name|
193
+ yield(name.intern, self[name])
194
+ end
195
+ end
196
+
197
+ def length
198
+ return self.class::MEMBERS.length
199
+ end
200
+
201
+ alias size length
202
+
203
+ def members
204
+ return self.class::MEMBERS.clone
205
+ end
206
+
207
+ def values
208
+ return members.map{|name| self[name] }
209
+ end
210
+
211
+ alias to_a values
212
+
213
+ def values_at (*names)
214
+ return names.map{|name| self[name] }
215
+ end
216
+
217
+ def inspect
218
+ table = {}
219
+ members.each do |key|
220
+ table[key] = self[key]
221
+ end
222
+ return ["<", self.class.inspect, " ", table.inspect[1..-2], ">"].join
223
+ end
224
+
225
+ def == (other)
226
+ case other
227
+ when self.class
228
+ return @data == other.__data__
229
+ else
230
+ return false
231
+ end
232
+ end
233
+
234
+ def decode (data)
235
+ case data
236
+ when String
237
+ @data.load_binary(data)
238
+ when CArray
239
+ @data = data
240
+ else
241
+ raise "unkown data to decode"
242
+ end
243
+ return self
244
+ end
245
+
246
+ def encode ### required element as data class
247
+ return @data.dump_binary
248
+ end
249
+
250
+ alias to_s encode
251
+
252
+ def swap_bytes!
253
+ @data.swap_bytes!
254
+ return self
255
+ end
256
+
257
+ def swap_bytes
258
+ return self.class.decode(@data.swap_bytes.dump_binary)
259
+ end
260
+
261
+ def to_ptr
262
+ return @data.to_ptr
263
+ end
264
+
265
+ end
266
+
267
+ class CA::Union < CA::Struct
268
+ class << self
269
+ def inspect
270
+ return name.empty? ? "AnonUnion" : name
271
+ end
272
+ end
273
+ end
274
+
275
+ module CA
276
+
277
+ def self.struct (opt={}, &block)
278
+ return Struct::Builder.new(:struct, opt).define(&block)
279
+ end
280
+
281
+ def self.union (opt={}, &block)
282
+ return Struct::Builder.new(:union, opt).define(&block)
283
+ end
284
+
285
+ end
286
+
287
+ # ---------------------------------------------------------------------
288
+ #
289
+ # Struct Builder Class
290
+ #
291
+ # ---------------------------------------------------------------------
292
+
293
+ class CA::Struct::Builder # :nodoc:
294
+
295
+ class Member # :nodoc:
296
+
297
+ def initialize (name, type, opt={})
298
+ @name, @type, @opt = name, type, opt
299
+ if @type.kind_of?(CArray)
300
+ @type = @type.to_ca
301
+ @byte_length = @type.bytes * @type.elements
302
+ @bytes = 0
303
+ else
304
+ data_type, @bytes = CArray.guess_type_and_bytes(@type, @opt[:bytes])
305
+ if data_type == CA_OBJECT
306
+ raise("CA_OBJECT type can't be a member of struct or union")
307
+ end
308
+ @byte_length = @bytes
309
+ end
310
+ @offset = @opt[:offset]
311
+ end
312
+
313
+ attr_reader :name, :type, :offset, :bytes, :byte_length
314
+
315
+ end
316
+
317
+ ALIGN_TABLE = {
318
+ CA_FIXLEN => CA_ALIGN_FIXLEN,
319
+ CA_BOOLEAN => CA_ALIGN_INT8,
320
+ CA_INT8 => CA_ALIGN_INT8,
321
+ CA_UINT8 => CA_ALIGN_INT8,
322
+ CA_INT16 => CA_ALIGN_INT16,
323
+ CA_UINT16 => CA_ALIGN_INT16,
324
+ CA_INT32 => CA_ALIGN_INT32,
325
+ CA_UINT32 => CA_ALIGN_INT32,
326
+ CA_INT64 => CA_ALIGN_INT64,
327
+ CA_UINT64 => CA_ALIGN_INT64,
328
+ CA_FLOAT32 => CA_ALIGN_FLOAT32,
329
+ CA_FLOAT64 => CA_ALIGN_FLOAT64,
330
+ CA_CMPLX64 => CA_ALIGN_FLOAT32,
331
+ CA_CMPLX128 => CA_ALIGN_FLOAT64,
332
+ }
333
+
334
+ CARRAY_METHODS = CArray.instance_methods.map{|m| m.intern }
335
+
336
+ def initialize (type, opt = {})
337
+ if not opt[:pack].nil? and not opt[:pack].is_a?(Integer)
338
+ raise "invalid alignment given '#{align}'"
339
+ end
340
+ @type = type ### :struct or :union
341
+ @align = opt[:pack] ### nil for alignment, int for pack(n)
342
+ @members = [] ### array of CArray::Struct::Builder::Member
343
+ @offset = 0 ### offset of each member and size of struct
344
+ @align_max = 1 ### maximum of alignment among members
345
+ @size = opt[:size] ### user defined struct size
346
+ end
347
+
348
+ def define (&block)
349
+ # ---
350
+ case block.arity
351
+ when 1
352
+ block.call(self) ### struct/union definition block
353
+ when -1, 0
354
+ instance_exec(&block) ### struct/union definition block
355
+ else
356
+ raise "invalid # of block parameters"
357
+ end
358
+ # ---
359
+ case @type
360
+ when :struct
361
+ klass = Class.new(CA::Struct)
362
+ when :union
363
+ klass = Class.new(CA::Union)
364
+ end
365
+ # ---
366
+ if @align.nil?
367
+ @offset = alignment(@offset, :align_max)
368
+ end
369
+ if @size
370
+ if @size < @offset
371
+ raise RuntimeError, "struct size exceeds the fixlen size"
372
+ end
373
+ @offset = @size
374
+ end
375
+ klass.const_set(:DATA_SIZE, @offset) ### required element as data class
376
+ # ---
377
+ table = Hash.new
378
+ names = []
379
+ @members.each do |mem|
380
+ name = mem.name
381
+ type = mem.type
382
+ offset = mem.offset
383
+ bytes = mem.bytes
384
+ if bytes
385
+ table[name] = [offset, type, {:bytes=>bytes}]
386
+ else
387
+ table[name] = [offset, type]
388
+ end
389
+ names.push(name)
390
+ end
391
+ klass.const_set(:MEMBER_TABLE, table) ### required element as data class
392
+ klass.const_set(:MEMBERS, names)
393
+ # ---
394
+ klass.module_eval {
395
+ names.each do |name|
396
+ define_method(name) {
397
+ return self[name]
398
+ }
399
+ define_method("#{name}=") { |val|
400
+ return self[name] = val
401
+ }
402
+ end
403
+ }
404
+ # ---
405
+ return klass
406
+ end
407
+
408
+ private
409
+
410
+ def alignment (addr, data_type, opt={})
411
+ case data_type
412
+ when Integer
413
+ align = ALIGN_TABLE[data_type]
414
+ when CArray, Class
415
+ align = CA_ALIGN_VOIDP
416
+ when :align_max
417
+ align = @align_max
418
+ else
419
+ data_type, bytes = CArray.guess_type_and_bytes(data_type, opt[:bytes])
420
+ return alignment(addr, data_type, :bytes=>bytes)
421
+ end
422
+ if align > @align_max
423
+ @align_max = align
424
+ end
425
+ if ( d = addr % align ) != 0
426
+ addr += (align - d)
427
+ end
428
+ return addr
429
+ end
430
+
431
+ def pack (addr, align, opt={})
432
+ if ( addr % align ) != 0
433
+ raise "invalid offset for packing"
434
+ end
435
+ return addr
436
+ end
437
+
438
+ public
439
+
440
+ def member (data_type, id = nil, opt = {})
441
+ opt = opt.clone
442
+ if id
443
+ id = id.to_s
444
+ else
445
+ id = "#{@members.size}"
446
+ end
447
+ case @type
448
+ when :struct ### struct
449
+ case @align
450
+ when nil ### -- aligned
451
+ @offset = alignment(@offset, data_type, opt)
452
+ opt[:offset] = @offset
453
+ else ### -- packed
454
+ if opt[:offset] ### ---- explicit offset
455
+ @offset = pack(opt[:offset], @align, opt)
456
+ else
457
+ opt[:offset] = @offset ### ---- auto offset
458
+ end
459
+ end
460
+ mem = Member.new(id, data_type, opt)
461
+ @members.push(mem)
462
+ @offset += mem.byte_length
463
+ when :union ### union
464
+ alignment(0, data_type, opt)
465
+ opt[:offset] = 0
466
+ mem = Member.new(id, data_type, opt)
467
+ @members.push(mem)
468
+ if mem.byte_length > @offset
469
+ @offset = mem.byte_length
470
+ end
471
+ end
472
+ end
473
+
474
+ # method for nested struct
475
+ def struct (*args, &block)
476
+ opt = args.last.is_a?(Hash) ? args.pop : {}
477
+ if block
478
+ opt = {:pack => @align}.update(opt)
479
+ st = self.class.new(:struct, opt).define(&block)
480
+ elsif opt[:type] and opt[:type] <= CA::Struct
481
+ st = opt[:type]
482
+ else
483
+ raise "type is not given for struct member of struct"
484
+ end
485
+ args.each do |arg|
486
+ member(st, arg)
487
+ end
488
+ return st
489
+ end
490
+
491
+ # method for nested union
492
+ def union (*args, &block)
493
+ opt = args.last.is_a?(Hash) ? args.pop : {}
494
+ if block
495
+ opt = {:pack => @align}.update(opt)
496
+ st = self.class.new(:union, opt).define(&block)
497
+ elsif opt[:type] and opt[:type] <= CA::Struct
498
+ st = opt[:type]
499
+ else
500
+ raise "type is not given for union member of struct"
501
+ end
502
+ args.each do |arg|
503
+ member(st, arg)
504
+ end
505
+ return st
506
+ end
507
+
508
+ def array (*args)
509
+ opt = args.last.is_a?(Hash) ? args.pop : {}
510
+ if not opt[:type] or not opt[:type].kind_of?(CArray)
511
+ raise "type is not given for array member of struct"
512
+ end
513
+ args.each do |arg|
514
+ member(opt[:type], arg)
515
+ end
516
+ end
517
+
518
+ [
519
+ "fixlen",
520
+ "boolean",
521
+ "int8",
522
+ "uint8",
523
+ "int16",
524
+ "uint16",
525
+ "int32",
526
+ "uint32",
527
+ "int64",
528
+ "uint64",
529
+ "float32",
530
+ "float64",
531
+ "float128",
532
+ "cmplx64",
533
+ "cmplx128",
534
+ "cmplx256",
535
+ ].each do |typename|
536
+ class_eval %{
537
+ def #{typename} (*args)
538
+ opt = args.last.is_a?(Hash) ? args.pop : {}
539
+ args.each do |arg|
540
+ member(:#{typename}, arg, opt)
541
+ end
542
+ end
543
+ }
544
+ end
545
+
546
+ alias char_p fixlen
547
+ alias byte uint8
548
+ alias short int16
549
+ alias int int32
550
+ alias float float32
551
+ alias double float64
552
+ alias complex cmplx64
553
+ alias dcomplex cmplx128
554
+
555
+ end
556
+
557
+
558
+
559
+ class CA::Struct
560
+
561
+ def self.spec
562
+ output = ""
563
+ table = self::MEMBER_TABLE
564
+ stlist = []
565
+ if self.name.empty?
566
+ if self <= CA::Union
567
+ prefix = "union"
568
+ else
569
+ prefix = "struct"
570
+ end
571
+ output << sprintf("%s_%i = ",
572
+ prefix, [object_id].pack("V").unpack("V").first)
573
+ else
574
+ output << sprintf("%s = ", self.name)
575
+ end
576
+ if self < CA::Union
577
+ output << sprintf("CA.union(:size=>%i) {\n", self::DATA_SIZE)
578
+ else
579
+ output << sprintf("CA.struct(:size=>%i) {\n", self::DATA_SIZE)
580
+ end
581
+ members.each do |member|
582
+ offset, type, option = *table[member]
583
+ case type
584
+ when Class
585
+ if type < CA::Struct
586
+ stlist << type
587
+ if type.name.empty?
588
+ if type <= CA::Union
589
+ prefix = "union"
590
+ else
591
+ prefix = "struct"
592
+ end
593
+ output << sprintf(" member %s_%i, :%s, :offset=>%i\n",
594
+ prefix,
595
+ [type.object_id].pack("V").unpack("V").first,
596
+ member, offset)
597
+ else
598
+ output << sprintf(" member %s, :%s, :offset=>%i\n",
599
+ type.name, member, offset)
600
+ end
601
+ else
602
+ raise "unknown type"
603
+ end
604
+ when CArray
605
+ output << sprintf(" member %s, :%s, :offset=>%i\n",
606
+ type.spec, member, offset)
607
+ when :fixlen
608
+ output << sprintf(" member :fixlen, :%s, :bytes=>%i, :offset=>%i\n",
609
+ member, option[:bytes], offset)
610
+ else
611
+ output << sprintf(" member :%s, :%s, :offset=>%i\n",
612
+ type, member, offset)
613
+ end
614
+ end
615
+ output << sprintf("}\n")
616
+ if stlist.empty?
617
+ return output
618
+ else
619
+ stlist.uniq!
620
+ preface = ""
621
+ stlist.each do |st|
622
+ preface << st.spec
623
+ end
624
+ return preface + output
625
+ end
626
+ end
627
+
628
+ def spec
629
+ return self.class.spec
630
+ end
631
+
632
+ end
633
+
634
+