carray 3.0.1 → 3.0.2
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 +520 -0
- data/README.md +2 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +202 -96
- data/ext/ca_categorical_iterator.c +108 -54
- data/ext/ca_kernel_iterator.c +317 -51
- data/ext/ca_kernel_iterator.h +142 -35
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +85 -26
- data/ext/ca_obj_face.c +24 -0
- data/ext/ca_obj_face.h +15 -0
- data/ext/ca_obj_fixlen_string.c +18 -5
- data/ext/ca_obj_meld.c +123 -25
- data/ext/ca_obj_object.c +8 -0
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +72 -1
- data/ext/ca_obj_string.c +8 -4
- data/ext/ca_obj_window.c +8 -2
- data/ext/ca_op_ipower.c +1 -2
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sweep_engine.c +307 -143
- data/ext/ca_sweep_engine.h +26 -5
- data/ext/carray.h +21 -2
- data/ext/carray_access.c +32 -20
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_broadcast.c +3 -3
- data/ext/carray_call_cfunc.c +667 -483
- data/ext/carray_cast.c +115 -41
- data/ext/carray_copy.c +55 -30
- data/ext/carray_core.c +83 -3
- data/ext/carray_count.c +9 -10
- data/ext/carray_factorize.c +46 -25
- data/ext/carray_internal.h +17 -0
- data/ext/carray_kernels_reduce_aggregate.c +168 -0
- data/ext/carray_kernels_reduce_cumulative.c +270 -1
- data/ext/carray_kernels_reduce_extreme.c +554 -8
- data/ext/carray_kernels_scan.c +4 -4
- data/ext/carray_kernels_search.c +94 -14
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +23 -8
- data/ext/carray_median_percentile.c +55 -0
- data/ext/carray_operator.c +4 -4
- data/ext/carray_order.c +1 -1
- data/ext/carray_random.c +384 -40
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +20 -22
- data/ext/mk_call_cfunc.rb +103 -116
- data/ext/mkkernel.rb +297 -29
- data/ext/ruby_carray.c +10 -1
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +5 -3
- data/lib/carray/autoload_method_extension.rb +12 -0
- data/lib/carray/axis_group.rb +77 -0
- data/lib/carray/basics.rb +4 -0
- data/lib/carray/block_iterator.rb +92 -16
- data/lib/carray/categorical.rb +150 -33
- data/lib/carray/categorical_iterator.rb +207 -80
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +81 -10
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +67 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/verbs.rb +14 -11
- data/lib/carray/inspect.rb +42 -9
- data/lib/carray/iterator.rb +143 -0
- data/lib/carray/lazy.rb +0 -37
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +13 -2
- data/lib/carray/methods/locate_addr.rb +75 -2
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/unique.rb +41 -1
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/slab_iterator.rb +58 -13
- data/lib/carray/string_operation_extension.rb +5 -1
- data/lib/carray/time.rb +18 -2
- data/lib/carray/window_iterator.rb +142 -20
- data/lib/carray.rb +2 -0
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_window.rb +10 -2
- data/yard-stubs/carray_access.rb +1 -1
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_core.rb +0 -80
- data/yard-stubs/carray_count.rb +7 -2
- data/yard-stubs/carray_lazy.rb +205 -0
- data/yard-stubs/carray_math.rb +1486 -3
- data/yard-stubs/carray_median_percentile.rb +16 -2
- data/yard-stubs/carray_order.rb +9 -69
- data/yard-stubs/carray_slab.rb +9 -7
- data/yard-stubs/carray_sort.rb +7 -5
- metadata +9 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 728236f069adb2a801da715596ac5ab87d8cf7c460e70de8667d3afa23e9b19f
|
|
4
|
+
data.tar.gz: fdf25919377fe2d90919712ecf8c50a0ed183c15a57ec925cefedc4a7066fb90
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 26f8ae296774c82b5bba4f9521cf2b53ec0b1804115c0a4a2f39e29d67419932487a4ff892cd115ab3eb34242c942711504c05945b5e95d44653e546e7c70d66
|
|
7
|
+
data.tar.gz: e8109043b73d2f71d395ee0cc5711e395f6964ba0cef7c2aea2d35759dadedca5aa649ec3ebe14de66b6034a788213fb0c0fa1a1ef2499eef03d8b0b021d4bc4
|
data/CHANGELOG.md
CHANGED
|
@@ -34,6 +34,526 @@ and a newer one. The 1.x history, up to the 2.0.0 release, is in
|
|
|
34
34
|
neighbour ("as well", "the producer above") or leave unnamed the
|
|
35
35
|
method, class or keyword it is about. -->
|
|
36
36
|
|
|
37
|
+
## 3.0.2
|
|
38
|
+
|
|
39
|
+
- New: `CArray::AddressBasis`, for a C extension whose code addresses cells
|
|
40
|
+
itself rather than being handed them — a kernel generated from an
|
|
41
|
+
expression, which writes its own loop. `open` lends a pointer and one byte
|
|
42
|
+
stride per axis for the length of a block, and closes what it opened even
|
|
43
|
+
when the block raises; `classify` reports how an array would be opened
|
|
44
|
+
without opening it. It is a runtime facility at the `ca_attach` layer, not
|
|
45
|
+
a user API: what it lends is a raw machine address, so it is described in
|
|
46
|
+
the developer's guide rather than in the user documentation.
|
|
47
|
+
|
|
48
|
+
- New: a `CAString` column can be searched, not only sorted: `bsearch`,
|
|
49
|
+
`bsearch_addr`, `search` and `count(v)` answer where they used to raise
|
|
50
|
+
`ArgumentError`. A cell of one is the Ruby String it shows, so a String query
|
|
51
|
+
compares against it directly, with nothing to reconcile. Sorting, which
|
|
52
|
+
already worked, is unchanged, and so is `CAConstString`, which answers
|
|
53
|
+
`search` / `count(v)` natively and still has no `bsearch`.
|
|
54
|
+
|
|
55
|
+
- New: `count(v)` counts an object or fixlen array, which used to raise
|
|
56
|
+
`CArray::DataTypeError`. An object array compares by Ruby `==`, so
|
|
57
|
+
`count(1)` and `count(1.0)` agree, and `true` / `false` / `nil` are values to
|
|
58
|
+
count rather than the boolean array's `true` / `false`. A fixlen array
|
|
59
|
+
compares the whole cell by `memcmp`, with a short String query padded out to
|
|
60
|
+
the cell width -- so a 4-byte cell holding `"a\0\0\0"` is counted by
|
|
61
|
+
`count("a")`.
|
|
62
|
+
|
|
63
|
+
- New: `CArray.empty(data_type, dim, bytes: nil)` allocates without the zero
|
|
64
|
+
fill, for an array whose every cell is written before anything reads it. One
|
|
65
|
+
existing call changes: `CArray.empty(3, [4])` raised `TypeError` in 3.0.1
|
|
66
|
+
and now matches `CArray.new(3, [4])`.
|
|
67
|
+
|
|
68
|
+
- New: `CAFrame.from_csv` reads an open IO as well as a path, so CSV already
|
|
69
|
+
in memory need not go through a temporary file first. A String argument is
|
|
70
|
+
still always a path, never CSV text.
|
|
71
|
+
|
|
72
|
+
- New: `inspect_full` renders an array the way `inspect` does but without the
|
|
73
|
+
`...` abbreviation.
|
|
74
|
+
|
|
75
|
+
- New: `repeat` lays each element of an array down several times --
|
|
76
|
+
`v.repeat(2)`, or `v.repeat([3, 1, 2])` for a count each. It is not `tile`,
|
|
77
|
+
which lays the whole array down again. The result is a view.
|
|
78
|
+
|
|
79
|
+
- New: `unique`, `nunique` and `mask_duplicates` take `along: k`, comparing
|
|
80
|
+
whole sub-arrays instead of cells -- `z.unique(along: 0)` gives the distinct
|
|
81
|
+
rows of a 2-D array. Giving both `along:` and `axis:` raises.
|
|
82
|
+
|
|
83
|
+
- New: each numeric data type names its own limits on its class --
|
|
84
|
+
`CArray::Int32::MIN` / `MAX`, and `TINY` / `EPSILON` for float and complex
|
|
85
|
+
types. `MIN` is the bottom of the range, where Ruby's `Float::MIN` is what
|
|
86
|
+
is called `TINY` here.
|
|
87
|
+
|
|
88
|
+
- New: `CArray::Rng` is a random number generator with its own state, which
|
|
89
|
+
`random!`, `randomn!` and `shuffle!` accept as `rng:` alongside a Ruby
|
|
90
|
+
`Random`. Without `rng:`, or with a Ruby `Random`, nothing changes.
|
|
91
|
+
|
|
92
|
+
- New: `CArray#factorize` answers `[codes, levels]` in one pass, for a caller
|
|
93
|
+
who wants the codes as storage rather than the `CACategorical` that
|
|
94
|
+
`categorize` builds from the same two.
|
|
95
|
+
|
|
96
|
+
- New: C extensions only. `CA_FOR_EACH_FIBER_PAIR` and
|
|
97
|
+
`CA_FOR_EACH_FIBER_PAIR_MASKED` yield one contiguous fiber from each of two
|
|
98
|
+
sources at the same position.
|
|
99
|
+
|
|
100
|
+
- Change: `CArray.meld` (and `CAMeld.new`, and so `CAFrame.meld`) now treats a
|
|
101
|
+
homogeneous list of Faces the way `CArray.stack` does: a Face whose state is
|
|
102
|
+
per-parent is refused, and one that can be carried is kept on the result.
|
|
103
|
+
`CAConstString` and `CAString` now raise `ArgumentError` — weld the storage
|
|
104
|
+
instead, with `.parent`, or use `CArray.concatenate`. `CAFixlenString`,
|
|
105
|
+
`CATime` and `CATimedelta` come back as themselves rather than as the raw
|
|
106
|
+
storage; melding pieces whose Face state differs, such as two `CATime`
|
|
107
|
+
columns in different units, now raises rather than welding the ticks. Lists
|
|
108
|
+
of plain arrays, and a list of one, are unaffected.
|
|
109
|
+
|
|
110
|
+
- Change: `CAConstString.wrap` now checks the `(start, end)` pairs it is given
|
|
111
|
+
against the buffer, and takes ownership of the offsets entity by marking it
|
|
112
|
+
read-only. A pair outside the buffer raises `ArgumentError` naming the
|
|
113
|
+
element; masked cells are exempt, since their bytes may be anything. Code
|
|
114
|
+
that built a column with well-formed offsets is unaffected, except that the
|
|
115
|
+
entity it passed can no longer be written afterwards — pass `.copy` to keep
|
|
116
|
+
a mutable one. This also means the storage behind an existing column
|
|
117
|
+
(`column.parent[i] = ...`) now raises rather than silently rewriting a column
|
|
118
|
+
that reports itself read-only.
|
|
119
|
+
|
|
120
|
+
- Change: `all` and `any` on an `axis_group` reduction now require a boolean
|
|
121
|
+
payload, as `CArray#all` / `#any` and the other iterators do. They folded any
|
|
122
|
+
numeric payload, counting a non-zero cell as true, so `data.all` refused and
|
|
123
|
+
`data[g].all(axis: :group)` answered for the same float array. Convert first
|
|
124
|
+
if you meant the old reading: `data.ne(0)[g].all(axis: :group)`.
|
|
125
|
+
|
|
126
|
+
- Change: the `axis:` reductions on `group_by_category` now read the source
|
|
127
|
+
array when asked, rather than some of them answering from a result kept
|
|
128
|
+
from an earlier call. `sum`, `mean`, `min`, `max` and the counts shared a
|
|
129
|
+
kept result per axis while `prod`, the variance family and `wsum` / `wmean`
|
|
130
|
+
did not, so after a write through the source one iterator could report a
|
|
131
|
+
mean and a variance that no data can produce together. Reading several
|
|
132
|
+
members off one iterator now costs one kernel run each instead of one
|
|
133
|
+
shared run; keep the result if you want the old sharing. The no-axis
|
|
134
|
+
reductions are unchanged: they still work from the copy taken when the
|
|
135
|
+
iterator was built.
|
|
136
|
+
|
|
137
|
+
- Change: `CAFrame#at(UNDEF)` now raises `ArgumentError` instead of returning a
|
|
138
|
+
row. An index can hold a masked cell -- an `:outer` / `:right` join and
|
|
139
|
+
`align` both produce one -- but a row with no label cannot be identified by
|
|
140
|
+
one, and two undefined labels are not the same label; the key matching behind
|
|
141
|
+
`join` and `align` already treats a masked key as matching nothing. Use
|
|
142
|
+
`df.filter { |f| f.index.is_masked }` for the rows with no label, which also
|
|
143
|
+
handles more than one of them. Asking for a real label whose cell is masked
|
|
144
|
+
still raises `KeyError`, unchanged.
|
|
145
|
+
|
|
146
|
+
- Change: functions built on the C-extension bridge (`ca_call_cfunc_*`,
|
|
147
|
+
`ca_call_cslab_*`, and `CAMath.spherical_to_xyz` / `xyz_to_spherical`)
|
|
148
|
+
pair two array operands only when their shapes agree, and otherwise
|
|
149
|
+
raise `ArgumentError` naming both shapes. Arrays of the same size but
|
|
150
|
+
different shape, such as (2,3) and (3,2), used to be accepted and read
|
|
151
|
+
in flat order; reshape one of them first. Arrays of different sizes
|
|
152
|
+
raised `RuntimeError` before, so a `rescue` of that class needs
|
|
153
|
+
updating. A scalar still pairs with any array.
|
|
154
|
+
|
|
155
|
+
- Change: `min`, `max`, `minmax`, `cummin` and `cummax` answer `NaN`, and
|
|
156
|
+
`min_index`, `max_index`, `min_addr` and `max_addr` answer `UNDEF`, when every
|
|
157
|
+
cell a float array contributes is `NaN`. They used to answer `Infinity`,
|
|
158
|
+
`-Infinity`, the interval `[Infinity, -Infinity]` and position `0`. A `NaN`
|
|
159
|
+
still loses to any number, so an array holding at least one number answers as
|
|
160
|
+
before, as does one holding only real infinities. Empty and all-masked still
|
|
161
|
+
answer `UNDEF`, and integer, boolean, fixlen and object arrays are unchanged
|
|
162
|
+
-- an object array already answered `NaN`. To have `NaN` counted as missing
|
|
163
|
+
rather than skipped, call `mask_invalid` first; `min_count:` and `fill_value:`
|
|
164
|
+
act on masked cells and do not reach `NaN` ones.
|
|
165
|
+
|
|
166
|
+
- Change: the `CAConstString` ordering family takes `axis:` -- and `kind:` /
|
|
167
|
+
`masked_position:` / `keep_axis:` where CArray does -- across `min`, `max`,
|
|
168
|
+
`minmax`, `min_index`, `max_index`, `sort`, `sort_copy`, `sort_addr`,
|
|
169
|
+
`sort_index`, `rank_index`, `order`, `partition_copy` and `partition_index`.
|
|
170
|
+
Three answers move to CArray's: `sort_index` gives per-fiber indices where it
|
|
171
|
+
gave view-flat addresses (ask `sort_addr` for those); `sort` with no `axis:`
|
|
172
|
+
flattens first, where it kept the shape (a 1-D column is unaffected); and
|
|
173
|
+
`min` / `max` on an empty or wholly masked column give UNDEF, not nil.
|
|
174
|
+
|
|
175
|
+
- Change: `CABlock#count` and `CAWindow#count` are gone. They gave back the
|
|
176
|
+
per-axis number of cells the view exposes -- which is what `shape` answers
|
|
177
|
+
-- and in doing so hid `CArray#count` on the two classes an indexing
|
|
178
|
+
expression lands on most: `a[2...8].count(true)` raised `ArgumentError`,
|
|
179
|
+
and `a[2...8].count` gave a shape rather than a population. Read the
|
|
180
|
+
geometry with `shape`. `size0` / `start` / `step` / `offset`, which say
|
|
181
|
+
where the view sits in its parent, are unchanged.
|
|
182
|
+
|
|
183
|
+
- Change: `CArray.jit_for`, `CArray.jit_each` and `CArray.jit_map` are no
|
|
184
|
+
longer defined here; they arrive with `require "carray/jit"`. Without it a
|
|
185
|
+
call raises `NoMethodError` where 3.0.1 raised `NotImplementedError`, so
|
|
186
|
+
code that rescued that to fall back asks `CArray.respond_to?(:jit_each)`.
|
|
187
|
+
|
|
188
|
+
- Change: the Ruby attach surface is gone from released builds:
|
|
189
|
+
`CArray.attach` / `.attach!`, `CArray#attach` / `#attach!`, and
|
|
190
|
+
`#__attach__` / `#__sync__` / `#__detach__`. Write through the array
|
|
191
|
+
directly instead. `CArray#attached?` and the C lifecycle are unchanged.
|
|
192
|
+
|
|
193
|
+
- Change: `a[1, :_]` returns a view of the axes `:_` asked for instead of
|
|
194
|
+
raising `IndexError`. To keep an axis rather than drop it, index it with
|
|
195
|
+
something that is not a scalar -- `a[[1], :_]`.
|
|
196
|
+
|
|
197
|
+
- Change: C extensions only. A kernel iterator init the engine refuses now
|
|
198
|
+
raises instead of returning a code the block macros discarded. To handle a
|
|
199
|
+
refusal rather than propagate it, call `ca_iter_state_init_l1` / `_l2`
|
|
200
|
+
directly and read the code.
|
|
201
|
+
|
|
202
|
+
- Change: `CACategorical.from_codes` now materialises `codes` when it is a
|
|
203
|
+
view rather than an array of its own, so writing through the array the view
|
|
204
|
+
was taken from no longer changes the categorical underneath it. A wrapped
|
|
205
|
+
memory view is an array of its own and is still adopted without a copy, so a
|
|
206
|
+
zero-copy import stays zero-copy. The array you pass is never marked
|
|
207
|
+
read-only beyond what you handed over.
|
|
208
|
+
|
|
209
|
+
- Change: `CACategorical.from_codes` now checks what it is handed and
|
|
210
|
+
normalises it. It raises `ArgumentError` for duplicate labels, for more
|
|
211
|
+
labels than the codes data type can carry once its top value is reserved as
|
|
212
|
+
the exclusion sentinel, and for an unmasked code outside `0...labels.size`
|
|
213
|
+
that is not the sentinel. A cell that arrives masked also gets the sentinel
|
|
214
|
+
written into its code byte, so the mask and the byte now agree for every
|
|
215
|
+
reader, a byte-reinterpret export included. Codes built by `categorize`
|
|
216
|
+
already satisfy all of this, so nothing changes for a categorical made that
|
|
217
|
+
way.
|
|
218
|
+
|
|
219
|
+
- Change: `search_nearest` and `search_nearest_addr` work on an object array of
|
|
220
|
+
numbers, and say why when they cannot. They measured only with `#distance`,
|
|
221
|
+
and since `Numeric#distance` became an opt-in refinement -- which a C-level
|
|
222
|
+
call does not see -- that raised `NoMethodError` for an Integer as readily as
|
|
223
|
+
for a String. A number is now measured as `(query - cell).abs`, exactly for
|
|
224
|
+
Rational and BigDecimal; an object defining a real `#distance` still uses it;
|
|
225
|
+
anything else raises `CArray::DataTypeError` naming the query's class, and
|
|
226
|
+
points at `search` / `bsearch` for an exact match. Numeric arrays are
|
|
227
|
+
unaffected.
|
|
228
|
+
|
|
229
|
+
- Change: `CAFrame.from_csv` reads a missing field as UNDEF in every column,
|
|
230
|
+
not only in one named by `types:`. An unquoted empty field, and a cell a
|
|
231
|
+
short row never reached, used to arrive as a Ruby `nil` sitting in an
|
|
232
|
+
uncast column, so a mask written by `to_csv` did not survive the trip back.
|
|
233
|
+
A quoted empty field (`""`) is still the empty string, which is a value.
|
|
234
|
+
Code that worked around this with `col[:eq, nil] = UNDEF` can drop the line.
|
|
235
|
+
|
|
236
|
+
- Change: `CArray.time` reads a string array about eight times faster with an
|
|
237
|
+
explicit `format:`, and about three times faster letting it auto-detect --
|
|
238
|
+
so `CAFrame#parse_to_time`, which calls it, speeds up by the same amount.
|
|
239
|
+
Parsed values are unchanged.
|
|
240
|
+
|
|
241
|
+
- Change: `window` accepts `bounds:` as a Symbol as well as a String, which is
|
|
242
|
+
the spelling `windows` already took. Strings keep working.
|
|
243
|
+
|
|
244
|
+
- Change: C extensions only. A partial fill of an array backed by a CAObject
|
|
245
|
+
or CASource subclass takes the `fill_block` / `fill_addrs` slots where the
|
|
246
|
+
subclass defines them, instead of one `store_addr` per cell. Which cells are
|
|
247
|
+
written is unchanged, and a subclass defining no fill slot keeps the
|
|
248
|
+
per-cell path.
|
|
249
|
+
|
|
250
|
+
- Fix: `is_in`, `count(v)`, the set operations, `locate_addr`, `search`,
|
|
251
|
+
`bsearch` and `linear_section` no longer compare a Face operand by its
|
|
252
|
+
storage when that storage is not the value it shows. Passing a
|
|
253
|
+
`CAConstString` (whose cells are byte ranges) to one of these on another
|
|
254
|
+
Face used to answer from the byte ranges: where the two cell widths
|
|
255
|
+
coincided — a `CAConstString` cell is 16 bytes, and so is a
|
|
256
|
+
`CAFixlenString` cell whose column is 16 bytes wide — you got a wrong
|
|
257
|
+
answer with no error, and a set operation could return raw offset bytes as
|
|
258
|
+
its values. Such an operand now raises `ArgumentError`; convert it first,
|
|
259
|
+
with `#to_string` for a string Face, or pass `.parent` on both sides to work
|
|
260
|
+
in storage space. Plain operands, and Faces whose cells are their values
|
|
261
|
+
(`CAString`, `CAFixlenString`), are unaffected, as is the cross-unit
|
|
262
|
+
reconciliation `CATime` does through `to_comparable`.
|
|
263
|
+
|
|
264
|
+
- Fix: the reductions without `axis:` on `group_by_category` now agree with one
|
|
265
|
+
another about which values they are reducing. `cumsum` and the other scans
|
|
266
|
+
read the array when called while every other member worked from the copy
|
|
267
|
+
taken when the iterator was built, so a write through the source between two
|
|
268
|
+
calls was visible to one and not the other. All of them now answer about the
|
|
269
|
+
values as they were when the iterator was built; build a new iterator to pick
|
|
270
|
+
up a write. The `axis:` reductions read the array when called, unchanged.
|
|
271
|
+
|
|
272
|
+
- Fix: `CArray.load_from_file` no longer exhausts the stack. It was
|
|
273
|
+
registered for autoload but defined nowhere, so calling it recursed until
|
|
274
|
+
Ruby gave up; it now raises `NoMethodError` like any other method that does
|
|
275
|
+
not exist. Use `CArray.load`, which is unchanged. An autoload registration
|
|
276
|
+
whose library defines no such method now says which method and which
|
|
277
|
+
library, rather than recursing.
|
|
278
|
+
|
|
279
|
+
- Fix: a `group_by_category` reduction over a read-only Face — a
|
|
280
|
+
`CAConstString` column — no longer fails with an `IndexError` about a buffer
|
|
281
|
+
range. Such a Face cannot be built by writing into it, so `min`, `max` and
|
|
282
|
+
the other value members hand back the surface values (the strings) rather
|
|
283
|
+
than the Face. A writable Face such as `CATime` still answers in its Face.
|
|
284
|
+
|
|
285
|
+
- Fix: a group iterator from `axis_group` now answers `shape`, `ndim` and
|
|
286
|
+
`dim`, which every other iterator answers and which it returned `nil` for,
|
|
287
|
+
and its `count` takes the two forms the family declares: `count(UNDEF)` for
|
|
288
|
+
masked cells and `count(v)` for cells equal to `v`. Both previously raised
|
|
289
|
+
`ArgumentError` about the number of arguments.
|
|
290
|
+
|
|
291
|
+
- Fix: a `group_by_category` reduction over values that carry a Face (a
|
|
292
|
+
`CATime` column, say) now answers in that Face, as `CArray`'s own reduction
|
|
293
|
+
does: `min`, `max` and `median` come back as a `CATime` of elements rather
|
|
294
|
+
than failing with an internal message about a zero width. A member the core
|
|
295
|
+
does not define for that Face still refuses, in the core's own words.
|
|
296
|
+
|
|
297
|
+
- Fix: the band-only classifier shape for a `group_by_category(axis:)`
|
|
298
|
+
reduction is now reachable on a two-dimensional source, where it was
|
|
299
|
+
refused and the refusal listed it among the accepted forms. Where both the
|
|
300
|
+
case A shape and the band-only shape fit, which a square source allows,
|
|
301
|
+
case A is taken, as before. The refusal no longer names `sum` when another
|
|
302
|
+
reduction was the one called.
|
|
303
|
+
|
|
304
|
+
- Fix: `count(axis:)` and `count_not_masked(axis:)` on `group_by_category`
|
|
305
|
+
now work for a complex, boolean or object payload. They counted cells
|
|
306
|
+
through a numeric-only kernel, which refused those payloads for an answer
|
|
307
|
+
that never depended on the payload. The no-axis form already worked.
|
|
308
|
+
|
|
309
|
+
- Fix: a `group_by_category` iterator whose classifier does not line up
|
|
310
|
+
cell-for-cell with the value now says so. A no-axis reduction on one raises
|
|
311
|
+
`ArgumentError` naming the mismatch and pointing at the `axis:` form, rather
|
|
312
|
+
than a `NoMethodError` about `nil`; `elements` raises the same instead of
|
|
313
|
+
answering `nil`; and `inspect` says "per-fiber only" instead of printing an
|
|
314
|
+
empty grouping. `accumulate(axis:)`, which failed outright on such an
|
|
315
|
+
iterator, now works.
|
|
316
|
+
|
|
317
|
+
- Fix: a reduction from `group_by_category` now hands back an array of the
|
|
318
|
+
caller's own. `min`, `max`, `minmax`, `count`, `count_not_masked`,
|
|
319
|
+
`elements`, `min_index` and `max_index` returned the iterator's memo itself,
|
|
320
|
+
so writing into a result changed what that iterator answered from then on,
|
|
321
|
+
and changed it for the other members reading the same memo. `sum` already
|
|
322
|
+
copied. Nothing to change in calling code unless you relied on writing
|
|
323
|
+
through a result.
|
|
324
|
+
|
|
325
|
+
- Fix: an `axis_group` reduction or scan that raises part-way through no
|
|
326
|
+
longer leaks the working memory it had taken. An object-valued scan
|
|
327
|
+
(`cumsum`, `cummax` and the rest) calls back into Ruby for every cell, so a
|
|
328
|
+
value that will not coerce or a `<=>` that answers `nil` raises from an
|
|
329
|
+
ordinary call and used to leave roughly 36 bytes per source element behind
|
|
330
|
+
each time. Nothing to change in calling code.
|
|
331
|
+
|
|
332
|
+
- Fix: `CAFrame#set_index` on a frame that already has an index no longer
|
|
333
|
+
discards it. The index being replaced now goes back to being a column, the
|
|
334
|
+
same demotion `reset_index` performs and in the same position, so re-indexing
|
|
335
|
+
keeps every column and `set_index("b")` on a frame indexed by `"a"` is the
|
|
336
|
+
same as `reset_index` followed by `set_index("b")`. Previously the column the
|
|
337
|
+
old index had been made from was gone, with nothing said.
|
|
338
|
+
|
|
339
|
+
- Fix: `CAFrame#reset_index` now restores the row axis name the frame had
|
|
340
|
+
before `set_index` promoted a column over it, so the two are each other's
|
|
341
|
+
inverse as documented. It used to leave `"row"`, which is user-visible: the
|
|
342
|
+
row axis name is the header of the index's column in `to_csv` and its key in
|
|
343
|
+
a row `Hash`. A frame built with an index, or derived from one, never had an
|
|
344
|
+
earlier name, so `reset_index` still leaves the default there.
|
|
345
|
+
|
|
346
|
+
- Fix: `min` and `max` on an `axis_group` reduction now answer in the source
|
|
347
|
+
array's data type, as `CArray#min` / `#max` do, instead of float64 -- an
|
|
348
|
+
int64 beyond the float mantissa came back rounded. A boolean array answers
|
|
349
|
+
as its 0/1 numeric storage (`all` / `any` are the boolean-returning twins).
|
|
350
|
+
A group holding nothing but `NaN` now answers `NaN` rather than the
|
|
351
|
+
accumulator's infinity, and `min_addr` / `max_addr` answer UNDEF for it,
|
|
352
|
+
since no cell won.
|
|
353
|
+
|
|
354
|
+
- Fix: an `axis_group` reduction over a grouping whose group axis has length
|
|
355
|
+
zero now answers each output cell the way a group with no member is answered
|
|
356
|
+
-- `sum` 0, `prod` 1, `count` 0, `all` true, `any` false, and UNDEF for
|
|
357
|
+
`mean`, `min`, `max`, `min_addr`, `max_addr` and the variance family. It
|
|
358
|
+
previously returned an unmasked 0 for all of them, so a mean and a variance
|
|
359
|
+
both read as 0.0. A zero-length band axis, which reduces to no cells at all,
|
|
360
|
+
is unchanged.
|
|
361
|
+
|
|
362
|
+
- Fix: a per-category `min`, `max`, `min_index`, `max_index`, `median`,
|
|
363
|
+
`percentile` or `quantile` from `group_by_category` now treats `NaN` the way
|
|
364
|
+
`CArray`'s own reduction does: a `NaN` loses every contest, a category
|
|
365
|
+
holding nothing but `NaN` answers `NaN` for an extremum and UNDEF for a
|
|
366
|
+
position, and an order statistic sorts `NaN` last. Before, the answer
|
|
367
|
+
depended on where in the category the `NaN` sat, so the same values in a
|
|
368
|
+
different row order gave different results. Nothing to change in calling
|
|
369
|
+
code.
|
|
370
|
+
|
|
371
|
+
- Fix: `p` / `inspect` on a `CAFrame` whose only data is its index now shows the
|
|
372
|
+
table. It printed the summary line alone, because it gated on the column set
|
|
373
|
+
while the table itself counts the index as a column.
|
|
374
|
+
|
|
375
|
+
- Fix: `CAFrame` no longer reports a row count that nothing in the frame backs.
|
|
376
|
+
Splicing a frame that has no columns into another that has neither columns nor
|
|
377
|
+
an index left the target claiming the spliced frame's row count, while its own
|
|
378
|
+
`copy`, `head` and `filter` all answered 0 and it would then accept only
|
|
379
|
+
columns of that length. The count is now read off a column, or off the index
|
|
380
|
+
when there are no columns. Nothing to change in calling code.
|
|
381
|
+
|
|
382
|
+
- Fix: `CAFrame`'s `df[rows] = UNDEF` now refuses a row outside the frame on a
|
|
383
|
+
frame with no columns, as the read and delete forms already did. It used to
|
|
384
|
+
return quietly, because the bound check came from the column indexer the
|
|
385
|
+
selector was handed to and there was no column to hand it to. Masking a row
|
|
386
|
+
that does exist on such a frame is still a no-op -- there are no data cells,
|
|
387
|
+
and the index is left alone by design.
|
|
388
|
+
|
|
389
|
+
- Fix: `CAFrame`'s `to_table` (and so `p` / `puts` / `to_s`) now prints a masked
|
|
390
|
+
element inside an N-D cell as `_`, the marker it already used for a masked
|
|
391
|
+
scalar cell, instead of the literal `UNDEF`. Nothing to change in calling
|
|
392
|
+
code.
|
|
393
|
+
|
|
394
|
+
- Fix: `CAFrame#group_by` with a composite key no longer makes a group of its
|
|
395
|
+
own for rows whose key has a masked component. Such a row now forms no group,
|
|
396
|
+
which is what a single masked key cell already did. Nothing to change in
|
|
397
|
+
calling code unless you relied on the UNDEF-labelled group.
|
|
398
|
+
|
|
399
|
+
- Fix: two `CAFrame` verbs that change every column now decide before changing
|
|
400
|
+
any, so a column that refuses no longer leaves the frame half-changed in an
|
|
401
|
+
order that depends on how the columns were inserted. `df[sel] = UNDEF` on a
|
|
402
|
+
frame holding a read-only column (a categorical) raises without masking
|
|
403
|
+
anything, and `promote(type)` raises without casting anything when some
|
|
404
|
+
column would narrow. Nothing to change in calling code.
|
|
405
|
+
|
|
406
|
+
- Fix: `CAFrame.from_records` now reads a `nil` cell back as UNDEF in every
|
|
407
|
+
column, not only in one a numeric cast happens to convert. A string, boolean,
|
|
408
|
+
object or N-D column used to keep the `nil` as a value, so a mask written by
|
|
409
|
+
`to_records` did not survive the trip and a row with no index label came back
|
|
410
|
+
labelled `nil`. Note that the data type is still rebuilt from the values, so
|
|
411
|
+
an integer column returns as `int64` and a boolean column as an object
|
|
412
|
+
column; `cast` afterwards if the exact type matters.
|
|
413
|
+
|
|
414
|
+
- Fix: a CSV written from a frame with a single column -- or with only an
|
|
415
|
+
index -- now reads back with all of its rows. A masked cell is written as an
|
|
416
|
+
empty field, which for a one-column row is a line with nothing on it, and the
|
|
417
|
+
reader skipped it as a blank line. Blank lines in a file with more than one
|
|
418
|
+
column are still skipped, as a row there always carries a separator. Nothing
|
|
419
|
+
to change in calling code.
|
|
420
|
+
|
|
421
|
+
- Fix: linear gap-fill on an **integer** array no longer fills the cells
|
|
422
|
+
outside the interpolable span with `0` and drops their mask. It now leaves
|
|
423
|
+
them masked, as it already did for a float array and as the documentation
|
|
424
|
+
says. This covers `unmask(method: :linear)` and `strip_mask(method: :linear)`
|
|
425
|
+
as well as `CAFrame#fill(name, :linear)`, with or without a frame index.
|
|
426
|
+
Nothing to change in calling code.
|
|
427
|
+
|
|
428
|
+
- Fix: on a frame grouped by a numeric column, `CAFrame`'s `mean`, `sum`, `min`
|
|
429
|
+
and `max` shortcuts now work. They raised `axis_name "..." collides with a
|
|
430
|
+
column of the same name`, because the key column was reduced into the result
|
|
431
|
+
while also being its index; a key only stayed out of the way when its data
|
|
432
|
+
type was one a reduction skips anyway -- a string, boolean, categorical or
|
|
433
|
+
time column. A composite numeric key no longer returns its key columns as
|
|
434
|
+
reduced columns either, so it gives the same column set a composite string
|
|
435
|
+
key gives. `aggregate` and `table` were never affected. Nothing to change in
|
|
436
|
+
calling code.
|
|
437
|
+
|
|
438
|
+
- Fix: `CAFrame#filter(keep_masked: true)` no longer hands back a frame whose
|
|
439
|
+
index writes through to the original. Its columns were already independent,
|
|
440
|
+
so writing the result's index changed the original while writing its columns
|
|
441
|
+
did not. The result is now materialized throughout -- columns and index --
|
|
442
|
+
whether or not the selector actually carries a masked cell, so the same call
|
|
443
|
+
site no longer switches between sharing and copying depending on the data.
|
|
444
|
+
Code that wants a frame sharing storage with the original should use plain
|
|
445
|
+
`filter`, which is still a view-frame.
|
|
446
|
+
|
|
447
|
+
- Fix: reductions, scans and order statistics no longer leak memory when
|
|
448
|
+
reading their source raises part way through -- for example
|
|
449
|
+
`cumsum`, `sum` or `median` over a float64 view of an object array
|
|
450
|
+
holding a cell that is not a number. Each call used to leave the
|
|
451
|
+
slab the walk was gathering into behind. Nothing to change in calling
|
|
452
|
+
code.
|
|
453
|
+
|
|
454
|
+
- Fix: `a[sel]` no longer leaks memory when reading the boolean selector
|
|
455
|
+
raises -- for example `fake(CA_BOOLEAN)` over an int32 array holding a
|
|
456
|
+
2. Nothing to change in calling code.
|
|
457
|
+
|
|
458
|
+
- Fix: a view that converts on read -- for example `fake(CA_BOOLEAN)` over
|
|
459
|
+
an int32 array holding a 2 -- now raises every time it is read, where
|
|
460
|
+
the second read used to succeed silently and return values from a
|
|
461
|
+
half-converted buffer. A view stacked or melded over such an array no
|
|
462
|
+
longer leaves its other parents attached when the read raises, and a
|
|
463
|
+
reshape of a lazy view no longer leaks its buffer. Nothing to change in
|
|
464
|
+
calling code.
|
|
465
|
+
|
|
466
|
+
- Fix: for C extensions, a callback passed to `ca_call_cfunc_*` or
|
|
467
|
+
`ca_call_cslab_*` may now `rb_raise` to refuse a value: the bridge
|
|
468
|
+
detaches and frees what it holds before the exception propagates,
|
|
469
|
+
where it used to leave an output view attached and its scratch memory
|
|
470
|
+
behind. The outputs are left partly written. Nothing to change in
|
|
471
|
+
calling code.
|
|
472
|
+
|
|
473
|
+
- Fix: when `to_type` on a view raises part way through the cast -- for
|
|
474
|
+
example an int32 value other than 0 or 1 cast to boolean -- the view is
|
|
475
|
+
no longer left holding a stale copy of its parent, which made later
|
|
476
|
+
reads through it return the old values. Nothing to change in calling
|
|
477
|
+
code.
|
|
478
|
+
|
|
479
|
+
- Fix: `copy` and `strip_mask(fill)` no longer leak the result's memory
|
|
480
|
+
when reading the source raises part way through -- for example a
|
|
481
|
+
float64 view of an object array holding a cell that is not a number.
|
|
482
|
+
Nothing to change in calling code.
|
|
483
|
+
|
|
484
|
+
- Fix: functions built on the C-extension bridge (`ca_call_cfunc_*`,
|
|
485
|
+
`ca_call_cslab_*`, the `CA_FOR_EACH_ELEMENT` macros, and
|
|
486
|
+
`CAMath.lgamma` and its siblings) no longer leak memory, or leave an
|
|
487
|
+
output view attached, when reading an operand raises part way through
|
|
488
|
+
-- for example a float64 view of an object array holding a cell that is
|
|
489
|
+
not a number. Nothing to change in calling code.
|
|
490
|
+
|
|
491
|
+
- Fix: `is_in`, `intersection`, `difference` and `union` take an Array or Range
|
|
492
|
+
of Strings against a fixlen array, where every such call raised
|
|
493
|
+
`CArray::DataTypeError` -- `CAFixlenString` included. The set is built at the
|
|
494
|
+
array's cell width, so a short String matches a padded cell the way it does
|
|
495
|
+
everywhere else. A set given as a CArray must still be of that width; when it
|
|
496
|
+
is not, the refusal now says which width was wanted instead of reporting a
|
|
497
|
+
data type mismatch between two fixlen arrays.
|
|
498
|
+
|
|
499
|
+
- Fix: comparing a fixlen array against a String compares it as a value of
|
|
500
|
+
that array's cell width. The String became an object operand, so `eq` / `ne` /
|
|
501
|
+
`lt` / `gt` / `ge` / `le` and the `[:eq, v]` indexer ran `String#==` per cell
|
|
502
|
+
against the cell's NUL-padded text -- and an array pads a short String on
|
|
503
|
+
write, so `a[i] = "be"` then `a.eq("be")` was false, `a.gt("be")` was true,
|
|
504
|
+
and the scan took 30x longer than the same one in `search`. Two fixlen
|
|
505
|
+
arrays of different widths compare as before, as does a Regexp for `match`.
|
|
506
|
+
`CAFixlenString` was never affected.
|
|
507
|
+
|
|
508
|
+
- Fix: `percentile` and `median` no longer interpolate between objects that
|
|
509
|
+
have no arithmetic. On a column of Strings `percentile(30)` quietly answered
|
|
510
|
+
`""` and even-length `median` raised `NoMethodError` from inside a funcall;
|
|
511
|
+
both now raise `CArray::DataTypeError` naming `method: :lower` / `:higher` /
|
|
512
|
+
`:nearest`, which pick an element and work. A `p` that lands exactly on an
|
|
513
|
+
element (`percentile(50)` of five) still answers, as does an odd-length
|
|
514
|
+
`median`. Numbers stored as objects -- Integer, Rational, BigDecimal -- are
|
|
515
|
+
unaffected.
|
|
516
|
+
|
|
517
|
+
- Fix: `sort_copy` takes whatever `sort` takes. It refused everything its own
|
|
518
|
+
fast path could not handle, so an object or boolean array sorted through
|
|
519
|
+
`sort` and raised `CArray::DataTypeError` through `sort_copy`; complex, which
|
|
520
|
+
neither can order, refused differently depending on which one was asked, and
|
|
521
|
+
now refuses alike. Numeric arrays keep the fast path and are unchanged.
|
|
522
|
+
|
|
523
|
+
- Fix: `CAConstString#sort_addr`, `#sort_index`, `#rank_index`, `#order`,
|
|
524
|
+
`#min_index`, `#max_index`, `#partition_copy` and `#partition_index` read the
|
|
525
|
+
strings. They read the `(start, end)` offsets that hold them, which order by
|
|
526
|
+
how the column was packed, so they gave well-formed wrong answers rather than
|
|
527
|
+
raising: `sort_addr` on an unsorted column gave the identity, and
|
|
528
|
+
`partition_copy` gave NUL bytes. `#minmax` answers instead of raising, and
|
|
529
|
+
sorting a column with masked cells no longer raises.
|
|
530
|
+
|
|
531
|
+
- Fix: `to_const_string` gives an N-D source back with its shape instead of
|
|
532
|
+
flattened, and `CAConstString#unique` / `#mode` / `#mask_duplicates` /
|
|
533
|
+
`#intersection` / `#difference` / `#union` keep the column's encoding --
|
|
534
|
+
on a column that was not UTF-8 they raised out of the builder's check.
|
|
535
|
+
|
|
536
|
+
- Fix: `each_with_index` and `map_with_index!` no longer raise
|
|
537
|
+
`SystemStackError` on a long array, and neither do `CArray#format` /
|
|
538
|
+
`CArray.format`, which are built on them. The ceiling was the C stack, so
|
|
539
|
+
where it fell depended on where the code ran: around a million cells on the
|
|
540
|
+
main thread, under a hundred thousand inside a `Thread`.
|
|
541
|
+
|
|
542
|
+
- Fix: `CArray.concatenate` and `CArray.mosaic` take a zero-length piece --
|
|
543
|
+
an empty slice such as `a[0...0]`, or `CArray.int32(0)` -- instead of
|
|
544
|
+
raising `IndexError`. The piece contributes nothing and the remaining ones
|
|
545
|
+
concatenate as before. `CArray#paste` likewise accepts a source covering no
|
|
546
|
+
cell, and writes nothing.
|
|
547
|
+
|
|
548
|
+
- Fix: C extensions only. A kernel writing into a view the caller supplied now
|
|
549
|
+
reaches the array; writes were lost, or crashed, for several view kinds
|
|
550
|
+
iterated along an axis whose fiber is not contiguous. Kernels writing into
|
|
551
|
+
an array they allocated themselves were never affected.
|
|
552
|
+
|
|
553
|
+
- Fix: `CArray#each_slab` yields a read-only slab, and writing through it
|
|
554
|
+
raises rather than reaching the array on one axis and being dropped on
|
|
555
|
+
another. Return values from the block instead, or assign through the array.
|
|
556
|
+
|
|
37
557
|
## 3.0.1
|
|
38
558
|
|
|
39
559
|
- New: `CArray.jit_for`, `CArray.jit_each` and `CArray.jit_map` name a block
|
data/README.md
CHANGED
|
@@ -129,9 +129,9 @@ Bug reports and feature requests are welcome — please open an issue.
|
|
|
129
129
|
|
|
130
130
|
## Credits
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
CArray is created and maintained by himotoyoshi.
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
Versions up to 2.0 were written by the author. For version 3.0, the author provided the design, and most of the implementation was rewritten with AI coding tools; it has been verified primarily through the test suite and practical use.
|
|
135
135
|
|
|
136
136
|
## License
|
|
137
137
|
|
data/carray.gemspec
CHANGED
data/ext/ca_axis_dispatch.c
CHANGED
|
@@ -339,13 +339,27 @@ ca_axis_dispatch_scatter_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
|
|
|
339
339
|
/* Callback context for fill_value (broadcast a single value). parent is set
|
|
340
340
|
when the value goes through the parent's own fill_stride instead of a
|
|
341
341
|
buffer this side has attached. */
|
|
342
|
+
/* Same size as the window ca_fill_stride_via_addrs collects into. */
|
|
343
|
+
#define CA_AXIS_FILL_ADDR_WINDOW 1024
|
|
344
|
+
|
|
342
345
|
typedef struct {
|
|
343
346
|
const void *val;
|
|
344
347
|
ca_size_t bytes;
|
|
345
348
|
char *parent_ptr;
|
|
346
349
|
CArray *parent;
|
|
350
|
+
ca_size_t window[CA_AXIS_FILL_ADDR_WINDOW];
|
|
351
|
+
ca_size_t nw;
|
|
347
352
|
} ca_axis_fill_ctx_t;
|
|
348
353
|
|
|
354
|
+
static void
|
|
355
|
+
ca_axis_dispatch_fill_flush (ca_axis_fill_ctx_t *c)
|
|
356
|
+
{
|
|
357
|
+
if ( c->nw ) {
|
|
358
|
+
ca_fill_addrs(c->parent, c->nw, c->window, (void *) c->val);
|
|
359
|
+
c->nw = 0;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
349
363
|
static void
|
|
350
364
|
ca_axis_dispatch_fill_value_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
|
|
351
365
|
{
|
|
@@ -354,11 +368,25 @@ ca_axis_dispatch_fill_value_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
|
|
|
354
368
|
if ( c->parent ) {
|
|
355
369
|
/* One slab is one contiguous run of parent cells, which is a region the
|
|
356
370
|
parent can fill for itself -- no borrowed buffer, so nothing outside
|
|
357
|
-
the run is read or written.
|
|
371
|
+
the run is read or written. A run of one cell is not worth a call of
|
|
372
|
+
its own, though: when the innermost selected axis picks individual
|
|
373
|
+
indices every run is one cell, and the same cell count that costs the
|
|
374
|
+
parent eight calls on an outer axis cost it one per cell here. Collect
|
|
375
|
+
those and hand them over as a list. The value is the same for every
|
|
376
|
+
cell and the walk visits each cell once, so batching cannot change
|
|
377
|
+
which cells are written. */
|
|
358
378
|
ca_size_t count = n / c->bytes;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
379
|
+
if ( count == 1 ) {
|
|
380
|
+
c->window[c->nw++] = off / c->bytes;
|
|
381
|
+
if ( c->nw == CA_AXIS_FILL_ADDR_WINDOW ) {
|
|
382
|
+
ca_axis_dispatch_fill_flush(c);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
ca_size_t step = 1;
|
|
387
|
+
ca_fill_stride(c->parent, off / c->bytes, 1, &count, &step,
|
|
388
|
+
(void *) c->val);
|
|
389
|
+
}
|
|
362
390
|
}
|
|
363
391
|
else {
|
|
364
392
|
ca_axis_dispatch_fill_slab(c->parent_ptr + off, c->val, c->bytes, n);
|
|
@@ -895,6 +923,7 @@ ca_axis_dispatch_fill_value_via_parent (CArray *parent,
|
|
|
895
923
|
ca_axis_dispatch_for_each_slab(parent, parent_axis_dims, axes, ndim,
|
|
896
924
|
bytes, total_elements,
|
|
897
925
|
ca_axis_dispatch_fill_value_cb, &ctx);
|
|
926
|
+
ca_axis_dispatch_fill_flush(&ctx);
|
|
898
927
|
}
|
|
899
928
|
|
|
900
929
|
/* ==========================================================================
|