main.c (3508B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 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 #include "stdlib/ndarray/base/vind2bind.h" 20 #include "stdlib/ndarray/index_modes.h" 21 #include "stdlib/ndarray/orders.h" 22 #include <stdint.h> 23 24 /** 25 * Converts a linear index in an array view to a linear index in an underlying data buffer. 26 * 27 * ## Notes 28 * 29 * - In "error" mode, the function returns `-1` if an index is out-of-bounds. 30 * 31 * @param ndims number of dimensions 32 * @param shape array shape (dimensions) 33 * @param strides array strides 34 * @param offset location of the first indexed value **based** on the stride array 35 * @param order specifies whether an array is row-major (C-style) or column-major (Fortran-style) 36 * @param idx linear index in an array view 37 * @param mode specifies how to handle a linear index which exceeds array dimensions 38 * @return index 39 * 40 * @example 41 * #include "stdlib/ndarray/base/vind2bind.h" 42 * #include "stdlib/ndarray/index_modes.h" 43 * #include "stdlib/ndarray/orders.h" 44 * 45 * int64_t ndims = 2; 46 * int64_t shape[] = { 3, 3 }; 47 * int64_t strides[] = { -3, 1 }; 48 * int64_t offset = 6; 49 * 50 * int64_t idx = stdlib_ndarray_vind2bind( ndims, shape, strides, offset, STDLIB_NDARRAY_ROW_MAJOR, 1, STDLIB_NDARRAY_INDEX_ERROR ); 51 * // returns 7 52 */ 53 int64_t stdlib_ndarray_vind2bind( int64_t ndims, int64_t *shape, int64_t *strides, int64_t offset, enum STDLIB_NDARRAY_ORDER order, int64_t idx, enum STDLIB_NDARRAY_INDEX_MODE mode ) { 54 int64_t len; 55 int64_t ind; 56 int64_t s; 57 int64_t i; 58 59 len = 1; 60 for ( i = 0; i < ndims; i++ ) { 61 len *= shape[ i ]; 62 } 63 if ( mode == STDLIB_NDARRAY_INDEX_CLAMP ) { 64 if ( idx < 0 ) { 65 idx = 0; 66 } else if ( idx >= len ) { 67 idx = len - 1; 68 } 69 } else if ( mode == STDLIB_NDARRAY_INDEX_WRAP ) { 70 if ( idx < 0 ) { 71 idx += len; // slight optimization to avoid modulo arithmetic when |idx| <= len 72 if ( idx < 0 ) { 73 idx -= len*( (int64_t)( idx/len ) ); // this is equivalent to `idx mod len`, where the result has same sign as dividend (i.e., `idx`); cannot use `%` as the sign of the result is implementation defined in C 74 if ( idx != 0 ) { 75 idx += len; 76 } 77 } 78 } else if ( idx >= len ) { 79 idx -= len; // slight optimization to avoid modulo arithmetic when len < idx <= 2*len 80 if ( idx >= len ) { 81 idx %= len; 82 } 83 } 84 } else if ( idx < 0 || idx >= len ) { 85 return -1; 86 } 87 // The approach which follows is to resolve a view index to its subscripts and then plug the subscripts into the standard formula for computing the linear index in the underlying data buffer... 88 ind = offset; 89 if ( order == STDLIB_NDARRAY_COLUMN_MAJOR ) { 90 for ( i = 0; i < ndims; i++ ) { 91 s = idx % shape[ i ]; // assume nonnegative "shape" 92 idx -= s; 93 idx /= shape[ i ]; 94 ind += s * strides[ i ]; 95 } 96 return ind; 97 } 98 // Case: row-major 99 for ( i = ndims-1; i >= 0; i-- ) { 100 s = idx % shape[ i ]; // assume nonnegative "shape" 101 idx -= s; 102 idx /= shape[ i ]; 103 ind += s * strides[ i ]; 104 } 105 return ind; 106 }