commit e08301d5925b11331bade915f5d2668e444c4835
Author: Louis Burda <quent.burda@gmail.com>
Date: Thu, 7 Apr 2022 12:27:33 +0200
Minimal Working Example
Diffstat:
A | .gitignore | | | 3 | +++ |
A | Makefile | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
A | include/idx.h | | | 60 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | libidx.abi | | | 9 | +++++++++ |
A | libidx.lds | | | 13 | +++++++++++++ |
A | src/idx.c | | | 272 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/test.c | | | 28 | ++++++++++++++++++++++++++++ |
7 files changed, 426 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+.cache
+build
+compile_commands.json
diff --git a/Makefile b/Makefile
@@ -0,0 +1,41 @@
+CFLAGS = -I include -g
+LDLIBS =
+DEPFLAGS = -MT $@ -MMD -MP -MF build/$*.d
+
+_SRCS = idx.c
+SRCS = $(_SRCS:%.c=src/%.c)
+OBJS = $(_SRCS:%.c=build/%.o)
+DEPS = $(_SRCS:%.c=build/%.d)
+PI_OBJS = $(_SRCS:%.c=build/%.pi.o)
+
+.PHONY: all clean
+
+all: build/libidx.so build/libidx.a build/test
+
+clean:
+ rm -rf build
+
+build:
+ mkdir build
+
+build/%.o: src/%.c build/%.d | build
+ $(CC) -c -o $@ $< $(DEPFLAGS) $(CFLAGS)
+
+build/%.pi.o: src/%.c build/%.d | build
+ $(CC) -c -o $@ $< $(DEPFLAGS) $(CFLAGS) -fPIC
+
+build/%.d: | build;
+
+include $(DEPS)
+
+build/libidx.a: $(OBJS) | build
+ $(CC) -o build/tmp.o $^ $(CFLAGS) -r
+ objcopy --keep-global-symbols=libidx.abi build/tmp.o build/fixed.o
+ ar rcs $@ build/fixed.o
+
+build/libidx.so: $(PI_OBJS) | build
+ $(CC) -o $@ $(PI_OBJS) $(CFLAGS) -shared -Wl,-version-script libidx.lds
+
+build/test: src/test.c build/libidx.a | build
+ $(CC) -o $@ $^ $(CFLAGS)
+
diff --git a/include/idx.h b/include/idx.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+
+enum {
+ IDX_TYPE_UNKNOWN = -1,
+ IDX_TYPE_UNSIGNED_BYTE,
+ IDX_TYPE_SIGNED_BYTE,
+ IDX_TYPE_SHORT,
+ IDX_TYPE_INT,
+ IDX_TYPE_FLOAT,
+ IDX_TYPE_DOUBLE,
+ IDX_TYPE_COUNT,
+};
+
+enum {
+ IDX_OK,
+ IDX_BAD_PARAM,
+ IDX_FILE_ACCESS,
+ IDX_FILE_BAD_MAGIC,
+ IDX_FILE_BAD_TYPE,
+ IDX_FILE_BAD_DIMS,
+ IDX_FILE_WRITE_MAGIC,
+ IDX_FILE_WRITE_DIMS,
+ IDX_FILE_WRITE_DATA,
+ IDX_FILE_READ_MAGIC,
+ IDX_FILE_READ_DIMS,
+ IDX_FILE_READ_DATA,
+ IDX_OUT_OF_MEMORY,
+};
+
+struct idx {
+ struct {
+ int val;
+ uint8_t size;
+ } type;
+
+ struct {
+ void *data;
+ size_t len;
+ } buf;
+
+ struct {
+ uint8_t count;
+ uint32_t *sizes;
+ } dims;
+};
+
+int idx_new(struct idx *idx, uint8_t dims_count, uint32_t *dims, int data_type);
+int idx_wrap(struct idx *idx, void *data, uint8_t dims_count,
+ uint32_t *dims, int data_type);
+
+int idx_load(struct idx *idx, const char *filename);
+int idx_save(struct idx *idx, const char *filename);
+
+void idx_deinit(struct idx *idx);
+
+void *idx_get(struct idx *idx, int dims, ...);
+
diff --git a/libidx.abi b/libidx.abi
@@ -0,0 +1,9 @@
+idx_new
+idx_wrap
+
+idx_load
+idx_save
+
+idx_deinit
+
+idx_get
diff --git a/libidx.lds b/libidx.lds
@@ -0,0 +1,13 @@
+LIBIDX_1.0 {
+ global:
+ idx_new;
+ idx_wrap;
+
+ idx_load;
+ idx_save;
+
+ idx_deinit;
+
+ idx_get;
+ local: *;
+};
diff --git a/src/idx.c b/src/idx.c
@@ -0,0 +1,272 @@
+#include "idx.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#define ASSERT(x) assert((x), __FILE__, __LINE__, #x)
+
+static const int idx_type_encode_lut[IDX_TYPE_COUNT] = {
+ [IDX_TYPE_UNSIGNED_BYTE] = 0x08,
+ [IDX_TYPE_SIGNED_BYTE] = 0x09,
+ [IDX_TYPE_SHORT] = 0x0B,
+ [IDX_TYPE_INT] = 0x0C,
+ [IDX_TYPE_FLOAT] = 0x0D,
+ [IDX_TYPE_DOUBLE] = 0x0E,
+};
+
+static const int idx_type_size[IDX_TYPE_COUNT] = {
+ [IDX_TYPE_UNSIGNED_BYTE] = 1,
+ [IDX_TYPE_SIGNED_BYTE] = 1,
+ [IDX_TYPE_SHORT] = 2,
+ [IDX_TYPE_INT] = 4,
+ [IDX_TYPE_FLOAT] = 4,
+ [IDX_TYPE_DOUBLE] = 8
+};
+
+static void assert(bool cond, const char *file,
+ size_t line, const char *condstr);
+
+static bool valid_idx_type(int type);
+
+static int idx_type_decode(int val);
+
+static bool fread_u32(FILE *f, uint32_t *val);
+static bool fwrite_u32(FILE *f, uint32_t val);
+
+void
+assert(bool cond, const char *file, size_t line, const char *condstr)
+{
+ if (cond) return;
+
+ fprintf(stderr, "LIBIDX: Assertion failed at %s:%li (%s)\n",
+ file, line, condstr);
+
+ exit(1);
+}
+
+bool
+valid_idx_type(int type)
+{
+ return type >= 0 && type < IDX_TYPE_COUNT;
+}
+
+int
+idx_type_decode(int val)
+{
+ int i;
+
+ for (i = 0; i < IDX_TYPE_COUNT; i++) {
+ if (val == idx_type_encode_lut[i])
+ return i;
+ }
+
+ return IDX_TYPE_UNKNOWN;
+}
+
+bool
+fread_u32(FILE *f, uint32_t *val)
+{
+ int len;
+
+ len = fread(val, 4, 1, f);
+ if (len != 1) return false;
+ *val = be32toh(*val);
+
+ return true;
+}
+
+bool
+fwrite_u32(FILE *f, uint32_t val)
+{
+ int len;
+
+ val = htobe32(val);
+ len = fwrite(&val, 4, 1, f);
+ if (len != 1) return false;
+
+ return true;
+}
+
+int
+idx_new(struct idx *idx, uint8_t dims_count, uint32_t *dims, int data_type)
+{
+ size_t i, size;
+
+ if (!valid_idx_type(data_type))
+ return IDX_BAD_PARAM;
+
+ size = idx_type_size[data_type];
+ for (i = 0; i < dims_count; i++)
+ size *= dims[i];
+
+ idx->buf.data = malloc(size);
+ if (idx->buf.data == NULL)
+ return IDX_OUT_OF_MEMORY;
+ idx->buf.len = size;
+
+ idx->dims.sizes = dims; /* move */
+ idx->dims.count = dims_count;
+
+ idx->type.size = idx_type_size[data_type];
+ idx->type.val = data_type;
+
+ return IDX_OK;
+}
+
+int
+idx_wrap(struct idx *idx, void *data, uint8_t dims_count,
+ uint32_t *dims, int data_type)
+{
+ size_t i, size;
+
+ if (!valid_idx_type(data_type))
+ return IDX_BAD_PARAM;
+
+ size = idx_type_size[data_type];
+ for (i = 0; i < dims_count; i++)
+ size *= dims[i];
+
+ idx->buf.data = data; /* move */
+ idx->buf.len = size;
+
+ idx->dims.sizes = dims; /* move */
+ idx->dims.count = dims_count;
+
+ idx->type.size = idx_type_size[data_type];
+ idx->type.val = data_type;
+
+ return IDX_OK;
+}
+
+int
+idx_load(struct idx *idx, const char *filename)
+{
+ uint32_t magic;
+ int len, i;
+ FILE *file;
+
+ file = fopen(filename, "r");
+ if (file == NULL)
+ return IDX_FILE_ACCESS;
+
+ /* read magic */
+ if (!fread_u32(file, &magic))
+ return IDX_FILE_READ_MAGIC;
+
+ if ((magic & 0xFFFF0000) != 0)
+ return IDX_FILE_BAD_MAGIC;
+
+ idx->type.val = idx_type_decode((magic & 0xFF00) >> 8);
+ if (idx->type.val == IDX_TYPE_UNKNOWN)
+ return IDX_FILE_BAD_TYPE;
+ idx->type.size = idx_type_size[idx->type.val];
+
+ idx->dims.count = magic & 0xFF;
+ if (idx->dims.count == 0)
+ return IDX_FILE_BAD_DIMS;
+
+ idx->dims.sizes = malloc(sizeof(uint32_t) * idx->dims.count);
+ if (idx->dims.sizes == NULL)
+ return IDX_OUT_OF_MEMORY;
+
+ /* read dims */
+ idx->buf.len = 1;
+ for (i = 0; i < idx->dims.count; i++) {
+ if (!fread_u32(file, &idx->dims.sizes[i]))
+ return IDX_FILE_READ_DIMS;
+ idx->buf.len *= idx->dims.sizes[i];
+ }
+
+ idx->buf.data = malloc(idx->buf.len);
+ if (idx->buf.data == NULL)
+ return IDX_OUT_OF_MEMORY;
+
+ /* read data */
+ len = fread(idx->buf.data, idx->type.size, idx->buf.len, file);
+ if (len != idx->buf.len)
+ return IDX_FILE_READ_DATA;
+
+ fclose(file);
+
+ return IDX_OK;
+}
+
+int
+idx_save(struct idx *idx, const char *filename)
+{
+ FILE *file;
+ uint32_t val;
+ size_t i, len, size;
+
+ file = fopen(filename, "w+");
+ if (file == NULL)
+ return IDX_FILE_ACCESS;
+
+ if (!valid_idx_type(idx->type.val))
+ return IDX_BAD_PARAM;
+ val = idx_type_encode_lut[idx->type.val];
+
+ /* write magic */
+ if (!fwrite_u32(file, (val << 8) + idx->dims.count))
+ return IDX_FILE_WRITE_MAGIC;
+
+ /* write dims */
+ for (i = 0; i < idx->dims.count; i++) {
+ if (!fwrite_u32(file, idx->dims.sizes[i]))
+ return IDX_FILE_WRITE_DIMS;
+ }
+
+ size = idx_type_size[idx->type.val];
+ for (i = 0; i < idx->dims.count; i++)
+ size *= idx->dims.sizes[i];
+
+ /* write data */
+ len = fwrite(idx->buf.data, 1, size, file);
+ if (len != size) return IDX_FILE_WRITE_DATA;
+
+ fclose(file);
+
+ return IDX_OK;
+}
+
+void
+idx_deinit(struct idx *idx)
+{
+ free(idx->buf.data);
+ free(idx->dims.sizes);
+}
+
+void *
+idx_get(struct idx *idx, int dims, ...)
+{
+ va_list ap;
+ size_t stride;
+ int i, val;
+ void *p;
+
+ if (dims < 0 || dims > idx->dims.count)
+ return NULL;
+
+ stride = 1;
+ for (i = 0; i < idx->dims.count; i++)
+ stride *= idx->dims.sizes[i];
+
+ p = idx->buf.data;
+ va_start(ap, dims);
+ for (i = 0; i < dims; i++) {
+ val = va_arg(ap, int);
+ if (val >= idx->dims.sizes[i])
+ return NULL;
+
+ stride /= idx->dims.sizes[i];
+ p += stride * val;
+ }
+ va_end(ap);
+
+ return p;
+}
+
+
diff --git a/src/test.c b/src/test.c
@@ -0,0 +1,28 @@
+#include "idx.h"
+
+#include <stdio.h>
+
+int
+main(int argc, const char **argv)
+{
+ struct idx data;
+ int i, status;
+ uint8_t *p;
+
+ status = idx_load(&data, argv[1]);
+ if (status != IDX_OK) {
+ printf("Failed to load file: %i\n", status);
+ return 1;
+ }
+
+ printf("DIMS: ");
+ for (i = 0; i < data.dims.count; i++)
+ printf("%s%i", i ? " x " : "", data.dims.sizes[i]);
+ printf("\n");
+
+ printf("Value at 10 x 10 x 10: ");
+ p = idx_get(&data, 3, 10, 10, 10);
+ printf("%02X\n", p ? *p : 0);
+
+ idx_deinit(&data);
+}