480 lines
19 KiB
C
480 lines
19 KiB
C
/*
|
|
MIT License
|
|
*
|
|
* Copyright (c) 2025 Tyge Løvset
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
/*
|
|
#include <stdio.h>
|
|
#include <stc/cspan.h>
|
|
#include <stc/algorithm.h>
|
|
use_cspan(Span2f, float, 2);
|
|
use_cspan(Intspan, int);
|
|
|
|
int demo1() {
|
|
float raw[4*5];
|
|
Span2f ms = cspan_md(raw, 4, 5);
|
|
|
|
for (int i=0; i<ms.shape[0]; i++)
|
|
for (int j=0; j<ms.shape[1]; j++)
|
|
*cspan_at(&ms, i, j) = i*1000 + j;
|
|
|
|
printf("%f\n", *cspan_at(&ms, 3, 4));
|
|
}
|
|
|
|
int demo2() {
|
|
int array[] = {10, 20, 30, 23, 22, 21};
|
|
Intspan span = cspan_from_array(array);
|
|
|
|
for (c_each(i, Intspan, span))
|
|
printf(" %d", *i.ref);
|
|
puts("");
|
|
|
|
c_filter(Intspan, span
|
|
, c_flt_skipwhile(*value < 25)
|
|
&& (*value & 1) == 0 // even only
|
|
&& (printf(" %d", *value),
|
|
c_flt_take(2))
|
|
);
|
|
puts("");
|
|
}
|
|
*/
|
|
#define i_header
|
|
#include "priv/linkage.h"
|
|
|
|
#ifndef STC_CSPAN_H_INCLUDED
|
|
#define STC_CSPAN_H_INCLUDED
|
|
#include "common.h"
|
|
#ifndef STC_CSPAN_INDEX_TYPE
|
|
#define STC_CSPAN_INDEX_TYPE int32_t
|
|
#endif
|
|
typedef STC_CSPAN_INDEX_TYPE _istride;
|
|
|
|
#define using_cspan use_cspan // [deprecated]
|
|
#define using_cspan2 use_cspan2 // [deprecated]
|
|
#define using_cspan3 use_cspan3 // [deprecated]
|
|
#define using_cspan2_with_eq use_cspan2_with_eq // [deprecated]
|
|
#define using_cspan3_with_eq use_cspan3_with_eq // [deprecated]
|
|
|
|
#define use_cspan(...) c_MACRO_OVERLOAD(use_cspan, __VA_ARGS__)
|
|
#define use_cspan_2(Self, T) \
|
|
use_cspan_3(Self, T, 1); \
|
|
STC_INLINE Self Self##_from_n(Self##_value* dataptr, isize n) \
|
|
{ return (Self)cspan_from_n(dataptr, n); } \
|
|
STC_INLINE const Self##_value* Self##_at(const Self* self, isize idx) \
|
|
{ return cspan_at(self, idx); } \
|
|
STC_INLINE Self##_value* Self##_at_mut(Self* self, isize idx) \
|
|
{ return cspan_at(self, idx); } \
|
|
struct stc_nostruct
|
|
|
|
#define use_cspan_with_eq(...) c_MACRO_OVERLOAD(use_cspan_with_eq, __VA_ARGS__)
|
|
#define use_cspan_with_eq_3(Self, T, i_eq) \
|
|
use_cspan_with_eq_4(Self, T, i_eq, 1); \
|
|
STC_INLINE Self Self##_from_n(Self##_value* dataptr, isize n) \
|
|
{ return (Self)cspan_from_n(dataptr, n); } \
|
|
struct stc_nostruct
|
|
|
|
#define use_cspan_3(Self, T, RANK) \
|
|
typedef T Self##_value; \
|
|
typedef T Self##_raw; \
|
|
typedef struct { \
|
|
Self##_value *data; \
|
|
_istride shape[RANK]; \
|
|
cspan_tuple##RANK stride; \
|
|
} Self; \
|
|
\
|
|
typedef struct { \
|
|
Self##_value *ref; \
|
|
const Self *_s; \
|
|
_istride pos[RANK]; \
|
|
} Self##_iter; \
|
|
\
|
|
STC_INLINE Self Self##_slice_(Self##_value* d, const _istride shape[], const _istride stri[], \
|
|
const isize args[][3], const int rank) { \
|
|
Self s; int outrank; \
|
|
s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, args, rank); \
|
|
c_assert(outrank == RANK); \
|
|
return s; \
|
|
} \
|
|
STC_INLINE Self##_iter Self##_begin(const Self* self) { \
|
|
return c_literal(Self##_iter){ \
|
|
.ref=RANK==1 && self->shape[0]==0 ? NULL : self->data, ._s=self}; \
|
|
} \
|
|
STC_INLINE Self##_iter Self##_end(const Self* self) { \
|
|
(void)self; \
|
|
return c_literal(Self##_iter){0}; \
|
|
} \
|
|
STC_INLINE void Self##_next(Self##_iter* it) { \
|
|
isize off = it->_s->stride.d[RANK - 1]; \
|
|
bool done = _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, &off); \
|
|
if (done) it->ref = NULL; else it->ref += off; \
|
|
} \
|
|
STC_INLINE isize Self##_size(const Self* self) \
|
|
{ return cspan_size(self); } \
|
|
STC_INLINE Self Self##_transposed(Self sp) \
|
|
{ _cspan_transpose(sp.shape, sp.stride.d, cspan_rank(&sp)); return sp; } \
|
|
STC_INLINE Self Self##_swapped_axes(Self sp, int ax1, int ax2) \
|
|
{ _cspan_swap_axes(sp.shape, sp.stride.d, cspan_rank(&sp), ax1, ax2); return sp; } \
|
|
struct stc_nostruct
|
|
|
|
#define use_cspan_with_eq_4(Self, T, i_eq, RANK) \
|
|
use_cspan_3(Self, T, RANK); \
|
|
STC_INLINE bool Self##_eq(const Self* x, const Self* y) { \
|
|
if (memcmp(x->shape, y->shape, sizeof x->shape) != 0) \
|
|
return false; \
|
|
for (Self##_iter _i = Self##_begin(x), _j = Self##_begin(y); \
|
|
_i.ref != NULL; Self##_next(&_i), Self##_next(&_j)) \
|
|
{ if (!(i_eq(_i.ref, _j.ref))) return false; } \
|
|
return true; \
|
|
} \
|
|
STC_INLINE bool Self##_equals(Self sp1, Self sp2) \
|
|
{ return Self##_eq(&sp1, &sp2); } \
|
|
struct stc_nostruct
|
|
|
|
#define use_cspan2(Self, T) use_cspan_2(Self, T); use_cspan_3(Self##2, T, 2)
|
|
#define use_cspan3(Self, T) use_cspan2(Self, T); use_cspan_3(Self##3, T, 3)
|
|
#define use_cspan2_with_eq(Self, T, eq) use_cspan_with_eq_3(Self, T, eq); \
|
|
use_cspan_with_eq_4(Self##2, T, eq, 2)
|
|
#define use_cspan3_with_eq(Self, T, eq) use_cspan2_with_eq(Self, T, eq); \
|
|
use_cspan_with_eq_4(Self##3, T, eq, 3)
|
|
#define use_cspan_tuple(N) typedef struct { _istride d[N]; } cspan_tuple##N
|
|
use_cspan_tuple(1); use_cspan_tuple(2);
|
|
use_cspan_tuple(3); use_cspan_tuple(4);
|
|
use_cspan_tuple(5); use_cspan_tuple(6);
|
|
use_cspan_tuple(7); use_cspan_tuple(8);
|
|
|
|
|
|
// Construct a cspan from a pointer+size
|
|
#define cspan_from_n(dataptr, n) \
|
|
{.data=dataptr, \
|
|
.shape={(_istride)(n)}, \
|
|
.stride=c_literal(cspan_tuple1){.d={1}}}
|
|
|
|
// Create a 1d-span in the local lexical scope. N must be a compile-time constant.
|
|
#define cspan_by_copy(dataptr, N) \
|
|
cspan_from_n(memcpy((char[(N)*sizeof *(dataptr)]){0}, dataptr, (N)*sizeof *(dataptr)), N)
|
|
|
|
// Create a zeroed out 1d-span in the local lexical scope. N must be a compile-time constant.
|
|
#define cspan_zeros(Span, N) \
|
|
((Span)cspan_from_n((Span##_value[N]){0}, N))
|
|
|
|
// Create a global scope 1d-span from constant initializer list, otherwise like c_make(Span, ...).
|
|
#define cspan_make(Span, ...) \
|
|
((Span)cspan_from_n(c_make_array(Span##_value, __VA_ARGS__), \
|
|
sizeof((Span##_value[])__VA_ARGS__)/sizeof(Span##_value)))
|
|
|
|
// Make 1d-span from a c-array.
|
|
#define cspan_from_array(array) \
|
|
cspan_from_n(array, c_arraylen(array))
|
|
|
|
// Make 1d-span from a vec or stack container.
|
|
#define cspan_from_vec(container) \
|
|
cspan_from_n((container)->data, (container)->size)
|
|
|
|
// Make a 1d-sub-span from a 1d-span
|
|
#define cspan_subspan(self, offset, count) \
|
|
{.data=cspan_at(self, offset), \
|
|
.shape={(_istride)(count)}, \
|
|
.stride=(self)->stride}
|
|
|
|
// Accessors
|
|
//
|
|
#define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self))
|
|
#define cspan_rank(self) c_arraylen((self)->shape) // constexpr
|
|
#define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__))
|
|
#define cspan_front(self) ((self)->data)
|
|
#define cspan_back(self) ((self)->data + cspan_size(self) - 1)
|
|
|
|
#define cspan_index(...) cspan_index_fn(__VA_ARGS__, c_COMMA_N(cspan_index_3d), c_COMMA_N(cspan_index_2d), \
|
|
c_COMMA_N(cspan_index_1d),)(__VA_ARGS__)
|
|
#define cspan_index_fn(self, i,j,k,n, ...) c_TUPLE_AT_1(n, cspan_index_nd,)
|
|
#define cspan_index_1d(self, i) (c_static_assert(cspan_rank(self) == 1), \
|
|
c_assert((i) < (self)->shape[0]), \
|
|
(i)*(self)->stride.d[0])
|
|
#define cspan_index_2d(self, i,j) (c_static_assert(cspan_rank(self) == 2), \
|
|
c_assert((i) < (self)->shape[0] && (j) < (self)->shape[1]), \
|
|
(i)*(self)->stride.d[0] + (j)*(self)->stride.d[1])
|
|
#define cspan_index_3d(self, i,j,k) (c_static_assert(cspan_rank(self) == 3), \
|
|
c_assert((i) < (self)->shape[0] && (j) < (self)->shape[1] && (k) < (self)->shape[2]), \
|
|
(i)*(self)->stride.d[0] + (j)*(self)->stride.d[1] + (k)*(self)->stride.d[2])
|
|
#define cspan_index_nd(self, ...) _cspan_index((self)->shape, (self)->stride.d, c_make_array(isize, {__VA_ARGS__}), \
|
|
(c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__)), cspan_rank(self)))
|
|
|
|
|
|
// Multi-dimensional span constructors
|
|
//
|
|
typedef enum {c_ROWMAJOR, c_COLMAJOR, c_STRIDED} cspan_layout;
|
|
|
|
#define cspan_is_colmajor(self) \
|
|
_cspan_is_layout(c_COLMAJOR, (self)->shape, (self)->stride.d, cspan_rank(self))
|
|
#define cspan_is_rowmajor(self) \
|
|
_cspan_is_layout(c_ROWMAJOR, (self)->shape, (self)->stride.d, cspan_rank(self))
|
|
#define cspan_get_layout(self) \
|
|
(cspan_is_rowmajor(self) ? c_ROWMAJOR : cspan_is_colmajor(self) ? c_COLMAJOR : c_STRIDED)
|
|
|
|
#define cspan_md(dataptr, ...) \
|
|
cspan_md_layout(c_ROWMAJOR, dataptr, __VA_ARGS__)
|
|
|
|
// Span2 sp1 = cspan_md(data, 30, 50);
|
|
// Span2 sp2 = {data, cspan_shape(15, 25), cspan_strides(50*2, 2)}; // every second in each dim
|
|
#define cspan_shape(...) {__VA_ARGS__}
|
|
#define cspan_strides(...) {.d={__VA_ARGS__}}
|
|
|
|
#define cspan_md_layout(layout, dataptr, ...) \
|
|
{.data=dataptr, \
|
|
.shape={__VA_ARGS__}, \
|
|
.stride=*(c_JOIN(cspan_tuple,c_NUMARGS(__VA_ARGS__))*) \
|
|
_cspan_shape2stride(layout, c_make_array(_istride, {__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))}
|
|
|
|
// Transpose matrix
|
|
#define cspan_transpose(self) \
|
|
_cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self))
|
|
|
|
// Swap two matrix axes
|
|
#define cspan_swap_axes(self, ax1, ax2) \
|
|
_cspan_swap_axes((self)->shape, (self)->stride.d, cspan_rank(self), ax1, ax2)
|
|
|
|
// Set all span elements to value.
|
|
#define cspan_set_all(Span, self, value) do { \
|
|
Span##_value _v = value; \
|
|
for (c_each_3(_it, Span, *(self))) *_it.ref = _v; \
|
|
} while (0)
|
|
|
|
// General slicing function.
|
|
//
|
|
#define c_END (_istride)(((size_t)1 << (sizeof(_istride)*8 - 1)) - 1)
|
|
#define c_ALL 0,c_END
|
|
|
|
#define cspan_slice(self, Outspan, ...) \
|
|
Outspan##_slice_((self)->data, (self)->shape, (self)->stride.d, \
|
|
c_make_array2d(const isize, 3, {__VA_ARGS__}), \
|
|
(c_static_assert(cspan_rank(self) == sizeof((isize[][3]){__VA_ARGS__})/sizeof(isize[3])), cspan_rank(self)))
|
|
|
|
// submd#(): Reduces rank, fully typesafe + range checked by default
|
|
// int ms3[N1][N2][N3];
|
|
// int (*ms2)[N3] = ms3[1]; // traditional, lose range test/info. VLA.
|
|
// Span3 ms3 = cspan_md(data, N1,N2,N3); // Uses cspan_md instead.
|
|
// *cspan_at(&ms3, 1,1,1) = 42;
|
|
// Span2 ms2 = cspan_slice(&ms3, Span2, {1}, {c_ALL}, {c_ALL});
|
|
// Span2 ms2 = cspan_submd3(&ms3, 1); // Same as line above, optimized.
|
|
#define cspan_submd2(self, x) \
|
|
{.data=cspan_at(self, x, 0), \
|
|
.shape={(self)->shape[1]}, \
|
|
.stride=c_literal(cspan_tuple1){.d={(self)->stride.d[1]}}}
|
|
|
|
#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__)
|
|
#define cspan_submd3_2(self, x) \
|
|
{.data=cspan_at(self, x, 0, 0), \
|
|
.shape={(self)->shape[1], (self)->shape[2]}, \
|
|
.stride=c_literal(cspan_tuple2){.d={(self)->stride.d[1], (self)->stride.d[2]}}}
|
|
#define cspan_submd3_3(self, x, y) \
|
|
{.data=cspan_at(self, x, y, 0), \
|
|
.shape={(self)->shape[2]}, \
|
|
.stride=c_literal(cspan_tuple1){.d={(self)->stride.d[2]}}}
|
|
|
|
#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__)
|
|
#define cspan_submd4_2(self, x) \
|
|
{.data=cspan_at(self, x, 0, 0, 0), \
|
|
.shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \
|
|
.stride=c_literal(cspan_tuple3){.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}}
|
|
#define cspan_submd4_3(self, x, y) \
|
|
{.data=cspan_at(self, x, y, 0, 0), \
|
|
.shape={(self)->shape[2], (self)->shape[3]}, \
|
|
.stride=c_literal(cspan_tuple2){.d={(self)->stride.d[2], (self)->stride.d[3]}}}
|
|
#define cspan_submd4_4(self, x, y, z) \
|
|
{.data=cspan_at(self, x, y, z, 0), \
|
|
.shape={(self)->shape[3]}, \
|
|
.stride=c_literal(cspan_tuple1){.d={(self)->stride.d[3]}}}
|
|
|
|
#define cspan_print(...) c_MACRO_OVERLOAD(cspan_print, __VA_ARGS__)
|
|
#define cspan_print_3(Span, fmt, span) \
|
|
cspan_print_4(Span, fmt, span, stdout)
|
|
#define cspan_print_4(Span, fmt, span, fp) \
|
|
cspan_print_5(Span, fmt, span, fp, "[]")
|
|
#define cspan_print_5(Span, fmt, span, fp, brackets) \
|
|
cspan_print_6(Span, fmt, span, fp, brackets, c_EXPAND)
|
|
#define cspan_print_complex(Span, prec, span, fp) \
|
|
cspan_print_6(Span, "%." #prec "f%+." #prec "fi", span, fp, "[]", cspan_CMPLX_FLD)
|
|
#define cspan_CMPLX_FLD(x) creal(x), cimag(x)
|
|
|
|
#define cspan_print_6(Span, fmt, span, fp, brackets, field) do { \
|
|
const Span _s = span; \
|
|
const char *_f = fmt, *_b = brackets; \
|
|
FILE* _fp = fp; \
|
|
int _w, _max = 0; \
|
|
char _res[2][20], _fld[64]; \
|
|
for (c_each_3(_it, Span, _s)) { \
|
|
_w = snprintf(NULL, 0ULL, _f, field(_it.ref[0])); \
|
|
if (_w > _max) _max = _w; \
|
|
} \
|
|
for (c_each_3(_it, Span, _s)) { \
|
|
_cspan_print_assist(_it.pos, _s.shape, cspan_rank(&_s), _b, _res); \
|
|
_w = _max + (_it.pos[cspan_rank(&_s) - 1] > 0); \
|
|
snprintf(_fld, sizeof _fld, _f, field(_it.ref[0])); \
|
|
fprintf(_fp, "%s%*s%s", _res[0], _w, _fld, _res[1]); \
|
|
} \
|
|
} while (0)
|
|
|
|
/* ----- PRIVATE ----- */
|
|
|
|
STC_INLINE isize _cspan_size(const _istride shape[], int rank) {
|
|
isize size = shape[0];
|
|
while (--rank) size *= shape[rank];
|
|
return size;
|
|
}
|
|
|
|
STC_INLINE void _cspan_swap_axes(_istride shape[], _istride stride[],
|
|
int rank, int ax1, int ax2) {
|
|
(void)rank;
|
|
c_assert(c_uless(ax1, rank) & c_uless(ax2, rank));
|
|
c_swap(shape + ax1, shape + ax2);
|
|
c_swap(stride + ax1, stride + ax2);
|
|
}
|
|
|
|
STC_INLINE void _cspan_transpose(_istride shape[], _istride stride[], int rank) {
|
|
for (int i = 0; i < --rank; ++i) {
|
|
c_swap(shape + i, shape + rank);
|
|
c_swap(stride + i, stride + rank);
|
|
}
|
|
}
|
|
|
|
STC_INLINE isize _cspan_index(const _istride shape[], const _istride stride[],
|
|
const isize args[], int rank) {
|
|
isize off = 0;
|
|
(void)shape;
|
|
while (rank-- != 0) {
|
|
c_assert(args[rank] < shape[rank]);
|
|
off += args[rank]*stride[rank];
|
|
}
|
|
return off;
|
|
}
|
|
|
|
STC_API void _cspan_print_assist(_istride pos[], const _istride shape[], const int rank,
|
|
const char* brackets, char result[2][20]);
|
|
|
|
STC_API bool _cspan_nextN(_istride pos[], const _istride shape[], const _istride stride[],
|
|
int rank, isize* off);
|
|
#define _cspan_next1(pos, shape, stride, rank, off) (++pos[0] == shape[0])
|
|
#define _cspan_next2(pos, shape, stride, rank, off) (++pos[1] == shape[1] && \
|
|
(pos[1] = 0, *off += stride[0] - (isize)shape[1]*stride[1], ++pos[0] == shape[0]))
|
|
#define _cspan_next3(pos, shape, stride, rank, off) (++pos[2] == shape[2] && \
|
|
(pos[2] = 0, *off += stride[1] - (isize)shape[2]*stride[2], ++pos[1] == shape[1]) && \
|
|
(pos[1] = 0, *off += stride[0] - (isize)shape[1]*stride[1], ++pos[0] == shape[0]))
|
|
#define _cspan_next4 _cspan_nextN
|
|
#define _cspan_next5 _cspan_nextN
|
|
#define _cspan_next6 _cspan_nextN
|
|
#define _cspan_next7 _cspan_nextN
|
|
#define _cspan_next8 _cspan_nextN
|
|
|
|
STC_API isize _cspan_slice(_istride oshape[], _istride ostride[], int* orank,
|
|
const _istride shape[], const _istride stride[],
|
|
const isize args[][3], int rank);
|
|
STC_API _istride* _cspan_shape2stride(cspan_layout layout, _istride shape[], int rank);
|
|
STC_API bool _cspan_is_layout(cspan_layout layout, const _istride shape[], const _istride strides[], int rank);
|
|
|
|
#endif // STC_CSPAN_H_INCLUDED
|
|
|
|
/* --------------------- IMPLEMENTATION --------------------- */
|
|
#if defined i_implement
|
|
|
|
STC_DEF bool _cspan_is_layout(cspan_layout layout, const _istride shape[], const _istride strides[], int rank) {
|
|
_istride tmpshape[16]; // 16 = "max" rank
|
|
size_t sz = (size_t)rank*sizeof(_istride);
|
|
memcpy(tmpshape, shape, sz);
|
|
return memcmp(strides, _cspan_shape2stride(layout, tmpshape, rank), sz) == 0;
|
|
}
|
|
|
|
STC_DEF void _cspan_print_assist(_istride pos[], const _istride shape[], const int rank,
|
|
const char* brackets, char result[2][20]) {
|
|
int n = 0, j = 0, r = rank - 1;
|
|
memset(result, 0, 32);
|
|
|
|
// left braces:
|
|
while (n <= r && pos[r - n] == 0)
|
|
++n;
|
|
if (n) for (; j < rank; ++j)
|
|
result[0][j] = j < rank - n ? ' ' : brackets[0];
|
|
|
|
// right braces:
|
|
for (j = 0; r >= 0 && pos[r] + 1 == shape[r]; --r, ++j)
|
|
result[1][j] = brackets[1];
|
|
|
|
// comma and newlines:
|
|
n = (j > 0) + ((j > 1) & (j < rank));
|
|
if (brackets[2] && j < rank)
|
|
result[1][j++] = brackets[2]; // comma
|
|
while (n--)
|
|
result[1][j++] = '\n';
|
|
}
|
|
|
|
STC_DEF bool _cspan_nextN(_istride pos[], const _istride shape[], const _istride stride[],
|
|
int rank, isize* off) {
|
|
++pos[--rank];
|
|
for (; rank && pos[rank] == shape[rank]; --rank) {
|
|
pos[rank] = 0; ++pos[rank - 1];
|
|
*off += stride[rank - 1] - (isize)shape[rank]*stride[rank];
|
|
}
|
|
return pos[rank] == shape[rank];
|
|
}
|
|
|
|
STC_DEF _istride* _cspan_shape2stride(cspan_layout layout, _istride shpstri[], int rank) {
|
|
int i, inc;
|
|
if (layout == c_COLMAJOR) i = 0, inc = 1;
|
|
else i = rank - 1, inc = -1;
|
|
_istride k = 1, s1 = shpstri[i], s2;
|
|
|
|
shpstri[i] = 1;
|
|
while (--rank) {
|
|
i += inc;
|
|
s2 = shpstri[i];
|
|
shpstri[i] = (k *= s1);
|
|
s1 = s2;
|
|
}
|
|
return shpstri;
|
|
}
|
|
|
|
STC_DEF isize _cspan_slice(_istride oshape[], _istride ostride[], int* orank,
|
|
const _istride shape[], const _istride stride[],
|
|
const isize args[][3], int rank) {
|
|
isize end, off = 0;
|
|
int i = 0, oi = 0;
|
|
|
|
for (; i < rank; ++i) {
|
|
off += args[i][0]*stride[i];
|
|
switch (args[i][1]) {
|
|
case 0: c_assert(c_uless(args[i][0], shape[i])); continue;
|
|
case c_END: end = shape[i]; break;
|
|
default: end = args[i][1];
|
|
}
|
|
oshape[oi] = (_istride)(end - args[i][0]);
|
|
ostride[oi] = stride[i];
|
|
c_assert((oshape[oi] > 0) & !c_uless(shape[i], end));
|
|
if (args[i][2] > 0) {
|
|
ostride[oi] *= (_istride)args[i][2];
|
|
oshape[oi] = (oshape[oi] - 1)/(_istride)args[i][2] + 1;
|
|
}
|
|
++oi;
|
|
}
|
|
*orank = oi;
|
|
return off;
|
|
}
|
|
#endif // IMPLEMENT
|
|
#include "priv/linkage2.h"
|