|
20 | 20 |
|
21 | 21 | // MODULES // |
22 | 22 |
|
23 | | -var base = require( './base.js' ); |
| 23 | +var isRowMajor = require( '@stdlib/ndarray/base/assert/is-row-major' ); |
| 24 | +var arraylike2object = require( '@stdlib/array/base/arraylike2object' ); |
| 25 | +var ones = require( '@stdlib/array/base/ones' ); |
| 26 | +var accessors = require( './accessors.js' ); |
24 | 27 |
|
25 | 28 |
|
26 | 29 | // MAIN // |
@@ -51,7 +54,85 @@ var base = require( './base.js' ); |
51 | 54 | * // returns 2 |
52 | 55 | */ |
53 | 56 | function glastIndexOfRow( M, N, A, strideA1, strideA2, offsetA, x, strideX, offsetX ) { // eslint-disable-line max-len |
54 | | - return base( M, N, A, strideA1, strideA2, offsetA, x, strideX, offsetX ); |
| 57 | + var matches; |
| 58 | + var da0; |
| 59 | + var da1; |
| 60 | + var S0; |
| 61 | + var S1; |
| 62 | + var ia; |
| 63 | + var ix; |
| 64 | + var i0; |
| 65 | + var i1; |
| 66 | + var oa; |
| 67 | + var ox; |
| 68 | + |
| 69 | + // Check whether the matrix is an empty matrix... |
| 70 | + if ( M <= 0 || N <= 0 ) { |
| 71 | + return -1; |
| 72 | + } |
| 73 | + oa = arraylike2object( A ); |
| 74 | + ox = arraylike2object( x ); |
| 75 | + if ( oa.accessorProtocol || ox.accessorProtocol ) { |
| 76 | + return accessors( M, N, oa, strideA1, strideA2, offsetA, ox, strideX, offsetX ); // eslint-disable-line max-len |
| 77 | + } |
| 78 | + // Search for the last row matching the search vector... |
| 79 | + if ( isRowMajor( [ strideA1, strideA2 ] ) ) { |
| 80 | + S0 = N; |
| 81 | + S1 = M; |
| 82 | + |
| 83 | + // Scan a row-major linear buffer from the last indexed element to the first indexed element, always moving in the same direction when both strides are the same sign, thus ensuring cache optimal traversal... |
| 84 | + for ( i1 = S1-1; i1 >= 0; i1-- ) { |
| 85 | + ia = offsetA + ( i1*strideA1 ) + ( (S0-1)*strideA2 ); |
| 86 | + ix = offsetX + ( (S0-1)*strideX ); |
| 87 | + for ( i0 = S0-1; i0 >= 0; i0-- ) { |
| 88 | + if ( A[ ia ] !== x[ ix ] ) { |
| 89 | + // We found an element which is not in the search vector... |
| 90 | + break; |
| 91 | + } |
| 92 | + ia -= strideA2; |
| 93 | + ix -= strideX; |
| 94 | + } |
| 95 | + // If we successfully iterated over all columns, then that means we've found a match... |
| 96 | + if ( i0 === -1 ) { |
| 97 | + return i1; |
| 98 | + } |
| 99 | + } |
| 100 | + // If we've made it here, then no rows match the search vector: |
| 101 | + return -1; |
| 102 | + } |
| 103 | + // Column-major... |
| 104 | + S0 = M; |
| 105 | + S1 = N; |
| 106 | + |
| 107 | + // Resolve loop offset (pointer) increments: |
| 108 | + da0 = -strideA1; |
| 109 | + da1 = ( S0*strideA1 ) - strideA2; |
| 110 | + |
| 111 | + // Create an array for tracking which rows contain matching elements: |
| 112 | + matches = ones( M ); |
| 113 | + |
| 114 | + // Finding the last matching row when a matrix is stored in column-major order requires effectively performing a full linear scan. In order to ensure cache-efficient traversal, scan up each column (otherwise, if we went row-by-row, we'd hop around linear memory, resulting in poor cache behavior)... |
| 115 | + ia = offsetA + ( (S0-1)*strideA1 ) + ( (S1-1)*strideA2 ); |
| 116 | + ix = offsetX + ( (S1-1)*strideX ); |
| 117 | + for ( i1 = S1-1; i1 >= 0; i1-- ) { |
| 118 | + // Scan up the rows in a column looking for a matching element... |
| 119 | + for ( i0 = S0-1; i0 >= 0; i0-- ) { |
| 120 | + if ( A[ ia ] !== x[ ix ] ) { |
| 121 | + // We found a non-matching element, which means we can exclude this row from the list of row candidates... |
| 122 | + matches[ i0 ] = 0; |
| 123 | + } |
| 124 | + ia += da0; |
| 125 | + } |
| 126 | + ia += da1; |
| 127 | + ix -= strideX; |
| 128 | + } |
| 129 | + // Search for the last matching row... |
| 130 | + for ( i0 = S0-1; i0 >= 0; i0-- ) { |
| 131 | + if ( matches[ i0 ] === 1 ) { |
| 132 | + break; |
| 133 | + } |
| 134 | + } |
| 135 | + return i0; |
55 | 136 | } |
56 | 137 |
|
57 | 138 |
|
|
0 commit comments