Reorganizing tests
This commit is contained in:
1 parent
5504f82052
commit
f454934b07
10 files changed
+848
-31
No files matched your search
@@ -14,5 +14,7 @@ script:
|
||||
- export CC=gcc-7
|
||||
- cd ./tests
|
||||
- make
|
||||
- cd main
|
||||
- make
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -1,7 +1,6 @@
|
||||
CC = gcc
|
||||
CFLAGS = -std=c11 -Wall -Wextra
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-paramter -Wno-unused-variable -Wno-unused-label
|
||||
CVFLAGS = --coverage -O0
|
||||
|
||||
main:
|
||||
$(CC) foreach.c -o foreach $(CFLAGS)
|
||||
@@ -16,6 +15,3 @@ main:
|
||||
$(CC) -c ./sep/main.c -o ./sep/main.o $(CFLAGS)
|
||||
$(CC) ./sep/sep.o ./sep/main.o -o ./sep/sep
|
||||
./sep/sep
|
||||
$(CC) list.c -o list $(CFLAGS) $(CVFLAGS)
|
||||
./list
|
||||
gcov ./list.c
|
||||
@@ -1,5 +1,6 @@
|
||||
# Tests
|
||||
|
||||
* `main` - Unit tests for the main C Macro Collections library with code coverage;
|
||||
* `sep/main.c`, `sep/sep.c` and `sep/sep.h` - Tests separate header and source compilation;
|
||||
* `contains.c` - Tests the `contains` function for all collections;
|
||||
* `foreach.c` - Tests the ForEach macros for all collections;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
CC = gcc
|
||||
CFLAGS = -std=c11 -Wall -Wextra
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-paramter -Wno-unused-variable -Wno-unused-label
|
||||
CVFLAGS = --coverage -O0
|
||||
INCLUDE = ../../src/
|
||||
|
||||
main:
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c
|
||||
@@ -0,0 +1,7 @@
|
||||
# main
|
||||
|
||||
Tests for the main C Macro Collections library. In order to provide a good code coverage, all macros have been expanded and added to `src/*.c`.
|
||||
|
||||
* `src` - Since gcov fails to detect code that was expanded by macro, all collections where manually expanded and dumped into their respective source files;
|
||||
* `unt` - Unit Tests;
|
||||
* `main.c` - Where all tests are compiled together and called by main().
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "unt/list.c"
|
||||
#include "unt/deque.c"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
deque_test();
|
||||
list_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
#include "macro_collections.h"
|
||||
|
||||
typedef struct deque_s
|
||||
{
|
||||
size_t *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
size_t front;
|
||||
size_t back;
|
||||
struct deque_iter_s (*it_start)(struct deque_s *);
|
||||
struct deque_iter_s (*it_end)(struct deque_s *);
|
||||
} deque, *deque_ptr;
|
||||
typedef struct deque_iter_s
|
||||
{
|
||||
struct deque_s *target;
|
||||
size_t cursor;
|
||||
size_t index;
|
||||
_Bool start;
|
||||
_Bool end;
|
||||
} deque_iter, *deque_iter_ptr;
|
||||
deque *d_new(size_t capacity);
|
||||
void d_clear(deque *_deque_);
|
||||
void d_free(deque *_deque_);
|
||||
_Bool d_push_front(deque *_deque_, size_t element);
|
||||
_Bool d_push_back(deque *_deque_, size_t element);
|
||||
_Bool d_pop_front(deque *_deque_);
|
||||
_Bool d_pop_back(deque *_deque_);
|
||||
_Bool d_push_front_if(deque *_deque_, size_t element, _Bool condition);
|
||||
_Bool d_push_back_if(deque *_deque_, size_t element, _Bool condition);
|
||||
_Bool d_pop_front_if(deque *_deque_, _Bool condition);
|
||||
_Bool d_pop_back_if(deque *_deque_, _Bool condition);
|
||||
size_t d_front(deque *_deque_);
|
||||
size_t d_back(deque *_deque_);
|
||||
_Bool d_contains(deque *_deque_, size_t element, int (*comparator)(size_t, size_t));
|
||||
_Bool d_empty(deque *_deque_);
|
||||
_Bool d_full(deque *_deque_);
|
||||
size_t d_count(deque *_deque_);
|
||||
size_t d_capacity(deque *_deque_);
|
||||
deque_iter *d_iter_new(deque *target);
|
||||
void d_iter_free(deque_iter *iter);
|
||||
void d_iter_init(deque_iter *iter, deque *target);
|
||||
_Bool d_iter_start(deque_iter *iter);
|
||||
_Bool d_iter_end(deque_iter *iter);
|
||||
void d_iter_to_start(deque_iter *iter);
|
||||
void d_iter_to_end(deque_iter *iter);
|
||||
_Bool d_iter_next(deque_iter *iter);
|
||||
_Bool d_iter_prev(deque_iter *iter);
|
||||
size_t d_iter_value(deque_iter *iter);
|
||||
size_t *d_iter_rvalue(deque_iter *iter);
|
||||
size_t d_iter_index(deque_iter *iter);
|
||||
static inline size_t d_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static _Bool d_impl_grow(deque *_deque_);
|
||||
static deque_iter d_impl_it_start(deque *_deque_);
|
||||
static deque_iter d_impl_it_end(deque *_deque_);
|
||||
deque *d_new(size_t capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
return ((void *)0);
|
||||
deque *_deque_ = malloc(sizeof(deque));
|
||||
if (!_deque_)
|
||||
return ((void *)0);
|
||||
_deque_->buffer = malloc(sizeof(size_t) * capacity);
|
||||
if (!_deque_->buffer)
|
||||
{
|
||||
free(_deque_);
|
||||
return ((void *)0);
|
||||
}
|
||||
memset(_deque_->buffer, 0, sizeof(size_t) * capacity);
|
||||
_deque_->capacity = capacity;
|
||||
_deque_->count = 0;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = 0;
|
||||
_deque_->it_start = d_impl_it_start;
|
||||
_deque_->it_end = d_impl_it_end;
|
||||
return _deque_;
|
||||
}
|
||||
void d_clear(deque *_deque_)
|
||||
{
|
||||
memset(_deque_->buffer, 0, sizeof(size_t) * _deque_->capacity);
|
||||
_deque_->count = 0;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = 0;
|
||||
}
|
||||
void d_free(deque *_deque_)
|
||||
{
|
||||
free(_deque_->buffer);
|
||||
free(_deque_);
|
||||
}
|
||||
_Bool d_push_front(deque *_deque_, size_t element)
|
||||
{
|
||||
if (d_full(_deque_))
|
||||
{
|
||||
if (!d_impl_grow(_deque_))
|
||||
return 0;
|
||||
}
|
||||
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1;
|
||||
_deque_->buffer[_deque_->front] = element;
|
||||
_deque_->count++;
|
||||
return 1;
|
||||
}
|
||||
_Bool d_push_back(deque *_deque_, size_t element)
|
||||
{
|
||||
if (d_full(_deque_))
|
||||
{
|
||||
if (!d_impl_grow(_deque_))
|
||||
return 0;
|
||||
}
|
||||
_deque_->buffer[_deque_->back] = element;
|
||||
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1;
|
||||
_deque_->count++;
|
||||
return 1;
|
||||
}
|
||||
_Bool d_pop_front(deque *_deque_)
|
||||
{
|
||||
if (d_empty(_deque_))
|
||||
return 0;
|
||||
_deque_->buffer[_deque_->front] = d_impl_default_value();
|
||||
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1;
|
||||
_deque_->count--;
|
||||
return 1;
|
||||
}
|
||||
_Bool d_pop_back(deque *_deque_)
|
||||
{
|
||||
if (d_empty(_deque_))
|
||||
return 0;
|
||||
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1;
|
||||
_deque_->buffer[_deque_->back] = d_impl_default_value();
|
||||
_deque_->count--;
|
||||
return 1;
|
||||
}
|
||||
_Bool d_push_front_if(deque *_deque_, size_t element, _Bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return d_push_front(_deque_, element);
|
||||
return 0;
|
||||
}
|
||||
_Bool d_push_back_if(deque *_deque_, size_t element, _Bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return d_push_back(_deque_, element);
|
||||
return 0;
|
||||
}
|
||||
_Bool d_pop_front_if(deque *_deque_, _Bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return d_pop_front(_deque_);
|
||||
return 0;
|
||||
}
|
||||
_Bool d_pop_back_if(deque *_deque_, _Bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return d_pop_back(_deque_);
|
||||
return 0;
|
||||
}
|
||||
size_t d_front(deque *_deque_)
|
||||
{
|
||||
if (d_empty(_deque_))
|
||||
d_impl_default_value();
|
||||
return _deque_->buffer[_deque_->front];
|
||||
}
|
||||
size_t d_back(deque *_deque_)
|
||||
{
|
||||
if (d_empty(_deque_))
|
||||
d_impl_default_value();
|
||||
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1];
|
||||
}
|
||||
_Bool d_contains(deque *_deque_, size_t element, int (*comparator)(size_t, size_t))
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->count, j++)
|
||||
{
|
||||
if (comparator(_deque_->buffer[i], element) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
_Bool d_empty(deque *_deque_) { return _deque_->count == 0; }
|
||||
_Bool d_full(deque *_deque_) { return _deque_->count >= _deque_->capacity; }
|
||||
size_t d_count(deque *_deque_) { return _deque_->count; }
|
||||
size_t d_capacity(deque *_deque_) { return _deque_->capacity; }
|
||||
deque_iter *d_iter_new(deque *target)
|
||||
{
|
||||
deque_iter *iter = malloc(sizeof(deque_iter));
|
||||
if (!iter)
|
||||
return ((void *)0);
|
||||
d_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void d_iter_free(deque_iter *iter) { free(iter); }
|
||||
void d_iter_init(deque_iter *iter, deque *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = target->front;
|
||||
iter->index = 0;
|
||||
iter->start = 1;
|
||||
iter->end = d_empty(target);
|
||||
}
|
||||
_Bool d_iter_start(deque_iter *iter) { return d_empty(iter->target) || iter->start; }
|
||||
_Bool d_iter_end(deque_iter *iter) { return d_empty(iter->target) || iter->end; }
|
||||
void d_iter_to_start(deque_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->front;
|
||||
iter->index = 0;
|
||||
iter->start = 1;
|
||||
iter->end = d_empty(iter->target);
|
||||
}
|
||||
void d_iter_to_end(deque_iter *iter)
|
||||
{
|
||||
if (d_empty(iter->target))
|
||||
iter->cursor = 0;
|
||||
else
|
||||
iter->cursor = (iter->target->back == 0) ? iter->target->capacity - 1 : iter->target->back - 1;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = d_empty(iter->target);
|
||||
iter->end = 1;
|
||||
}
|
||||
_Bool d_iter_next(deque_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return 0;
|
||||
iter->start = d_empty(iter->target);
|
||||
if (iter->index == iter->target->count - 1)
|
||||
iter->end = 1;
|
||||
else
|
||||
{
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity);
|
||||
iter->index++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
_Bool d_iter_prev(deque_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return 0;
|
||||
iter->end = d_empty(iter->target);
|
||||
if (iter->index == 0)
|
||||
iter->start = 1;
|
||||
else
|
||||
{
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1;
|
||||
iter->index--;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
size_t d_iter_value(deque_iter *iter)
|
||||
{
|
||||
if (d_empty(iter->target))
|
||||
d_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
size_t *d_iter_rvalue(deque_iter *iter)
|
||||
{
|
||||
if (d_empty(iter->target))
|
||||
return ((void *)0);
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
size_t d_iter_index(deque_iter *iter) { return iter->index; }
|
||||
static _Bool d_impl_grow(deque *_deque_)
|
||||
{
|
||||
size_t new_capacity = _deque_->capacity * 2;
|
||||
size_t *new_buffer = malloc(sizeof(size_t) * new_capacity);
|
||||
if (!new_buffer)
|
||||
return 0;
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++)
|
||||
{
|
||||
new_buffer[j] = _deque_->buffer[i];
|
||||
}
|
||||
free(_deque_->buffer);
|
||||
_deque_->buffer = new_buffer;
|
||||
_deque_->capacity = new_capacity;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = _deque_->count;
|
||||
return 1;
|
||||
}
|
||||
static deque_iter d_impl_it_start(deque *_deque_)
|
||||
{
|
||||
deque_iter iter;
|
||||
d_iter_init(&iter, _deque_);
|
||||
return iter;
|
||||
}
|
||||
static deque_iter d_impl_it_end(deque *_deque_)
|
||||
{
|
||||
deque_iter iter;
|
||||
d_iter_init(&iter, _deque_);
|
||||
d_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
#include "macro_collections.h"
|
||||
|
||||
typedef struct list_s
|
||||
{
|
||||
size_t *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
struct list_iter_s (*it_start)(struct list_s *);
|
||||
struct list_iter_s (*it_end)(struct list_s *);
|
||||
} list, *list_ptr;
|
||||
typedef struct list_iter_s
|
||||
{
|
||||
struct list_s *target;
|
||||
size_t cursor;
|
||||
bool start;
|
||||
bool end;
|
||||
} list_iter, *list_iter_ptr;
|
||||
list *l_new(size_t capacity);
|
||||
list *l_new_from(size_t *elements, size_t size);
|
||||
void l_clear(list *_list_);
|
||||
void l_free(list *_list_);
|
||||
bool l_push_front(list *_list_, size_t element);
|
||||
bool l_push(list *_list_, size_t element, size_t index);
|
||||
bool l_push_back(list *_list_, size_t element);
|
||||
bool l_pop_front(list *_list_);
|
||||
bool l_pop(list *_list_, size_t index);
|
||||
bool l_pop_back(list *_list_);
|
||||
bool l_push_if(list *_list_, size_t element, size_t index, bool condition);
|
||||
bool l_pop_if(list *_list_, size_t index, bool condition);
|
||||
bool l_prepend(list *_list_, size_t *elements, size_t size);
|
||||
bool l_insert(list *_list_, size_t *elements, size_t size, size_t index);
|
||||
bool l_append(list *_list_, size_t *elements, size_t size);
|
||||
bool l_remove(list *_list_, size_t from, size_t to);
|
||||
list *l_extract(list *_list_, size_t from, size_t to);
|
||||
size_t l_front(list *_list_);
|
||||
size_t l_get(list *_list_, size_t index);
|
||||
size_t *l_get_ref(list *_list_, size_t index);
|
||||
size_t l_back(list *_list_);
|
||||
size_t l_indexof(list *_list_, size_t element, int (*comparator)(size_t, size_t), bool from_start);
|
||||
bool l_contains(list *_list_, size_t element, int (*comparator)(size_t, size_t));
|
||||
bool l_empty(list *_list_);
|
||||
bool l_full(list *_list_);
|
||||
size_t l_count(list *_list_);
|
||||
bool l_fits(list *_list_, size_t size);
|
||||
size_t l_capacity(list *_list_);
|
||||
list_iter *l_iter_new(list *target);
|
||||
void l_iter_free(list_iter *iter);
|
||||
void l_iter_init(list_iter *iter, list *target);
|
||||
bool l_iter_start(list_iter *iter);
|
||||
bool l_iter_end(list_iter *iter);
|
||||
void l_iter_to_start(list_iter *iter);
|
||||
void l_iter_to_end(list_iter *iter);
|
||||
bool l_iter_next(list_iter *iter);
|
||||
bool l_iter_prev(list_iter *iter);
|
||||
size_t l_iter_value(list_iter *iter);
|
||||
size_t *l_iter_rvalue(list_iter *iter);
|
||||
size_t l_iter_index(list_iter *iter);
|
||||
static inline size_t l_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
|
||||
static bool l_impl_grow(list *_list_, size_t required);
|
||||
static list_iter l_impl_it_start(list *_list_);
|
||||
static list_iter l_impl_it_end(list *_list_);
|
||||
list *l_new(size_t capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
list *_list_ = malloc(sizeof(list));
|
||||
if (!_list_)
|
||||
return NULL;
|
||||
_list_->buffer = malloc(capacity * sizeof(size_t));
|
||||
if (!_list_->buffer)
|
||||
{
|
||||
free(_list_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_list_->buffer, 0, capacity * sizeof(size_t));
|
||||
_list_->capacity = capacity;
|
||||
_list_->count = 0;
|
||||
_list_->it_start = l_impl_it_start;
|
||||
_list_->it_end = l_impl_it_end;
|
||||
return _list_;
|
||||
}
|
||||
list *l_new_from(size_t *elements, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
list *_list_ = l_new(size + size / 2);
|
||||
if (!_list_)
|
||||
return NULL;
|
||||
memcpy(_list_->buffer, elements, size * sizeof(size_t));
|
||||
_list_->count = size;
|
||||
return _list_;
|
||||
}
|
||||
void l_clear(list *_list_)
|
||||
{
|
||||
memset(_list_->buffer, 0, sizeof(size_t) * _list_->capacity);
|
||||
_list_->count = 0;
|
||||
}
|
||||
void l_free(list *_list_)
|
||||
{
|
||||
free(_list_->buffer);
|
||||
free(_list_);
|
||||
}
|
||||
bool l_push_front(list *_list_, size_t element)
|
||||
{
|
||||
if (l_full(_list_))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + 1))
|
||||
return false;
|
||||
}
|
||||
if (!l_empty(_list_))
|
||||
{
|
||||
memmove(_list_->buffer + 1, _list_->buffer, _list_->count * sizeof(size_t));
|
||||
}
|
||||
_list_->buffer[0] = element;
|
||||
_list_->count++;
|
||||
return true;
|
||||
}
|
||||
bool l_push(list *_list_, size_t element, size_t index)
|
||||
{
|
||||
if (index > _list_->count)
|
||||
return false;
|
||||
if (index == 0)
|
||||
{
|
||||
return l_push_front(_list_, element);
|
||||
}
|
||||
else if (index == _list_->count)
|
||||
{
|
||||
return l_push_back(_list_, element);
|
||||
}
|
||||
if (l_full(_list_))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + 1))
|
||||
return false;
|
||||
}
|
||||
memmove(_list_->buffer + index + 1, _list_->buffer + index, (_list_->count - index) * sizeof(size_t));
|
||||
_list_->buffer[index] = element;
|
||||
_list_->count++;
|
||||
return true;
|
||||
}
|
||||
bool l_push_back(list *_list_, size_t element)
|
||||
{
|
||||
if (l_full(_list_))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + 1))
|
||||
return false;
|
||||
}
|
||||
_list_->buffer[_list_->count++] = element;
|
||||
return true;
|
||||
}
|
||||
bool l_pop_front(list *_list_)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return false;
|
||||
memmove(_list_->buffer, _list_->buffer + 1, _list_->count * sizeof(size_t));
|
||||
_list_->buffer[--_list_->count] = l_impl_default_value();
|
||||
return true;
|
||||
}
|
||||
bool l_pop(list *_list_, size_t index)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return false;
|
||||
if (index >= _list_->count)
|
||||
return false;
|
||||
if (index == 0)
|
||||
{
|
||||
return l_pop_front(_list_);
|
||||
}
|
||||
else if (index == _list_->count - 1)
|
||||
{
|
||||
return l_pop_back(_list_);
|
||||
}
|
||||
memmove(_list_->buffer + index, _list_->buffer + index + 1, (_list_->count - index) * sizeof(size_t));
|
||||
_list_->buffer[--_list_->count] = l_impl_default_value();
|
||||
return true;
|
||||
}
|
||||
bool l_pop_back(list *_list_)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return false;
|
||||
_list_->buffer[--_list_->count] = l_impl_default_value();
|
||||
return true;
|
||||
}
|
||||
bool l_push_if(list *_list_, size_t element, size_t index, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return l_push(_list_, element, index);
|
||||
return false;
|
||||
}
|
||||
bool l_pop_if(list *_list_, size_t index, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return l_pop(_list_, index);
|
||||
return false;
|
||||
}
|
||||
bool l_prepend(list *_list_, size_t *elements, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return false;
|
||||
if (!l_fits(_list_, size))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
memmove(_list_->buffer + size, _list_->buffer, _list_->count * sizeof(size_t));
|
||||
memcpy(_list_->buffer, elements, size * sizeof(size_t));
|
||||
_list_->count += size;
|
||||
return true;
|
||||
}
|
||||
bool l_insert(list *_list_, size_t *elements, size_t size, size_t index)
|
||||
{
|
||||
if (size == 0 || index > _list_->count)
|
||||
return false;
|
||||
if (index == 0)
|
||||
return l_prepend(_list_, elements, size);
|
||||
else if (index == _list_->count)
|
||||
return l_append(_list_, elements, size);
|
||||
else
|
||||
{
|
||||
if (!l_fits(_list_, size))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
memmove(_list_->buffer + index + size, _list_->buffer + index, (_list_->count - index) * sizeof(size_t));
|
||||
memcpy(_list_->buffer + index, elements, size * sizeof(size_t));
|
||||
_list_->count += size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool l_append(list *_list_, size_t *elements, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return false;
|
||||
if (!l_fits(_list_, size))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
memcpy(_list_->buffer + _list_->count, elements, size * sizeof(size_t));
|
||||
_list_->count += size;
|
||||
return true;
|
||||
}
|
||||
bool l_remove(list *_list_, size_t from, size_t to)
|
||||
{
|
||||
if (from > to || to >= _list_->count)
|
||||
return false;
|
||||
size_t length = (to - from + 1);
|
||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(size_t));
|
||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(size_t));
|
||||
_list_->count -= to - from + 1;
|
||||
return true;
|
||||
}
|
||||
list *l_extract(list *_list_, size_t from, size_t to)
|
||||
{
|
||||
if (from > to || to >= _list_->count)
|
||||
return false;
|
||||
size_t length = to - from + 1;
|
||||
list *result = l_new_from(_list_->buffer + from, length);
|
||||
if (!result)
|
||||
return NULL;
|
||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(size_t));
|
||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(size_t));
|
||||
_list_->count -= length;
|
||||
return result;
|
||||
}
|
||||
size_t l_front(list *_list_)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return l_impl_default_value();
|
||||
return _list_->buffer[0];
|
||||
}
|
||||
size_t l_get(list *_list_, size_t index)
|
||||
{
|
||||
if (index >= _list_->count || l_empty(_list_))
|
||||
return l_impl_default_value();
|
||||
return _list_->buffer[index];
|
||||
}
|
||||
size_t *l_get_ref(list *_list_, size_t index)
|
||||
{
|
||||
if (index >= _list_->count)
|
||||
return NULL;
|
||||
if (l_empty(_list_))
|
||||
return NULL;
|
||||
return &(_list_->buffer[index]);
|
||||
}
|
||||
size_t l_back(list *_list_)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return l_impl_default_value();
|
||||
return _list_->buffer[_list_->count - 1];
|
||||
}
|
||||
size_t l_indexof(list *_list_, size_t element, int (*comparator)(size_t, size_t), bool from_start)
|
||||
{
|
||||
if (from_start)
|
||||
{
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
{
|
||||
if (comparator(_list_->buffer[i], element) == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = _list_->count; i > 0; i--)
|
||||
{
|
||||
if (comparator(_list_->buffer[i - 1], element) == 0)
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
return _list_->count;
|
||||
}
|
||||
bool l_contains(list *_list_, size_t element, int (*comparator)(size_t, size_t))
|
||||
{
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
{
|
||||
if (comparator(_list_->buffer[i], element) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool l_empty(list *_list_) { return _list_->count == 0; }
|
||||
bool l_full(list *_list_) { return _list_->count >= _list_->capacity; }
|
||||
size_t l_count(list *_list_) { return _list_->count; }
|
||||
bool l_fits(list *_list_, size_t size) { return _list_->count + size <= _list_->capacity; }
|
||||
size_t l_capacity(list *_list_) { return _list_->capacity; }
|
||||
list_iter *l_iter_new(list *target)
|
||||
{
|
||||
list_iter *iter = malloc(sizeof(list_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
l_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void l_iter_free(list_iter *iter) { free(iter); }
|
||||
void l_iter_init(list_iter *iter, list *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = l_empty(target);
|
||||
}
|
||||
bool l_iter_start(list_iter *iter) { return l_empty(iter->target) || iter->start; }
|
||||
bool l_iter_end(list_iter *iter) { return l_empty(iter->target) || iter->end; }
|
||||
void l_iter_to_start(list_iter *iter)
|
||||
{
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = l_empty(iter->target);
|
||||
}
|
||||
void l_iter_to_end(list_iter *iter)
|
||||
{
|
||||
iter->start = l_empty(iter->target);
|
||||
iter->cursor = l_empty(iter->target) ? 0 : iter->target->count - 1;
|
||||
iter->end = true;
|
||||
}
|
||||
bool l_iter_next(list_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = l_empty(iter->target);
|
||||
if (iter->cursor == iter->target->count - 1)
|
||||
iter->end = true;
|
||||
else
|
||||
iter->cursor++;
|
||||
return true;
|
||||
}
|
||||
bool l_iter_prev(list_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = l_empty(iter->target);
|
||||
if (iter->cursor == 0)
|
||||
iter->start = true;
|
||||
else
|
||||
iter->cursor--;
|
||||
return true;
|
||||
}
|
||||
size_t l_iter_value(list_iter *iter)
|
||||
{
|
||||
if (l_empty(iter->target))
|
||||
return l_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
size_t *l_iter_rvalue(list_iter *iter)
|
||||
{
|
||||
if (l_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
size_t l_iter_index(list_iter *iter) { return iter->cursor; }
|
||||
static bool l_impl_grow(list *_list_, size_t required)
|
||||
{
|
||||
size_t new_capacity = _list_->capacity * 2;
|
||||
if (new_capacity < required)
|
||||
new_capacity = required;
|
||||
size_t *new_buffer = realloc(_list_->buffer, sizeof(size_t) * new_capacity);
|
||||
if (!new_buffer)
|
||||
return false;
|
||||
_list_->buffer = new_buffer;
|
||||
_list_->capacity = new_capacity;
|
||||
return true;
|
||||
}
|
||||
static list_iter l_impl_it_start(list *_list_)
|
||||
{
|
||||
list_iter iter;
|
||||
l_iter_init(&iter, _list_);
|
||||
l_iter_to_start(&iter);
|
||||
return iter;
|
||||
}
|
||||
static list_iter l_impl_it_end(list *_list_)
|
||||
{
|
||||
list_iter iter;
|
||||
l_iter_init(&iter, _list_);
|
||||
l_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "../src/deque.c"
|
||||
|
||||
CMC_CREATE_UNIT(deque_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
deque *d = d_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
bool passed = d->capacity == 1000000 && d->count == 0 && d->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, d->capacity);
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
cmc_assert_not_equals(ptr, NULL, d->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
d_free(d);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
deque *d = d_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, d);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d == NULL);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "../src/macro_collections.h"
|
||||
|
||||
LIST_GENERATE(l, list, , size_t)
|
||||
#include "../src/list.c"
|
||||
|
||||
CMC_CREATE_UNIT(list_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
@@ -22,7 +20,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new [edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
list *l = l_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, l);
|
||||
@@ -56,7 +54,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new_from [edge_case:size = 1], {
|
||||
CMC_CREATE_TEST(new_from[edge_case:size = 1], {
|
||||
size_t a = 10;
|
||||
|
||||
size_t *values = &a;
|
||||
@@ -173,7 +171,17 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front [edge_case:count = 1], {
|
||||
CMC_CREATE_TEST(pop_front[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop_front(l));
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
@@ -185,24 +193,13 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front [edge_case:count = 2], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_push_front(l, 10));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_pop_front(l) && l_count(l) == 1);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[buffer_clear], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_push_front(l, 10));
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_push_front(l, 2));
|
||||
|
||||
// Default value is all bytes are 0
|
||||
bool passed = l_pop_front(l) && l->buffer[1] == 0;
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[1]);
|
||||
@@ -211,11 +208,64 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(!l_pop(l, 1));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_pop(l, 0));
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[0]);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[buffer_clear], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_push_back(l, 2));
|
||||
cmc_assert(l_push_back(l, 3));
|
||||
cmc_assert(l_pop(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(0 == l->buffer[2]);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop_back(l));
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_pop_back(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
})
|
||||
|
||||
int main(void)
|
||||
{
|
||||
list_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user