main.c (3599B)
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/sub2ind.h" 20 #include "stdlib/ndarray/index_modes.h" 21 #include <stdint.h> 22 23 /** 24 * Converts subscripts to a linear index. 25 * 26 * ## Notes 27 * 28 * - When provided fewer modes than dimensions, the function recycles modes using modulo arithmetic. 29 * - When provided a stride array containing negative strides, if an `offset` is greater than `0`, the function treats subscripts as mapping to a linear index in an underlying data buffer for the array, thus returning a linear index from the perspective of that buffer. If an `offset` is equal to `0`, the function treats subscripts as mapping to a linear index in an array view, thus returning a linear index from the perspective of that view. In short, from the perspective of a view, view data is always ordered. 30 * - In "error" mode, the function returns `-1` if a subscript is out-of-bounds. 31 * 32 * @param ndims number of dimensions 33 * @param shape array shape (dimensions) 34 * @param strides array strides 35 * @param offset location of the first indexed value **based** on the stride array 36 * @param sub subscripts 37 * @param nmodes number of modes 38 * @param modes specifies how to handle subscripts which exceed array dimensions 39 * @return linear index 40 * 41 * @example 42 * #include "stdlib/ndarray/index_modes.h" 43 * #include "stdlib/ndarray/base/sub2ind.h" 44 * 45 * int64_t ndims = 3; 46 * int64_t shape[] = { 3, 3, 3 }; 47 * int64_t strides[] = { 9, 3, 1 }; 48 * int64_t offset = 0; 49 * 50 * int64_t nmodes = 1; 51 * int8_t modes[] = { STDLIB_NDARRAY_INDEX_ERROR }; 52 * 53 * int64_t sub[] = { 1, 2, 2 }; 54 * 55 * int64_t idx = stdlib_ndarray_sub2ind( ndims, shape, strides, offset, sub, nmodes, modes ); 56 * // returns 17 57 */ 58 int64_t stdlib_ndarray_sub2ind( int64_t ndims, int64_t *shape, int64_t *strides, int64_t offset, int64_t *sub, int64_t nmodes, int8_t *modes ) { 59 enum STDLIB_NDARRAY_INDEX_MODE mode; 60 int64_t idx; 61 int64_t s; 62 int64_t m; 63 int64_t j; 64 int64_t i; 65 66 idx = offset; 67 for ( i = 0; i < ndims; i++ ) { 68 m = shape[ i ]; 69 j = sub[ i ]; 70 mode = modes[ i%nmodes ]; 71 if ( mode == STDLIB_NDARRAY_INDEX_CLAMP ) { 72 if ( j < 0 ) { 73 j = 0; 74 } else if ( j >= m ) { 75 j = m - 1; 76 } 77 } else if ( mode == STDLIB_NDARRAY_INDEX_WRAP ) { 78 if ( j < 0 ) { 79 j += m; // slight optimization to avoid modulo arithmetic when |j| <= m 80 if ( j < 0 ) { 81 j -= m*( (int64_t)( j/m ) ); // this is equivalent to `j mod m`, where the result has same sign as dividend (i.e., `j`); cannot use `%` as the sign of the result is implementation defined in C 82 if ( j != 0 ) { 83 j += m; 84 } 85 } 86 } else if ( j >= m ) { 87 j -= m; // slight optimization to avoid modulo arithmetic when m < j <= 2m 88 if ( j >= m ) { 89 j %= m; 90 } 91 } 92 } else if ( j < 0 || j >= m ) { // mode == 'error' 93 return -1; 94 } 95 s = strides[ i ]; 96 97 // Check if array view... 98 if ( s < 0 && offset == 0 ) { 99 idx -= j * s; // increments idx 100 } else { 101 idx += j * s; // may increment or decrement idx 102 } 103 } 104 return idx; 105 }