carray 3.0.2 → 3.0.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +104 -81
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
|
@@ -234,8 +234,17 @@ class CAStruct::Builder # :nodoc:
|
|
|
234
234
|
end
|
|
235
235
|
|
|
236
236
|
# @!visibility private
|
|
237
|
+
# A nested member reads as an element of the nested struct over the
|
|
238
|
+
# parent's own bytes (a field view), so writing to it writes to the
|
|
239
|
+
# parent, as writing to an array member does. A frozen parent gives a
|
|
240
|
+
# frozen nested element.
|
|
237
241
|
def self.build_nested_struct_dispatcher (offset, nested_class)
|
|
238
|
-
reader = ->(data) {
|
|
242
|
+
reader = ->(data) {
|
|
243
|
+
element = nested_class.allocate
|
|
244
|
+
element.instance_variable_set(:@data, data.field(offset, nested_class).parent)
|
|
245
|
+
element.freeze if data.frozen?
|
|
246
|
+
element
|
|
247
|
+
}
|
|
239
248
|
writer = ->(data, val) { data.field(offset, nested_class)[0] = val }
|
|
240
249
|
[reader, writer].freeze
|
|
241
250
|
end
|
|
@@ -279,6 +288,15 @@ class CAStruct::Builder # :nodoc:
|
|
|
279
288
|
end
|
|
280
289
|
|
|
281
290
|
# @!visibility private
|
|
291
|
+
# Shared with every Ractor when it can be. A member whose type is an
|
|
292
|
+
# array template holds a CArray, which cannot be shared, and its struct
|
|
293
|
+
# is then used in the main Ractor only.
|
|
294
|
+
def self.shareable (object)
|
|
295
|
+
Ractor.make_shareable(object)
|
|
296
|
+
rescue Ractor::Error
|
|
297
|
+
object.freeze
|
|
298
|
+
end
|
|
299
|
+
|
|
282
300
|
ALIGN_TABLE = {
|
|
283
301
|
CA_FIXLEN => CA_ALIGN_FIXLEN,
|
|
284
302
|
CA_BOOLEAN => CA_ALIGN_INT8,
|
|
@@ -295,8 +313,24 @@ class CAStruct::Builder # :nodoc:
|
|
|
295
313
|
CA_CMPLX64 => CA_ALIGN_FLOAT32,
|
|
296
314
|
CA_CMPLX128 => CA_ALIGN_FLOAT64,
|
|
297
315
|
}
|
|
316
|
+
Ractor.make_shareable(ALIGN_TABLE)
|
|
317
|
+
|
|
318
|
+
# Raises ArgumentError when `opt` names a key outside `allowed`. The
|
|
319
|
+
# options are read one key at a time, so a misspelt key would otherwise
|
|
320
|
+
# be ignored and the layout would change without a word.
|
|
321
|
+
def self.check_keys! (opt, allowed, where)
|
|
322
|
+
unknown = opt.keys - allowed
|
|
323
|
+
return if unknown.empty?
|
|
324
|
+
raise ArgumentError, "#{where}: unknown keyword#{unknown.size > 1 ? "s" : ""}: " +
|
|
325
|
+
unknown.map(&:inspect).join(", ")
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
BUILDER_KEYS = [:pack, :size, :order_by].freeze
|
|
329
|
+
MEMBER_KEYS = [:offset, :bytes, :endian].freeze
|
|
330
|
+
NESTED_KEYS = (BUILDER_KEYS + [:type, :offset]).freeze
|
|
298
331
|
|
|
299
332
|
def initialize (type, opt = {})
|
|
333
|
+
CAStruct::Builder.check_keys!(opt, BUILDER_KEYS, type.to_s)
|
|
300
334
|
if not opt[:pack].nil? and not opt[:pack].is_a?(Integer)
|
|
301
335
|
raise CAStruct::DefinitionError,
|
|
302
336
|
"invalid :pack value #{opt[:pack].inspect} (expected nil or Integer)"
|
|
@@ -305,11 +339,43 @@ class CAStruct::Builder # :nodoc:
|
|
|
305
339
|
@align = opt[:pack] ### nil for alignment, int for pack(n)
|
|
306
340
|
@members = [] ### array of CArray::Struct::Builder::Member
|
|
307
341
|
@offset = 0 ### offset of each member and size of struct
|
|
342
|
+
@extent = 0 ### furthest byte any member reaches
|
|
308
343
|
@align_max = 1 ### maximum of alignment among members
|
|
309
344
|
@size = opt[:size] ### user defined struct size
|
|
310
345
|
@bit_offset = 0 ### 0..7, sub-byte position for bitfield accumulator
|
|
346
|
+
@order_by = opt[:order_by] ### member names the records are ordered by
|
|
311
347
|
end
|
|
312
348
|
|
|
349
|
+
# The `order_by:` members, as member names. Each has to be a member of
|
|
350
|
+
# this struct that holds one ordered value: not a nested record, an array
|
|
351
|
+
# member or a complex number.
|
|
352
|
+
def order_keys (table)
|
|
353
|
+
keys = Array(@order_by).map(&:to_s)
|
|
354
|
+
if keys.empty?
|
|
355
|
+
raise CAStruct::DefinitionError, "order_by: names no member"
|
|
356
|
+
end
|
|
357
|
+
keys.each do |key|
|
|
358
|
+
unless table.key?(key)
|
|
359
|
+
raise CAStruct::DefinitionError, "order_by: #{key.inspect} is not a member"
|
|
360
|
+
end
|
|
361
|
+
type = table[key][1]
|
|
362
|
+
if type.is_a?(Class) && type <= CAStruct
|
|
363
|
+
raise CAStruct::DefinitionError,
|
|
364
|
+
"order_by: #{key.inspect} is a nested record; order by its members instead"
|
|
365
|
+
end
|
|
366
|
+
if type.is_a?(CArray)
|
|
367
|
+
raise CAStruct::DefinitionError,
|
|
368
|
+
"order_by: #{key.inspect} is an array member, which has no order"
|
|
369
|
+
end
|
|
370
|
+
if [:cmplx64, :cmplx128].include?(type)
|
|
371
|
+
raise CAStruct::DefinitionError,
|
|
372
|
+
"order_by: #{key.inspect} is complex, which has no order"
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
keys.freeze
|
|
376
|
+
end
|
|
377
|
+
private :order_keys
|
|
378
|
+
|
|
313
379
|
# Round up the byte cursor if the bitfield accumulator is mid-byte.
|
|
314
380
|
# Called before placing a non-bit member so the byte member starts
|
|
315
381
|
# on a clean byte boundary (and after the body is fully built so
|
|
@@ -364,6 +430,9 @@ class CAStruct::Builder # :nodoc:
|
|
|
364
430
|
klass = Class.new(CAUnion)
|
|
365
431
|
end
|
|
366
432
|
# ---
|
|
433
|
+
# A member placed by an explicit offset can end before an earlier one
|
|
434
|
+
# does, so the body runs to the furthest member, not the last one.
|
|
435
|
+
@offset = @extent if @extent > @offset
|
|
367
436
|
if @align.nil?
|
|
368
437
|
@offset = alignment(@offset, :align_max)
|
|
369
438
|
end
|
|
@@ -404,8 +473,9 @@ class CAStruct::Builder # :nodoc:
|
|
|
404
473
|
end
|
|
405
474
|
table.freeze
|
|
406
475
|
names.freeze
|
|
407
|
-
klass.const_set(:MEMBER_TABLE, table) ### required element as data class
|
|
408
|
-
klass.const_set(:MEMBERS, names)
|
|
476
|
+
klass.const_set(:MEMBER_TABLE, self.class.shareable(table)) ### required element as data class
|
|
477
|
+
klass.const_set(:MEMBERS, self.class.shareable(names))
|
|
478
|
+
klass.const_set(:ORDER_BY, self.class.shareable(order_keys(table))) if @order_by
|
|
409
479
|
# ---
|
|
410
480
|
# Step 3 dispatch table: precompute a per-member [reader, writer]
|
|
411
481
|
# Proc pair so `record[name]` is one Hash lookup + one Proc call,
|
|
@@ -413,7 +483,7 @@ class CAStruct::Builder # :nodoc:
|
|
|
413
483
|
# checks and view-shape decisions happen here, once, at class
|
|
414
484
|
# definition time.
|
|
415
485
|
klass.const_set(:DISPATCH_TABLE,
|
|
416
|
-
self.class.build_dispatch_table(table, @offset)
|
|
486
|
+
self.class.shareable(self.class.build_dispatch_table(table, @offset)))
|
|
417
487
|
# Also precompute FAST_PRIMITIVES, the subset of members that the
|
|
418
488
|
# C-side `[]` / `[]=` can handle without
|
|
419
489
|
# allocating a CAField view. Entries are `[offset, type_code]`;
|
|
@@ -424,14 +494,24 @@ class CAStruct::Builder # :nodoc:
|
|
|
424
494
|
klass.const_set(:FAST_PRIMITIVES,
|
|
425
495
|
self.class.build_fast_primitives(table, @offset).freeze)
|
|
426
496
|
# ---
|
|
497
|
+
# An accessor for each member, unless the name is already a method of
|
|
498
|
+
# the element (hash, size, class, initialize, ...): the accessor would
|
|
499
|
+
# replace it. Such a member is read as s["name"] only, as a record
|
|
500
|
+
# array's members always are.
|
|
427
501
|
klass.module_eval {
|
|
502
|
+
taken = ->(m) { method_defined?(m) || private_method_defined?(m) }
|
|
428
503
|
names.each do |name|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
504
|
+
Ractor.make_shareable(name) # the accessors below capture it
|
|
505
|
+
unless taken.(name)
|
|
506
|
+
define_method(name, &Ractor.make_shareable(proc {
|
|
507
|
+
return self[name]
|
|
508
|
+
}))
|
|
509
|
+
end
|
|
510
|
+
unless taken.("#{name}=")
|
|
511
|
+
define_method("#{name}=", &Ractor.make_shareable(proc { |val|
|
|
512
|
+
return self[name] = val
|
|
513
|
+
}))
|
|
514
|
+
end
|
|
435
515
|
end
|
|
436
516
|
}
|
|
437
517
|
# ---
|
|
@@ -471,6 +551,9 @@ class CAStruct::Builder # :nodoc:
|
|
|
471
551
|
end
|
|
472
552
|
|
|
473
553
|
def pack (addr, align, opt={})
|
|
554
|
+
if addr < 0
|
|
555
|
+
raise CAStruct::DefinitionError, format("negative member offset: %d", addr)
|
|
556
|
+
end
|
|
474
557
|
if ( addr % align ) != 0
|
|
475
558
|
raise CAStruct::DefinitionError,
|
|
476
559
|
format("invalid offset for packing: %d not aligned to %d", addr, align)
|
|
@@ -491,6 +574,7 @@ class CAStruct::Builder # :nodoc:
|
|
|
491
574
|
# @param opt [Hash] member options (`:offset`, `:bytes`, `:endian`, ...).
|
|
492
575
|
# @return [Member]
|
|
493
576
|
def member (data_type, id = nil, opt = {})
|
|
577
|
+
CAStruct::Builder.check_keys!(opt, MEMBER_KEYS, "member")
|
|
494
578
|
opt = opt.clone
|
|
495
579
|
# If a bit member sequence was in flight, round up to a clean byte
|
|
496
580
|
# boundary before placing this byte-typed member.
|
|
@@ -504,6 +588,10 @@ class CAStruct::Builder # :nodoc:
|
|
|
504
588
|
when :struct ### struct
|
|
505
589
|
case @align
|
|
506
590
|
when nil ### -- aligned
|
|
591
|
+
if opt[:offset]
|
|
592
|
+
raise CAStruct::DefinitionError,
|
|
593
|
+
"offset: places a member only in a packed struct (pass pack:)"
|
|
594
|
+
end
|
|
507
595
|
@offset = alignment(@offset, data_type, opt)
|
|
508
596
|
opt[:offset] = @offset
|
|
509
597
|
else ### -- packed
|
|
@@ -516,7 +604,12 @@ class CAStruct::Builder # :nodoc:
|
|
|
516
604
|
mem = Member.new(id, data_type, opt)
|
|
517
605
|
@members.push(mem)
|
|
518
606
|
@offset += mem.byte_length
|
|
607
|
+
@extent = @offset if @offset > @extent
|
|
519
608
|
when :union ### union
|
|
609
|
+
if opt[:offset] && opt[:offset] != 0
|
|
610
|
+
raise CAStruct::DefinitionError,
|
|
611
|
+
"a union member is always at offset 0 (got offset: #{opt[:offset]})"
|
|
612
|
+
end
|
|
520
613
|
alignment(0, data_type, opt)
|
|
521
614
|
opt[:offset] = 0
|
|
522
615
|
mem = Member.new(id, data_type, opt)
|
|
@@ -537,17 +630,19 @@ class CAStruct::Builder # :nodoc:
|
|
|
537
630
|
# `type:` is provided.
|
|
538
631
|
def struct (*args, &block)
|
|
539
632
|
opt = args.last.is_a?(Hash) ? args.pop : {}
|
|
633
|
+
CAStruct::Builder.check_keys!(opt, NESTED_KEYS, "struct")
|
|
540
634
|
if block
|
|
541
|
-
|
|
542
|
-
st = self.class.new(:struct,
|
|
635
|
+
inner = {:pack => @align}.update(opt.slice(*BUILDER_KEYS))
|
|
636
|
+
st = self.class.new(:struct, inner).define(&block)
|
|
543
637
|
elsif opt[:type] and opt[:type] <= CAStruct
|
|
544
638
|
st = opt[:type]
|
|
545
639
|
else
|
|
546
640
|
raise CAStruct::DefinitionError,
|
|
547
641
|
"no type given for nested struct member (pass a block or :type)"
|
|
548
642
|
end
|
|
643
|
+
place = opt.key?(:offset) ? {:offset => opt[:offset]} : {}
|
|
549
644
|
args.each do |arg|
|
|
550
|
-
member(st, arg)
|
|
645
|
+
member(st, arg, place)
|
|
551
646
|
end
|
|
552
647
|
return st
|
|
553
648
|
end
|
|
@@ -562,17 +657,19 @@ class CAStruct::Builder # :nodoc:
|
|
|
562
657
|
# `type:` is provided.
|
|
563
658
|
def union (*args, &block)
|
|
564
659
|
opt = args.last.is_a?(Hash) ? args.pop : {}
|
|
660
|
+
CAStruct::Builder.check_keys!(opt, NESTED_KEYS, "union")
|
|
565
661
|
if block
|
|
566
|
-
|
|
567
|
-
st = self.class.new(:union,
|
|
662
|
+
inner = {:pack => @align}.update(opt.slice(*BUILDER_KEYS))
|
|
663
|
+
st = self.class.new(:union, inner).define(&block)
|
|
568
664
|
elsif opt[:type] and opt[:type] <= CAStruct
|
|
569
665
|
st = opt[:type]
|
|
570
666
|
else
|
|
571
667
|
raise CAStruct::DefinitionError,
|
|
572
668
|
"no type given for nested union member (pass a block or :type)"
|
|
573
669
|
end
|
|
670
|
+
place = opt.key?(:offset) ? {:offset => opt[:offset]} : {}
|
|
574
671
|
args.each do |arg|
|
|
575
|
-
member(st, arg)
|
|
672
|
+
member(st, arg, place)
|
|
576
673
|
end
|
|
577
674
|
return st
|
|
578
675
|
end
|
|
@@ -585,12 +682,14 @@ class CAStruct::Builder # :nodoc:
|
|
|
585
682
|
# CArray template.
|
|
586
683
|
def array (*args)
|
|
587
684
|
opt = args.last.is_a?(Hash) ? args.pop : {}
|
|
685
|
+
CAStruct::Builder.check_keys!(opt, [:type, :offset], "array")
|
|
588
686
|
if not opt[:type] or not opt[:type].kind_of?(CArray)
|
|
589
687
|
raise CAStruct::DefinitionError,
|
|
590
688
|
"no :type given for array member (expected a CArray template)"
|
|
591
689
|
end
|
|
690
|
+
place = opt.key?(:offset) ? {:offset => opt[:offset]} : {}
|
|
592
691
|
args.each do |arg|
|
|
593
|
-
member(opt[:type], arg)
|
|
692
|
+
member(opt[:type], arg, place)
|
|
594
693
|
end
|
|
595
694
|
end
|
|
596
695
|
|
|
@@ -618,6 +717,13 @@ class CAStruct::Builder # :nodoc:
|
|
|
618
717
|
"bit member requires bits: as an Integer in 1..64 (got #{bits.inspect})"
|
|
619
718
|
end
|
|
620
719
|
total_bit_offset = @offset * 8 + @bit_offset
|
|
720
|
+
# A bit member is read from one word of up to 8 bytes starting at the
|
|
721
|
+
# byte it begins in, so it may not reach past the 64th bit of that word.
|
|
722
|
+
if (total_bit_offset % 8) + bits > 64
|
|
723
|
+
raise CAStruct::DefinitionError,
|
|
724
|
+
"bit member #{name.to_s.inspect} (bits: #{bits}) starts at bit " \
|
|
725
|
+
"#{total_bit_offset % 8} of a byte and would span more than 8 bytes"
|
|
726
|
+
end
|
|
621
727
|
mem = Member.new(name.to_s, :bitfield,
|
|
622
728
|
{:bits => bits,
|
|
623
729
|
:bit_offset => total_bit_offset,
|
|
@@ -676,6 +782,7 @@ class CAStruct::Builder # :nodoc:
|
|
|
676
782
|
"#{typename} requires at least one member name " \
|
|
677
783
|
"(use nil for anonymous padding)"
|
|
678
784
|
end
|
|
785
|
+
CAStruct::Builder.check_keys!(opt, MEMBER_KEYS, "#{typename}")
|
|
679
786
|
CAStruct::Builder.validate_endian!(opt, "#{typename}", #{allow_endian})
|
|
680
787
|
args.each do |arg|
|
|
681
788
|
member(:#{typename}, arg, opt)
|