diff options
-rw-r--r-- | Makefile | 21 | ||||
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | include/container.h | 367 | ||||
-rw-r--r-- | include/rstypes.h | 39 | ||||
-rw-r--r-- | tests/linked_list.c | 35 | ||||
-rw-r--r-- | tests/types.c | 35 |
6 files changed, 489 insertions, 29 deletions
@@ -3,24 +3,27 @@ CC := gcc CFLAGS := -g -Wall -Wextra -Wpedantic -Werror -Wno-language-extension-token -tests: dynarray +tests: container -dynarray: tests/dynarray.c tests/dynarray_struct.c tests/obscure.c tests/binary_search.c +container: tests/dynarray.c tests/dynarray_struct.c tests/obscure.c tests/binary_search.c tests/types.c $(CC) $(CFLAGS) -o $@ $< -DTT_CHAR - ./dynarray + ./$@ $(CC) $(CFLAGS) -o $@ $< -DTT_SHORT - ./dynarray + ./$@ $(CC) $(CFLAGS) -o $@ $< -DTT_INT - ./dynarray + ./$@ $(CC) $(CFLAGS) -o $@ $< -DTT_LONG - ./dynarray + ./$@ $(CC) $(CFLAGS) -o $@ tests/dynarray_struct.c - ./dynarray + ./$@ $(CC) $(CFLAGS) -o $@ tests/obscure.c - ./dynarray + ./$@ $(CC) $(CFLAGS) -o $@ tests/binary_search.c - ./dynarray + ./$@ + $(CC) $(CFLAGS) -o $@ tests/types.c + ./$@ + rm $@ @@ -5,16 +5,17 @@ This is just a collection of (usually single-purpos) header files that I use ref * Names starting with underscores are kind of private-use for this libraries, but they may be declared not `static` because they are used in macros that expose API. * `snake_case` * Function-like macros are not all-caps. -* For now i only support GCC-based compilers. I will consider removing this dependency in future (e.g. getting rid of that [`__qsort_cmps` declaration](include/utility.h)). +* For now i only support GCC-based compilers. I will consider removing this dependency in future (e.g. getting rid of all `typeof` uses) # Descriptions for heders: -## [`dynarray.h`](include/dynarray.h) -* Summary: A flexible and easy-to-use dynamically-sized array implementation based on the idea of storing metadata about array to the left of actual data. this allows it to be used interchangabely as a regular C array and as dynamic array. -* How to use: Define `DYNARRAY_IMPLEMENTATION` macro before including `dynarray.h`. If you are using functions to sort the array (`array_qsort_integral`), you also have to define `UTILITY_IMPLEMENTATION` (as it uses integer comparison functions from there) -* Examples: See [tests](tests/dynarray.c) -## [`utility.h`](include/utility.h) -* Summary: Some commonly-used macros and functions in this library, could as well be called `miscellaneous`. -* How to use: Define `UTILITY_IMPLEMENTATION` macro before including `utility.h`. If you want it to expose helper functions/variables (which you may want, check the source), define macro `UTILITY_EXPOSE_HELPERS`. -* Examples: there are kind of no examples for this, i guess you could search for the usages in [`dynarray.h`](include/dynarray.h) +## [`container.h`](include/container.h) +* Summary: originally was several headers, but since `hash_map.h` used `dynarray.h`, which itself used `utility.h`, it was too complex to work with. So i combined everything in a single header. +* How to use: Define `CONTAINER_IMPLEMENTATION` macro before including `container.h`. It's probably better to `#undef` it after inclusion as well. To use some functions (`__default_int_cmp` and alikes), define `CONTAINER_EXPOSE_HELPERS`. +* Examples: See [tests](tests) +## [`rstypes.h`](include/rstypes.h) +* Summary: rust type aliases (like `u32`, `f128` e.t.c.) +* How to use: if you don't need `i128` or `u128`, then just include the header. If you do need them, define macro `RS_TYPES_USE_128`. +* Examples: See [tests](tests/types.c). +* Notes: Not many compilers support 128-bit wide integers, and ones which DO support them tend to warn you that these are non ISO-C. That's why I've put them behind a macro. If they are not supported, their usage will fail with compilation error. ## [`embed.h`](include/embed.h) * Summary: Code generator for embedding resources directly into an executable. * How to use: It exposes C interface, so in order to use it, you will need to have a C program that builds resources for you. It has it's own repo, but i will be adding CLI to there soon. @@ -25,5 +26,5 @@ nearest TODO for now. # Warning! Everything here is written by a relatively inexperienced student (me), so I guarantee basically nothing. Memory leaks? I am sorry for them, but also not responsible. Security? Haven't heard of that either. That's just how it is. But I try to make everything as good as possible, so you can use the code after a careful review. # License -I did not decide on it yet, but I am inclined towards MIT or even public domain. Don't want to restrict the usage with LGPL, because it's not like this code is a big deal, anyone could write it. Also, I don't want to deal with license issues that I created for myself in future, so yeah, that's how it is. For now, public domain. +I did not decide on it yet, but I am inclined towards MIT or even public domain. Don't want to restrict the usage with LGPL, because it's not like this code is a big deal, anyone could write it. Also, I don't want to deal with license issues that I can create for my future self, so yeah, that's how it is. For now, public domain. diff --git a/include/container.h b/include/container.h index b987d35..7399bed 100644 --- a/include/container.h +++ b/include/container.h @@ -1,7 +1,6 @@ #ifndef JUSTANOTHERCATGIRL_HEADERS_CONTAINER #define JUSTANOTHERCATGIRL_HEADERS_CONTAINER -#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -18,6 +17,7 @@ #define struct_member_size(type, member) sizeof(( (type*)0 )->member) typedef unsigned char byte; +/// Find closest powers of 2 #ifdef __GNUC__ #define upper_2_power_32(number) (32 - __builtin_clz(number)) #define upper_2_power_64(number) (64 - __builtin_clzl(number)) @@ -29,6 +29,8 @@ typedef unsigned char byte; unsigned long __bit_scan_32(int32_t number); unsigned long __bit_scan_64(int64_t number); #endif + +/// define FALLTHROUGH macro #if defined(__clang__) || defined(__GNUC__) #define FALLTHROUGH __attribute__((fallthrough)) #elif defined(_MSC_VER) @@ -37,10 +39,17 @@ typedef unsigned char byte; #define FALLTHROUGH ((void)0) #endif +/// define TODO macro +#define TODO (void)(*(volatile char*)0) + +/// typedefs for array qsort typedef int(*qsort_cmp_t)(const void*, const void*); #define get_qsort_cmp(type) __qsort_cmps[sizeof(type)] extern const qsort_cmp_t __qsort_cmps[64]; +typedef void*(*memcpy_t)(void* restrict, const void*, size_t); + +/// default qsort_cmp_t functions to be used with integral types. #ifdef CONTAINER_EXPOSE_HELPERS #define _CONTAINER_STATIC int __default_char_cmp(const void* a, const void* b); @@ -122,12 +131,127 @@ extern const qsort_cmp_t __qsort_cmps[64]; int array_compare(const void *const a1, const void *const a2, qsort_cmp_t comp); /// Exact copy of the array. you have to free the pointer as well. void* array_copy(void* old); +/// Search for element `element` in array `array` using comparator `cmp`. +/// Returns bool. Assumes that the array is sorted. char array_binary_search(void* array, void* element, qsort_cmp_t cmp); /* ----------------------------------------------------------------- */ /* ----------------------LINKED LIST HEADER------------------------- */ /* ----------------------------------------------------------------- */ -// TODO! + +struct __linked_list_meta { + size_t element_size; + size_t assumed_size; +}; +struct linked_list_node { + void* data; + struct linked_list_node *next; +}; +/// holds meta about list and first element. you should not use it's members. +struct linked_list { + struct __linked_list_meta meta; + struct linked_list_node *first; + struct linked_list_node *last; +}; +/// creates an empty linked list. `memb_size` should usually be sizeof(element type), +/// O(1) +struct linked_list ll_create(size_t memb_size); +/// Created linked list with elements as in buf. copies the memory with `memcpy`. +/// Assumes buffer size is >= buff_len * memb_size +/// O(buff_len) +struct linked_list ll_create_from_buffer(size_t memb_size, const void* buf, size_t buff_len); +/// iteratively frees a linked list +/// O(n) +void ll_free(struct linked_list* list); +/// searches an `element` in the list using `cmp`. returst whether it found it or not. +/// O(n) +char ll_search(const struct linked_list* list, const void* element, qsort_cmp_t cmp); +/// get a pointer to node at index i. DO NOT FREE THIS POINTER. returns NULL if +/// list is not long enough. +/// O(i) +struct linked_list_node* ll_at(const struct linked_list* list, const size_t i); +/// truncate a list starting from index i. if i==0, frees the list and you have to initialize a new one. +/// O(n) +void ll_truncate(struct linked_list* list, const size_t i); +/// returns a size of a list as stored in metadata. +/// Should be same as `ll_definite_size` unless user modifies nodes directly. Which you should not do. +/// O(1) +size_t ll_probably_size(const struct linked_list* list); +/// Counts elements in linked list, updating size in metadata if necessary. +/// if `ll_probably_size` is greater than `ll_definite_size`, there was a memory leak. +// if it is equal, everything is fine +/// else, the creator of the library is dumb. +/// O(n) +size_t ll_definite_size(struct linked_list *list); +/// creates a new node at the end of list and copies memory from element to new node. +/// The amount of memory copied is `memb_size` that was passed in `ll_create*` function. +/// If list->last->next == NULL, O(1) (which is guaranteed if you don't touch the nodes). +void ll_append(struct linked_list *list, const void* restrict element); +/// same as `ll_append`, except it does not perform memcpy and directly assigns pointer to node. +/// the only reqirement to this function is that `pointer` must be freeable with `free` function. +/// ONLY USE THIS IF YOU ARE 100% SURE THAT POINTER CAME UNMODIFIED FROM MALLOC, +/// OTHERWISE THE `ll_free` FUNCTION MAY DOUBLE-FREE, LEAK MEMORY AND OTHER TERRIBLE THINGS. +/// Complexity same as `ll_append`, usually O(1) +void ll_append_mallocated_pointer(struct linked_list *list, void* pointer); +/// inserts an element to the front of the list. +/// O(1) +void ll_insert_front(struct linked_list *list, const void* restrict element); +/// This to `ll_insert_front` is same as `ll_append_mallocated_pointer` to `ll_append`. +/// Copies `pointer` into newly created node. Same security considerations +/// as in `ll_append_mallocated_pointer`. +/// O(1) +void ll_insert_front_mallocated_pointer(struct linked_list *list, void* pointer); +/// inserts an element at index I if it exists. Returns 1 if insertion was successfull, +/// 0 if list is not long enough. +/// O(i) +char ll_insert_at(struct linked_list *list, const void* restrict element, size_t i); +/// copies a pointer directly into newly created node. see `ll_insert_at` +/// and `ll_append_mallocated_pointer` for more details. +/// O(i) +char ll_insert_at_mallocated_pointer(struct linked_list *list, void* pointer, size_t i); +/// removes the element from the front, or, if the list is empty, does nothing +/// O(1) +void ll_remove_front(struct linked_list* list); +/// removes the element from the back, or, if the list is empty, does nothing +/// O(n) +void ll_remove_back(struct linked_list* list); +/// Removes element at index i. if there is no such index, does nothing. +/// O(n) +char ll_remove_at(struct linked_list *list, size_t i); +/// splits a linked list into two, the second one starting from element at index `i`. +/// List that you passed stays valid, only it's size changes. return value is the second list. +/// O(n) +struct linked_list ll_split_at(struct linked_list *list, size_t i); +/// merges 2 lists into one, with elements of second list appearing at the end of first list +/// invalidates second list, leaving only first one valid. +/// O(1) +void ll_merge(struct linked_list* fst, struct linked_list* snd); +/// splits linked list into N linked lists at indexes given in varargs. +/// INDEXES MUST BE IN ASCENDING ORGER, OR ELSE ARE IGNORED. +/// Returns array (as defined in array implementation above). +/// O(n) +struct linked_list* ll_split_n(size_t splits, size_t i, ...); +/// merges N linked lists into one. +/// Leaves first list valid (being), all other ones are invalidated. +/// Lists are appended in the order they are given in varargs. +/// O(`merges`) +void ll_merge_n(size_t merges, struct linked_list *l, ...); +/// creates array (not an array of pointers, array of elements! it uses memcpy to copy elements) +/// Leaves linked list unchanged +void* ll_to_array(const struct linked_list* list); +/// Same as `ll_to_array`, except it acceps function used for copying. Use if you think +/// that your data should not be `memcpy`'d +void* ll_to_array_custom_cpy(const struct linked_list* list, memcpy_t cpy); +/// literally does: +/// 1. linked list to array +/// 2. sort the array using qsort +/// 3. array to linked list +/// since linked list in not random-access, i think this is literally more efficient. +/// Also, I am not in a mood to write sorting algorithms today +void ll_sort(struct linked_list *list, qsort_cmp_t cmp); +/// Deallocates a node and returns next one; +struct linked_list_node* ll_free_node(struct linked_list_node* node); + /* ------------------------------------------------------------------------- */ /* ------From now on, the rest of the header is implementation details------ */ @@ -158,7 +282,7 @@ void *_insert_to_index_dynarray(void *const dynarray, const void *const element, // uncomment in dev mode so that LSP highlights the code -/*#define CONTAINER_IMPLEMENTATION*/ +#define CONTAINER_IMPLEMENTATION #ifdef CONTAINER_IMPLEMENTATION /* ----------------------------------------------------------------- */ @@ -328,7 +452,6 @@ void *_insert_to_index_dynarray(void *const dynarray, const void *const element, int array_compare(const void *const a1, const void *const a2, qsort_cmp_t comp) { struct _dynarray_header *hdr = array_header(a1); struct _dynarray_header *hdr2 = array_header(a2); - assert(hdr->memb_size == hdr2->memb_size && "The arrays being compared do not have same element size"); const size_t s1 = hdr->size, s2 = hdr->size; const size_t elsize = hdr->memb_size; size_t i; @@ -339,14 +462,13 @@ int array_compare(const void *const a1, const void *const a2, qsort_cmp_t comp) if (s1 == s2) return 0; if (i == s1) return -1; if (i == s2) return 1; -#define NDEBUG - assert(0); -#undef NDEBUG + TODO; + __builtin_unreachable(); } -/*void* array_copy(void* old) {*/ -/* //TODO!*/ -/*}*/ +void* array_copy(void* old) { + return _alloc_dynarray_buffer(array_element_size(old), array_size(old), old, array_size(old) * array_element_size(old)); +} char array_binary_search(void* array, void* element, qsort_cmp_t cmp) { ssize_t index1 = -1, @@ -362,6 +484,231 @@ char array_binary_search(void* array, void* element, qsort_cmp_t cmp) { } } +/* ----------------------------------------------------------------- */ +/* ------------------LINKED LIST IMPLEMENTATION--------------------- */ +/* ----------------------------------------------------------------- */ +struct linked_list ll_create(size_t memb_size) { + struct __linked_list_meta meta = { + .assumed_size = 0, + .element_size = memb_size, + }; + struct linked_list ret = { + .meta = meta, + .first = NULL, + .last = NULL, + }; + return ret; +} +struct linked_list ll_create_from_buffer(size_t memb_size, const void* buf, size_t buff_len) { + struct __linked_list_meta meta = { + .assumed_size = buff_len, + .element_size = memb_size, + }; + struct linked_list_node *current_node = calloc(1, sizeof(struct linked_list_node)); + struct linked_list ret = { .meta = meta, .first = current_node }; + for (size_t i = 0; i < buff_len; ++i) { + current_node->data = malloc(memb_size); + memcpy(current_node->data, (const byte *)buf + memb_size * i, memb_size); + if (i != buff_len - 1) { + current_node->next = calloc(1, sizeof(struct linked_list_node)); + current_node = current_node->next; + } + } + ret.last = current_node; + return ret; +} +/// An older, more ugly implementation +void ll_free_(struct linked_list* list) { + struct linked_list_node *to_dealloc = NULL; + for (struct linked_list_node *current = list->first; current != NULL; current = current->next) { + free(to_dealloc); + free(current->data); + to_dealloc = current; + } + free(to_dealloc); + memset(list, 0, sizeof(*list)); +} +void ll_free(struct linked_list* list) { + struct linked_list_node* node = list->first; + while ((node = ll_free_node(node)) != NULL) {} + memset(list, 0, sizeof(*list)); +} +char ll_search(const struct linked_list* list, const void* element, qsort_cmp_t cmp) { + for (struct linked_list_node *current = list->first; current != NULL; current = current->next) { + if (cmp(element, current->data) == 0) return 1; + } + return 0; +} +struct linked_list_node* ll_at(const struct linked_list* list, const size_t i) { + size_t j = 0; + if (i == list->meta.assumed_size - 1) return list->last; + if (i >= list->meta.assumed_size) return NULL; + for (struct linked_list_node *current = list->first; current != NULL; current = current->next) { + if (i == j) return current; + ++j; + } + return NULL; +} +void ll_truncate(struct linked_list* list, const size_t i) { + if (i == 0) { + ll_free(list); + return; + } + struct linked_list_node *start = ll_at(list, i-1); + if (start == NULL) return; + struct linked_list freeable = { + .meta = {list->meta.element_size, list->meta.assumed_size - i}, + .first = start->next, + }; + ll_free(&freeable); + list->meta.assumed_size = i; + start->next = NULL; + list->last = start; +} +size_t ll_probably_size(const struct linked_list* list) { + return list->meta.assumed_size; +} +size_t ll_definite_size(struct linked_list *list) { + int i = 0; + for (struct linked_list_node *current = list->first; current != NULL; current = current->next) + ++i; + list->meta.assumed_size = i; + return i; +} +void ll_append(struct linked_list *list, const void* restrict element) { + struct linked_list_node *new = calloc(1, sizeof(struct linked_list_node)); + new->data = malloc(list->meta.element_size); + memcpy(new->data, element, list->meta.element_size); + if (list->last == NULL) list->first = list->last = new; + else list->last->next = new; + ++list->meta.assumed_size; + list->last = new; +} +void ll_append_mallocated_pointer(struct linked_list *list, void* pointer) { + struct linked_list_node *new = calloc(1, sizeof(struct linked_list_node)); + new->data = pointer; + if (list->last == NULL) list->first = list->last = new; + else list->last->next = new; + ++list->meta.assumed_size; + list->last = new; +} +void ll_insert_front(struct linked_list *list, const void* restrict element) { + struct linked_list_node *new = calloc(1, sizeof(struct linked_list_node)); + new->data = malloc(list->meta.element_size); + memcpy(new->data, element, list->meta.element_size); + if (list->first == NULL) list->first = list->last = new; + else { + new->next = list->first; + list->first = new; + } + ++list->meta.assumed_size; +} +void ll_insert_front_mallocated_pointer(struct linked_list *list, void* pointer) { + struct linked_list_node *new = calloc(1, sizeof(struct linked_list_node)); + new->data = pointer; + if (list->first == NULL) list->first = list->last = new; + else { + new->next = list->first; + list->first = new; + } + ++list->meta.assumed_size; +} +char ll_insert_at(struct linked_list *list, const void* restrict element, size_t i) { + if (i == 0) { + ll_insert_front(list, element); + return 1; + } + if (i == list->meta.assumed_size) { + ll_append(list, element); + return 1; + } + if (list->last == NULL) return 0; + + struct linked_list_node* delim; + if ( (delim = ll_at(list, i-1)) == NULL ) return 0; + struct linked_list_node* new = malloc(sizeof(struct linked_list_node)); + new->next = delim->next; + delim->next = new; + new->data = malloc(list->meta.element_size); + memcpy(new->data, element, list->meta.element_size); + ++list->meta.assumed_size; + return 1; +} +char ll_insert_at_mallocated_pointer(struct linked_list *list, void* pointer, size_t i) { + if (i == 0) { + ll_insert_front_mallocated_pointer(list, pointer); + return 1; + } + if (i == list->meta.assumed_size) { + ll_append_mallocated_pointer(list, pointer); + return 1; + } + if (list->last == NULL) return 0; + + struct linked_list_node* delim; + if ((delim = ll_at(list, i-1)) == NULL) return 0; + struct linked_list_node* new = malloc(sizeof(struct linked_list_node)); + new->next = delim->next; + delim->next = new; + new->data = pointer; + ++list->meta.assumed_size; + return 1; +} +void ll_remove_front(struct linked_list* list) { + if (list->first == NULL) return; + list->first = ll_free_node(list->first); + --list->meta.assumed_size; + if (list->meta.assumed_size <= 1) list->last = list->first; +} +void ll_remove_back(struct linked_list* list) { + if (list->meta.assumed_size == 0) return; + if (list->meta.assumed_size == 1) { + list->first = ll_free_node(list->first); + goto common; + } + if (list->meta.assumed_size == 2) { + list->first->next = ll_free_node(list->last); + list->last = list->first; + goto common; + } + struct linked_list_node* prelast; + if ((prelast = ll_at(list, list->meta.assumed_size-1-1)) == NULL) return; + prelast->next = ll_free_node(list->last); + list->last = prelast; +common: + --list->meta.assumed_size; +} +char ll_remove_at(struct linked_list *list, size_t i) { + if (list->first == NULL) return 0; + if (i == 0) { + ll_remove_front(list); + return 1; + } + if (i == list->meta.assumed_size - 1) { + ll_remove_back(list); + return 1; + } + struct linked_list_node *before_removed; + if ((before_removed = ll_at(list, i-1)) == NULL) return 0; + before_removed->next = ll_free_node(before_removed->next); + --list->meta.assumed_size; + return 1; +} +struct linked_list ll_split_at(struct linked_list *list, size_t i); +void ll_merge(struct linked_list* fst, struct linked_list* snd); +struct linked_list* ll_split_n(size_t splits, size_t i, ...); +void ll_merge_n(size_t merges, struct linked_list *l, ...); +void* ll_to_array(const struct linked_list* list); +void* ll_to_array_custom_cpy(const struct linked_list* list, memcpy_t cpy); +void ll_sort(struct linked_list *list, qsort_cmp_t cmp); +struct linked_list_node* ll_free_node(struct linked_list_node* node) { + if (node == NULL) return NULL; + struct linked_list_node* ret = node->next; + free(node->data); + free(node); + return ret; +} + #endif // CONTAINER_IMPLEMENTATION diff --git a/include/rstypes.h b/include/rstypes.h new file mode 100644 index 0000000..5af5ec5 --- /dev/null +++ b/include/rstypes.h @@ -0,0 +1,39 @@ +#ifndef JUSTANOTHERCATGITL_RSTYPES_H +#define JUSTANOTHERCATGITL_RSTYPES_H + +#include <stdint.h> + +typedef uint8_t u8; +typedef int8_t i8; +typedef uint16_t u16; +typedef int16_t i16; +typedef uint32_t u32; +typedef int32_t i32; +typedef uint64_t u64; +typedef int64_t i64; + +typedef float f32; +typedef double f64; + + +#if defined(__SIZEOF_LONG_DOUBLE__) && __SIZEOF_LONG_DOUBLE__ == 128/8 +typedef long double f128; +#else // __SIZEOF_LONG_DOUBLE__ + #if defined(__clang__) || defined(__GNUC__) + typedef __float128 f128; + #else + #define f128 "128-bit floats are not supported on this platform/compiler" + #endif // __clang__ || __GNUC__ +#endif // __SIZEOF_LONG_DOUBLE__ + +#ifdef RS_TYPES_USE_128 + #if defined(__clang__) || defined(__GNUC__) + typedef __int128 i128; + typedef unsigned __int128 u128; + #else // __clang__ || __GNUC__ + #define i128 "128-bit integers are not supported in this compiler" + #define u128 "128-bit integers are not supported in this compiler" + #endif // __clang__ || __GNUC__ +#endif // RS_TYPES_USE_128 + +#endif // JUSTANOTHERCATGITL_RSTYPES_H diff --git a/tests/linked_list.c b/tests/linked_list.c new file mode 100644 index 0000000..93c5f64 --- /dev/null +++ b/tests/linked_list.c @@ -0,0 +1,35 @@ +#define CONTAINER_IMPLEMENTATION +#include "../include/container.h" +#include <stdio.h> + +void print_linked_list(struct linked_list* list) { + int i = 0; + printf("linked list at %p, size = %zu\n", list, list->meta.assumed_size); + for (struct linked_list_node* current = list->first; current != NULL; current = current->next) { + printf("[%i] = {%i, %p}\n", i, *(int*)current->data, current->next); + ++i; + } +} + +int main() { + struct linked_list list = ll_create(sizeof(int)); + int a = 10; + ll_insert_at(&list, &a, 0); + a = 11; + ll_insert_at(&list, &a, 0); + a = 14; + ll_insert_at(&list, &a, 2); + ll_insert_at(&list, &a, 3); + ll_insert_at(&list, &a, 1); + + print_linked_list(&list); + ll_remove_back(&list); + ll_remove_front(&list); + print_linked_list(&list); + ll_remove_at(&list, 1); + ll_remove_at(&list, 0); + ll_remove_at(&list, 0); + print_linked_list(&list); + ll_free(&list); + return 0; +} diff --git a/tests/types.c b/tests/types.c new file mode 100644 index 0000000..4320e8d --- /dev/null +++ b/tests/types.c @@ -0,0 +1,35 @@ +#include <stdio.h> +#include "../include/rstypes.h" + +i32 main() { + u8 a = 215; + i8 b = -127; + u16 c = 65535; + i16 d = -32000; + u32 e = 0xFFFFFFF; + i32 f = -1; + u64 g = 0xFAFAFAFAFAFAFAFA; + i64 h = -4000000000000000000; + u128 i = 0xFFFFFFFFFFFFFFFF; + i128 j = 0; + i <<= 64; i |= 0xFFFFFFFFFFFFFFFF; + j = i; + + f32 k = 5e-23; + f64 l = -2e300; + f128 m = 3e300; + m *= 1e100; + + printf( "a: %hhu, b: %hhi\n" + "c: %hu, d: %hi\n" + "e: %u, f: %d\n" + "g: %lu, h: %li\n", + a, b, c, d, e, f, g, h); + printf("i: %lX%.16lX, jL %lx%.16lx\n", + (unsigned long) (i >> 64), (unsigned long) i, + (long) (j >> 64), (long) j ); + + printf("k: %.2E\nl: %.2lE\nm: %.2LE\n", k, l, m); + + return (j == -1 && i+1 == 0 ? 0 : 1); +} |