carray 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +5 -25
  3. data/CHANGELOG.md +16 -0
  4. data/LICENSE +1 -1
  5. data/NEWS.md +3 -0
  6. data/README.md +128 -44
  7. data/carray.gemspec +22 -24
  8. data/ext/ca_array_pool.c +91 -0
  9. data/ext/ca_axis_descriptor.h +186 -0
  10. data/ext/ca_axis_dispatch.c +924 -0
  11. data/ext/ca_axis_group.c +1208 -0
  12. data/ext/ca_bincmp_dispatch.c +76 -0
  13. data/ext/ca_bincmp_dispatch.h +85 -0
  14. data/ext/ca_binop_dispatch.c +125 -0
  15. data/ext/ca_binop_dispatch.h +159 -0
  16. data/ext/ca_categorical_iterator.c +1375 -0
  17. data/ext/ca_compare.c +94 -0
  18. data/ext/ca_compare.h +26 -0
  19. data/ext/ca_composite_dispatch.c +414 -0
  20. data/ext/ca_composite_dispatch.h +116 -0
  21. data/ext/ca_for_buffer.h +96 -0
  22. data/ext/ca_for_each_element.h +241 -0
  23. data/ext/ca_group_iter.c +304 -0
  24. data/ext/ca_iter_substrate.h +325 -0
  25. data/ext/ca_kernel_iterator.c +4321 -0
  26. data/ext/ca_kernel_iterator.h +2603 -0
  27. data/ext/ca_moncmp_dispatch.c +37 -0
  28. data/ext/ca_moncmp_dispatch.h +62 -0
  29. data/ext/ca_monop_dispatch.c +200 -0
  30. data/ext/ca_monop_dispatch.h +235 -0
  31. data/ext/ca_obj_array.c +355 -359
  32. data/ext/ca_obj_bincmp.c +809 -0
  33. data/ext/ca_obj_binop.c +892 -0
  34. data/ext/ca_obj_bitarray.c +369 -164
  35. data/ext/ca_obj_bitfield.c +294 -234
  36. data/ext/ca_obj_block.c +189 -711
  37. data/ext/ca_obj_byte_swap.c +766 -0
  38. data/ext/ca_obj_const_string.c +965 -0
  39. data/ext/ca_obj_face.c +670 -0
  40. data/ext/ca_obj_face.h +247 -0
  41. data/ext/ca_obj_fake.c +228 -100
  42. data/ext/ca_obj_farray.c +54 -441
  43. data/ext/ca_obj_field.c +82 -529
  44. data/ext/ca_obj_fixlen_string.c +306 -0
  45. data/ext/ca_obj_grid.c +858 -440
  46. data/ext/ca_obj_meld.c +1034 -0
  47. data/ext/ca_obj_moncmp.c +569 -0
  48. data/ext/ca_obj_monop.c +1111 -0
  49. data/ext/ca_obj_object.c +774 -298
  50. data/ext/ca_obj_record.c +468 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +569 -459
  53. data/ext/ca_obj_remap.c +475 -0
  54. data/ext/ca_obj_repeat.c +92 -477
  55. data/ext/ca_obj_roll.c +616 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1296 -0
  58. data/ext/ca_obj_shift.c +230 -792
  59. data/ext/ca_obj_source.c +78 -0
  60. data/ext/ca_obj_stack.c +1173 -0
  61. data/ext/ca_obj_stride.c +2501 -0
  62. data/ext/ca_obj_string.c +268 -0
  63. data/ext/ca_obj_tile.c +614 -0
  64. data/ext/ca_obj_time.c +546 -0
  65. data/ext/ca_obj_timedelta.c +435 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +746 -0
  68. data/ext/ca_obj_unbound_repeat.c +208 -241
  69. data/ext/ca_obj_window.c +1131 -563
  70. data/ext/ca_op_byte_swap.c +175 -0
  71. data/ext/ca_op_ipower.c +319 -0
  72. data/ext/ca_op_powi.h +88 -0
  73. data/ext/ca_sort_kernels.h +132 -0
  74. data/ext/ca_sweep_engine.c +430 -0
  75. data/ext/ca_sweep_engine.h +157 -0
  76. data/ext/ca_transform_common.c +228 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +795 -402
  80. data/ext/carray_access.c +831 -711
  81. data/ext/carray_attribute.c +98 -330
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +283 -0
  84. data/ext/carray_call_cfunc.c +1360 -828
  85. data/ext/carray_call_cfunc.h +160 -0
  86. data/ext/carray_cast.c +1212 -301
  87. data/ext/carray_cast_func.rb +81 -40
  88. data/ext/carray_class.c +53 -63
  89. data/ext/carray_config.h +28 -0
  90. data/ext/carray_conversion.c +350 -346
  91. data/ext/carray_copy.c +156 -268
  92. data/ext/carray_core.c +1342 -199
  93. data/ext/carray_count.c +312 -0
  94. data/ext/carray_data_type.c +43 -19
  95. data/ext/carray_element.c +585 -213
  96. data/ext/carray_factorize.c +2542 -0
  97. data/ext/carray_generate.c +230 -559
  98. data/ext/carray_histogram.c +490 -0
  99. data/ext/carray_hold.c +228 -0
  100. data/ext/carray_index_classifier.c +1035 -0
  101. data/ext/carray_index_classifier.h +27 -0
  102. data/ext/carray_internal.h +120 -0
  103. data/ext/carray_kernels_bincmp.c +4445 -0
  104. data/ext/carray_kernels_binop.c +10979 -0
  105. data/ext/carray_kernels_init.c +36 -0
  106. data/ext/carray_kernels_map.c +3466 -0
  107. data/ext/carray_kernels_moncmp.c +2096 -0
  108. data/ext/carray_kernels_monop.c +18312 -0
  109. data/ext/carray_kernels_reduce_aggregate.c +25836 -0
  110. data/ext/carray_kernels_reduce_boolean.c +329 -0
  111. data/ext/carray_kernels_reduce_cumulative.c +14592 -0
  112. data/ext/carray_kernels_reduce_extreme.c +16947 -0
  113. data/ext/carray_kernels_reduce_variance.c +3909 -0
  114. data/ext/carray_kernels_scan.c +3692 -0
  115. data/ext/carray_kernels_search.c +32137 -0
  116. data/ext/carray_kernels_sort.c +10625 -0
  117. data/ext/carray_kernels_triop.c +1391 -0
  118. data/ext/carray_lazy.c +567 -0
  119. data/ext/carray_loop.c +88 -200
  120. data/ext/carray_mask.c +848 -154
  121. data/ext/carray_math_kernel.h +120 -0
  122. data/ext/carray_mathfunc.c +10 -241
  123. data/ext/carray_median_percentile.c +1257 -0
  124. data/ext/carray_memory_view.c +1625 -0
  125. data/ext/carray_operator.c +1526 -318
  126. data/ext/carray_order.c +664 -1394
  127. data/ext/carray_partition.c +416 -0
  128. data/ext/carray_random.c +518 -0
  129. data/ext/carray_scatter.c +357 -0
  130. data/ext/carray_slab.c +1219 -0
  131. data/ext/carray_slab.h +84 -0
  132. data/ext/carray_sort.c +829 -0
  133. data/ext/carray_sort_kernel.c +620 -0
  134. data/ext/carray_struct.c +695 -0
  135. data/ext/carray_test.c +343 -229
  136. data/ext/carray_undef.c +34 -17
  137. data/ext/carray_utils.c +175 -74
  138. data/ext/extconf.rb +216 -55
  139. data/ext/mk_call_cfunc.rb +480 -0
  140. data/ext/mkkernel.rb +8842 -0
  141. data/ext/ruby_carray.c +202 -101
  142. data/ext/version.h +4 -14
  143. data/ext/version.rb +5 -13
  144. data/lib/carray/arrow_tensor.rb +401 -0
  145. data/lib/carray/attribute.rb +166 -0
  146. data/lib/carray/autoload_carray.rb +220 -0
  147. data/lib/carray/autoload_method_extension.rb +44 -0
  148. data/lib/carray/axis_group.rb +711 -0
  149. data/lib/carray/basics.rb +481 -0
  150. data/lib/carray/bincount_nd.rb +358 -0
  151. data/lib/carray/block_iterator.rb +604 -0
  152. data/lib/carray/boolean_reduce.rb +109 -0
  153. data/lib/carray/categorical.rb +561 -0
  154. data/lib/carray/categorical_iterator.rb +1062 -0
  155. data/lib/carray/complex.rb +150 -0
  156. data/lib/carray/conditional.rb +216 -0
  157. data/lib/carray/const_string.rb +228 -0
  158. data/lib/carray/construct.rb +139 -328
  159. data/lib/carray/core_extensions.rb +240 -0
  160. data/lib/carray/data_type_extension.rb +233 -0
  161. data/lib/carray/fixlen_string.rb +95 -0
  162. data/lib/carray/frame/concat.rb +132 -0
  163. data/lib/carray/frame/convert.rb +95 -0
  164. data/lib/carray/frame/csv_parser.rb +211 -0
  165. data/lib/carray/frame/frame.rb +649 -0
  166. data/lib/carray/frame/group.rb +186 -0
  167. data/lib/carray/frame/io.rb +164 -0
  168. data/lib/carray/frame/join.rb +248 -0
  169. data/lib/carray/frame/records.rb +99 -0
  170. data/lib/carray/frame/sort.rb +113 -0
  171. data/lib/carray/frame/verbs.rb +299 -0
  172. data/lib/carray/frame.rb +16 -0
  173. data/lib/carray/histogram.rb +512 -0
  174. data/lib/carray/inspect.rb +37 -20
  175. data/lib/carray/iterator.rb +57 -349
  176. data/lib/carray/lazy.rb +889 -0
  177. data/lib/carray/mask_gap_fill.rb +200 -0
  178. data/lib/carray/math.rb +78 -342
  179. data/lib/carray/meld_reduce.rb +289 -0
  180. data/lib/carray/methods/align_addr.rb +116 -0
  181. data/lib/carray/methods/bin.rb +128 -0
  182. data/lib/carray/methods/bincount.rb +87 -0
  183. data/lib/carray/methods/bit_string.rb +92 -0
  184. data/lib/carray/methods/broadcast.rb +63 -0
  185. data/lib/carray/methods/choose.rb +39 -0
  186. data/lib/carray/methods/composition.rb +280 -0
  187. data/lib/carray/methods/gather_nd.rb +206 -0
  188. data/lib/carray/methods/index.rb +39 -0
  189. data/lib/carray/methods/insert_block.rb +99 -0
  190. data/lib/carray/methods/is_in.rb +141 -0
  191. data/lib/carray/methods/join.rb +90 -0
  192. data/lib/carray/methods/locate_addr.rb +47 -0
  193. data/lib/carray/methods/mask_duplicates.rb +41 -0
  194. data/lib/carray/methods/meshgrid.rb +91 -0
  195. data/lib/carray/methods/mode.rb +126 -0
  196. data/lib/carray/methods/nunique.rb +46 -0
  197. data/lib/carray/methods/resize.rb +56 -0
  198. data/lib/carray/methods/snap.rb +156 -0
  199. data/lib/carray/methods/string_format.rb +57 -0
  200. data/lib/carray/methods/unique.rb +47 -0
  201. data/lib/carray/methods/value_counts.rb +71 -0
  202. data/lib/carray/mkmf.rb +124 -101
  203. data/lib/carray/runtime.rb +108 -0
  204. data/lib/carray/serialize.rb +478 -167
  205. data/lib/carray/slab_iterator.rb +292 -0
  206. data/lib/carray/stack.rb +291 -0
  207. data/lib/carray/string.rb +56 -180
  208. data/lib/carray/string_operation_extension.rb +289 -0
  209. data/lib/carray/struct.rb +335 -323
  210. data/lib/carray/struct_builder.rb +697 -0
  211. data/lib/carray/table.rb +41 -2
  212. data/lib/carray/time.rb +2255 -38
  213. data/lib/carray/window_iterator.rb +655 -0
  214. data/lib/carray.rb +55 -57
  215. metadata +163 -130
  216. data/Rakefile +0 -51
  217. data/TODO.md +0 -18
  218. data/ext/ca_iter_block.c +0 -257
  219. data/ext/ca_iter_dimension.c +0 -299
  220. data/ext/ca_iter_window.c +0 -214
  221. data/ext/ca_obj_mapping.c +0 -644
  222. data/ext/carray_iterator.c +0 -641
  223. data/ext/carray_math.rb +0 -850
  224. data/ext/carray_numeric.c +0 -259
  225. data/ext/carray_sort_addr.c +0 -254
  226. data/ext/carray_stat.c +0 -2100
  227. data/ext/carray_stat_proc.rb +0 -1999
  228. data/ext/mkmath.rb +0 -741
  229. data/ext/ruby_ccomplex.c +0 -509
  230. data/ext/ruby_float_func.c +0 -86
  231. data/lib/carray/array.rb +0 -8
  232. data/lib/carray/autoload/autoload_base.rb +0 -19
  233. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  234. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  235. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  236. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  237. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  238. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  239. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  240. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  241. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  242. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  243. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  244. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  245. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  246. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  247. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  248. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  249. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  250. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  251. data/lib/carray/autoload.rb +0 -141
  252. data/lib/carray/basic.rb +0 -191
  253. data/lib/carray/broadcast.rb +0 -101
  254. data/lib/carray/compose.rb +0 -315
  255. data/lib/carray/convert.rb +0 -115
  256. data/lib/carray/info.rb +0 -110
  257. data/lib/carray/io/imagemagick.rb +0 -235
  258. data/lib/carray/mask.rb +0 -102
  259. data/lib/carray/math/histogram.rb +0 -177
  260. data/lib/carray/math/recurrence.rb +0 -93
  261. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  262. data/lib/carray/object/ca_obj_link.rb +0 -50
  263. data/lib/carray/object/ca_obj_pack.rb +0 -99
  264. data/lib/carray/obsolete.rb +0 -256
  265. data/lib/carray/ordering.rb +0 -181
  266. data/lib/carray/testing.rb +0 -51
  267. data/lib/carray/transform.rb +0 -109
  268. data/misc/Methods.ja.md +0 -182
  269. data/misc/NOTE +0 -51
  270. data/spec/Classes/CABitfield_spec.rb +0 -58
  271. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  272. data/spec/Classes/CABlock_spec.rb +0 -205
  273. data/spec/Classes/CAField_spec.rb +0 -39
  274. data/spec/Classes/CAGrid_spec.rb +0 -75
  275. data/spec/Classes/CAMap_spec.rb +0 -0
  276. data/spec/Classes/CAMapping_spec.rb +0 -105
  277. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  278. data/spec/Classes/CAObject_spec.rb +0 -33
  279. data/spec/Classes/CARefer_spec.rb +0 -93
  280. data/spec/Classes/CARepeat_spec.rb +0 -65
  281. data/spec/Classes/CASelect_spec.rb +0 -22
  282. data/spec/Classes/CAShift_spec.rb +0 -16
  283. data/spec/Classes/CAStruct_spec.rb +0 -71
  284. data/spec/Classes/CATranspose_spec.rb +0 -60
  285. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  286. data/spec/Classes/CAWindow_spec.rb +0 -54
  287. data/spec/Classes/CAWrap_spec.rb +0 -8
  288. data/spec/Classes/CArray_spec.rb +0 -184
  289. data/spec/Classes/CScalar_spec.rb +0 -55
  290. data/spec/Classes/ex1.rb +0 -46
  291. data/spec/Features/feature_130_spec.rb +0 -19
  292. data/spec/Features/feature_attributes_spec.rb +0 -280
  293. data/spec/Features/feature_boolean_spec.rb +0 -98
  294. data/spec/Features/feature_broadcast.rb +0 -116
  295. data/spec/Features/feature_cast_function.rb +0 -19
  296. data/spec/Features/feature_cast_spec.rb +0 -33
  297. data/spec/Features/feature_class_spec.rb +0 -84
  298. data/spec/Features/feature_complex_spec.rb +0 -42
  299. data/spec/Features/feature_composite_spec.rb +0 -124
  300. data/spec/Features/feature_convert_spec.rb +0 -46
  301. data/spec/Features/feature_copy_spec.rb +0 -123
  302. data/spec/Features/feature_creation_spec.rb +0 -84
  303. data/spec/Features/feature_element_spec.rb +0 -144
  304. data/spec/Features/feature_extream_spec.rb +0 -54
  305. data/spec/Features/feature_generate_spec.rb +0 -74
  306. data/spec/Features/feature_index_spec.rb +0 -69
  307. data/spec/Features/feature_mask_spec.rb +0 -580
  308. data/spec/Features/feature_math_spec.rb +0 -97
  309. data/spec/Features/feature_order_spec.rb +0 -146
  310. data/spec/Features/feature_ref_store_spec.rb +0 -209
  311. data/spec/Features/feature_serialization_spec.rb +0 -125
  312. data/spec/Features/feature_stat_spec.rb +0 -397
  313. data/spec/Features/feature_virtual_spec.rb +0 -48
  314. data/spec/Features/method_eq_spec.rb +0 -81
  315. data/spec/Features/method_is_nan_spec.rb +0 -12
  316. data/spec/Features/method_map_spec.rb +0 -54
  317. data/spec/Features/method_max_with.rb +0 -20
  318. data/spec/Features/method_min_with.rb +0 -19
  319. data/spec/Features/method_ne_spec.rb +0 -18
  320. data/spec/Features/method_project_spec.rb +0 -188
  321. data/spec/Features/method_ref_spec.rb +0 -27
  322. data/spec/Features/method_round_spec.rb +0 -11
  323. data/spec/Features/method_s_linspace_spec.rb +0 -48
  324. data/spec/Features/method_s_span_spec.rb +0 -14
  325. data/spec/Features/method_seq_spec.rb +0 -47
  326. data/spec/Features/method_sort_with.rb +0 -43
  327. data/spec/Features/method_sorted_with.rb +0 -29
  328. data/spec/Features/method_span_spec.rb +0 -42
  329. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  330. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  331. data/spec/spec_all.rb +0 -10
  332. data/utils/ca_ase.rb +0 -21
  333. data/utils/ca_methods.rb +0 -15
  334. data/utils/cast_checker.rb +0 -30
  335. data/utils/convert_test.rb +0 -73
  336. data/utils/extract_yard.rb +0 -22
  337. data/utils/guess_shape.rb +0 -76
  338. data/utils/monkey_patch_methods.rb +0 -62
  339. data/utils/remove_resource_fork.sh +0 -5
@@ -0,0 +1,697 @@
1
+ # CAStruct::Builder -- the DSL backend behind CArray.struct { ... } and
2
+ # CArray.union { ... }. Autoloaded from lib/carray/struct.rb on first
3
+ # reference to CAStruct::Builder, so applications that only consume
4
+ # pre-defined struct classes never pay for loading the Builder.
5
+
6
+ # ---------------------------------------------------------------------
7
+ #
8
+ # Struct Builder Class
9
+ #
10
+ # ---------------------------------------------------------------------
11
+
12
+ class CAStruct::Builder # :nodoc:
13
+
14
+ class Member # :nodoc:
15
+
16
+ def initialize (name, type, opt={})
17
+ @name, @type, @opt = name, type, opt
18
+ if @type == :bitfield
19
+ # Bit members carry their own offset/length math via the
20
+ # Builder's bit() method; the standard byte cursor in
21
+ # member() does not advance for them. Setting byte_length=0
22
+ # keeps any defensive byte-loop arithmetic harmless.
23
+ @bytes = 0
24
+ @byte_length = 0
25
+ elsif @type.kind_of?(CArray)
26
+ @type = @type.copy
27
+ @byte_length = @type.bytes * @type.elements
28
+ @bytes = 0
29
+ else
30
+ data_type, @bytes = CArray.guess_type_and_bytes(@type, @opt[:bytes])
31
+ if data_type == CA_OBJECT
32
+ raise CAStruct::DefinitionError,
33
+ "CA_OBJECT cannot be a member of struct or union"
34
+ end
35
+ @byte_length = @bytes
36
+ end
37
+ @offset = @opt[:offset]
38
+ end
39
+
40
+ attr_reader :name, :type, :offset, :bytes, :byte_length, :opt
41
+
42
+ end
43
+
44
+ # Build the DISPATCH_TABLE for a finalized MEMBER_TABLE.
45
+ # Returns `{ name => [reader_proc, writer_proc] }` where each Proc
46
+ # closes over the per-member offset / opts. Called once, at the
47
+ # bottom of `define`. Public so it can be tested in isolation.
48
+ #
49
+ # `data_size` is the struct's DATA_SIZE; needed up front so we can
50
+ # bounds-check bit-field projections at definition time rather than
51
+ # at first access.
52
+ def self.build_dispatch_table (member_table, data_size)
53
+ dispatch = {}
54
+ member_table.each do |name, entry|
55
+ offset, type, opts = *entry
56
+ case
57
+ when type == :bitfield
58
+ dispatch[name] = build_bitfield_dispatcher(name, opts, data_size)
59
+ when type.is_a?(Class)
60
+ dispatch[name] = build_nested_struct_dispatcher(offset, type)
61
+ when type.is_a?(CArray)
62
+ dispatch[name] = build_carray_template_dispatcher(offset, type)
63
+ else
64
+ dispatch[name] = build_primitive_dispatcher(offset, type, opts)
65
+ end
66
+ end
67
+ dispatch
68
+ end
69
+
70
+ # CIFY: build the FAST_PRIMITIVES table consumed by the C-native
71
+ # CAStruct#[] / #[]=. Includes the members the C path can handle
72
+ # without allocating any CAField / CABitfield / CAByteSwap view:
73
+ #
74
+ # - Plain primitives (int8..uint64, float32/64) without `endian:`
75
+ # - Bit-fields: word load + shift + mask in C
76
+ # - Endian-tagged primitives: __builtin_bswap in C, but
77
+ # only when the requested endian differs from the host -- when
78
+ # they match, the member is folded into the primitive path with
79
+ # no swap at all.
80
+ #
81
+ # Bit-fields whose spanning power-of-2 word reaches past
82
+ # `data_size` cannot be fast-pathed (CABitfield's existing guard
83
+ # also rejects them); they fall through to DISPATCH_TABLE so the
84
+ # Ruby Proc can produce a clear DefinitionError-style failure.
85
+ #
86
+ # Nested-struct / CArray-template / fixlen / cmplx / object stay
87
+ # absent; for them the C path falls back to DISPATCH_TABLE's Proc.
88
+ #
89
+ # Entry shape: `name => [kind, ...args]` (frozen Array).
90
+ #
91
+ # FAST_KIND_PRIMITIVE = 0
92
+ # [0, offset, ca_type_code]
93
+ # FAST_KIND_BITFIELD = 1
94
+ # [1, start_byte, view_bytes, bit_in_word, bits]
95
+ # FAST_KIND_ENDIAN = 2
96
+ # [2, offset, ca_type_code]
97
+ #
98
+ # Kind tags are kept in sync with FAST_KIND_* in
99
+ # ext/carray_struct.c.
100
+ FAST_KIND_PRIMITIVE = 0
101
+ # @!visibility private
102
+ FAST_KIND_BITFIELD = 1
103
+ # @!visibility private
104
+ FAST_KIND_ENDIAN = 2
105
+
106
+ # @!visibility private
107
+ def self.build_fast_primitives (member_table, data_size = nil)
108
+ fast = {}
109
+ host_endian = CArray.endian
110
+ member_table.each do |name, entry|
111
+ offset, type, opts = *entry
112
+ case
113
+ when type == :bitfield
114
+ fast_entry = build_fast_bitfield_entry(opts, data_size)
115
+ fast[name] = fast_entry if fast_entry
116
+ when type.is_a?(Class)
117
+ # nested struct — DISPATCH_TABLE
118
+ when type.is_a?(CArray)
119
+ # CArray template — DISPATCH_TABLE
120
+ else
121
+ type_code = FAST_PRIMITIVE_TYPE_CODES[type]
122
+ next unless type_code
123
+ endian = opts && opts[:endian]
124
+ if endian && endian_needs_swap?(endian, host_endian) &&
125
+ ENDIAN_FAST_TYPE_CODES.include?(type_code)
126
+ fast[name] = [FAST_KIND_ENDIAN, offset, type_code].freeze
127
+ else
128
+ fast[name] = [FAST_KIND_PRIMITIVE, offset, type_code].freeze
129
+ end
130
+ end
131
+ end
132
+ fast
133
+ end
134
+
135
+ # Bit-field FAST entry, mirroring build_bitfield_dispatcher's
136
+ # geometry calculation but emitting the C-friendly tuple
137
+ # [FAST_KIND_BITFIELD, start_byte, view_bytes, bit_in_word, bits].
138
+ # Returns nil if the field can't be fast-pathed (e.g. its spanning
139
+ # word reaches past DATA_SIZE -- the existing build_bitfield_dispatcher
140
+ # raises in that case at definition time; here we just bow out and
141
+ # let DISPATCH_TABLE raise).
142
+ def self.build_fast_bitfield_entry (opts, data_size)
143
+ bits = opts[:bits]
144
+ bit_offset = opts[:bit_offset]
145
+ start_byte = bit_offset / 8
146
+ bit_in_word = bit_offset % 8
147
+ span = (bit_offset + bits + 7) / 8 - start_byte
148
+ view_bytes = case
149
+ when span <= 1 then 1
150
+ when span <= 2 then 2
151
+ when span <= 4 then 4
152
+ else 8
153
+ end
154
+ return nil if data_size && start_byte + view_bytes > data_size
155
+ [FAST_KIND_BITFIELD, start_byte, view_bytes, bit_in_word, bits].freeze
156
+ end
157
+
158
+ # True iff a member tagged with the given `endian:` keyword needs
159
+ # an actual byte swap on the current host. Matches CArray#endian's
160
+ # short-circuit logic: :preserve and :native are always identity;
161
+ # :big / :little are identity when the host already matches.
162
+ def self.endian_needs_swap? (endian_sym, host_endian)
163
+ case endian_sym
164
+ when :preserve, :native then false
165
+ when :big then host_endian != CA_BIG_ENDIAN
166
+ when :little then host_endian != CA_LITTLE_ENDIAN
167
+ else false # unknown sym — be conservative, defer to DISPATCH_TABLE
168
+ end
169
+ end
170
+
171
+ # Symbol → CA_* integer constant for the primitive numeric types
172
+ # the C fast path handles directly. Anything missing here routes
173
+ # through DISPATCH_TABLE (slower but correct).
174
+ # These values are consumed by the C-side FAST_PRIMITIVES dispatcher
175
+ # (ext/carray_struct.c) which expects raw int8_t data_type codes via
176
+ # NUM2INT. CA_* are Symbols, so we eagerly convert to Integer codes
177
+ # here at definition time.
178
+ FAST_PRIMITIVE_TYPE_CODES = {
179
+ :boolean => CArray.data_type_code(CA_BOOLEAN),
180
+ :int8 => CArray.data_type_code(CA_INT8),
181
+ :uint8 => CArray.data_type_code(CA_UINT8),
182
+ :int16 => CArray.data_type_code(CA_INT16),
183
+ :uint16 => CArray.data_type_code(CA_UINT16),
184
+ :int32 => CArray.data_type_code(CA_INT32),
185
+ :uint32 => CArray.data_type_code(CA_UINT32),
186
+ :int64 => CArray.data_type_code(CA_INT64),
187
+ :uint64 => CArray.data_type_code(CA_UINT64),
188
+ :float32 => CArray.data_type_code(CA_FLOAT32),
189
+ :float64 => CArray.data_type_code(CA_FLOAT64),
190
+ }.freeze
191
+
192
+ # ca_type_code → eligible for the endian-swapped fast path. 1-byte
193
+ # types are excluded because byte-swap is a no-op (they go through
194
+ # the plain primitive path). Complex types are excluded too;
195
+ # their per-component swap matches CAByteSwap behaviour and stays
196
+ # on the DISPATCH_TABLE Proc. Values are Integer codes (same
197
+ # rationale as FAST_PRIMITIVE_TYPE_CODES above).
198
+ ENDIAN_FAST_TYPE_CODES = FAST_PRIMITIVE_TYPE_CODES.values_at(
199
+ :int16, :uint16, :int32, :uint32, :int64, :uint64,
200
+ :float32, :float64,
201
+ ).freeze
202
+
203
+ # -- per-kind dispatcher builders -------------------------------------
204
+
205
+ def self.build_bitfield_dispatcher (name, opts, data_size)
206
+ bits = opts[:bits]
207
+ bit_offset = opts[:bit_offset]
208
+ start_byte = bit_offset / 8
209
+ bit_in_byte = bit_offset % 8
210
+ span = (bit_offset + bits + 7) / 8 - start_byte
211
+ view_bytes = case
212
+ when span <= 1 then 1
213
+ when span <= 2 then 2
214
+ when span <= 4 then 4
215
+ else 8
216
+ end
217
+ if start_byte + view_bytes > data_size
218
+ raise CAStruct::DefinitionError,
219
+ "bit member #{name.inspect} (bit_offset=#{bit_offset}, " \
220
+ "bits=#{bits}) needs a #{view_bytes}-byte view starting " \
221
+ "at byte #{start_byte}, but the record is only " \
222
+ "#{data_size} bytes — deferred to A.3+ (multi-byte bit " \
223
+ "members spanning unaligned record tails)"
224
+ end
225
+ vtype = {1 => :uint8, 2 => :uint16, 4 => :uint32, 8 => :uint64}[view_bytes]
226
+ range = bit_in_byte..(bit_in_byte + bits - 1)
227
+ reader = ->(data) {
228
+ data.field(start_byte, vtype).bitfield(range)[0]
229
+ }
230
+ writer = ->(data, val) {
231
+ data.field(start_byte, vtype).bitfield(range)[0] = val
232
+ }
233
+ [reader, writer].freeze
234
+ end
235
+
236
+ # @!visibility private
237
+ def self.build_nested_struct_dispatcher (offset, nested_class)
238
+ reader = ->(data) { nested_class.decode(data.field(offset, nested_class)) }
239
+ writer = ->(data, val) { data.field(offset, nested_class)[0] = val }
240
+ [reader, writer].freeze
241
+ end
242
+
243
+ # @!visibility private
244
+ def self.build_carray_template_dispatcher (offset, template)
245
+ reader = ->(data) { data.field(offset, template)[0, false] }
246
+ writer = ->(data, val) { data.field(offset, template)[0, false] = val }
247
+ [reader, writer].freeze
248
+ end
249
+
250
+ # @!visibility private
251
+ def self.build_primitive_dispatcher (offset, type, opts)
252
+ # Specialise the reader/writer to the smallest amount of work
253
+ # this particular member needs: no opts → 2-arg field; opts with
254
+ # only :bytes → 3-arg field; opts with :endian → 3-arg field +
255
+ # endian view chain.
256
+ endian = opts && opts[:endian]
257
+ if opts.nil?
258
+ reader = ->(data) { data.field(offset, type)[0] }
259
+ writer = ->(data, val) { data.field(offset, type)[0] = val }
260
+ elsif endian.nil?
261
+ reader = ->(data) { data.field(offset, type, opts)[0] }
262
+ writer = ->(data, val) { data.field(offset, type, opts)[0] = val }
263
+ else
264
+ # CArray#field only accepts `bytes:`; the endian swap is applied by
265
+ # the chained #endian view, not by field. Strip :endian from the
266
+ # hash handed to field so it is not rejected.
267
+ field_opts = opts.reject { |k, _| k == :endian }
268
+ if field_opts.empty?
269
+ reader = ->(data) { data.field(offset, type).endian(endian)[0] }
270
+ writer = ->(data, val) { data.field(offset, type).endian(endian)[0] = val }
271
+ else
272
+ reader = ->(data) { data.field(offset, type, field_opts).endian(endian)[0] }
273
+ writer = ->(data, val) {
274
+ data.field(offset, type, field_opts).endian(endian)[0] = val
275
+ }
276
+ end
277
+ end
278
+ [reader, writer].freeze
279
+ end
280
+
281
+ # @!visibility private
282
+ ALIGN_TABLE = {
283
+ CA_FIXLEN => CA_ALIGN_FIXLEN,
284
+ CA_BOOLEAN => CA_ALIGN_INT8,
285
+ CA_INT8 => CA_ALIGN_INT8,
286
+ CA_UINT8 => CA_ALIGN_INT8,
287
+ CA_INT16 => CA_ALIGN_INT16,
288
+ CA_UINT16 => CA_ALIGN_INT16,
289
+ CA_INT32 => CA_ALIGN_INT32,
290
+ CA_UINT32 => CA_ALIGN_INT32,
291
+ CA_INT64 => CA_ALIGN_INT64,
292
+ CA_UINT64 => CA_ALIGN_INT64,
293
+ CA_FLOAT32 => CA_ALIGN_FLOAT32,
294
+ CA_FLOAT64 => CA_ALIGN_FLOAT64,
295
+ CA_CMPLX64 => CA_ALIGN_FLOAT32,
296
+ CA_CMPLX128 => CA_ALIGN_FLOAT64,
297
+ }
298
+
299
+ def initialize (type, opt = {})
300
+ if not opt[:pack].nil? and not opt[:pack].is_a?(Integer)
301
+ raise CAStruct::DefinitionError,
302
+ "invalid :pack value #{opt[:pack].inspect} (expected nil or Integer)"
303
+ end
304
+ @type = type ### :struct or :union
305
+ @align = opt[:pack] ### nil for alignment, int for pack(n)
306
+ @members = [] ### array of CArray::Struct::Builder::Member
307
+ @offset = 0 ### offset of each member and size of struct
308
+ @align_max = 1 ### maximum of alignment among members
309
+ @size = opt[:size] ### user defined struct size
310
+ @bit_offset = 0 ### 0..7, sub-byte position for bitfield accumulator
311
+ end
312
+
313
+ # Round up the byte cursor if the bitfield accumulator is mid-byte.
314
+ # Called before placing a non-bit member so the byte member starts
315
+ # on a clean byte boundary (and after the body is fully built so
316
+ # DATA_SIZE includes the trailing bits' byte).
317
+ def flush_bit_offset
318
+ if @bit_offset > 0
319
+ @offset += 1
320
+ @bit_offset = 0
321
+ end
322
+ end
323
+
324
+ # @!visibility private
325
+ def define (&block)
326
+ # ---
327
+ case block.arity
328
+ when 1
329
+ block.call(self) ### struct/union definition block
330
+ when -1, 0
331
+ instance_exec(&block) ### struct/union definition block
332
+ else
333
+ raise CAStruct::DefinitionError,
334
+ "invalid # of block parameters (expected 0 or 1)"
335
+ end
336
+ # Flush any trailing bit accumulator so DATA_SIZE includes the
337
+ # final byte that carries the last bit member's tail.
338
+ flush_bit_offset
339
+ # ---
340
+ # Detect duplicate member names before doing anything else. A
341
+ # duplicate would silently overwrite MEMBER_TABLE entries and
342
+ # produce a struct whose MEMBERS list contains the same name
343
+ # twice, which downstream code (MEMBERS.map { ... }, define_method
344
+ # loop, .spec) cannot recover from cleanly.
345
+ seen = {}
346
+ dups = []
347
+ @members.each do |mem|
348
+ if seen[mem.name]
349
+ dups << mem.name
350
+ else
351
+ seen[mem.name] = true
352
+ end
353
+ end
354
+ unless dups.empty?
355
+ raise CAStruct::DefinitionError,
356
+ format("duplicate member name(s): %s",
357
+ dups.uniq.map(&:inspect).join(", "))
358
+ end
359
+ # ---
360
+ case @type
361
+ when :struct
362
+ klass = Class.new(CAStruct)
363
+ when :union
364
+ klass = Class.new(CAUnion)
365
+ end
366
+ # ---
367
+ if @align.nil?
368
+ @offset = alignment(@offset, :align_max)
369
+ end
370
+ if @size
371
+ if @size < @offset
372
+ raise CAStruct::DefinitionError,
373
+ format("declared :size (%d) is smaller than packed body (%d)",
374
+ @size, @offset)
375
+ end
376
+ @offset = @size
377
+ end
378
+ klass.const_set(:DATA_SIZE, @offset) ### required element as data class
379
+ # ---
380
+ table = Hash.new
381
+ names = []
382
+ @members.each do |mem|
383
+ name = mem.name
384
+ type = mem.type
385
+ offset = mem.offset
386
+ bytes = mem.bytes
387
+ if type == :bitfield
388
+ # Bit members carry their addressing info (bits + bit_offset)
389
+ # in opts; CAStruct#[] / #[]= dispatches on this type and
390
+ # routes to @data.bitfield(bit_offset, bits).
391
+ table[name] = [offset, :bitfield,
392
+ { :bits => mem.opt[:bits],
393
+ :bit_offset => mem.opt[:bit_offset] }]
394
+ elsif bytes
395
+ ent = {:bytes => bytes}
396
+ ent[:endian] = mem.opt[:endian] if mem.opt[:endian]
397
+ table[name] = [offset, type, ent]
398
+ elsif mem.opt[:endian]
399
+ table[name] = [offset, type, {:endian => mem.opt[:endian]}]
400
+ else
401
+ table[name] = [offset, type]
402
+ end
403
+ names.push(name)
404
+ end
405
+ table.freeze
406
+ names.freeze
407
+ klass.const_set(:MEMBER_TABLE, table) ### required element as data class
408
+ klass.const_set(:MEMBERS, names)
409
+ # ---
410
+ # Step 3 dispatch table: precompute a per-member [reader, writer]
411
+ # Proc pair so `record[name]` is one Hash lookup + one Proc call,
412
+ # with no `case type` reclassification on each access. All bounds
413
+ # checks and view-shape decisions happen here, once, at class
414
+ # definition time.
415
+ klass.const_set(:DISPATCH_TABLE,
416
+ self.class.build_dispatch_table(table, @offset).freeze)
417
+ # Also precompute FAST_PRIMITIVES, the subset of members that the
418
+ # C-side `[]` / `[]=` can handle without
419
+ # allocating a CAField view. Entries are `[offset, type_code]`;
420
+ # the C reader does a typed memcpy + INT2FIX/DBL2NUM/... directly
421
+ # on @data.ptr + offset. Bit / endian / nested / template / fixlen
422
+ # members are absent here -- they stay on the DISPATCH_TABLE Proc
423
+ # path.
424
+ klass.const_set(:FAST_PRIMITIVES,
425
+ self.class.build_fast_primitives(table, @offset).freeze)
426
+ # ---
427
+ klass.module_eval {
428
+ names.each do |name|
429
+ define_method(name) {
430
+ return self[name]
431
+ }
432
+ define_method("#{name}=") { |val|
433
+ return self[name] = val
434
+ }
435
+ end
436
+ }
437
+ # ---
438
+ return klass
439
+ end
440
+
441
+ private
442
+
443
+ def alignment (addr, data_type, opt={})
444
+ # ALIGN_TABLE keys are CA_* constants, which are Symbols. Dispatch on
445
+ # Symbol directly; the Integer path (= raw data_type code) maps via the
446
+ # canonical Symbol name.
447
+ case data_type
448
+ when :align_max
449
+ align = @align_max
450
+ when Symbol
451
+ align = ALIGN_TABLE[data_type]
452
+ unless align
453
+ data_type, bytes = CArray.guess_type_and_bytes(data_type, opt[:bytes])
454
+ return alignment(addr, data_type, :bytes=>bytes)
455
+ end
456
+ when Integer
457
+ align = ALIGN_TABLE[CArray.data_type_name(data_type).to_sym]
458
+ when CArray, Class
459
+ align = CA_ALIGN_VOIDP
460
+ else
461
+ data_type, bytes = CArray.guess_type_and_bytes(data_type, opt[:bytes])
462
+ return alignment(addr, data_type, :bytes=>bytes)
463
+ end
464
+ if align > @align_max
465
+ @align_max = align
466
+ end
467
+ if ( d = addr % align ) != 0
468
+ addr += (align - d)
469
+ end
470
+ return addr
471
+ end
472
+
473
+ def pack (addr, align, opt={})
474
+ if ( addr % align ) != 0
475
+ raise CAStruct::DefinitionError,
476
+ format("invalid offset for packing: %d not aligned to %d", addr, align)
477
+ end
478
+ return addr
479
+ end
480
+
481
+ public
482
+
483
+ # @overload member(data_type, id = nil, opt = {})
484
+ # Declares a member with the given storage `data_type`. Used
485
+ # internally by the typed DSL methods (`int32`, `float64`, ...);
486
+ # call directly to place a custom template or nested type.
487
+ # @param data_type [Object] data type (Symbol, Integer, CArray
488
+ # template, or nested struct class).
489
+ # @param id [Symbol, String, nil] member name; auto-generated
490
+ # when `nil`.
491
+ # @param opt [Hash] member options (`:offset`, `:bytes`, `:endian`, ...).
492
+ # @return [Member]
493
+ def member (data_type, id = nil, opt = {})
494
+ opt = opt.clone
495
+ # If a bit member sequence was in flight, round up to a clean byte
496
+ # boundary before placing this byte-typed member.
497
+ flush_bit_offset
498
+ if id
499
+ id = id.to_s
500
+ else
501
+ id = "#{@members.size}"
502
+ end
503
+ case @type
504
+ when :struct ### struct
505
+ case @align
506
+ when nil ### -- aligned
507
+ @offset = alignment(@offset, data_type, opt)
508
+ opt[:offset] = @offset
509
+ else ### -- packed
510
+ if opt[:offset] ### ---- explicit offset
511
+ @offset = pack(opt[:offset], @align, opt)
512
+ else
513
+ opt[:offset] = @offset ### ---- auto offset
514
+ end
515
+ end
516
+ mem = Member.new(id, data_type, opt)
517
+ @members.push(mem)
518
+ @offset += mem.byte_length
519
+ when :union ### union
520
+ alignment(0, data_type, opt)
521
+ opt[:offset] = 0
522
+ mem = Member.new(id, data_type, opt)
523
+ @members.push(mem)
524
+ if mem.byte_length > @offset
525
+ @offset = mem.byte_length
526
+ end
527
+ end
528
+ end
529
+
530
+ # @overload struct(*names, &block)
531
+ # Declares a nested struct member. With a block, defines an
532
+ # inline nested struct; otherwise requires `type:` naming an
533
+ # existing {CAStruct} subclass.
534
+ # @param names [Array<Symbol>] member names.
535
+ # @return [Class] the nested struct class.
536
+ # @raise [CAStruct::DefinitionError] when neither a block nor
537
+ # `type:` is provided.
538
+ def struct (*args, &block)
539
+ opt = args.last.is_a?(Hash) ? args.pop : {}
540
+ if block
541
+ opt = {:pack => @align}.update(opt)
542
+ st = self.class.new(:struct, opt).define(&block)
543
+ elsif opt[:type] and opt[:type] <= CAStruct
544
+ st = opt[:type]
545
+ else
546
+ raise CAStruct::DefinitionError,
547
+ "no type given for nested struct member (pass a block or :type)"
548
+ end
549
+ args.each do |arg|
550
+ member(st, arg)
551
+ end
552
+ return st
553
+ end
554
+
555
+ # @overload union(*names, &block)
556
+ # Declares a nested union member. With a block, defines an
557
+ # inline nested union; otherwise requires `type:` naming an
558
+ # existing {CAUnion} subclass.
559
+ # @param names [Array<Symbol>] member names.
560
+ # @return [Class] the nested union class.
561
+ # @raise [CAStruct::DefinitionError] when neither a block nor
562
+ # `type:` is provided.
563
+ def union (*args, &block)
564
+ opt = args.last.is_a?(Hash) ? args.pop : {}
565
+ if block
566
+ opt = {:pack => @align}.update(opt)
567
+ st = self.class.new(:union, opt).define(&block)
568
+ elsif opt[:type] and opt[:type] <= CAStruct
569
+ st = opt[:type]
570
+ else
571
+ raise CAStruct::DefinitionError,
572
+ "no type given for nested union member (pass a block or :type)"
573
+ end
574
+ args.each do |arg|
575
+ member(st, arg)
576
+ end
577
+ return st
578
+ end
579
+
580
+ # @overload array(*names, type:)
581
+ # Declares one or more members holding a CArray template.
582
+ # @param names [Array<Symbol>] member names.
583
+ # @return [void]
584
+ # @raise [CAStruct::DefinitionError] when `type:` is not a
585
+ # CArray template.
586
+ def array (*args)
587
+ opt = args.last.is_a?(Hash) ? args.pop : {}
588
+ if not opt[:type] or not opt[:type].kind_of?(CArray)
589
+ raise CAStruct::DefinitionError,
590
+ "no :type given for array member (expected a CArray template)"
591
+ end
592
+ args.each do |arg|
593
+ member(opt[:type], arg)
594
+ end
595
+ end
596
+
597
+ # @overload bit(name, bits:)
598
+ # Declares a bitfield member. Bits accumulate within the
599
+ # current byte; when a byte member follows, the cursor rounds
600
+ # up to the next byte boundary. Only supported in `:struct`
601
+ # (not `:union`) and always requires a name.
602
+ # @param name [Symbol, String] member name.
603
+ # @param bits [Integer] bit width in `1..64`.
604
+ # @return [void]
605
+ # @raise [CAStruct::DefinitionError] on `:union` context, a
606
+ # missing name, or an invalid `bits` value.
607
+ def bit (name, bits:)
608
+ if @type == :union
609
+ raise CAStruct::DefinitionError,
610
+ "bit members in :union are not supported"
611
+ end
612
+ if name.nil?
613
+ raise CAStruct::DefinitionError,
614
+ "bit member must have a name (no anonymous bit padding)"
615
+ end
616
+ unless bits.is_a?(Integer) && bits >= 1 && bits <= 64
617
+ raise CAStruct::DefinitionError,
618
+ "bit member requires bits: as an Integer in 1..64 (got #{bits.inspect})"
619
+ end
620
+ total_bit_offset = @offset * 8 + @bit_offset
621
+ mem = Member.new(name.to_s, :bitfield,
622
+ {:bits => bits,
623
+ :bit_offset => total_bit_offset,
624
+ :offset => @offset})
625
+ @members.push(mem)
626
+ @bit_offset += bits
627
+ while @bit_offset >= 8
628
+ @offset += 1
629
+ @bit_offset -= 8
630
+ end
631
+ if @align_max < 1
632
+ @align_max = 1
633
+ end
634
+ end
635
+
636
+ # @!visibility private
637
+ VALID_ENDIAN = [:preserve, :native, :big, :little].freeze
638
+
639
+ # Validate the `endian:` option on a typed-member declaration.
640
+ # `allow` is false for non-numeric types (e.g. fixlen) where a
641
+ # byte-swap view would mangle the value.
642
+ def self.validate_endian! (opt, typename, allow)
643
+ return unless opt.key?(:endian)
644
+ unless allow
645
+ raise CAStruct::DefinitionError,
646
+ "endian: is not supported for #{typename} members"
647
+ end
648
+ unless VALID_ENDIAN.include?(opt[:endian])
649
+ raise CAStruct::DefinitionError,
650
+ "endian: must be one of #{VALID_ENDIAN.inspect} " \
651
+ "(got #{opt[:endian].inspect})"
652
+ end
653
+ end
654
+
655
+ [
656
+ ["fixlen", false],
657
+ ["boolean", true],
658
+ ["int8", true],
659
+ ["uint8", true],
660
+ ["int16", true],
661
+ ["uint16", true],
662
+ ["int32", true],
663
+ ["uint32", true],
664
+ ["int64", true],
665
+ ["uint64", true],
666
+ ["float32", true],
667
+ ["float64", true],
668
+ ["cmplx64", true],
669
+ ["cmplx128", true],
670
+ ].each do |typename, allow_endian|
671
+ class_eval %{
672
+ def #{typename} (*args)
673
+ opt = args.last.is_a?(Hash) ? args.pop : {}
674
+ if args.empty?
675
+ raise CAStruct::DefinitionError,
676
+ "#{typename} requires at least one member name " \
677
+ "(use nil for anonymous padding)"
678
+ end
679
+ CAStruct::Builder.validate_endian!(opt, "#{typename}", #{allow_endian})
680
+ args.each do |arg|
681
+ member(:#{typename}, arg, opt)
682
+ end
683
+ end
684
+ }
685
+ end
686
+
687
+ alias char_p fixlen
688
+ alias byte uint8
689
+ alias short int16
690
+ alias int int32
691
+ alias float float32
692
+ alias double float64
693
+ alias complex cmplx64
694
+ alias dcomplex cmplx128
695
+
696
+ end
697
+