diff --git a/Documentation.md b/Documentation.md index 4238baa..960d62c 100644 --- a/Documentation.md +++ b/Documentation.md @@ -43,6 +43,7 @@ A contiguous growable array. Elements can be added and removed from both ends of ### Defined Functions * [\_new()](#list_new) +* [\_new\_from()](#list_new_from) * [\_clear()](#list_clear) * [\_free()](#list_free) * [\_push\_front()](#list_push_front) @@ -53,12 +54,17 @@ A contiguous growable array. Elements can be added and removed from both ends of * [\_pop\_back()](#list_pop_back) * [\_push\_if()](#list_push_if) * [\_pop\_if()](#list_pop_if) +* [\_prepend()](#list_prepend) +* [\_insert()](#list_insert) +* [\_append()](#list_append) +* [\_remove()](#list_remove) * [\_front()](#list_front) * [\_get()](#list_get) * [\_back()](#list_back) * [\_empty()](#list_empty) * [\_full()](#list_full) * [\_count()](#list_count) +* [\_fits()](#list_fits) * [\_capacity()](#list_capacity) * [\_iter\_new()](#list_iter_new) * [\_iter\_start()](#list_iter_start) @@ -89,6 +95,28 @@ Allocates and returns a new list with an internal capacity of `size`. If allocat * O(1) +## [ \_new\_from() ](#list_function_index) + +Allocates and returns a new list from an already existing array. The list internal buffer's size will match the size of the given array. + +#### Declaration + +> `FMOD SNAME *PFX##_new_from(V *elements, size_t size);` + +#### Parameters + +1. `V *elements` - Array of elements to be added to the list. +2. `size_t size` - Size of the array of elements. + +#### Returns + +1. `SNAME *` - A pointer to a heap allocated list with the given elements. +2. `NULL` - If allocation fails, or if size equals `0`. + +#### Complexity + +* O(1) + ## [ \_clear() ](#list_function_index) Removes all elements in the list but does not frees the list structure. @@ -303,6 +331,99 @@ Removes an element from a given index if the condition evaluates to true. * O(n) +## [ \_prepend() ](#list_function_index) + +Adds to the front of the list an array of elements with a given size. + +#### Declaration + +> `FMOD bool PFX##_prepend(SNAME *_list_, V *elements, size_t size);` + +#### Parameters + +1. `SNAME *_list_` - Target list. +2. `V *elements` - Array of elements to be added. +3. `size_t size` - The size of the array of elements. + +#### Returns + +1. `true` - If the elements were successfully added to the list. +2. `false` - If buffer reallocation failed, or if `size` parameter equals `0`. + +#### Complexity + +* O(n2) + +## [ \_insert() ](#list_function_index) + +Adds to the specified list an array of elements with a given size to a specific index. The first element of the array of elements will be positioned at that index. + +#### Declaration + +> `FMOD bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index);` + +#### Parameters + +1. `SNAME *_list_` - Target list. +2. `V *elements` - Array of elements to be added. +3. `size_t size` - The size of the array of elements. +4. `size_t index` - Where the array of elements are to be inserted. + +#### Returns + +1. `true` - If the elements were successfully added to the list. +2. `false` - If buffer reallocation failed, if `size` parameter equals `0`, or if the index is greater than `count`. + +#### Complexity + +* O(n2) + +## [ \_append() ](#list_function_index) + +Adds to the back of the list an array of elements with a given size. + +#### Declaration + +> `FMOD bool PFX##_append(SNAME *_list_, V *elements, size_t size);` + +#### Parameters + +1. `SNAME *_list_` - Target list. +2. `V *elements` - Array of elements to be added. +3. `size_t size` - The size of the array of elements. + +#### Returns + +1. `true` - If the elements were successfully added to the list. +2. `false` - If buffer reallocation failed, or if `size` parameter equals `0`. + +#### Complexity + +* O(n) + +## [ \_remove() ](#list_function_index) + +Removes a sequence of elements starting at `from` up to `to`. Both indexes are inclusive. + +#### Declaration + +> `FMOD bool PFX##_remove(SNAME *_list_, size_t from, size_t to);` + +#### Parameters + +1. `SNAME *_list_` - Target list. +2. `V *elements` - Array of elements to be added. +3. `size_t size` - The size of the array of elements. + +#### Returns + +1. `true` - If the elements were successfully removed from the list. +2. `false` - If `from` is greater than `to`, or if `to` is greater than or equal to `count`. + +#### Complexity + +* O(n) + ## [ \_front() ](#list_function_index) Returns the first element (located at index `0`) if the list is not empty. @@ -430,6 +551,28 @@ Returns the amount of elements in the list. * O(1) +## [ \_fits() ](#list_function_index) + +Returns true if a given size fits into the list internal buffer without triggering it to be reallocated. + +#### Declaration + +> `FMOD bool PFX##_fits(SNAME *_list_, size_t size);` + +#### Parameters + +1. `SNAME *_list_` - Target list. +2. `size_t size` - Size of anything. + +#### Returns + +1. `true` - If the given size fits into the internal buffer of the list. +2. `false` - If the given size doesn't fit into the internal buffer of the list. + +#### Complexity + +* O(1) + ## [ \_capacity() ](#list_function_index) Returns the internal buffer's current capacity. diff --git a/examples/list/README.md b/examples/list/README.md index 2219c59..75ea3b9 100644 --- a/examples/list/README.md +++ b/examples/list/README.md @@ -1,3 +1,4 @@ # List examples -Currently none +* list.c - Example of using a list and its iterator. +* string.c - How to treat a list as a mutable string. diff --git a/examples/list/list.c b/examples/list/list.c new file mode 100644 index 0000000..b156186 --- /dev/null +++ b/examples/list/list.c @@ -0,0 +1,72 @@ +/** + * list.c + * + * Creation Date: 08/04/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ +#include +#include "list.h" + +LIST_GENERATE(l, list, /* FMOD */, int) + +int main(int argc, char const *argv[]) +{ + // Create a list with internal capacity of 100 + list *my_list = l_new(100); + + // - push_front (index: 0) [Complexity: O(N)] + // - push (index: give) [Complexity: O(N)*] + // - push_back (index: count) [Complexity: O(1)] + // + // - pop_front (index: 0) [Complexity: O(N)] + // - pop (index: given) [Complexity: O(N)*] + // - push_back (index: count - 1) [Complexity: O(1)] + // + // *average + // + // Average list Input/Output: O(N) + + for (int i = 0; i < 200; i++) + { + // Add elements to the list + l_push_back(my_list, i); + } + + // Erase all values from the list + l_clear(my_list); + + // Now that list is empty, add only even numbers + for (int i = 0; i < 200; i++) + { + // Add even numbers to a given index. In this case they are being added + // to the end of the list (count index == push_back). With a condition + // of being even (i % 2 == 0) + l_push_if(my_list, i, l_count(my_list), i % 2 == 0); + } + + // Iterator + list_iter iter; + int result, sum = 0; + size_t index; + + // Iterate over each element starting from the start (iter_new positions + // the iterator to the start of the list) until the end of the list. + for (l_iter_new(&iter, my_list); !l_iter_end(&iter);) + { + // Here index corresponds to the position of the result relative to all + // other elements in the iteration. It is only a coincidence that the + // index here is the same as the result's position in the list. + l_iter_next(&iter, &result, &index); + + // Do whatever you want with result and index, e.g. + sum += result * index; + } + + // Release resources + l_free(my_list); + + return 0; +} diff --git a/examples/list/string.c b/examples/list/string.c new file mode 100644 index 0000000..022cd90 --- /dev/null +++ b/examples/list/string.c @@ -0,0 +1,85 @@ +/** + * string.c + * + * Creation Date: 08/04/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ +#include +#include +#include "list.h" + +LIST_GENERATE(str, string, /* FMOD */, char) + +int main(int argc, char const *argv[]) +{ + // How to treat a list as a mutable string without \0 at the end + char *example1 = "Lorem ipsum"; + char *example2 = "dolor sit amet"; + char *example3 = "consectetur"; + + string *my_str = str_new_from(example2, strlen(example2)); + + // Add a single character to the front of the list + str_push_front(my_str, ' '); + + // Add a sequence of characters to the front of the list + str_prepend(my_str, example1, strlen(example1)); + + // Add a charater to the back of the list + str_push_back(my_str, ' '); + + // Add a sequence of characters to the back of the list + str_append(my_str, example3, strlen(example3)); + + // Iterate through each letter and print it + string_iter iter; + str_iter_new(&iter, my_str); + size_t index; + char result; + + for (str_iter_tostart(&iter); !str_iter_end(&iter);) + { + str_iter_next(&iter, &result, &index); + putchar(result); + } + + printf("\n"); + + // You can also print it reversed + for (str_iter_toend(&iter); !str_iter_start(&iter);) + { + str_iter_prev(&iter, &result, &index); + putchar(result); + } + + printf("\n"); + + // Now remove the first letter supposing we don't know where it starts + for (size_t i = 0; i < str_count(my_str); i++) + { + // Find first white space + if (str_get(my_str, i) == ' ') + { + index = i; + break; + } + } + + // Now that we know where the first word is, remove it, including the + // extra space. [from, to] are inclusive. + str_remove(my_str, 0, index); + + // Print it once again + for (str_iter_tostart(&iter); !str_iter_end(&iter);) + { + str_iter_next(&iter, &result, &index); + putchar(result); + } + + printf("\nString length: %lu\n", str_count(my_str)); + + return 0; +} diff --git a/src/list.h b/src/list.h index 5f3a69d..e72c096 100644 --- a/src/list.h +++ b/src/list.h @@ -61,6 +61,7 @@ typedef struct SNAME##_iter_s SNAME##_iter; \ \ FMOD SNAME *PFX##_new(size_t size); \ + FMOD SNAME *PFX##_new_from(V *elements, size_t size); \ FMOD void PFX##_clear(SNAME *_list_); \ FMOD void PFX##_free(SNAME *_list_); \ FMOD bool PFX##_push_front(SNAME *_list_, V element); \ @@ -71,12 +72,17 @@ FMOD bool PFX##_pop_back(SNAME *_list_); \ FMOD bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \ FMOD bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition); \ + FMOD bool PFX##_prepend(SNAME *_list_, V *elements, size_t size); \ + FMOD bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index); \ + FMOD bool PFX##_append(SNAME *_list_, V *elements, size_t size); \ + FMOD bool PFX##_remove(SNAME *_list_, size_t from, size_t to); \ FMOD V PFX##_front(SNAME *_list_); \ FMOD V PFX##_get(SNAME *_list_, size_t index); \ FMOD V PFX##_back(SNAME *_list_); \ FMOD bool PFX##_empty(SNAME *_list_); \ FMOD bool PFX##_full(SNAME *_list_); \ FMOD size_t PFX##_count(SNAME *_list_); \ + FMOD bool PFX##_fits(SNAME *_list_, size_t size); \ FMOD size_t PFX##_capacity(SNAME *_list_); \ \ FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \ @@ -90,7 +96,7 @@ /* SOURCE ********************************************************************/ #define LIST_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \ \ - FMOD bool PFX##_grow(SNAME *_list_); \ + FMOD bool PFX##_grow(SNAME *_list_, size_t required); \ \ FMOD SNAME *PFX##_new(size_t size) \ { \ @@ -123,6 +129,28 @@ return _list_; \ } \ \ + FMOD SNAME *PFX##_new_from(V *elements, size_t size) \ + { \ + if (size == 0) \ + return NULL; \ + \ + SNAME *_list_ = PFX##_new(size); \ + \ + if (!_list_) \ + return NULL; \ + \ + for (size_t i = 0; i < size; i++) \ + { \ + if (!PFX##_push_back(_list_, elements[i])) \ + { \ + PFX##_free(_list_); \ + return NULL; \ + } \ + } \ + \ + return _list_; \ + } \ + \ FMOD void PFX##_clear(SNAME *_list_) \ { \ memset(_list_->buffer, 0, sizeof(V) * _list_->capacity); \ @@ -140,7 +168,7 @@ { \ if (PFX##_full(_list_)) \ { \ - if (!PFX##_grow(_list_)) \ + if (!PFX##_grow(_list_, _list_->count + 1)) \ return false; \ } \ \ @@ -175,7 +203,7 @@ \ if (PFX##_full(_list_)) \ { \ - if (!PFX##_grow(_list_)) \ + if (!PFX##_grow(_list_, _list_->count + 1)) \ return false; \ } \ \ @@ -195,7 +223,7 @@ { \ if (PFX##_full(_list_)) \ { \ - if (!PFX##_grow(_list_)) \ + if (!PFX##_grow(_list_, _list_->count + 1)) \ return false; \ } \ \ @@ -272,6 +300,101 @@ return false; \ } \ \ + FMOD bool PFX##_prepend(SNAME *_list_, V *elements, size_t size) \ + { \ + if (size == 0) \ + return false; \ + \ + if (!PFX##_fits(_list_, size)) \ + { \ + if (!PFX##_grow(_list_, _list_->count + size)) \ + return false; \ + } \ + \ + for (size_t i = _list_->count; i > 0; i--) \ + { \ + _list_->buffer[i + size - 1] = _list_->buffer[i - 1]; \ + } \ + \ + for (size_t i = 0; i < size; i++) \ + { \ + _list_->buffer[i] = elements[i]; \ + } \ + \ + _list_->count += size; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index) \ + { \ + if (size == 0 || index > _list_->count) \ + return false; \ + \ + if (index == 0) \ + return PFX##_prepend(_list_, elements, size); \ + else if (index == _list_->count) \ + return PFX##_append(_list_, elements, size); \ + else \ + { \ + if (!PFX##_fits(_list_, size)) \ + { \ + if (!PFX##_grow(_list_, _list_->count + size)) \ + return false; \ + } \ + \ + for (size_t i = _list_->count; i >= index; i--) \ + { \ + _list_->buffer[i + size] = _list_->buffer[i]; \ + } \ + \ + for (size_t i = index, j = 0; j < size; i++, j++) \ + { \ + _list_->buffer[i] = elements[j]; \ + } \ + \ + _list_->count += size; \ + } \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_append(SNAME *_list_, V *elements, size_t size) \ + { \ + if (size == 0) \ + return false; \ + \ + if (!PFX##_fits(_list_, size)) \ + { \ + if (!PFX##_grow(_list_, _list_->count + size)) \ + return false; \ + } \ + \ + for (size_t i = _list_->count, j = 0; j < size; i++, j++) \ + { \ + _list_->buffer[i] = elements[j]; \ + } \ + \ + _list_->count += size; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_remove(SNAME *_list_, size_t from, size_t to) \ + { \ + if (from > to || to >= _list_->count) \ + return false; \ + \ + for (size_t i = from, j = to + 1; i < _list_->count; i++, j++) \ + { \ + _list_->buffer[i] = _list_->buffer[j]; \ + } \ + \ + _list_->count -= to - from + 1; \ + \ + return true; \ + } \ + \ FMOD V PFX##_front(SNAME *_list_) \ { \ if (PFX##_empty(_list_)) \ @@ -314,15 +437,23 @@ return _list_->count; \ } \ \ + FMOD bool PFX##_fits(SNAME *_list_, size_t size) \ + { \ + return _list_->count + size <= _list_->capacity; \ + } \ + \ FMOD size_t PFX##_capacity(SNAME *_list_) \ { \ return _list_->capacity; \ } \ \ - FMOD bool PFX##_grow(SNAME *_list_) \ + FMOD bool PFX##_grow(SNAME *_list_, size_t required) \ { \ size_t new_capacity = _list_->capacity * 2; \ \ + if (new_capacity < required) \ + new_capacity = required; \ + \ V *new_buffer = realloc(_list_->buffer, sizeof(V) * new_capacity); \ \ if (!new_buffer) \