diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | LICENSE | 24 | ||||
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | meson.build | 8 | ||||
| -rw-r--r-- | src/lisiblestd/assert.h | 22 | ||||
| -rw-r--r-- | src/lisiblestd/log.h | 18 | ||||
| -rw-r--r-- | src/lisiblestd/math.h | 6 | ||||
| -rw-r--r-- | src/lisiblestd/memory.c | 135 | ||||
| -rw-r--r-- | src/lisiblestd/memory.h | 41 | ||||
| -rw-r--r-- | src/lisiblestd/string.c | 33 | ||||
| -rw-r--r-- | src/lisiblestd/string.h | 19 | ||||
| -rw-r--r-- | src/lisiblestd/types.h | 20 | ||||
| -rw-r--r-- | tests/string.c | 14 | ||||
| -rw-r--r-- | tests/test.h | 74 | ||||
| -rw-r--r-- | tests/test_runner.c | 17 |
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 @@ -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; +} |
