Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ vector_add(&char_vec, 'a');

// print the item from the vector
printf("first item: %c\n", char_vec[0]);

// add elements in array
const char s[] = " test with char vector"
vector_add_arr(&char_vec, s, sizeof(s));

// insert elements in array
const char s2[] = "(inserting)"
int insert_pos = sizeof("a test with");// a trick about indexing a string
vector_insert_arr(&char_vec, insert_pos, s2, strlen(s2));

// print the char vector as string(char*)
printf("full char vector: \"%s\"\n", char_vec);
```

Vectors require that their pointer type corresponds to the contents of the vector (e.g. `int*` for a vector containing `int`s); otherwise, you have to explicitly cast the vector pointer to the correct type when accessing elements or making library calls:
Expand All @@ -40,6 +52,11 @@ int* foo = vector_create();

vector_add(&foo, 5);

vector_add_multiple(&foo, 5, 6, 8);

int insert_pos = 2;
vector_insert_multiple(&foo, insert_pos, -15, -61, -78);

// reassignment
foo[0] = 3;

Expand Down Expand Up @@ -117,7 +134,7 @@ The *recommended* way to differentiate between vectors and arrays is to simply n

# What About Structures?

If you have a vector storing some kind of structure, you can't initialize new elements of the vector like you would a variable, e.g. `{ a, b, c }`. To get around this, there's a set of special macros that allow for more control over element initialization.
If you have a vector storing some kind of structure, you can't initialize new elements of the vector like you would a variable, e.g. `{ a, b, c }`. To get around this in regular way, there's a set of special macros that allow for more control over element initialization.

Here is an example:

Expand All @@ -132,6 +149,40 @@ temp->a = 1;
temp->b = 2;
temp->c = 3;
temp = NULL; // stop using temp now that the element is initialized

// add multiple structs
foo* temps = vector_add_dst_multiple(&foo_vec, 2);
temps[0].a = 1;
temps[0].b = 2;
temps[0].c = 3;
temps[1].a = 6;
temps[1].b = 9;
temps[1].c = 7;
temps = NULL;
```

However, the implementation of `vector_add_multiple`,`vector_add_arr`,`vector_insert_multiple`,`vector_insert_arr` uses **memcopy**, so they support add/insert structs to the vector simply by copying data.

For example:
```c
typedef struct { ... } foo;

foo* foo_vec = vector_create();

foo a = {1,2,3}, b = {12,54,32};

// add structs
// parsing in the pointer of item and the count "1" to pretend it's an array.
vector_add_arr(&foo_vec, &a, 1);
vector_add_multiple(&foo_vec, a);
vector_add_multiple(&foo_vec, (foo){-1,-2,-3}, (foo){4,5,6});

// insert structs
int insert_pos = 1;
vector_insert_multiple(&foo_vec, insert_pos, b);
vector_insert_multiple(&foo_vec, insert_pos, (foo){-31,-442,-31}, (foo){1234,222,611});

vector_free(foo_vec);
```

# Reference Sheet
Expand All @@ -145,7 +196,11 @@ Some functions and macros take a normal vector argument, e.g. `vec`, while other
| create a vector | `type* vec = vector_create();` | N/A |
| free a vector | `vector_free(vec);` | N/A |
| add `item` to the vector `vec` | `vector_add(&vec, item);` | yes |
| add multiple items to the vector `vec` | `vector_add_multiple(&vec, item1, item2, ...);` | yes |
| add `count` elements in `array` to the vector `vec` | `vector_add_arr(&vec, array, count);` | yes |
| insert `item` into `vec` at index `9` | `vector_insert(&vec, 9, item)` | yes |
| insert multiple items to the vector `vec` at index `9` | `vector_insert_multiple(&vec, 9, item1, item2, ...);` | yes |
| insert `count` elements in `array` to the vector `vec` at index `5` | `vector_insert_arr(&vec, 5, array, count);` | yes |
| erase `4` items from `vec` at index `3` | `vector_erase(vec, 3, 4);` | no (moves elements) |
| remove item at index `3` from `vec` | `vector_remove(vec, 3);` | no (moves elements) |
| remove last item from `vec` | `vector_pop(vec);` | no |
Expand All @@ -164,7 +219,11 @@ Because some compilers don't support the `typeof` operator, which is used for st
| Action | Code | Changes vector address? |
|-----------------------------------------|--------------------------------------------------|-------------------------|
| add `item` to the vector `vec` | `vector_add(&vec, type) = item;` | yes |
| add multiple items to the vector `vec` | `vector_add_multiple(&vec, type, item1, item2, ...);` | yes |
| add `count` elements in `array` to the vector `vec` | `vector_add_arr(&vec, type, array, count);` | yes |
| insert `item` into `vec` at index `9` | `vector_insert(&vec, type, 9) = item;` | yes |
| insert multiple items to the vector `vec` at index `9` | `vector_insert_multiple(&vec, type, 9, item1, item2, ...);` | yes |
| insert `count` elements in `array` to the vector `vec` at index `5` | `vector_insert_arr(&vec, type, 5, array, count);` | yes |
| erase `4` items from `vec` at index `3` | `vector_erase(vec, type, 3, 4);` | no (moves elements) |
| remove item at index `3` from `vec` | `vector_remove(vec, type, 3);` | no (moves elements) |
| add `item` to the vector `vec` | `type* temp = vector_add_dst(&vec, type);` | yes |
Expand Down
54 changes: 54 additions & 0 deletions vec.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ bool vector_has_space(vector_header* h)
return h->capacity - h->size > 0;
}

vector_header* vector_realloc_require(vector_header* h, vec_type_t type_size, vec_size_t reuire_count)
{
vec_size_t new_capacity = (h->capacity == 0) ? 1 : h->capacity * 2;
while (new_capacity < reuire_count) new_capacity *= 2;

vector_header* new_h = (vector_header*)realloc(h, sizeof(vector_header) + new_capacity * type_size);
new_h->capacity = new_capacity;

return new_h;
}

bool vector_has_multiple_space(vector_header* h,vec_size_t reuire_count)
{
return h->capacity - h->size >= reuire_count;
}

void* _vector_add_dst(vector* vec_addr, vec_type_t type_size)
{
vector_header* h = vector_get_header(*vec_addr);
Expand All @@ -84,6 +100,22 @@ void* _vector_add_dst(vector* vec_addr, vec_type_t type_size)
return &h->data[type_size * h->size++];
}

void* _vector_add_dst_multiple(vector* vec_addr, vec_type_t type_size, vec_size_t reuire_count)
{
vector_header* h = vector_get_header(*vec_addr);

if (!vector_has_multiple_space(h, reuire_count))
{
h = vector_realloc_require(h, type_size, reuire_count);
*vec_addr = h->data;
}

// return &h->data[type_size * h->size++];
void* ptr=&h->data[type_size * h->size];
h->size+=reuire_count;
return ptr;
}

void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos)
{
vector_header* h = vector_get_header(*vec_addr);
Expand All @@ -106,6 +138,28 @@ void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos)
return &h->data[pos * type_size];
}

void* _vector_insert_dst_multiple(vector* vec_addr, vec_type_t type_size, vec_size_t pos, vec_size_t reuire_count)
{
vector_header* h = vector_get_header(*vec_addr);

vec_size_t new_length = h->size + reuire_count;

// make sure there is enough room for the new element
if (!vector_has_multiple_space(h, reuire_count))
{
h = vector_realloc_require(h, type_size, reuire_count);
*vec_addr = h->data;
}
// move trailing elements
memmove(&h->data[(pos + reuire_count) * type_size],
&h->data[pos * type_size],
(h->size - pos) * type_size);

h->size = new_length;

return &h->data[pos * type_size];
}

void _vector_erase(vector vec, vec_type_t type_size, vec_size_t pos, vec_size_t len)
{
vector_header* h = vector_get_header(vec);
Expand Down
51 changes: 51 additions & 0 deletions vec.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ typedef size_t vec_size_t;
// number of bytes for a type
typedef size_t vec_type_t;

// create a temporary array in C99 "Compound Literals" feature
// to support adding multiple elements.
#define vector_mkarr(type, ...) (type[]){__VA_ARGS__}

// TODO: more rigorous check for typeof support with different compilers
#if _MSC_VER == 0 || __STDC_VERSION__ >= 202311L || defined __cpp_decltype

Expand All @@ -62,26 +66,69 @@ typedef size_t vec_type_t;
((typeof(*vec_addr))(\
_vector_add_dst((vector*)vec_addr, sizeof(**vec_addr))\
))
#define vector_add_dst_multiple(vec_addr, count)\
((typeof(*vec_addr))(\
_vector_add_dst_multiple((vector*)vec_addr, sizeof(**vec_addr), count)\
))
#define vector_insert_dst(vec_addr, pos)\
((typeof(*vec_addr))(\
_vector_insert_dst((vector*)vec_addr, sizeof(**vec_addr), pos)))
#define vector_insert_dst_multiple(vec_addr, pos, count)\
((typeof(*vec_addr))(\
_vector_insert_dst_multiple((vector*)vec_addr, sizeof(**vec_addr), pos, count)))

#define vector_add(vec_addr, value)\
(*vector_add_dst(vec_addr) = value)
#define vector_add_multiple(vec_addr, ...)\
memcpy(\
vector_add_dst_multiple( vec_addr, sizeof(vector_mkarr(typeof(**vec_addr), __VA_ARGS__))/sizeof(**vec_addr) ),\
vector_mkarr(typeof(**vec_addr), __VA_ARGS__),\
sizeof(vector_mkarr(typeof(**vec_addr), __VA_ARGS__))\
)
#define vector_add_arr(vec_addr, arrptr, count)\
memcpy(vector_add_dst_multiple(vec_addr, count), arrptr, (count) * sizeof(**vec_addr))
#define vector_insert(vec_addr, pos, value)\
(*vector_insert_dst(vec_addr, pos) = value)
#define vector_insert_multiple(vec_addr, pos, ...)\
memcpy(\
vector_insert_dst_multiple( vec_addr, pos, sizeof(vector_mkarr(typeof(**vec_addr), __VA_ARGS__))/sizeof(**vec_addr) ),\
vector_mkarr(typeof(**vec_addr), __VA_ARGS__),\
sizeof(vector_mkarr(typeof(**vec_addr), __VA_ARGS__))\
)
#define vector_insert_arr(vec_addr, pos, arrptr, count)\
memcpy( vector_insert_dst_multiple( vec_addr, pos, count ), arrptr, (count)*sizeof(**vec_addr) )

#else

#define vector_add_dst(vec_addr, type)\
((type*)_vector_add_dst((vector*)vec_addr, sizeof(type)))
#define vector_add_dst_multiple(vec_addr, type, count)\
((type*)_vector_add_dst_multiple((vector*)vec_addr, sizeof(type), count))
#define vector_insert_dst(vec_addr, type, pos)\
((type*)_vector_insert_dst((vector*)vec_addr, sizeof(type), pos))
#define vector_insert_dst_multiple(vec_addr, type, pos, count)\
((type*)_vector_insert_dst_multiple((vector*)vec_addr, sizeof(type), pos, count))

#define vector_add(vec_addr, type, value)\
(*vector_add_dst(vec_addr, type) = value)
#define vector_add_multiple(vec_addr, type, ...)\
memcpy(\
vector_add_dst_multiple( vec_addr, type, sizeof(vector_mkarr(type, __VA_ARGS__))/sizeof(type) ),\
vector_mkarr(type, __VA_ARGS__),\
sizeof(vector_mkarr(type, __VA_ARGS__))\
)
#define vector_add_arr(vec_addr, type, listptr, count)\
memcpy(vector_add_dst_multiple(vec_addr, type, count), listptr, (count) * sizeof(type))
#define vector_insert(vec_addr, type, pos, value)\
(*vector_insert_dst(vec_addr, type, pos) = value)
#define vector_insert_multiple(vec_addr, type, pos, ...)\
memcpy(\
vector_insert_dst_multiple( vec_addr, type, pos, sizeof(vector_mkarr(typeof(type), __VA_ARGS__))/sizeof(type) ),\
vector_mkarr(typeof(type), __VA_ARGS__),\
sizeof(vector_mkarr(typeof(type), __VA_ARGS__))\
)
#define vector_insert_arr(vec_addr, type, pos, arrptr, count)\
memcpy( vector_insert_dst_multiple( vec_addr, type, pos, count ), arrptr, (count)*sizeof(type) )

#endif

Expand All @@ -103,8 +150,12 @@ void vector_free(vector vec);

void* _vector_add_dst(vector* vec_addr, vec_type_t type_size);

void* _vector_add_dst_multiple(vector* vec_addr, vec_type_t type_size, vec_size_t reuire_count);

void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos);

void* _vector_insert_dst_multiple(vector* vec_addr, vec_type_t type_size, vec_size_t pos, vec_size_t reuire_count);

void _vector_erase(vector vec_addr, vec_type_t type_size, vec_size_t pos, vec_size_t len);

void _vector_remove(vector vec_addr, vec_type_t type_size, vec_size_t pos);
Expand Down