red-arrow-format 23.0.1 → 24.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -2
  3. data/Rakefile +23 -1
  4. data/lib/arrow-format/array.rb +486 -117
  5. data/lib/arrow-format/bitmap.rb +25 -6
  6. data/lib/arrow-format/buffer-alignable.rb +35 -0
  7. data/lib/arrow-format/dictionary.rb +29 -0
  8. data/lib/arrow-format/error.rb +1 -1
  9. data/lib/arrow-format/field.rb +24 -3
  10. data/lib/arrow-format/file-reader.rb +47 -25
  11. data/lib/arrow-format/file-writer.rb +56 -0
  12. data/lib/arrow-format/flatbuffers.rb +67 -0
  13. data/lib/arrow-format/org/apache/arrow/flatbuf/binary.rb +5 -1
  14. data/lib/arrow-format/org/apache/arrow/flatbuf/binary_view.rb +5 -1
  15. data/lib/arrow-format/org/apache/arrow/flatbuf/block.rb +10 -2
  16. data/lib/arrow-format/org/apache/arrow/flatbuf/body_compression.rb +8 -1
  17. data/lib/arrow-format/org/apache/arrow/flatbuf/body_compression_method.rb +3 -1
  18. data/lib/arrow-format/org/apache/arrow/flatbuf/bool.rb +5 -1
  19. data/lib/arrow-format/org/apache/arrow/flatbuf/buffer.rb +8 -1
  20. data/lib/arrow-format/org/apache/arrow/flatbuf/compression_type.rb +1 -1
  21. data/lib/arrow-format/org/apache/arrow/flatbuf/date.rb +7 -1
  22. data/lib/arrow-format/org/apache/arrow/flatbuf/date_unit.rb +1 -1
  23. data/lib/arrow-format/org/apache/arrow/flatbuf/decimal.rb +9 -1
  24. data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_batch.rb +9 -1
  25. data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_encoding.rb +11 -2
  26. data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_kind.rb +1 -1
  27. data/lib/arrow-format/org/apache/arrow/flatbuf/duration.rb +7 -1
  28. data/lib/arrow-format/org/apache/arrow/flatbuf/endianness.rb +1 -1
  29. data/lib/arrow-format/org/apache/arrow/flatbuf/feature.rb +1 -1
  30. data/lib/arrow-format/org/apache/arrow/flatbuf/field.rb +13 -1
  31. data/lib/arrow-format/org/apache/arrow/flatbuf/field_node.rb +8 -1
  32. data/lib/arrow-format/org/apache/arrow/flatbuf/fixed_size_binary.rb +7 -1
  33. data/lib/arrow-format/org/apache/arrow/flatbuf/fixed_size_list.rb +7 -1
  34. data/lib/arrow-format/org/apache/arrow/flatbuf/floating_point.rb +7 -1
  35. data/lib/arrow-format/org/apache/arrow/flatbuf/footer.rb +22 -2
  36. data/lib/arrow-format/org/apache/arrow/flatbuf/int.rb +8 -1
  37. data/lib/arrow-format/org/apache/arrow/flatbuf/interval.rb +7 -1
  38. data/lib/arrow-format/org/apache/arrow/flatbuf/interval_unit.rb +1 -1
  39. data/lib/arrow-format/org/apache/arrow/flatbuf/key_value.rb +8 -1
  40. data/lib/arrow-format/org/apache/arrow/flatbuf/large_binary.rb +5 -1
  41. data/lib/arrow-format/org/apache/arrow/flatbuf/large_list.rb +5 -1
  42. data/lib/arrow-format/org/apache/arrow/flatbuf/large_list_view.rb +5 -1
  43. data/lib/arrow-format/org/apache/arrow/flatbuf/large_utf8.rb +5 -1
  44. data/lib/arrow-format/org/apache/arrow/flatbuf/list.rb +5 -1
  45. data/lib/arrow-format/org/apache/arrow/flatbuf/list_view.rb +5 -1
  46. data/lib/arrow-format/org/apache/arrow/flatbuf/map.rb +8 -2
  47. data/lib/arrow-format/org/apache/arrow/flatbuf/message.rb +22 -2
  48. data/lib/arrow-format/org/apache/arrow/flatbuf/message_header.rb +1 -1
  49. data/lib/arrow-format/org/apache/arrow/flatbuf/metadata_version.rb +1 -1
  50. data/lib/arrow-format/org/apache/arrow/flatbuf/null.rb +5 -1
  51. data/lib/arrow-format/org/apache/arrow/flatbuf/precision.rb +1 -1
  52. data/lib/arrow-format/org/apache/arrow/flatbuf/record_batch.rb +12 -2
  53. data/lib/arrow-format/org/apache/arrow/flatbuf/run_end_encoded.rb +5 -1
  54. data/lib/arrow-format/org/apache/arrow/flatbuf/schema.rb +10 -1
  55. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_matrix_compressed_axis.rb +1 -1
  56. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_matrix_index_csx.rb +12 -2
  57. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor.rb +13 -1
  58. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index.rb +1 -1
  59. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index_coo.rb +13 -4
  60. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index_csf.rb +14 -4
  61. data/lib/arrow-format/org/apache/arrow/flatbuf/struct_.rb +5 -1
  62. data/lib/arrow-format/org/apache/arrow/flatbuf/tensor.rb +11 -1
  63. data/lib/arrow-format/org/apache/arrow/flatbuf/tensor_dim.rb +8 -1
  64. data/lib/arrow-format/org/apache/arrow/flatbuf/time.rb +8 -1
  65. data/lib/arrow-format/org/apache/arrow/flatbuf/time_unit.rb +1 -1
  66. data/lib/arrow-format/org/apache/arrow/flatbuf/timestamp.rb +8 -1
  67. data/lib/arrow-format/org/apache/arrow/flatbuf/type.rb +1 -1
  68. data/lib/arrow-format/org/apache/arrow/flatbuf/union.rb +8 -1
  69. data/lib/arrow-format/org/apache/arrow/flatbuf/union_mode.rb +1 -1
  70. data/lib/arrow-format/org/apache/arrow/flatbuf/utf8.rb +5 -1
  71. data/lib/arrow-format/org/apache/arrow/flatbuf/utf8view.rb +5 -1
  72. data/lib/arrow-format/readable.rb +151 -96
  73. data/lib/arrow-format/record-batch.rb +70 -1
  74. data/lib/arrow-format/schema.rb +14 -1
  75. data/lib/arrow-format/streaming-pull-reader.rb +49 -23
  76. data/lib/arrow-format/streaming-reader.rb +51 -14
  77. data/lib/arrow-format/streaming-writer.rb +156 -0
  78. data/lib/arrow-format/type.rb +397 -34
  79. data/lib/arrow-format/version.rb +1 -1
  80. data/lib/arrow-format.rb +2 -0
  81. data/red-arrow-format.gemspec +2 -1
  82. metadata +9 -4
@@ -23,35 +23,133 @@ module ArrowFormat
23
23
  attr_reader :type
24
24
  attr_reader :size
25
25
  alias_method :length, :size
26
+ attr_reader :offset
27
+ attr_reader :validity_buffer
26
28
  def initialize(type, size, validity_buffer)
27
29
  @type = type
28
30
  @size = size
31
+ @offset = 0
29
32
  @validity_buffer = validity_buffer
33
+ @sliced_buffers = {}
34
+ end
35
+
36
+ def slice(offset, size=nil)
37
+ sliced = dup
38
+ sliced.slice!(@offset + offset, size || @size - offset)
39
+ sliced
30
40
  end
31
41
 
32
42
  def valid?(i)
33
43
  return true if @validity_buffer.nil?
34
- (@validity_buffer.get_value(:U8, i / 8) & (1 << (i % 8))) > 0
44
+ validity_bitmap[i]
35
45
  end
36
46
 
37
47
  def null?(i)
38
48
  not valid?(i)
39
49
  end
40
50
 
51
+ def n_nulls
52
+ if @validity_buffer.nil?
53
+ 0
54
+ else
55
+ @size - validity_bitmap.popcount
56
+ end
57
+ end
58
+
59
+ def empty?
60
+ @size.zero?
61
+ end
62
+
63
+ protected
64
+ def slice!(offset, size)
65
+ @offset = offset
66
+ @size = size
67
+ clear_cache
68
+ end
69
+
41
70
  private
71
+ def validity_bitmap
72
+ @validity_bitmap ||= Bitmap.new(@validity_buffer, @offset, @size)
73
+ end
74
+
42
75
  def apply_validity(array)
43
76
  return array if @validity_buffer.nil?
44
- @validity_bitmap ||= Bitmap.new(@validity_buffer, @size)
45
- @validity_bitmap.each_with_index do |bit, i|
46
- array[i] = nil if bit.zero?
77
+ validity_bitmap.each_with_index do |is_valid, i|
78
+ array[i] = nil unless is_valid
47
79
  end
48
80
  array
49
81
  end
82
+
83
+ def clear_cache
84
+ @validity_bitmap = nil
85
+ @sliced_buffers = {}
86
+ end
87
+
88
+ def slice_buffer(id, buffer)
89
+ return buffer if buffer.nil?
90
+ return buffer if @offset.zero?
91
+
92
+ @sliced_buffers[id] ||= yield(buffer)
93
+ end
94
+
95
+ def slice_bitmap_buffer(id, buffer)
96
+ slice_buffer(id, buffer) do
97
+ if (@offset % 8).zero?
98
+ buffer.slice(@offset / 8)
99
+ else
100
+ # We need to copy because we can't do bit level slice.
101
+ # TODO: Optimize.
102
+ valid_bytes = []
103
+ Bitmap.new(buffer, @offset, @size).each_slice(8) do |valids|
104
+ valid_byte = 0
105
+ valids.each_with_index do |valid, i|
106
+ valid_byte |= 1 << (i % 8) if valid
107
+ end
108
+ valid_bytes << valid_byte
109
+ end
110
+ IO::Buffer.for(valid_bytes.pack("C*"))
111
+ end
112
+ end
113
+ end
114
+
115
+ def slice_fixed_element_size_buffer(id, buffer, element_size)
116
+ slice_buffer(id, buffer) do
117
+ buffer.slice(element_size * @offset)
118
+ end
119
+ end
120
+
121
+ def slice_offsets_buffer(id, buffer, buffer_type)
122
+ slice_buffer(id, buffer) do
123
+ offset_size = IO::Buffer.size_of(buffer_type)
124
+ buffer_offset = offset_size * @offset
125
+ first_offset = nil
126
+ # TODO: Optimize
127
+ sliced_buffer = IO::Buffer.new(offset_size * (@size + 1))
128
+ buffer.each(buffer_type,
129
+ buffer_offset,
130
+ @size + 1).with_index do |(_, offset), i|
131
+ first_offset ||= offset
132
+ new_offset = offset - first_offset
133
+ sliced_buffer.set_value(buffer_type,
134
+ offset_size * i,
135
+ new_offset)
136
+ end
137
+ sliced_buffer
138
+ end
139
+ end
50
140
  end
51
141
 
52
142
  class NullArray < Array
53
- def initialize(type, size)
54
- super(type, size, nil)
143
+ def initialize(size)
144
+ super(NullType.singleton, size, nil)
145
+ end
146
+
147
+ def each_buffer
148
+ return to_enum(__method__) unless block_given?
149
+ end
150
+
151
+ def n_nulls
152
+ @size
55
153
  end
56
154
 
57
155
  def to_a
@@ -59,94 +157,175 @@ module ArrowFormat
59
157
  end
60
158
  end
61
159
 
62
- class BooleanArray < Array
160
+ class PrimitiveArray < Array
63
161
  def initialize(type, size, validity_buffer, values_buffer)
64
162
  super(type, size, validity_buffer)
65
163
  @values_buffer = values_buffer
66
164
  end
67
165
 
68
166
  def to_a
69
- @values_bitmap ||= Bitmap.new(@values_buffer, @size)
70
- values = @values_bitmap.each.collect do |bit|
71
- not bit.zero?
72
- end
73
- apply_validity(values)
167
+ return [] if empty?
168
+
169
+ offset = element_size * @offset
170
+ apply_validity(@values_buffer.values(@type.buffer_type, offset, @size))
171
+ end
172
+
173
+ def each_buffer
174
+ return to_enum(__method__) unless block_given?
175
+
176
+ yield(slice_bitmap_buffer(:validity, @validity_buffer))
177
+ yield(slice_fixed_element_size_buffer(:values,
178
+ @values_buffer,
179
+ element_size))
180
+ end
181
+
182
+ private
183
+ def element_size
184
+ IO::Buffer.size_of(@type.buffer_type)
74
185
  end
75
186
  end
76
187
 
77
- class IntArray < Array
78
- def initialize(type, size, validity_buffer, values_buffer)
79
- super(type, size, validity_buffer)
80
- @values_buffer = values_buffer
188
+ class BooleanArray < PrimitiveArray
189
+ def initialize(size, validity_buffer, values_buffer)
190
+ super(BooleanType.singleton, size, validity_buffer, values_buffer)
81
191
  end
82
192
 
83
193
  def to_a
84
- apply_validity(@values_buffer.values(@type.buffer_type, 0, @size))
194
+ return [] if empty?
195
+
196
+ @values_bitmap ||= Bitmap.new(@values_buffer, @offset, @size)
197
+ values = @values_bitmap.to_a
198
+ apply_validity(values)
199
+ end
200
+
201
+ def each_buffer
202
+ return to_enum(__method__) unless block_given?
203
+
204
+ yield(slice_bitmap_buffer(:validity, @validity_buffer))
205
+ yield(slice_bitmap_buffer(:values, @values_buffer))
206
+ end
207
+
208
+ private
209
+ def clear_cache
210
+ super
211
+ @values_bitmap = nil
212
+ end
213
+ end
214
+
215
+ class IntArray < PrimitiveArray
216
+ def initialize(size, validity_buffer, values_buffer)
217
+ super(self.class.type, size, validity_buffer, values_buffer)
85
218
  end
86
219
  end
87
220
 
88
221
  class Int8Array < IntArray
222
+ class << self
223
+ def type
224
+ Int8Type.singleton
225
+ end
226
+ end
89
227
  end
90
228
 
91
229
  class UInt8Array < IntArray
230
+ class << self
231
+ def type
232
+ UInt8Type.singleton
233
+ end
234
+ end
92
235
  end
93
236
 
94
237
  class Int16Array < IntArray
238
+ class << self
239
+ def type
240
+ Int16Type.singleton
241
+ end
242
+ end
95
243
  end
96
244
 
97
245
  class UInt16Array < IntArray
246
+ class << self
247
+ def type
248
+ UInt16Type.singleton
249
+ end
250
+ end
98
251
  end
99
252
 
100
253
  class Int32Array < IntArray
254
+ class << self
255
+ def type
256
+ Int32Type.singleton
257
+ end
258
+ end
101
259
  end
102
260
 
103
261
  class UInt32Array < IntArray
262
+ class << self
263
+ def type
264
+ UInt32Type.singleton
265
+ end
266
+ end
104
267
  end
105
268
 
106
269
  class Int64Array < IntArray
270
+ class << self
271
+ def type
272
+ Int64Type.singleton
273
+ end
274
+ end
107
275
  end
108
276
 
109
277
  class UInt64Array < IntArray
278
+ class << self
279
+ def type
280
+ UInt64Type.singleton
281
+ end
282
+ end
110
283
  end
111
284
 
112
- class FloatingPointArray < Array
113
- def initialize(type, size, validity_buffer, values_buffer)
114
- super(type, size, validity_buffer)
115
- @values_buffer = values_buffer
285
+ class FloatingPointArray < PrimitiveArray
286
+ def initialize(size, validity_buffer, values_buffer)
287
+ super(self.class.type, size, validity_buffer, values_buffer)
116
288
  end
117
289
  end
118
290
 
119
291
  class Float32Array < FloatingPointArray
120
- def to_a
121
- apply_validity(@values_buffer.values(:f32, 0, @size))
292
+ class << self
293
+ def type
294
+ Float32Type.singleton
295
+ end
122
296
  end
123
297
  end
124
298
 
125
299
  class Float64Array < FloatingPointArray
126
- def to_a
127
- apply_validity(@values_buffer.values(:f64, 0, @size))
300
+ class << self
301
+ def type
302
+ Float64Type.singleton
303
+ end
128
304
  end
129
305
  end
130
306
 
131
- class TemporalArray < Array
132
- def initialize(type, size, validity_buffer, values_buffer)
133
- super(type, size, validity_buffer)
134
- @values_buffer = values_buffer
135
- end
307
+ class TemporalArray < PrimitiveArray
136
308
  end
137
309
 
138
310
  class DateArray < TemporalArray
311
+ def initialize(size, validity_buffer, values_buffer)
312
+ super(self.class.type, size, validity_buffer, values_buffer)
313
+ end
139
314
  end
140
315
 
141
316
  class Date32Array < DateArray
142
- def to_a
143
- apply_validity(@values_buffer.values(:s32, 0, @size))
317
+ class << self
318
+ def type
319
+ Date32Type.singleton
320
+ end
144
321
  end
145
322
  end
146
323
 
147
324
  class Date64Array < DateArray
148
- def to_a
149
- apply_validity(@values_buffer.values(:s64, 0, @size))
325
+ class << self
326
+ def type
327
+ Date64Type.singleton
328
+ end
150
329
  end
151
330
  end
152
331
 
@@ -154,122 +333,141 @@ module ArrowFormat
154
333
  end
155
334
 
156
335
  class Time32Array < TimeArray
157
- def to_a
158
- apply_validity(@values_buffer.values(:s32, 0, @size))
159
- end
160
336
  end
161
337
 
162
338
  class Time64Array < TimeArray
163
- def to_a
164
- apply_validity(@values_buffer.values(:s64, 0, @size))
165
- end
166
339
  end
167
340
 
168
341
  class TimestampArray < TemporalArray
169
- def to_a
170
- apply_validity(@values_buffer.values(:s64, 0, @size))
171
- end
172
342
  end
173
343
 
174
344
  class IntervalArray < TemporalArray
175
345
  end
176
346
 
177
347
  class YearMonthIntervalArray < IntervalArray
178
- def to_a
179
- apply_validity(@values_buffer.values(:s32, 0, @size))
180
- end
181
348
  end
182
349
 
183
350
  class DayTimeIntervalArray < IntervalArray
184
351
  def to_a
352
+ return [] if empty?
353
+
354
+ offset = element_size * @offset
185
355
  values = @values_buffer.
186
- each(:s32, 0, @size * 2).
356
+ each(@type.buffer_type, offset, @size * 2).
187
357
  each_slice(2).
188
358
  collect do |(_, day), (_, time)|
189
359
  [day, time]
190
360
  end
191
361
  apply_validity(values)
192
362
  end
363
+
364
+ private
365
+ def element_size
366
+ super * 2
367
+ end
193
368
  end
194
369
 
195
370
  class MonthDayNanoIntervalArray < IntervalArray
196
371
  def to_a
197
- buffer_types = [:s32, :s32, :s64]
372
+ return [] if empty?
373
+
374
+ buffer_types = @type.buffer_types
198
375
  value_size = IO::Buffer.size_of(buffer_types)
376
+ base_offset = value_size * @offset
199
377
  values = @size.times.collect do |i|
200
- offset = value_size * i
378
+ offset = base_offset + value_size * i
201
379
  @values_buffer.get_values(buffer_types, offset)
202
380
  end
203
381
  apply_validity(values)
204
382
  end
383
+
384
+ private
385
+ def element_size
386
+ IO::Buffer.size_of(@type.buffer_types)
387
+ end
205
388
  end
206
389
 
207
390
  class DurationArray < TemporalArray
208
- def to_a
209
- apply_validity(@values_buffer.values(:s64, 0, @size))
210
- end
211
391
  end
212
392
 
213
- class VariableSizeBinaryLayoutArray < Array
214
- def initialize(type, size, validity_buffer, offsets_buffer, values_buffer)
215
- super(type, size, validity_buffer)
393
+ class VariableSizeBinaryArray < Array
394
+ def initialize(size, validity_buffer, offsets_buffer, values_buffer)
395
+ super(self.class.type, size, validity_buffer)
216
396
  @offsets_buffer = offsets_buffer
217
397
  @values_buffer = values_buffer
218
398
  end
219
399
 
220
- def to_a
221
- values = @offsets_buffer.
222
- each(buffer_type, 0, @size + 1).
223
- each_cons(2).
224
- collect do |(_, offset), (_, next_offset)|
225
- length = next_offset - offset
226
- @values_buffer.get_string(offset, length, encoding)
400
+ def each_buffer
401
+ return to_enum(__method__) unless block_given?
402
+
403
+ yield(slice_bitmap_buffer(:validity, @validity_buffer))
404
+ yield(slice_offsets_buffer(:offsets,
405
+ @offsets_buffer,
406
+ @type.offset_buffer_type))
407
+ sliced_values_buffer = slice_buffer(:values, @values_buffer) do
408
+ first_offset = @offsets_buffer.get_value(@type.offset_buffer_type,
409
+ offset_size * @offset)
410
+ @values_buffer.slice(first_offset)
227
411
  end
228
- apply_validity(values)
412
+ yield(sliced_values_buffer)
229
413
  end
230
- end
231
414
 
232
- class BinaryArray < VariableSizeBinaryLayoutArray
233
- private
234
- def buffer_type
235
- :s32 # TODO: big endian support
415
+ def offsets
416
+ return [0] if empty?
417
+
418
+ @offsets_buffer.
419
+ each(@type.offset_buffer_type, offset_size * @offset, @size + 1).
420
+ collect {|_, offset| offset}
236
421
  end
237
422
 
238
- def encoding
239
- Encoding::ASCII_8BIT
423
+ def to_a
424
+ return [] if empty?
425
+
426
+ values = offsets.each_cons(2).collect do |offset, next_offset|
427
+ length = next_offset - offset
428
+ @values_buffer.get_string(offset, length, @type.encoding)
429
+ end
430
+ apply_validity(values)
240
431
  end
241
- end
242
432
 
243
- class LargeBinaryArray < VariableSizeBinaryLayoutArray
244
433
  private
245
- def buffer_type
246
- :s64 # TODO: big endian support
434
+ def offset_size
435
+ IO::Buffer.size_of(@type.offset_buffer_type)
247
436
  end
437
+ end
248
438
 
249
- def encoding
250
- Encoding::ASCII_8BIT
439
+ class BinaryArray < VariableSizeBinaryArray
440
+ class << self
441
+ def type
442
+ BinaryType.singleton
443
+ end
251
444
  end
252
445
  end
253
446
 
254
- class UTF8Array < VariableSizeBinaryLayoutArray
255
- private
256
- def buffer_type
257
- :s32 # TODO: big endian support
447
+ class LargeBinaryArray < VariableSizeBinaryArray
448
+ class << self
449
+ def type
450
+ LargeBinaryType.singleton
451
+ end
258
452
  end
453
+ end
259
454
 
260
- def encoding
261
- Encoding::UTF_8
262
- end
455
+ class VariableSizeUTF8Array < VariableSizeBinaryArray
263
456
  end
264
457
 
265
- class LargeUTF8Array < VariableSizeBinaryLayoutArray
266
- private
267
- def buffer_type
268
- :s64 # TODO: big endian support
458
+ class UTF8Array < VariableSizeUTF8Array
459
+ class << self
460
+ def type
461
+ UTF8Type.singleton
462
+ end
269
463
  end
464
+ end
270
465
 
271
- def encoding
272
- Encoding::UTF_8
466
+ class LargeUTF8Array < VariableSizeUTF8Array
467
+ class << self
468
+ def type
469
+ LargeUTF8Type.singleton
470
+ end
273
471
  end
274
472
  end
275
473
 
@@ -279,7 +477,18 @@ module ArrowFormat
279
477
  @values_buffer = values_buffer
280
478
  end
281
479
 
480
+ def each_buffer
481
+ return to_enum(__method__) unless block_given?
482
+
483
+ yield(slice_bitmap_buffer(:validity, @validity_buffer))
484
+ yield(slice_fixed_element_size_buffer(:values,
485
+ @values_buffer,
486
+ @type.byte_width))
487
+ end
488
+
282
489
  def to_a
490
+ return [] if empty?
491
+
283
492
  byte_width = @type.byte_width
284
493
  values = 0.step(@size * byte_width - 1, byte_width).collect do |offset|
285
494
  @values_buffer.get_string(offset, byte_width)
@@ -290,10 +499,13 @@ module ArrowFormat
290
499
 
291
500
  class DecimalArray < FixedSizeBinaryArray
292
501
  def to_a
502
+ return [] if empty?
503
+
293
504
  byte_width = @type.byte_width
294
505
  buffer_types = [:u64] * (byte_width / 8 - 1) + [:s64]
506
+ base_offset = byte_width * @offset
295
507
  values = 0.step(@size * byte_width - 1, byte_width).collect do |offset|
296
- @values_buffer.get_values(buffer_types, offset)
508
+ @values_buffer.get_values(buffer_types, base_offset + offset)
297
509
  end
298
510
  apply_validity(values).collect do |value|
299
511
  if value.nil?
@@ -319,8 +531,8 @@ module ArrowFormat
319
531
  elsif @type.scale > 0
320
532
  n_digits = string.bytesize
321
533
  n_digits -= 1 if value < 0
322
- if n_digits < @type.scale
323
- prefix = "0." + ("0" * (@type.scale - n_digits - 1))
534
+ if n_digits <= @type.scale
535
+ prefix = "0." + ("0" * (@type.scale - n_digits))
324
536
  if value < 0
325
537
  string[1, 0] = prefix
326
538
  else
@@ -341,45 +553,107 @@ module ArrowFormat
341
553
  end
342
554
 
343
555
  class VariableSizeListArray < Array
556
+ attr_reader :child
344
557
  def initialize(type, size, validity_buffer, offsets_buffer, child)
345
558
  super(type, size, validity_buffer)
346
559
  @offsets_buffer = offsets_buffer
347
560
  @child = child
348
561
  end
349
562
 
563
+ def each_buffer(&block)
564
+ return to_enum(__method__) unless block_given?
565
+
566
+ yield(slice_bitmap_buffer(:validity, @validity_buffer))
567
+ yield(slice_offsets_buffer(:offsets,
568
+ @offsets_buffer,
569
+ @type.offset_buffer_type))
570
+ end
571
+
572
+ def offsets
573
+ return [0] if empty?
574
+
575
+ @offsets_buffer.
576
+ each(@type.offset_buffer_type, offset_size * @offset, @size + 1).
577
+ collect {|_, offset| offset}
578
+ end
579
+
350
580
  def to_a
581
+ return [] if empty?
582
+
351
583
  child_values = @child.to_a
352
- values = @offsets_buffer.
353
- each(offset_type, 0, @size + 1).
354
- each_cons(2).
355
- collect do |(_, offset), (_, next_offset)|
584
+ values = offsets.each_cons(2).collect do |offset, next_offset|
356
585
  child_values[offset...next_offset]
357
586
  end
358
587
  apply_validity(values)
359
588
  end
360
- end
361
589
 
362
- class ListArray < VariableSizeListArray
363
590
  private
364
- def offset_type
365
- :s32 # TODO: big endian support
591
+ def offset_size
592
+ IO::Buffer.size_of(@type.offset_buffer_type)
593
+ end
594
+
595
+ def slice!(offset, size)
596
+ super
597
+ first_offset =
598
+ @offsets_buffer.get_value(@type.offset_buffer_type,
599
+ offset_size * @offset)
600
+ last_offset =
601
+ @offsets_buffer.get_value(@type.offset_buffer_type,
602
+ offset_size * (@offset + @size + 1))
603
+ @child = @child.slice(first_offset, last_offset - first_offset)
366
604
  end
367
605
  end
368
606
 
607
+ class ListArray < VariableSizeListArray
608
+ end
609
+
369
610
  class LargeListArray < VariableSizeListArray
611
+ end
612
+
613
+ class FixedSizeListArray < Array
614
+ attr_reader :child
615
+ def initialize(type, size, validity_buffer, child)
616
+ super(type, size, validity_buffer)
617
+ @child = child
618
+ end
619
+
620
+ def each_buffer(&block)
621
+ return to_enum(__method__) unless block_given?
622
+
623
+ yield(slice_bitmap_buffer(:validity, @validity_buffer))
624
+ end
625
+
626
+ def to_a
627
+ return [] if empty?
628
+
629
+ values = @child.to_a.each_slice(@type.size).to_a
630
+ apply_validity(values)
631
+ end
632
+
370
633
  private
371
- def offset_type
372
- :s64 # TODO: big endian support
634
+ def slice!(offset, size)
635
+ super
636
+ @child = @child.slice(@type.size * @offset,
637
+ @type.size * (@offset + @size + 1))
373
638
  end
374
639
  end
375
640
 
376
641
  class StructArray < Array
642
+ attr_reader :children
377
643
  def initialize(type, size, validity_buffer, children)
378
644
  super(type, size, validity_buffer)
379
645
  @children = children
380
646
  end
381
647
 
648
+ def each_buffer(&block)
649
+ return to_enum(__method__) unless block_given?
650
+
651
+ yield(slice_bitmap_buffer(:validity, @validity_buffer))
652
+ end
653
+
382
654
  def to_a
655
+ return [] if empty?
656
+
383
657
  if @children.empty?
384
658
  values = [[]] * @size
385
659
  else
@@ -388,10 +662,20 @@ module ArrowFormat
388
662
  end
389
663
  apply_validity(values)
390
664
  end
665
+
666
+ private
667
+ def slice!(offset, size)
668
+ super
669
+ @children = @children.collect do |child|
670
+ child.slice(offset, size)
671
+ end
672
+ end
391
673
  end
392
674
 
393
675
  class MapArray < VariableSizeListArray
394
676
  def to_a
677
+ return [] if empty?
678
+
395
679
  super.collect do |entries|
396
680
  if entries.nil?
397
681
  entries
@@ -404,19 +688,37 @@ module ArrowFormat
404
688
  end
405
689
  end
406
690
  end
407
-
408
- private
409
- def offset_type
410
- :s32 # TODO: big endian support
411
- end
412
691
  end
413
692
 
414
693
  class UnionArray < Array
694
+ attr_reader :types_buffer
695
+ attr_reader :children
415
696
  def initialize(type, size, types_buffer, children)
416
697
  super(type, size, nil)
417
698
  @types_buffer = types_buffer
418
699
  @children = children
419
700
  end
701
+
702
+ def each_type(&block)
703
+ return [].each(&block) if empty?
704
+
705
+ return to_enum(__method__) unless block_given?
706
+
707
+ @types_buffer.each(type_buffer_type,
708
+ type_element_size * @offset,
709
+ @size) do |_, type|
710
+ yield(type)
711
+ end
712
+ end
713
+
714
+ private
715
+ def type_buffer_type
716
+ :S8
717
+ end
718
+
719
+ def type_element_size
720
+ IO::Buffer.size_of(type_buffer_type)
721
+ end
420
722
  end
421
723
 
422
724
  class DenseUnionArray < UnionArray
@@ -429,41 +731,108 @@ module ArrowFormat
429
731
  @offsets_buffer = offsets_buffer
430
732
  end
431
733
 
734
+ def each_buffer(&block)
735
+ return to_enum(__method__) unless block_given?
736
+
737
+ # TODO: Dictionary delta support (slice support)
738
+ yield(@types_buffer)
739
+ yield(@offsets_buffer)
740
+ end
741
+
742
+ def each_offset(&block)
743
+ return [].each(&block) if empty?
744
+
745
+ return to_enum(__method__) unless block_given?
746
+
747
+ @offsets_buffer.each(@type.offset_buffer_type,
748
+ offset_element_size * @offset,
749
+ @size) do |_, offset|
750
+ yield(offset)
751
+ end
752
+ end
753
+
432
754
  def to_a
755
+ return [] if empty?
756
+
433
757
  children_values = @children.collect(&:to_a)
434
- types = @types_buffer.each(:S8, 0, @size)
435
- offsets = @offsets_buffer.each(:s32, 0, @size)
436
- types.zip(offsets).collect do |(_, type), (_, offset)|
758
+ each_type.zip(each_offset).collect do |type, offset|
437
759
  index = @type.resolve_type_index(type)
438
760
  children_values[index][offset]
439
761
  end
440
762
  end
763
+
764
+ private
765
+ def offset_buffer_type
766
+ :s32
767
+ end
768
+
769
+ def offset_element_size
770
+ IO::Buffer.size_of(offset_buffer_type)
771
+ end
441
772
  end
442
773
 
443
774
  class SparseUnionArray < UnionArray
775
+ def each_buffer(&block)
776
+ return to_enum(__method__) unless block_given?
777
+
778
+ yield(slice_fixed_element_size_buffer(:types,
779
+ @types_buffer,
780
+ type_element_size))
781
+ end
782
+
444
783
  def to_a
784
+ return [] if empty?
785
+
445
786
  children_values = @children.collect(&:to_a)
446
- @types_buffer.each(:S8, 0, @size).with_index.collect do |(_, type), i|
787
+ each_type.with_index.collect do |type, i|
447
788
  index = @type.resolve_type_index(type)
448
789
  children_values[index][i]
449
790
  end
450
791
  end
792
+
793
+ private
794
+ def slice!(offset, size)
795
+ super
796
+ @children = @children.collect do |child|
797
+ child.slice(offset, size)
798
+ end
799
+ end
451
800
  end
452
801
 
453
802
  class DictionaryArray < Array
454
- def initialize(type, size, validity_buffer, indices_buffer, dictionary)
803
+ attr_reader :indices_buffer
804
+ attr_reader :dictionaries
805
+ def initialize(type,
806
+ size,
807
+ validity_buffer,
808
+ indices_buffer,
809
+ dictionaries)
455
810
  super(type, size, validity_buffer)
456
811
  @indices_buffer = indices_buffer
457
- @dictionary = dictionary
812
+ @dictionaries = dictionaries
813
+ end
814
+
815
+ # TODO: Slice support
816
+ def each_buffer
817
+ return to_enum(__method__) unless block_given?
818
+
819
+ yield(@validity_buffer)
820
+ yield(@indices_buffer)
821
+ end
822
+
823
+ def indices
824
+ buffer_type = @type.index_type.buffer_type
825
+ offset = IO::Buffer.size_of(buffer_type) * @offset
826
+ apply_validity(@indices_buffer.values(buffer_type, offset, @size))
458
827
  end
459
828
 
460
829
  def to_a
830
+ return [] if empty?
831
+
461
832
  values = []
462
- @dictionary.each do |dictionary_chunk|
463
- values.concat(dictionary_chunk.to_a)
833
+ @dictionaries.each do |dictionary|
834
+ values.concat(dictionary.array.to_a)
464
835
  end
465
- buffer_type = @type.index_type.buffer_type
466
- indices = apply_validity(@indices_buffer.values(buffer_type, 0, @size))
467
836
  indices.collect do |index|
468
837
  if index.nil?
469
838
  nil