summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--LICENSE24
-rw-r--r--README.md3
-rw-r--r--meson.build8
-rw-r--r--src/lisiblestd/assert.h22
-rw-r--r--src/lisiblestd/log.h18
-rw-r--r--src/lisiblestd/math.h6
-rw-r--r--src/lisiblestd/memory.c135
-rw-r--r--src/lisiblestd/memory.h41
-rw-r--r--src/lisiblestd/string.c33
-rw-r--r--src/lisiblestd/string.h19
-rw-r--r--src/lisiblestd/types.h20
-rw-r--r--tests/string.c14
-rw-r--r--tests/test.h74
-rw-r--r--tests/test_runner.c17
15 files changed, 436 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b010b19
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.cache/
+compile_commands.json
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3271bec
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+BSD 2-Clause License
+
+Copyright (c) 2024, Clément Sibille
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2f9411d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# LisibleStd
+
+My personal C library with common utilities.
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..da667ce
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,8 @@
+project('lisiblestd', 'c', default_options: ['c_std=c18', 'warning_level=3'])
+
+lisiblestd_incdir = include_directories('src/')
+lisiblestd_lib = library('lisiblestd', 'src/lisiblestd/memory.c', 'src/lisiblestd/string.c')
+lisiblestd_dep = declare_dependency(include_directories: lisiblestd_incdir, link_with: [lisiblestd_lib])
+
+test_string = executable('test_string', 'tests/test_runner.c', 'tests/string.c', dependencies: [lisiblestd_dep])
+test('test_string', test_string)
diff --git a/src/lisiblestd/assert.h b/src/lisiblestd/assert.h
new file mode 100644
index 0000000..9bd7514
--- /dev/null
+++ b/src/lisiblestd/assert.h
@@ -0,0 +1,22 @@
+#ifndef LSTD_ASSERT_H
+#define LSTD_ASSERT_H
+
+#include "log.h"
+
+extern void exit(int);
+
+#define LSTD_ASSERT(expr) \
+ do { \
+ if (!(expr)) { \
+ LOG("Assertion failed:\n\t%s", #expr); \
+ exit(1); \
+ } \
+ } while (0)
+
+#define LSTD_UNIMPLEMENTED() \
+ do { \
+ LOG0("Unimplemented code reached"); \
+ exit(1); \
+ } while (0)
+
+#endif // LSTD_ASSERT_H
diff --git a/src/lisiblestd/log.h b/src/lisiblestd/log.h
new file mode 100644
index 0000000..c280034
--- /dev/null
+++ b/src/lisiblestd/log.h
@@ -0,0 +1,18 @@
+#ifndef LSTD_LOG_H
+#define LSTD_LOG_H
+
+#include <stdio.h>
+
+#define LOG_PREFIX "[%s:%d] "
+
+#define LOG0(msg) \
+ do { \
+ fprintf(stderr, LOG_PREFIX "%s\n", __FILE__, __LINE__, msg); \
+ } while (0)
+
+#define LOG(fmt, ...) \
+ do { \
+ fprintf(stderr, LOG_PREFIX fmt "\n", __FILE__, __LINE__, __VA_ARGS__); \
+ } while (0)
+
+#endif // LSTD_LOG_H
diff --git a/src/lisiblestd/math.h b/src/lisiblestd/math.h
new file mode 100644
index 0000000..96771fa
--- /dev/null
+++ b/src/lisiblestd/math.h
@@ -0,0 +1,6 @@
+#ifndef LSTD_MATH_H
+#define LSTD_MATH_H
+
+#define MAX(a, b) (a > b ? a : b)
+
+#endif // LSTD_MATH_H
diff --git a/src/lisiblestd/memory.c b/src/lisiblestd/memory.c
new file mode 100644
index 0000000..1f6b3c9
--- /dev/null
+++ b/src/lisiblestd/memory.c
@@ -0,0 +1,135 @@
+#include "memory.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "assert.h"
+#include "math.h"
+
+static const usize MINIMUM_ALIGNMENT = sizeof(void *);
+
+void *memory_allocate(usize size, void *ctx) {
+ (void)ctx;
+ return malloc(size);
+}
+void *memory_allocate_aligned(usize alignment, usize size, void *ctx) {
+ (void)ctx;
+ return aligned_alloc(MAX(alignment, MINIMUM_ALIGNMENT), size);
+}
+void *memory_allocate_array(usize count, usize item_size, void *ctx) {
+ (void)ctx;
+ return calloc(count, item_size);
+}
+void *memory_reallocate(void *ptr, usize old_size, usize new_size, void *ctx) {
+ (void)old_size;
+ (void)ctx;
+ return realloc(ptr, new_size);
+}
+void memory_free(void *ptr, void *ctx) {
+ (void)ctx;
+ free(ptr);
+}
+Allocator system_allocator = {.allocate = memory_allocate,
+ .allocate_aligned = memory_allocate_aligned,
+ .allocate_array = memory_allocate_array,
+ .reallocate = memory_reallocate,
+ .free = memory_free,
+ NULL};
+void *Allocator_allocate(Allocator *allocator, usize size) {
+ LSTD_ASSERT(allocator != NULL);
+ return allocator->allocate(size, allocator->ctx);
+}
+void *Allocator_allocate_aligned(Allocator *allocator, usize alignment,
+ usize size) {
+ LSTD_ASSERT(allocator != NULL);
+ return allocator->allocate_aligned(alignment, size, allocator->ctx);
+}
+void *Allocator_allocate_array(Allocator *allocator, usize count,
+ usize item_size) {
+ LSTD_ASSERT(allocator != NULL);
+ return allocator->allocate_array(count, item_size, allocator->ctx);
+}
+void *Allocator_reallocate(Allocator *allocator, void *ptr, usize old_size,
+ usize new_size) {
+ LSTD_ASSERT(allocator != NULL);
+ return allocator->reallocate(ptr, old_size, new_size, allocator->ctx);
+}
+void Allocator_free(Allocator *allocator, void *ptr) {
+ LSTD_ASSERT(allocator != NULL);
+ allocator->free(ptr, allocator->ctx);
+}
+
+void *arena_allocator_allocate(usize size, void *ctx) {
+ LSTD_ASSERT(ctx != NULL);
+ return Arena_allocate((Arena *)ctx, size);
+}
+void *arena_allocator_allocate_aligned(usize alignment, usize size, void *ctx) {
+ LSTD_ASSERT(ctx != NULL);
+ (void)alignment;
+ (void)size;
+ LSTD_UNIMPLEMENTED();
+}
+void *arena_allocator_allocate_array(usize count, usize item_size, void *ctx) {
+ LSTD_ASSERT(ctx != NULL);
+ return Arena_allocate_array((Arena *)ctx, count, item_size);
+}
+void *arena_allocator_reallocate(void *ptr, usize old_size, usize new_size,
+ void *ctx) {
+ (void)ptr;
+ (void)old_size;
+ (void)new_size;
+ (void)ctx;
+ LSTD_UNIMPLEMENTED();
+}
+
+void arena_allocator_free(void *ptr, void *ctx) {
+ (void)ptr;
+ (void)ctx;
+}
+
+Allocator Arena_allocator(Arena *arena) {
+ return (Allocator){.ctx = arena,
+ .allocate = arena_allocator_allocate,
+ .allocate_aligned = arena_allocator_allocate_aligned,
+ .allocate_array = arena_allocator_allocate_array,
+ .reallocate = arena_allocator_reallocate,
+ .free = arena_allocator_free};
+}
+
+void Arena_init(Arena *arena, Allocator *allocator, usize size) {
+ LSTD_ASSERT(arena != NULL);
+ LSTD_ASSERT(allocator != NULL);
+ arena->size = 0;
+ arena->capacity = size;
+ arena->data = Allocator_allocate(allocator, size);
+}
+void *Arena_allocate(Arena *arena, usize size) {
+ LSTD_ASSERT(arena->size + size <= arena->capacity);
+ void *ptr = arena->data + arena->size;
+ arena->size += size;
+ return ptr;
+}
+void *Arena_allocate_array(Arena *arena, usize count, usize item_size) {
+ void *ptr = Arena_allocate(arena, count * item_size);
+ memset(ptr, 0, count * item_size);
+ return ptr;
+}
+void *arena_reallocate(Arena *arena, void *ptr, usize old_size,
+ usize new_size) {
+ LSTD_ASSERT(new_size > old_size);
+ void *new_ptr = Arena_allocate(arena, new_size);
+ memcpy(new_ptr, ptr, old_size);
+ return new_ptr;
+}
+void Arena_clear(Arena *arena) { arena->size = 0; }
+void Arena_deinit(Arena *arena, Allocator *allocator) {
+ Allocator_free(allocator, arena->data);
+}
+
+char *memory_clone_string(Allocator *allocator, const char *str) {
+ usize string_length = strlen(str) + 1;
+ char *duplicate_string =
+ Allocator_allocate_array(allocator, string_length, sizeof(char));
+ memcpy(duplicate_string, str, strlen(str));
+ return duplicate_string;
+}
diff --git a/src/lisiblestd/memory.h b/src/lisiblestd/memory.h
new file mode 100644
index 0000000..2282206
--- /dev/null
+++ b/src/lisiblestd/memory.h
@@ -0,0 +1,41 @@
+#ifndef LSTD_MEMORY_H
+#define LSTD_MEMORY_H
+
+#include "types.h"
+
+typedef struct {
+ void *(*allocate)(usize size, void *ctx);
+ void *(*allocate_aligned)(usize alignment, usize size, void *ctx);
+ void *(*allocate_array)(usize count, usize item_size, void *ctx);
+ void *(*reallocate)(void *ptr, usize old_size, usize new_size, void *ctx);
+ void (*free)(void *ptr, void *ctx);
+ void *ctx;
+} Allocator;
+
+void *Allocator_allocate(Allocator *allocator, usize size);
+void *Allocator_allocate_aligned(Allocator *allocator, usize alignment,
+ usize size);
+void *Allocator_allocate_array(Allocator *allocator, usize count,
+ usize item_size);
+void *Allocator_reallocate(Allocator *allocator, void *ptr, usize old_size,
+ usize new_size);
+void Allocator_free(Allocator *allocator, void *ptr);
+
+extern Allocator system_allocator;
+
+typedef struct {
+ usize capacity;
+ usize size;
+ u8 *data;
+} Arena;
+
+Allocator Arena_allocator(Arena *arena);
+void Arena_init(Arena *arena, Allocator *allocator, usize size);
+void *Arena_allocate(Arena *arena, usize size);
+void *Arena_allocate_array(Arena *arena, usize count, usize item_size);
+void Arena_clear(Arena *arena);
+void Arena_deinit(Arena *arena, Allocator *allocator);
+
+char *memory_clone_string(Allocator *allocator, const char *str);
+
+#endif // LSTD_MEMORY_H
diff --git a/src/lisiblestd/string.c b/src/lisiblestd/string.c
new file mode 100644
index 0000000..3de3272
--- /dev/null
+++ b/src/lisiblestd/string.c
@@ -0,0 +1,33 @@
+#include "string.h"
+#include "assert.h"
+#include "src/lisiblestd/memory.h"
+
+#include <string.h>
+
+bool String_from_str(Allocator *allocator, String *string, const char *str) {
+ LSTD_ASSERT(allocator != NULL);
+ LSTD_ASSERT(string != NULL);
+ LSTD_ASSERT(str != NULL);
+
+ usize length = strlen(str);
+ char *value = Allocator_allocate_array(allocator, length + 1, sizeof(char));
+ if (!value) {
+ return false;
+ }
+ value[length] = '\0';
+
+ string->value = value;
+ string->length = length;
+ return true;
+}
+
+void String_destroy(Allocator *allocator, String *string) {
+ LSTD_ASSERT(allocator != NULL);
+ LSTD_ASSERT(string != NULL);
+ Allocator_free(allocator, string->value);
+}
+
+usize String_length(const String *string) {
+ LSTD_ASSERT(string != NULL);
+ return string->length;
+}
diff --git a/src/lisiblestd/string.h b/src/lisiblestd/string.h
new file mode 100644
index 0000000..79ee6b8
--- /dev/null
+++ b/src/lisiblestd/string.h
@@ -0,0 +1,19 @@
+#ifndef LSTD_STRING_H
+#define LSTD_STRING_H
+
+#include "memory.h"
+#include "types.h"
+#include <stdbool.h>
+
+struct String {
+ char *value;
+ usize length;
+};
+
+typedef struct String String;
+
+bool String_from_str(Allocator *allocator, String *string, const char *str);
+void String_destroy(Allocator *allocator, String *string);
+usize String_length(const String *string);
+
+#endif // LSTD_STRING_H
diff --git a/src/lisiblestd/types.h b/src/lisiblestd/types.h
new file mode 100644
index 0000000..e16728a
--- /dev/null
+++ b/src/lisiblestd/types.h
@@ -0,0 +1,20 @@
+#ifndef LSTD_TYPES_H
+#define LSTD_TYPES_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+typedef int8_t i8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef int64_t i64;
+
+typedef size_t usize;
+
+#endif // LSTD_TYPES_H
diff --git a/tests/string.c b/tests/string.c
new file mode 100644
index 0000000..e3d68f4
--- /dev/null
+++ b/tests/string.c
@@ -0,0 +1,14 @@
+#include "lisiblestd/memory.h"
+#include "test.h"
+#include <lisiblestd/string.h>
+
+void t_String_from_str(void) {
+ String string;
+ String_from_str(&system_allocator, &string, "Some string");
+ T_ASSERT(strncmp(string.value, "Some string", 11));
+ T_ASSERT_EQ(string.length, 11);
+
+ String_destroy(&system_allocator, &string);
+}
+
+TEST_SUITE(TEST(t_String_from_str))
diff --git a/tests/test.h b/tests/test.h
new file mode 100644
index 0000000..223abf5
--- /dev/null
+++ b/tests/test.h
@@ -0,0 +1,74 @@
+#ifndef LSTD_TESTS_TEST_H
+#define LSTD_TESTS_TEST_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_DATA_PATH "../cuttereng/tests/tests_data/"
+
+typedef void (*TestFn)(void);
+
+typedef struct {
+ const char *name;
+ TestFn fn;
+} Test;
+
+extern Test tests[];
+extern size_t test_count;
+
+inline static void assert0(int boolean, const char *msg) {
+ if (!boolean) {
+ fprintf(stderr, "%s", msg);
+ exit(1);
+ }
+}
+
+inline static void assert(int boolean, const char *fmt, ...) {
+ if (!boolean) {
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, fmt, args);
+ va_end(args);
+ exit(1);
+ }
+}
+
+#define T_ASSERT(expr) T_ASSERT_MSG(expr, "%s", #expr)
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+#define T_ASSERT_MSG(expr, fmt, ...) \
+ do { \
+ assert((expr), \
+ "Assertion failed in " __FILE__ ":" TOSTRING(__LINE__) ": " fmt \
+ "\n", \
+ __VA_ARGS__); \
+ } while (0)
+#define T_ASSERT_MSG0(expr, msg) \
+ do { \
+ assert0((expr), "Assertion failed in " __FILE__ \
+ ":" TOSTRING(__LINE__) ": " msg "\n"); \
+ } while (0)
+
+#define T_ASSERT_EQ(a, b) T_ASSERT_MSG0((a == b), #a " != " #b)
+#define T_ASSERT_FLOAT_EQ(a, b, epsilon) \
+ T_ASSERT_MSG0((fabs(a - b) < epsilon), #a " != " #b)
+
+#define T_ASSERT_NULL(a) T_ASSERT_MSG0((a == NULL), #a " is not NULL")
+#define T_ASSERT_NOT_NULL(a) T_ASSERT_MSG0((a != NULL), #a " is NULL")
+
+#define T_ASSERT_STR_EQ(a, b, length) \
+ T_ASSERT_MSG0((strncmp(a, b, length) == 0), #a " != " #b)
+
+#define ARG_COUNT(...) (sizeof((Test[]){__VA_ARGS__}) / sizeof(Test))
+#define TEST_SUITE(...) \
+ Test tests[] = {__VA_ARGS__}; \
+ size_t test_count = ARG_COUNT(__VA_ARGS__);
+#define TEST(x) \
+ { .name = #x, .fn = x }
+
+#endif // LSTD_TESTS_TEST_H
diff --git a/tests/test_runner.c b/tests/test_runner.c
new file mode 100644
index 0000000..f05cd02
--- /dev/null
+++ b/tests/test_runner.c
@@ -0,0 +1,17 @@
+#include "test.h"
+
+#define ANSI_COLOR_GREEN "\x1b[32m"
+#define ANSI_COLOR_RESET "\x1b[0m"
+
+int main(int argc, char **argv) {
+ (void)argc;
+ (void)argv;
+
+ for (size_t i = 0; i < test_count; i++) {
+ fprintf(stderr, "Running test: %s...\n", tests[i].name);
+ tests[i].fn();
+ fprintf(stderr, ANSI_COLOR_GREEN " OK" ANSI_COLOR_RESET "\n");
+ }
+
+ return 0;
+}
Go back to lisible.xyz