--- /dev/null
+#ifndef _ARRAY_H
+#define _ARRAY_H
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ALIGN 0x10
+
+// data is at struct address + header
+// stride array has length n_dims + 1
+// stride[0] is size of the data
+// stride[n_dims] == 1 except if n_dims == 0
+// dimension i has size stride[i] / stride[i + 1], where i < n_dims
+struct array {
+ int header;
+ int n_dims;
+ size_t stride[0];
+};
+
+static inline __attribute__((always_inline)) void *array_new0(void) {
+ struct array *p = aligned_alloc(
+ ALIGN,
+ sizeof(struct array) + sizeof(size_t)
+ );
+ if (p == NULL) {
+ perror("aligned_alloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ p->header =
+ (sizeof(struct array) + sizeof(size_t) + ALIGN - 1) & ~ALIGN;
+ p->n_dims = 0;
+ p->stride[0] = 0;
+ return p;
+}
+
+static inline __attribute__((always_inline)) void *array_new1(size_t dim0) {
+ struct array *p = aligned_alloc(
+ ALIGN,
+ (
+ (sizeof(struct array) + 2 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ ) + dim0
+ );
+ if (p == NULL) {
+ perror("aligned_alloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ p->header =
+ (sizeof(struct array) + 2 * sizeof(size_t) + ALIGN - 1) & ~ALIGN;
+ p->n_dims = 1;
+ p->stride[1] = 1;
+ p->stride[0] = dim0;
+ return p;
+}
+
+static inline __attribute__((always_inline)) void *array_new2(size_t dim0, size_t dim1) {
+ struct array *p = aligned_alloc(
+ ALIGN,
+ (
+ (sizeof(struct array) + 3 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ ) + dim0 * dim1
+ );
+ if (p == NULL) {
+ perror("aligned_alloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ p->header =
+ (sizeof(struct array) + 3 * sizeof(size_t) + ALIGN - 1) & ~ALIGN;
+ p->n_dims = 2;
+ p->stride[2] = 1;
+ p->stride[1] = dim1;
+ p->stride[0] = dim0 * dim1;
+ return p;
+}
+
+static inline __attribute__((always_inline)) void *array_new3(size_t dim0, size_t dim1, size_t dim2) {
+ struct array *p = aligned_alloc(
+ ALIGN,
+ (
+ (sizeof(struct array) + 4 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ ) + dim0 * dim1 * dim2
+ );
+ if (p == NULL) {
+ perror("aligned_alloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ p->header =
+ (sizeof(struct array) + 4 * sizeof(size_t) + ALIGN - 1) & ~ALIGN;
+ p->n_dims = 3;
+ p->stride[3] = 1;
+ p->stride[2] = dim2;
+ p->stride[1] = dim1 * dim2;
+ p->stride[0] = dim0 * p->stride[1];
+ return p;
+}
+
+static inline __attribute__((always_inline)) void *array_new4(size_t dim0, size_t dim1, size_t dim2, size_t dim3) {
+ struct array *p = aligned_alloc(
+ ALIGN,
+ (
+ (sizeof(struct array) + 5 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ ) + dim0 * dim1 * dim2 * dim3
+ );
+ if (p == NULL) {
+ perror("aligned_alloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ p->header =
+ (sizeof(struct array) + 5 * sizeof(size_t) + ALIGN - 1) & ~ALIGN;
+ p->n_dims = 3;
+ p->stride[4] = 1;
+ p->stride[3] = dim3;
+ p->stride[2] = dim2 * dim3;
+ p->stride[1] = dim1 * p->stride[2];
+ p->stride[0] = dim0 * p->stride[1];
+ return p;
+}
+
+static inline __attribute__((always_inline)) void array_free(struct array *self) {
+ free(self);
+}
+
+static inline __attribute__((always_inline)) void *array_index0(
+ struct array *self,
+ size_t *size
+) {
+ *size = self->stride[0];
+ return
+ (char *)self +
+ self->header;
+}
+
+static inline __attribute__((always_inline)) void *array_index1(
+ struct array *self,
+ size_t *size,
+ size_t i0
+) {
+ assert(self->n_dims >= 1);
+ *size = self->stride[1];
+ return
+ (char *)self +
+ self->header +
+ i0 * self->stride[1];
+}
+
+static inline __attribute__((always_inline)) void *array_index2(
+ struct array *self,
+ size_t *size,
+ size_t i0,
+ size_t i1
+) {
+ assert(self->n_dims >= 2);
+ *size = self->stride[2];
+ return
+ (char *)self +
+ self->header +
+ i1 * self->stride[2] +
+ i0 * self->stride[1];
+}
+
+static inline __attribute__((always_inline)) void *array_index3(
+ struct array *self,
+ size_t *size,
+ size_t i0,
+ size_t i1,
+ size_t i2
+) {
+ assert(self->n_dims >= 3);
+ *size = self->stride[3];
+ return
+ (char *)self +
+ self->header +
+ i2 * self->stride[3] +
+ i1 * self->stride[2] +
+ i0 * self->stride[1];
+}
+
+static inline __attribute__((always_inline)) void *array_index4(
+ struct array *self,
+ size_t *size,
+ size_t i0,
+ size_t i1,
+ size_t i2,
+ size_t i3
+) {
+ assert(self->n_dims >= 4);
+ *size = self->stride[4];
+ return
+ (char *)self +
+ self->header +
+ i3 * self->stride[4] +
+ i2 * self->stride[3] +
+ i1 * self->stride[2] +
+ i0 * self->stride[1];
+}
+
+static inline __attribute__((always_inline)) void array_get0(
+ struct array *self,
+ void *dest
+) {
+ size_t size;
+ void *p = array_index0(self, &size);
+ memcpy(dest, p, size);
+}
+
+static inline __attribute__((always_inline)) void array_get1(
+ struct array *self,
+ void *dest,
+ size_t i0
+) {
+ size_t size;
+ void *p = array_index1(self, &size, i0);
+ memcpy(dest, p, size);
+}
+
+static inline __attribute__((always_inline)) void array_get2(
+ struct array *self,
+ void *dest,
+ size_t i0,
+ size_t i1
+) {
+ size_t size;
+ void *p = array_index2(self, &size, i0, i1);
+ memcpy(dest, p, size);
+}
+
+static inline __attribute__((always_inline)) void array_get3(
+ struct array *self,
+ void *dest,
+ size_t i0,
+ size_t i1,
+ size_t i2
+) {
+ size_t size;
+ void *p = array_index3(self, &size, i0, i1, i2);
+ memcpy(dest, p, size);
+}
+
+static inline __attribute__((always_inline)) void array_get4(
+ struct array *self,
+ void *dest,
+ size_t i0,
+ size_t i1,
+ size_t i2,
+ size_t i3
+) {
+ size_t size;
+ void *p = array_index4(self, &size, i0, i1, i2, i3);
+ memcpy(dest, p, size);
+}
+
+static inline __attribute__((always_inline)) void array_set0(
+ struct array *self,
+ const void *src
+) {
+ size_t size;
+ void *p = array_index0(self, &size);
+ memcpy(p, src, size);
+}
+
+static inline __attribute__((always_inline)) void array_set1(
+ struct array *self,
+ const void *src,
+ size_t i0
+) {
+ size_t size;
+ void *p = array_index1(self, &size, i0);
+ memcpy(p, src, size);
+}
+
+static inline __attribute__((always_inline)) void array_set2(
+ struct array *self,
+ const void *src,
+ size_t i0,
+ size_t i1
+) {
+ size_t size;
+ void *p = array_index2(self, &size, i0, i1);
+ memcpy(p, src, size);
+}
+
+static inline __attribute__((always_inline)) void array_set3(
+ struct array *self,
+ const void *src,
+ size_t i0,
+ size_t i1,
+ size_t i2
+) {
+ size_t size;
+ void *p = array_index3(self, &size, i0, i1, i2);
+ memcpy(p, src, size);
+}
+
+static inline __attribute__((always_inline)) void array_set4(
+ struct array *self,
+ const void *src,
+ size_t i0,
+ size_t i1,
+ size_t i2,
+ size_t i3
+) {
+ size_t size;
+ void *p = array_index4(self, &size, i0, i1, i2, i3);
+ memcpy(p, src, size);
+}
+
+static inline __attribute__((always_inline)) void array_clear0(
+ struct array *self
+) {
+ size_t size;
+ void *p = array_index0(self, &size);
+ memset(p, 0, size);
+}
+
+static inline __attribute__((always_inline)) void array_clear1(
+ struct array *self,
+ size_t i0
+) {
+ size_t size;
+ void *p = array_index1(self, &size, i0);
+ memset(p, 0, size);
+}
+
+static inline __attribute__((always_inline)) void array_clear2(
+ struct array *self,
+ size_t i0,
+ size_t i1
+) {
+ size_t size;
+ void *p = array_index2(self, &size, i0, i1);
+ memset(p, 0, size);
+}
+
+static inline __attribute__((always_inline)) void array_clear3(
+ struct array *self,
+ size_t i0,
+ size_t i1,
+ size_t i2
+) {
+ size_t size;
+ void *p = array_index3(self, &size, i0, i1, i2);
+ memset(p, 0, size);
+}
+
+static inline __attribute__((always_inline)) void array_clear4(
+ struct array *self,
+ size_t i0,
+ size_t i1,
+ size_t i2,
+ size_t i3
+) {
+ size_t size;
+ void *p = array_index4(self, &size, i0, i1, i2, i3);
+ memset(p, 0, size);
+}
+
+#endif
--- /dev/null
+#include <stdbool.h>
+#include <stdlib.h>
+#include <SDL2/SDL.h>
+#include "array.h"
+
+#define WINDOW_WIDTH 1024
+#define WINDOW_HEIGHT 768
+
+SDL_Window *window;
+SDL_Renderer *renderer;
+SDL_Surface *window_surface;
+
+int main(void) {
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ fprintf(stderr, "SDL_Init(): %s\n\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+ }
+
+ if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
+ fprintf(stderr, "SDL_SetHint(): %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+ }
+
+ window = SDL_CreateWindow(
+ "render",
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ WINDOW_WIDTH,
+ WINDOW_HEIGHT,
+ SDL_WINDOW_SHOWN
+ );
+ if (window == NULL) {
+ fprintf(stderr, "SDL_CreateWindow(): %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+ }
+
+ window_surface = SDL_GetWindowSurface(window);
+ if (window_surface == NULL) {
+ fprintf(stderr, "SDL_GetWindowSurface(): %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+ }
+
+ renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
+ if (renderer == NULL) {
+ fprintf(stderr, "SDL_CreateRenderer(): %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+ }
+
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff);
+
+ struct array *a = array_new3(4, 4, sizeof(float));
+ array_clear0(a);
+ for (int i = 0; i < 4; ++i)
+ for (int j = 0; j < i; ++j) {
+ float v = i + j;
+ array_set2(a, &v, i, j);
+ }
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ float v;
+ array_get2(a, &v, i, j);
+ printf("%s%7.3f", j ? ", " : i ? " [" : "[[", v);
+ }
+ printf("%s\n", i < 3 ? "]" : "]]");
+ }
+
+ while (true) {
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ switch (event.type) {
+ case SDL_QUIT:
+ goto quit;
+ }
+
+ SDL_RenderClear(renderer);
+ SDL_RenderPresent(renderer);
+ SDL_Delay(1);
+ }
+
+quit:
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+ return 0;
+}