#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
+// stride[n_dims] == 1
+// note that a zero-dimensional array is a scalar (with size 1 byte)
struct array {
- int header;
int n_dims;
- size_t stride[0];
+ void *data;
+ size_t *stride;
+ size_t dim[0];
};
+static inline __attribute__((always_inline)) void *array_new(
+ int n_dims,
+ size_t *dim,
+ size_t *stride
+) {
+#ifndef NDEBUG
+ {
+ size_t s = 1;
+ int i = n_dims;
+ while (i >= 1) {
+ assert(stride[i] == s);
+ s *= dim[--i];
+ }
+ assert(stride[i] == s);
+ }
+#endif
+
+ int header = (
+ sizeof(struct array) +
+ sizeof(size_t) +
+ ALIGN -
+ 1 +
+ n_dims * (2 * sizeof(size_t))
+ ) & ~ALIGN;
+ struct array *p = aligned_alloc(ALIGN, header + stride[0]);
+ if (p == NULL) {
+ perror("aligned_alloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ p->n_dims = n_dims;
+ p->data = (char *)p + header;
+ p->stride = p->dim + n_dims;
+ memcpy(p->dim, dim, n_dims * sizeof(size_t));
+ memcpy(p->stride, stride, (n_dims + 1) * sizeof(size_t));
+ return p;
+}
+
static inline __attribute__((always_inline)) void *array_new0(void) {
struct array *p = aligned_alloc(
ALIGN,
- sizeof(struct array) + sizeof(size_t)
+ (
+ (sizeof(struct array) + sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ ) + 1
);
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;
+ p->data = (char *)p + (
+ (sizeof(struct array) + sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ );
+ p->stride = p->dim;
+ p->stride[0] = 1;
return p;
}
-static inline __attribute__((always_inline)) void *array_new1(size_t dim0) {
+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
+ (sizeof(struct array) + 3 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
) + dim0
);
if (p == NULL) {
exit(EXIT_FAILURE);
}
- p->header =
- (sizeof(struct array) + 2 * sizeof(size_t) + ALIGN - 1) & ~ALIGN;
p->n_dims = 1;
+ p->data = (char *)p + (
+ (sizeof(struct array) + 3 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ );
+ p->stride = p->dim + 1;
+ p->dim[0] = dim0;
p->stride[1] = 1;
p->stride[0] = dim0;
return p;
}
-static inline __attribute__((always_inline)) void *array_new2(size_t dim0, size_t dim1) {
+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
+ (sizeof(struct array) + 5 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
) + dim0 * dim1
);
if (p == NULL) {
exit(EXIT_FAILURE);
}
- p->header =
- (sizeof(struct array) + 3 * sizeof(size_t) + ALIGN - 1) & ~ALIGN;
p->n_dims = 2;
+ p->data = (char *)p + (
+ (sizeof(struct array) + 5 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ );
+ p->stride = p->dim + 2;
+ p->dim[0] = dim0;
+ p->dim[1] = dim1;
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) {
+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
+ (sizeof(struct array) + 7 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
) + dim0 * dim1 * dim2
);
if (p == NULL) {
exit(EXIT_FAILURE);
}
- p->header =
- (sizeof(struct array) + 4 * sizeof(size_t) + ALIGN - 1) & ~ALIGN;
p->n_dims = 3;
+ p->data = (char *)p + (
+ (sizeof(struct array) + 7 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ );
+ p->stride = p->dim + 3;
+ p->dim[0] = dim0;
+ p->dim[1] = dim1;
+ p->dim[2] = dim2;
p->stride[3] = 1;
p->stride[2] = dim2;
p->stride[1] = dim1 * dim2;
return p;
}
-static inline __attribute__((always_inline)) void *array_new4(size_t dim0, size_t dim1, size_t dim2, size_t dim3) {
+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
+ (sizeof(struct array) + 9 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
) + dim0 * dim1 * dim2 * dim3
);
if (p == NULL) {
exit(EXIT_FAILURE);
}
- p->header =
- (sizeof(struct array) + 5 * sizeof(size_t) + ALIGN - 1) & ~ALIGN;
- p->n_dims = 3;
+ p->n_dims = 4;
+ p->data = (char *)p + (
+ (sizeof(struct array) + 9 * sizeof(size_t) + ALIGN - 1) & ~ALIGN
+ );
+ p->stride = p->dim + 3;
+ p->dim[0] = dim0;
+ p->dim[1] = dim1;
+ p->dim[2] = dim2;
+ p->dim[3] = dim3;
p->stride[4] = 1;
p->stride[3] = dim3;
p->stride[2] = dim2 * dim3;
return p;
}
-static inline __attribute__((always_inline)) void array_free(struct array *self) {
+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
+ struct array *self
) {
- *size = self->stride[0];
- return
- (char *)self +
- self->header;
+ assert(self->n_dims >= 0);
+ return self->data;
}
static inline __attribute__((always_inline)) void *array_index1(
struct array *self,
- size_t *size,
size_t i0
) {
assert(self->n_dims >= 1);
-#ifndef NDEBUG
- assert(i0 >= 0 && i0 < self->stride[0] / self->stride[1]);
-#endif
- *size = self->stride[1];
+ assert(i0 >= 0 && i0 < self->dim[0]);
return
- (char *)self +
- self->header +
+ (char *)self->data +
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);
-#ifndef NDEBUG
- assert(i0 >= 0 && i0 < self->stride[0] / self->stride[1]);
- assert(i1 >= 0 && i1 < self->stride[1] / self->stride[2]);
-#endif
- *size = self->stride[2];
+ assert(i0 >= 0 && i0 < self->dim[0]);
+ assert(i1 >= 0 && i1 < self->dim[1]);
return
- (char *)self +
- self->header +
+ (char *)self->data +
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);
-#ifndef NDEBUG
- assert(i0 >= 0 && i0 < self->stride[0] / self->stride[1]);
- assert(i1 >= 0 && i1 < self->stride[1] / self->stride[2]);
- assert(i2 >= 0 && i2 < self->stride[2] / self->stride[3]);
-#endif
- *size = self->stride[3];
+ assert(i0 >= 0 && i0 < self->dim[0]);
+ assert(i1 >= 0 && i1 < self->dim[1]);
+ assert(i2 >= 0 && i2 < self->dim[2]);
return
- (char *)self +
- self->header +
+ (char *)self->data +
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);
-#ifndef NDEBUG
- assert(i0 >= 0 && i0 < self->stride[0] / self->stride[1]);
- assert(i1 >= 0 && i1 < self->stride[1] / self->stride[2]);
- assert(i2 >= 0 && i2 < self->stride[2] / self->stride[3]);
- assert(i3 >= 0 && i2 < self->stride[3] / self->stride[4]);
-#endif
- *size = self->stride[4];
+ assert(i0 >= 0 && i0 < self->dim[0]);
+ assert(i1 >= 0 && i1 < self->dim[1]);
+ assert(i2 >= 0 && i2 < self->dim[2]);
+ assert(i3 >= 0 && i3 < self->dim[3]);
return
- (char *)self +
- self->header +
+ (char *)self->data +
i3 * self->stride[4] +
i2 * self->stride[3] +
i1 * self->stride[2] +
struct array *self,
void *dest
) {
- size_t size;
- void *p = array_index0(self, &size);
- memcpy(dest, p, size);
+ memcpy(dest, array_index0(self), self->stride[0]);
}
static inline __attribute__((always_inline)) void array_get1(
void *dest,
size_t i0
) {
- size_t size;
- void *p = array_index1(self, &size, i0);
- memcpy(dest, p, size);
+ memcpy(dest, array_index1(self, i0), self->stride[1]);
}
static inline __attribute__((always_inline)) void array_get2(
size_t i0,
size_t i1
) {
- size_t size;
- void *p = array_index2(self, &size, i0, i1);
- memcpy(dest, p, size);
+ memcpy(dest, array_index2(self, i0, i1), self->stride[2]);
}
static inline __attribute__((always_inline)) void array_get3(
size_t i1,
size_t i2
) {
- size_t size;
- void *p = array_index3(self, &size, i0, i1, i2);
- memcpy(dest, p, size);
+ memcpy(dest, array_index3(self, i0, i1, i2), self->stride[3]);
}
static inline __attribute__((always_inline)) void array_get4(
size_t i2,
size_t i3
) {
- size_t size;
- void *p = array_index4(self, &size, i0, i1, i2, i3);
- memcpy(dest, p, size);
+ memcpy(dest, array_index4(self, i0, i1, i2, i3), self->stride[4]);
}
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);
+ memcpy(array_index0(self), src, self->stride[0]);
}
static inline __attribute__((always_inline)) void array_set1(
const void *src,
size_t i0
) {
- size_t size;
- void *p = array_index1(self, &size, i0);
- memcpy(p, src, size);
+ memcpy(array_index1(self, i0), src, self->stride[1]);
}
static inline __attribute__((always_inline)) void array_set2(
size_t i0,
size_t i1
) {
- size_t size;
- void *p = array_index2(self, &size, i0, i1);
- memcpy(p, src, size);
+ memcpy(array_index2(self, i0, i1), src, self->stride[2]);
}
static inline __attribute__((always_inline)) void array_set3(
size_t i1,
size_t i2
) {
- size_t size;
- void *p = array_index3(self, &size, i0, i1, i2);
- memcpy(p, src, size);
+ memcpy(array_index3(self, i0, i1, i2), src, self->stride[3]);
}
static inline __attribute__((always_inline)) void array_set4(
size_t i2,
size_t i3
) {
- size_t size;
- void *p = array_index4(self, &size, i0, i1, i2, i3);
- memcpy(p, src, size);
+ memcpy(array_index4(self, i0, i1, i2, i3), src, self->stride[4]);
}
static inline __attribute__((always_inline)) void array_clear0(
struct array *self
) {
- size_t size;
- void *p = array_index0(self, &size);
- memset(p, 0, size);
+ memset(array_index0(self), 0, self->stride[0]);
}
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);
+ memset(array_index1(self, i0), 0, self->stride[1]);
}
static inline __attribute__((always_inline)) void array_clear2(
size_t i0,
size_t i1
) {
- size_t size;
- void *p = array_index2(self, &size, i0, i1);
- memset(p, 0, size);
+ memset(array_index2(self, i0, i1), 0, self->stride[2]);
}
static inline __attribute__((always_inline)) void array_clear3(
size_t i1,
size_t i2
) {
- size_t size;
- void *p = array_index3(self, &size, i0, i1, i2);
- memset(p, 0, size);
+ memset(array_index3(self, i0, i1, i2), 0, self->stride[3]);
}
static inline __attribute__((always_inline)) void array_clear4(
size_t i2,
size_t i3
) {
- size_t size;
- void *p = array_index4(self, &size, i0, i1, i2, i3);
- memset(p, 0, size);
+ memset(array_index4(self, i0, i1, i2, i3), 0, self->stride[4]);
+}
+
+static inline __attribute__((always_inline)) struct array *array_dup0(
+ struct array *self
+) {
+ assert(self->n_dims >= 0);
+ struct array *p = array_new(
+ self->n_dims,
+ self->dim,
+ self->stride
+ );
+ array_get0(self, p->data);
+ return p;
+}
+
+static inline __attribute__((always_inline)) struct array *array_dup1(
+ struct array *self,
+ size_t i0
+) {
+ assert(self->n_dims >= 1);
+ struct array *p = array_new(
+ self->n_dims - 1,
+ self->dim + 1,
+ self->stride + 1
+ );
+ array_get1(self, p->data, i0);
+ return p;
+}
+
+static inline __attribute__((always_inline)) struct array *array_dup2(
+ struct array *self,
+ size_t i0,
+ size_t i1
+) {
+ assert(self->n_dims >= 2);
+ struct array *p = array_new(
+ self->n_dims - 2,
+ self->dim + 2,
+ self->stride + 2
+ );
+ array_get2(self, p->data, i0, i1);
+ return p;
+}
+
+static inline __attribute__((always_inline)) struct array *array_dup3(
+ struct array *self,
+ size_t i0,
+ size_t i1,
+ size_t i2
+) {
+ assert(self->n_dims >= 3);
+ struct array *p = array_new(
+ self->n_dims - 3,
+ self->dim + 3,
+ self->stride + 3
+ );
+ array_get3(self, p->data, i0, i1, i2);
+ return p;
+}
+
+static inline __attribute__((always_inline)) struct array *array_dup4(
+ struct array *self,
+ size_t i0,
+ size_t i1,
+ size_t i2,
+ size_t i3
+) {
+ assert(self->n_dims >= 4);
+ struct array *p = array_new(
+ self->n_dims - 4,
+ self->dim + 4,
+ self->stride + 4
+ );
+ array_get4(self, p->data, i0, i1, i2, i3);
+ return p;
}
#endif