Skip to content

Commit 2a17361

Browse files
committed
feat: add 2d accessors implementation
1 parent 148d9d1 commit 2a17361

1 file changed

Lines changed: 220 additions & 0 deletions

File tree

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2026 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MAIN //
22+
23+
/**
24+
* Applies a condition to two two-dimensional input ndarrays according to a two-dimensional boolean ndarray and assigns results to elements in a two-dimensional output ndarray.
25+
*
26+
* @private
27+
* @param {Object} condition - object containing boolean condition ndarray meta data
28+
* @param {*} condition.dtype - data type
29+
* @param {Collection} condition.data - data buffer
30+
* @param {NonNegativeIntegerArray} condition.shape - dimensions
31+
* @param {IntegerArray} condition.strides - stride lengths
32+
* @param {NonNegativeInteger} condition.offset - index offset
33+
* @param {string} condition.order - specifies whether `condition` is row-major (C-style) or column-major (Fortran-style)
34+
* @param {Object} x - object containing input ndarray meta data
35+
* @param {*} x.dtype - data type
36+
* @param {Collection} x.data - data buffer
37+
* @param {NonNegativeIntegerArray} x.shape - dimensions
38+
* @param {IntegerArray} x.strides - stride lengths
39+
* @param {NonNegativeInteger} x.offset - index offset
40+
* @param {string} x.order - specifies whether `x` is row-major (C-style) or column-major (Fortran-style)
41+
* @param {Object} y - object containing input ndarray meta data
42+
* @param {*} y.dtype - data type
43+
* @param {Collection} y.data - data buffer
44+
* @param {NonNegativeIntegerArray} y.shape - dimensions
45+
* @param {IntegerArray} y.strides - stride lengths
46+
* @param {NonNegativeInteger} y.offset - index offset
47+
* @param {string} y.order - specifies whether `y` is row-major (C-style) or column-major (Fortran-style)
48+
* @param {Object} out - object containing output ndarray meta data
49+
* @param {*} out.dtype - data type
50+
* @param {Collection} out.data - data buffer
51+
* @param {NonNegativeIntegerArray} out.shape - dimensions
52+
* @param {IntegerArray} out.strides - stride lengths
53+
* @param {NonNegativeInteger} out.offset - index offset
54+
* @param {string} out.order - specifies whether `out` is row-major (C-style) or column-major (Fortran-style)
55+
* @param {boolean} isRowMajor - boolean indicating if provided arrays are in row-major order
56+
* @returns {void}
57+
*
58+
* @example
59+
* var Float64Array = require( '@stdlib/array/float64' );
60+
* var Uint8Array = require( '@stdlib/array/uint8' );
61+
*
62+
* // Create data buffers:
63+
* var cbuf = new Uint8Array( [ 1, 0, 0, 1 ] );
64+
* var xbuf = new Float64Array( [ 1.0, 2.0, 3.0, 4.0 ] );
65+
* var ybuf = new Float64Array( [ -1.0, -2.0, -3.0, -4.0 ] );
66+
* var obuf = new Float64Array( 4 );
67+
*
68+
* // Define the shape of the arrays:
69+
* var shape = [ 2, 2 ];
70+
*
71+
* // Define the array strides:
72+
* var sc = [ 2, 1 ];
73+
* var sx = [ 2, 1 ];
74+
* var sy = [ 2, 1 ];
75+
* var so = [ 2, 1 ];
76+
*
77+
* // Define the index offsets:
78+
* var oc = 0;
79+
* var ox = 0;
80+
* var oy = 0;
81+
* var oo = 0;
82+
*
83+
* // Create the ndarray-like objects:
84+
* var condition = {
85+
* 'dtype': 'uint8',
86+
* 'data': cbuf,
87+
* 'shape': shape,
88+
* 'strides': sc,
89+
* 'offset': oc,
90+
* 'order': 'row-major'
91+
* };
92+
* var x = {
93+
* 'dtype': 'float64',
94+
* 'data': xbuf,
95+
* 'shape': shape,
96+
* 'strides': sx,
97+
* 'offset': ox,
98+
* 'order': 'row-major'
99+
* };
100+
* var y = {
101+
* 'dtype': 'float64',
102+
* 'data': ybuf,
103+
* 'shape': shape,
104+
* 'strides': sy,
105+
* 'offset': oy,
106+
* 'order': 'row-major'
107+
* };
108+
* var out = {
109+
* 'dtype': 'float64',
110+
* 'data': obuf,
111+
* 'shape': shape,
112+
* 'strides': so,
113+
* 'offset': oo,
114+
* 'order': 'row-major'
115+
* };
116+
*
117+
* // Apply the condition:
118+
* where2d( condition, x, y, out, true );
119+
*
120+
* console.log( out.data );
121+
* // => <Float64Array>[ 1.0, -2.0, -3.0, 4.0 ]
122+
*/
123+
function where2d( condition, x, y, out, isRowMajor ) {
124+
var cbuf;
125+
var xbuf;
126+
var ybuf;
127+
var obuf;
128+
var dc0;
129+
var dc1;
130+
var dx0;
131+
var dx1;
132+
var dy0;
133+
var dy1;
134+
var do0;
135+
var do1;
136+
var sh;
137+
var S0;
138+
var S1;
139+
var sc;
140+
var sx;
141+
var sy;
142+
var so;
143+
var ic;
144+
var ix;
145+
var iy;
146+
var io;
147+
var i0;
148+
var i1;
149+
150+
// Note on variable naming convention: S#, dc#, dx#, dy#, do#, i# where # corresponds to the loop number, with `0` being the innermost loop...
151+
152+
// Extract loop variables for purposes of loop interchange: dimensions and loop offset (pointer) increments...
153+
sh = condition.shape;
154+
sc = condition.strides;
155+
sx = x.strides;
156+
sy = y.strides;
157+
so = out.strides;
158+
if ( isRowMajor ) {
159+
// For row-major ndarrays, the last dimensions have the fastest changing indices...
160+
S0 = sh[ 1 ];
161+
S1 = sh[ 0 ];
162+
dc0 = sc[ 1 ]; // offset increment for innermost loop
163+
dc1 = sc[ 0 ] - ( S0*sc[1] ); // offset increment for outermost loop
164+
dx0 = sx[ 1 ];
165+
dx1 = sx[ 0 ] - ( S0*sx[1] );
166+
dy0 = sy[ 1 ];
167+
dy1 = sy[ 0 ] - ( S0*sy[1] );
168+
do0 = so[ 1 ];
169+
do1 = so[ 0 ] - ( S0*so[1] );
170+
} else { // order === 'column-major'
171+
// For column-major ndarrays, the first dimensions have the fastest changing indices...
172+
S0 = sh[ 0 ];
173+
S1 = sh[ 1 ];
174+
dc0 = sc[ 0 ]; // offset increment for innermost loop
175+
dc1 = sc[ 1 ] - ( S0*sc[0] ); // offset increment for outermost loop
176+
dx0 = sx[ 0 ];
177+
dx1 = sx[ 1 ] - ( S0*sx[0] );
178+
dy0 = sy[ 0 ];
179+
dy1 = sy[ 1 ] - ( S0*sy[0] );
180+
do0 = so[ 0 ];
181+
do1 = so[ 1 ] - ( S0*so[0] );
182+
}
183+
// Set the pointers to the first indexed elements in the respective ndarrays...
184+
ic = condition.offset;
185+
ix = x.offset;
186+
iy = y.offset;
187+
io = out.offset;
188+
189+
// Cache references to the ndarray buffers...
190+
cbuf = condition.data;
191+
xbuf = x.data;
192+
ybuf = y.data;
193+
obuf = out.data;
194+
195+
// Cache accessors
196+
getx = x.accessors[ 0 ];
197+
gety = y.accessors[ 0 ];
198+
getc = condition.accessors[ 0 ];
199+
seto = out.accessors[ 1 ];
200+
201+
// Iterate over the ndarray dimensions...
202+
for ( i1 = 0; i1 < S1; i1++ ) {
203+
for ( i0 = 0; i0 < S0; i0++ ) {
204+
seto( obuf, io, ( getc( cbuf, ic ) ) ? getx( xbuf, ix ) : gety( ybuf, iy ) );
205+
ic += dc0;
206+
ix += dx0;
207+
iy += dy0;
208+
io += do0;
209+
}
210+
ic += dc1;
211+
ix += dx1;
212+
iy += dy1;
213+
io += do1;
214+
}
215+
}
216+
217+
218+
// EXPORTS //
219+
220+
module.exports = where2d;

0 commit comments

Comments
 (0)