summaryrefslogtreecommitdiffhomepage
path: root/docs/cspan_api.md
blob: 616b090e432ed4f7cb09165da25a02cf15561213 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# STC [cspan](../include/stc/cspan.h): Multi-dimensional Array View
![Array](pics/array.jpg)

The **cspan** is templated non-owning multi-dimensional view of an array. See the c++ classes 
[std::span](https://en.cppreference.com/w/cpp/container/span) and 
[std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan) for similar functionality.

## Header file and declaration

```c
#include <stc/cspan.h>
using_cspan(SpanType, ValueType);        // define a 1-d SpanType with ValueType elements.
using_cspan(SpanTypeN, ValueType, Rank); // define multi-dimensional span with Rank.
                                         // Rank is number of dimensions (max 5)
// Shorthands:
using_cspan2(S, ValueType);              // define span types S, S2 with ranks 1, 2.
using_cspan3(S, ValueType);              // define span types S, S2, S3 with ranks 1, 2, 3.
using_cspan4(S, ValueType);              // define span types S, S2, S3, S4 with ranks 1, 2, 3, 4.
```
## Methods
Note that `cspan_md()`, `cmake_from*()`, `cspan_atN()`, `and cspan_subspanN()` require a (safe) cast to its span-type
on assignment, but not on initialization of a span variable. All functions are type-safe, and arguments are side-effect safe, except for SpanType arg. which must not have side-effects.
```c
SpanTypeN       cspan_md(ValueType* data,  intptr_t xdim, ...);     // create a multi-dimensional cspan
SpanType        cspan_make(T SpanType, {v1, v2, ...});              // make a 1d-dimensional cspan from values
SpanType        cspan_from(STCContainer* cnt);                      // create a 1d cspan from a compatible STC container
SpanType        cspan_from_array(ValueType array[]);                // create a 1d cspan from a C array

intptr_t        cspan_size(const SpanTypeN* self);                  // return number of elements
unsigned        cspan_rank(const SpanTypeN* self);                  // return number of dimensions
intptr_t        cspan_index(const SpanTypeN* self, intptr_t x, ..); // index of element
                
ValueType*      cspan_at(const SpanTypeN* self, intptr_t x, ...);   // at(): num of args specifies rank of input span.
ValueType*      cspan_front(const SpanTypeN* self);
ValueType*      cspan_back(const SpanTypeN* self);

                // general index slicing to create a subspan.
                // {x} reduces rank. {x,c_END} slice to end. {c_ALL} take the full extent.
SpanTypeN       cspan_slice(T SpanTypeN, const SpanTypeM* parent, {x0,x1}, {y0,y1}, ...);
                
                // create a subspan of lower rank. Like e.g. cspan_slice(Span2, &ms3, {x}, {c_ALL}, {c_ALL});
SpanType        cspan_submd2(const SpanType2* self, intptr_t x);        // return a 1d subspan from a 2d span.
SpanTypeN       cspan_submd3(const SpanType3* self, intptr_t x, ...);   // return a 1d or 2d subspan from a 3d span.
SpanTypeN       cspan_submd4(const SpanType4* self, intptr_t x, ...);   // number of args determines rank of output span.

                // create a subspan of same rank. Like e.g. cspan_slice(Span3, &ms3, {off, off+count}, {c_ALL}, {c_ALL});
SpanType        cspan_subspan(const SpanType* self, intptr_t offset, intptr_t count);
SpanType2       cspan_subspan2(const SpanType2 self, intptr_t offset, intptr_t count);
SpanType3       cspan_subspan3(const SpanType3 self, intptr_t offset, intptr_t count);

SpanTypeN_iter  SpanType_begin(const SpanTypeN* self);
SpanTypeN_iter  SpanType_end(const SpanTypeN* self);
void            SpanType_next(SpanTypeN_iter* it);
```
## Types

| Type name         | Type definition                                | Used to represent... |
|:------------------|:-----------------------------------------------|:---------------------|
| SpanTypeN         | `struct { ValueType *data; uint32_t shape[N]; }` | SpanType with rank N |
| SpanTypeN`_value` | `ValueType`                                    | The ValueType        |
| `c_ALL`           | `0,-1`                                         | Full extent          |
| `c_END`           | `-1`                                           | End of extent        |

## Example 1

The *cspan_slice()* function is similar to pythons numpy multi-dimensional arrays slicing, e.g.:
```py
import numpy as np

if __name__ == '__main__':
    ms3 = np.array((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24), int)

    ms3 = np.reshape(ms3, (2, 3, 4))
    ss3 = ms3[:, 1:3, 2:]
    ss2 = ss3[1]

    for i in range(ss2.shape[0]):
        for j in range(ss2.shape[1]):
            print(" {}".format(ss2[i, j]), end='')
    print('')

    for i in ss2.flat:
        print(" {}".format(i), end='')

# 19 20 23 24
# 19 20 23 24
```
... can be done in C with cspan:
```c
#include <c11/fmt.h>
#include <stc/cspan.h>
using_cspan3(myspan, int); // define myspan, myspan2, myspan3.

int main() {
    int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};

    myspan3 ms3 = cspan_md(arr, 2, 3, 4);
    myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END});
    myspan2 ss2 = cspan_submd3(&ss3, 1);

    c_FORRANGE (i, ss2.shape[0])
        c_FORRANGE (j, ss2.shape[1])
            fmt_print(" {}", *cspan_at(&ss2, i, j));
    puts("");

    c_FOREACH (i, myspan2, ss2)
        fmt_print(" {}", *i.ref);
}
```
... and (almost) in C++23:
```c++
#include <print>
#include <mdspan>
#include <tuple>

int main() {
    int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};

    std::mdspan ms3(arr, 2, 3, 4);
    auto ss3 = std::submdspan(ms3, std::full_extent, std::tuple{1,3}, std::tuple{2,4});
    auto ss2 = std::submdspan(ss3, 1, std::full_extent, std::full_extent);

    for (std::size_t i = 0; i < ss2.extent(0); ++i)
        for (std::size_t j = 0; j < ss2.extent(1); ++j)
            std::print(" {}", ss2[i, j]);
    std::println();

    // std::mdspan can't be iterated as a flat container!
}
```
## Example 2
```c
#include <c11/fmt.h>
#include <stc/cspan.h>
#define i_val float
#include <stc/cstack.h>

using_cspan3(Span, float); // Shorthand to define span types Span, Span2, and Span3.

int main()
{
    int xd = 6, yd = 4, zd = 3;
    c_AUTO (cstack_float, vec)
    {
        c_FORRANGE (i, xd*yd*zd)
            cstack_float_push(&vec, i);

        // define "span3[xd][yd][zd]"
        Span3 span3 = cspan_md(vec.data, xd, yd, zd);
        *cspan_at(&span3, 4, 3, 2) = 3.14159f;
        fmt_print("index: {}", cspan_index(&span3, 4, 3, 2));

        Span span1 = cspan_submd3(&span3, 4, 3);
        printf("\niterate span1: ");
        c_FOREACH (i, Span, span1)
            fmt_print("{} ", *i.ref);

        Span2 span2 = cspan_submd3(&span3, 4);
        printf("\niterate span2: ");
        c_FOREACH (i, Span2, span2)
            fmt_print("{} ", *i.ref);

        puts("\niterate span3 by dimensions:");
        c_FORRANGE (i, span3.shape[0]) {
            c_FORRANGE (j, span3.shape[1]) {
                c_FORRANGE (k, span3.shape[2])
                    fmt_printf(" {:2}", *cspan_at(&span3, i, j, k));
                printf(" |");
            }
            puts("");
        }

        fmt_println("{}", *cspan_at(&span3, 4, 3, 2));
        fmt_println("{}", *cspan_at(&span2, 3, 2));
        fmt_println("{}", *cspan_at(&span1, 2));
    }
}
```
Output:
```
index: 59
iterate span1: 57 58 3.14159 
iterate span2: 48 49 50 51 52 53 54 55 56 57 58 3.14159 
iterate span3 by dimensions:
  0  1  2 |  3  4  5 |  6  7  8 |  9 10 11 |
 12 13 14 | 15 16 17 | 18 19 20 | 21 22 23 |
 24 25 26 | 27 28 29 | 30 31 32 | 33 34 35 |
 36 37 38 | 39 40 41 | 42 43 44 | 45 46 47 |
 48 49 50 | 51 52 53 | 54 55 56 | 57 58 3.14159 |
 60 61 62 | 63 64 65 | 66 67 68 | 69 70 71 |
3.14159
3.14159
3.14159
```