Huge refactor, documentation incoming
This commit is contained in:
parent
1e86a8736f
commit
8e29343f3e
@ -4,7 +4,7 @@ AlignAfterOpenBracket: Align
|
|||||||
AlignConsecutiveMacros: 'true'
|
AlignConsecutiveMacros: 'true'
|
||||||
AlignConsecutiveAssignments: 'true'
|
AlignConsecutiveAssignments: 'true'
|
||||||
AlignConsecutiveDeclarations: 'true'
|
AlignConsecutiveDeclarations: 'true'
|
||||||
AlignEscapedNewlines: Left
|
AlignEscapedNewlines: Right
|
||||||
AlignOperands: 'true'
|
AlignOperands: 'true'
|
||||||
AlignTrailingComments: 'true'
|
AlignTrailingComments: 'true'
|
||||||
AllowAllArgumentsOnNextLine: 'true'
|
AllowAllArgumentsOnNextLine: 'true'
|
||||||
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.out
|
||||||
|
vgcore*
|
10
README.org
Normal file
10
README.org
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#+TITLE: CVec: A Simple Vector Implementation in C
|
||||||
|
#+AUTHOR: Lucien Cartier-Tilet
|
||||||
|
#+EMAIL: lucien@phundrak.com
|
||||||
|
#+DATE: 2020-10-03
|
||||||
|
|
||||||
|
* What is this project?
|
||||||
|
CVec is a simple Vector implementation in C, inspired by C++’s ~std::vector~
|
||||||
|
and Rust’s ~std::vec::Vec~. It doesn’t try to be on par with these in terms of
|
||||||
|
features, but simply tries to provide basic features most people will find
|
||||||
|
useful.
|
101
src/vector.c
Normal file
101
src/vector.c
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
Vector vec_new(Destructor destructor)
|
||||||
|
{
|
||||||
|
Vector self;
|
||||||
|
self.length = 0;
|
||||||
|
self.capacity = INITIAL_CAPACITY;
|
||||||
|
self.offset = sizeof(void *);
|
||||||
|
self.elements = (void *)malloc(self.offset * INITIAL_CAPACITY);
|
||||||
|
self.destroy = destructor;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector vec_with_capacity(Destructor t_destructor, size_t t_capacity)
|
||||||
|
{
|
||||||
|
Vector self = vec_new(t_destructor);
|
||||||
|
free(self.elements);
|
||||||
|
self.elements = (void **)malloc(self.offset * t_capacity);
|
||||||
|
self.capacity = t_capacity;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vec_at(Vector *self, size_t t_index)
|
||||||
|
{
|
||||||
|
return self->elements[t_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vec_safe_at(Vector *self, size_t t_index)
|
||||||
|
{
|
||||||
|
return (t_index >= vec_length(self)) ? NULL : vec_at(self, t_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vec_maybe_destroy_element(Vector *self, size_t t_index)
|
||||||
|
{
|
||||||
|
void *element = vec_at(self, t_index);
|
||||||
|
if (self->destroy) {
|
||||||
|
self->destroy(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vec_last(Vector *self)
|
||||||
|
{
|
||||||
|
return vec_at(self, vec_length(self) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t vec_length(Vector *self)
|
||||||
|
{
|
||||||
|
return self->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t vec_capacity(Vector *self)
|
||||||
|
{
|
||||||
|
return self->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vec_realloc(Vector *self)
|
||||||
|
{
|
||||||
|
self->capacity *= 2;
|
||||||
|
self->elements = realloc(self->elements, sizeof(void *) * vec_capacity(self));
|
||||||
|
if (!self->elements) {
|
||||||
|
PDEB("Could not reallocate Vector’s memory, aborting...", NULL);
|
||||||
|
exit(ERR_MEM_ALLOC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec_push(Vector *self, void *t_element)
|
||||||
|
{
|
||||||
|
if (vec_length(self) >= vec_capacity(self)) {
|
||||||
|
vec_realloc(self);
|
||||||
|
}
|
||||||
|
self->elements[(*self).length++] = t_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec_pop(Vector *self)
|
||||||
|
{
|
||||||
|
if (vec_length(self) <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vec_maybe_destroy_element(self, vec_length(self) - 1);
|
||||||
|
--(*self).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec_shrink_to_fit(Vector *self)
|
||||||
|
{
|
||||||
|
self->capacity = self->length;
|
||||||
|
self->elements = realloc(self->elements, sizeof(void *) * vec_capacity(self));
|
||||||
|
if (!self->elements) {
|
||||||
|
PDEB("Could not reallocate Vector’s memory, aborting...", NULL);
|
||||||
|
exit(ERR_MEM_ALLOC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec_delete(Vector *self)
|
||||||
|
{
|
||||||
|
if (self->destroy) {
|
||||||
|
for (size_t i = 0; i < vec_length(self); ++i) {
|
||||||
|
self->destroy(self->elements[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(self->elements);
|
||||||
|
}
|
74
src/vector.h
Normal file
74
src/vector.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef VECTOR_H
|
||||||
|
#define VECTOR_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
# define DEBUG 0
|
||||||
|
#endif
|
||||||
|
#define ERR_MEM_ALLOC 1
|
||||||
|
#define NO_COLOR "\x1b[0m"
|
||||||
|
#define RED "\x1b[31m"
|
||||||
|
#define GREEN "\x1b[32m"
|
||||||
|
#define BROWN "\x1b[33m"
|
||||||
|
#define BLUE "\x1b[34m"
|
||||||
|
#define MAGENTA "\x1b[35m"
|
||||||
|
#define CYAN "\x1b[36m"
|
||||||
|
#define GRAY "\x1b[37m"
|
||||||
|
|
||||||
|
#define UNINPLEMENTED printf("%s:%d: Not yet implemented", __FILE__, __LINE__)
|
||||||
|
#define INITIAL_CAPACITY 4
|
||||||
|
#define PDEB(format, ...) \
|
||||||
|
if (DEBUG) { \
|
||||||
|
fprintf(stderr, \
|
||||||
|
GREEN "%s:%d\t" NO_COLOR format "\n", \
|
||||||
|
__FILE__, \
|
||||||
|
__LINE__, \
|
||||||
|
__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
#define foreach(item, vector) \
|
||||||
|
for (int keep = 1, \
|
||||||
|
count = 0, \
|
||||||
|
size = sizeof(vector->elements) / sizeof vector->elements; \
|
||||||
|
keep && count != size; \
|
||||||
|
keep = !keep, count++) \
|
||||||
|
for (item = \
|
||||||
|
(void *)((char *)(vector->elements) + (count * sizeof(void *))); \
|
||||||
|
keep; \
|
||||||
|
keep = !keep)
|
||||||
|
|
||||||
|
#ifndef ARRAY_SIZE
|
||||||
|
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// `sizeof()' does NOT work with dynamically allocated memory. Vector capacity
|
||||||
|
// must be tracked manually
|
||||||
|
|
||||||
|
/* Destructor typedef */
|
||||||
|
typedef void (*Destructor)(void *element);
|
||||||
|
|
||||||
|
typedef struct Vector_s {
|
||||||
|
size_t length;
|
||||||
|
size_t capacity;
|
||||||
|
size_t offset;
|
||||||
|
void ** elements;
|
||||||
|
Destructor destroy;
|
||||||
|
} Vector;
|
||||||
|
|
||||||
|
Vector vec_new(Destructor destructor);
|
||||||
|
Vector vec_with_capacity(Destructor destructor, size_t capacity);
|
||||||
|
|
||||||
|
void * vec_at(Vector *self, size_t index);
|
||||||
|
void * vec_safe_at(Vector *self, size_t index);
|
||||||
|
void * vec_last(Vector *self);
|
||||||
|
size_t vec_length(Vector *self);
|
||||||
|
size_t vec_capacity(Vector *self);
|
||||||
|
void vec_push(Vector *self, void *element);
|
||||||
|
void vec_pop(Vector *self);
|
||||||
|
void vec_shrink_to_fit(Vector *self);
|
||||||
|
void vec_delete(Vector *self);
|
||||||
|
|
||||||
|
#endif /* VECTOR_H */
|
84
vector.c
84
vector.c
@ -1,84 +0,0 @@
|
|||||||
#include "vector.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
Vector *vec_new(uint32_t obj_size, Destructor destructor)
|
|
||||||
{
|
|
||||||
Vector *self = (Vector *)malloc(sizeof(Vector));
|
|
||||||
(*self).elements = NULL;
|
|
||||||
(*self).obj_size = obj_size;
|
|
||||||
(*self).len = 0;
|
|
||||||
(*self).destructor = destructor;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector *vec_new_with_capacity(uint32_t obj_size,
|
|
||||||
uint32_t obj_number,
|
|
||||||
Destructor destructor)
|
|
||||||
{
|
|
||||||
Vector *self = (Vector *)malloc(sizeof(Vector));
|
|
||||||
(*self).elements = (void **)malloc(obj_number);
|
|
||||||
(*self).obj_size = obj_size;
|
|
||||||
(*self).len = 0;
|
|
||||||
(*self).destructor = destructor;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t vec_len(Vector *self)
|
|
||||||
{
|
|
||||||
return self->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t vec_capacity(Vector *self)
|
|
||||||
{
|
|
||||||
return sizeof(self->elements);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t vec_realloc(Vector *self)
|
|
||||||
{
|
|
||||||
void ** elements = self->elements;
|
|
||||||
uint32_t new_capacity = (vec_capacity(self) > 0) ? vec_capacity(self) * 2 : 1;
|
|
||||||
self->elements = realloc(self->elements, new_capacity);
|
|
||||||
if (!self->elements) {
|
|
||||||
self->elements = elements;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t vec_push(Vector *self, void *element)
|
|
||||||
{
|
|
||||||
UNINPLEMENTED;
|
|
||||||
return 1;
|
|
||||||
/* if (self->len + 1 > vec_capacity(self)) { */
|
|
||||||
/* vec_realloc(self); */
|
|
||||||
/* } */
|
|
||||||
/* ++(*self).len; */
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t vec_pop(Vector *self) {
|
|
||||||
UNINPLEMENTED;
|
|
||||||
return 1;
|
|
||||||
} // TODO
|
|
||||||
|
|
||||||
void *vec_at(Vector *self, uint32_t index)
|
|
||||||
{
|
|
||||||
return self->elements + (index * self->obj_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *vec_at_safe(Vector *self, uint32_t index)
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= self->len) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return vec_at(self, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vec_delete(Vector *self)
|
|
||||||
{
|
|
||||||
foreach (void *elem, self) {
|
|
||||||
self->destructor(elem);
|
|
||||||
}
|
|
||||||
free(self->elements);
|
|
||||||
free(self);
|
|
||||||
}
|
|
38
vector.h
38
vector.h
@ -1,38 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define UNINPLEMENTED printf("%s:%d: Not yet implemented", __FILE__, __LINE__)
|
|
||||||
|
|
||||||
#define foreach(item, vector) \
|
|
||||||
for (int keep = 1, \
|
|
||||||
count = 0, \
|
|
||||||
size = sizeof(vector->elements) / sizeof *(vector->elements); \
|
|
||||||
keep && count != size; \
|
|
||||||
keep = !keep, count++) \
|
|
||||||
for (item = (vector->elements) + (count * vector->obj_size); keep; \
|
|
||||||
keep = !keep)
|
|
||||||
|
|
||||||
typedef void (*Destructor)(void *element);
|
|
||||||
|
|
||||||
struct Vector_s {
|
|
||||||
void ** elements;
|
|
||||||
uint32_t obj_size;
|
|
||||||
uint32_t len;
|
|
||||||
Destructor destructor;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Vector_s Vector;
|
|
||||||
|
|
||||||
Vector * vec_new_with_capacity(uint32_t obj_size,
|
|
||||||
uint32_t obj_number,
|
|
||||||
Destructor destructor); // DONE
|
|
||||||
Vector * vec_new(uint32_t obj_size,
|
|
||||||
Destructor destructor); // DONE
|
|
||||||
uint32_t vec_len(Vector *self); // DONE
|
|
||||||
uint32_t vec_capacity(Vector *self); // DONE
|
|
||||||
uint8_t vec_push(Vector *self, void *element); // TODO
|
|
||||||
uint8_t vec_pop(Vector *self); // TODO
|
|
||||||
void * vec_at(Vector *self, uint32_t index); // DONE
|
|
||||||
void * vec_at_safe(Vector *self, uint32_t index); // DONE
|
|
||||||
void vec_delete(Vector *self); // DONE
|
|
Loading…
Reference in New Issue
Block a user