Skip to content

Commit a2d1926

Browse files
committed
implement puava_vector dynamic array
1 parent ea1650d commit a2d1926

6 files changed

Lines changed: 343 additions & 0 deletions

File tree

c/includes/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
exports_files(["greet.h"])
2+
exports_files(["puava_vector.h"])

c/includes/puava_vector.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef C_PUAVA_VECTOR_H
2+
#define C_PUAVA_VECTOR_H
3+
#include <stddef.h>
4+
5+
typedef struct PuavaVector PuavaVector;
6+
7+
PuavaVector* puava_vector_new(int capacity);
8+
size_t puava_vector_size(PuavaVector* vector);
9+
size_t puava_vector_capacity(PuavaVector* vector);
10+
short puava_vector_empty(PuavaVector* vector);
11+
void puava_vector_push(PuavaVector* vector, const void* item);
12+
void* puava_vector_at(PuavaVector* vector, int index);
13+
void puava_vector_insert(PuavaVector* vector, int index, const void* item);
14+
void puava_vector_prepend(PuavaVector* vector, const void* item);
15+
void* puava_vector_pop(PuavaVector* vector);
16+
void puava_vector_delete(PuavaVector* vector, int index);
17+
void puava_vector_remove(PuavaVector* vector, const void* item);
18+
size_t puava_vector_find(PuavaVector* vector, const void* item);
19+
void puava_vector_free(PuavaVector* vector);
20+
21+
#endif // C_PUAVA_VECTOR_H

c/src/vector/BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
load("@rules_cc//cc:defs.bzl", "cc_library")
2+
3+
cc_library(
4+
name = "puava_vector",
5+
srcs = ["puava_vector.c"],
6+
hdrs = ["//c/includes:puava_vector.h"],
7+
strip_include_prefix = "//c",
8+
visibility = ["//visibility:public"],
9+
)

c/src/vector/puava_vector.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#include "includes/puava_vector.h"
2+
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
7+
struct PuavaVector {
8+
size_t size;
9+
size_t capacity;
10+
void** data;
11+
};
12+
13+
static void resize(PuavaVector* vector, size_t new_capacity) {
14+
void** new_data = realloc(vector->data, new_capacity * sizeof(void*));
15+
if (new_data == NULL) return;
16+
17+
vector->data = new_data;
18+
vector->capacity = new_capacity;
19+
}
20+
21+
uint32_t next_power_of_2(uint32_t n) {
22+
if (n == 0) return 1;
23+
24+
n--;
25+
26+
n |= n >> 1;
27+
n |= n >> 2;
28+
n |= n >> 4;
29+
n |= n >> 8;
30+
n |= n >> 16;
31+
32+
return n + 1;
33+
}
34+
35+
PuavaVector* puava_vector_new(int capacity) {
36+
PuavaVector* vector = malloc(sizeof(PuavaVector));
37+
if (!vector) return NULL;
38+
39+
if (capacity < 16) capacity = 16;
40+
capacity = next_power_of_2(capacity);
41+
42+
vector->size = 0;
43+
vector->capacity = capacity;
44+
vector->data = calloc(capacity, sizeof(void*));
45+
46+
if (!vector->data) {
47+
free(vector);
48+
return NULL;
49+
}
50+
51+
return vector;
52+
}
53+
54+
size_t puava_vector_size(PuavaVector* vector) { return vector->size; }
55+
56+
size_t puava_vector_capacity(PuavaVector* vector) { return vector->capacity; }
57+
58+
short puava_vector_empty(PuavaVector* vector) { return vector->size == 0; }
59+
60+
void puava_vector_push(PuavaVector* vector, const void* item) {
61+
if (vector->size == vector->capacity) {
62+
resize(vector, vector->capacity * 2);
63+
}
64+
65+
*(vector->data + vector->size) = (void*)item;
66+
vector->size++;
67+
}
68+
69+
void* puava_vector_at(PuavaVector* vector, int index) {
70+
if (index < 0 || index >= vector->size) return NULL;
71+
72+
return *(vector->data + index);
73+
}
74+
75+
void puava_vector_insert(PuavaVector* vector, int index, const void* item) {
76+
if (index < 0 || index > vector->size) return;
77+
78+
if (vector->size == vector->capacity) {
79+
resize(vector, vector->capacity * 2);
80+
}
81+
82+
memmove(vector->data + index + 1, vector->data + index, (vector->size - index) * sizeof(void*));
83+
84+
*(vector->data + index) = (void*)item;
85+
vector->size++;
86+
}
87+
88+
void puava_vector_prepend(PuavaVector* vector, const void* item) {
89+
puava_vector_insert(vector, 0, item);
90+
}
91+
92+
void* puava_vector_pop(PuavaVector* vector) {
93+
if (vector->size == 0) return NULL;
94+
95+
void* item = *(vector->data + (vector->size - 1));
96+
vector->size--;
97+
98+
if (vector->size > 0 && vector->size == vector->capacity / 4)
99+
resize(vector, vector->capacity / 2);
100+
101+
return item;
102+
}
103+
104+
void puava_vector_delete(PuavaVector* vector, int index) {
105+
if (index < 0 || index >= vector->size) return;
106+
107+
memmove(vector->data + index, vector->data + index + 1,
108+
(vector->size - index - 1) * sizeof(void*));
109+
110+
vector->size--;
111+
112+
if (vector->size > 0 && vector->size == vector->capacity / 4)
113+
resize(vector, vector->capacity / 2);
114+
}
115+
116+
void puava_vector_remove(PuavaVector* vector, const void* item) {
117+
for (size_t i = 0; i < vector->size; i++)
118+
if (*(vector->data + i) == item) {
119+
puava_vector_delete(vector, i);
120+
return;
121+
}
122+
}
123+
124+
size_t puava_vector_find(PuavaVector* vector, const void* item) {
125+
for (size_t i = 0; i < vector->size; i++)
126+
if (*(vector->data + i) == item) return i; // Return index found
127+
return -1; // Not found
128+
}
129+
130+
void puava_vector_free(PuavaVector* vector) {
131+
free(vector->data);
132+
free(vector);
133+
}

c/tests/BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,12 @@ cc_test(
88
"@googletest//:gtest_main", # Link the GoogleTest framework
99
],
1010
)
11+
12+
cc_test(
13+
name = "puava_vector_test",
14+
srcs = ["puava_vector_test.cc"],
15+
deps = [
16+
"//c/src/vector:puava_vector",
17+
"@googletest//:gtest_main",
18+
],
19+
)

c/tests/puava_vector_test.cc

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#include "gtest/gtest.h"
2+
3+
extern "C" {
4+
#include "includes/puava_vector.h"
5+
}
6+
7+
TEST(PuavaVectorTest, NewVector) {
8+
PuavaVector* vector = puava_vector_new(10);
9+
ASSERT_NE(vector, nullptr);
10+
ASSERT_EQ(puava_vector_size(vector), 0);
11+
ASSERT_EQ(puava_vector_capacity(vector), 16);
12+
puava_vector_free(vector);
13+
}
14+
15+
TEST(PuavaVectorTest, PushTriggersResize) {
16+
// 1. Create vector (Clamped to 16 internally)
17+
PuavaVector* vector = puava_vector_new(1);
18+
ASSERT_EQ(puava_vector_capacity(vector), 16);
19+
20+
int item = 42;
21+
22+
// 2. Fill it exactly to the limit
23+
for (int i = 0; i < 16; i++) {
24+
puava_vector_push(vector, &item);
25+
}
26+
ASSERT_EQ(puava_vector_size(vector), 16);
27+
ASSERT_EQ(puava_vector_capacity(vector), 16); // Still 16
28+
29+
// 3. The Trigger (The 17th Element)
30+
puava_vector_push(vector, &item);
31+
32+
// 4. Verify the Resize (Doubling)
33+
ASSERT_EQ(puava_vector_size(vector), 17);
34+
ASSERT_EQ(puava_vector_capacity(vector), 32); // 16 * 2 = 32
35+
36+
puava_vector_free(vector);
37+
}
38+
39+
TEST(PuavaVectorTest, PushAndPop) {
40+
PuavaVector* vector = puava_vector_new(2);
41+
42+
int item1 = 10;
43+
int item2 = 20;
44+
int item3 = 30;
45+
46+
puava_vector_push(vector, &item1);
47+
puava_vector_push(vector, &item2);
48+
puava_vector_push(vector, &item3);
49+
50+
// Test At (Pointer Arithmetic Check)
51+
int* retrieved = (int*)puava_vector_at(vector, 1);
52+
ASSERT_EQ(*retrieved, 20);
53+
54+
// Test Pop
55+
int* popped = (int*)puava_vector_pop(vector);
56+
ASSERT_EQ(*popped, 30);
57+
ASSERT_EQ(puava_vector_size(vector), 2);
58+
59+
puava_vector_free(vector);
60+
}
61+
62+
TEST(PuavaVectorTest, InsertAndDelete) {
63+
PuavaVector* vector = puava_vector_new(10);
64+
ASSERT_NE(vector, nullptr);
65+
ASSERT_EQ(puava_vector_size(vector), 0);
66+
ASSERT_EQ(puava_vector_capacity(vector), 16);
67+
68+
int item1 = 10;
69+
int item2 = 20;
70+
int item3 = 30;
71+
int item4 = 40;
72+
int item5 = 50;
73+
74+
puava_vector_push(vector, &item1);
75+
puava_vector_push(vector, &item2);
76+
puava_vector_push(vector, &item3);
77+
puava_vector_push(vector, &item4);
78+
puava_vector_push(vector, &item5);
79+
ASSERT_EQ(puava_vector_size(vector), 5);
80+
ASSERT_EQ(puava_vector_capacity(vector), 16);
81+
82+
// Test Insert
83+
int item6 = 60;
84+
puava_vector_insert(vector, 2, &item6);
85+
ASSERT_EQ(puava_vector_size(vector), 6);
86+
ASSERT_EQ(puava_vector_capacity(vector), 16);
87+
ASSERT_EQ(puava_vector_at(vector, 2), &item6);
88+
89+
// Test Delete
90+
puava_vector_delete(vector, 2);
91+
ASSERT_EQ(puava_vector_size(vector), 5);
92+
ASSERT_EQ(puava_vector_capacity(vector), 16);
93+
ASSERT_EQ(puava_vector_at(vector, 2), &item3);
94+
95+
puava_vector_free(vector);
96+
}
97+
98+
TEST(PuavaVectorTest, PrependAndFind) {
99+
PuavaVector* vector = puava_vector_new(10);
100+
ASSERT_NE(vector, nullptr);
101+
ASSERT_EQ(puava_vector_size(vector), 0);
102+
ASSERT_EQ(puava_vector_capacity(vector), 16);
103+
104+
int item1 = 10;
105+
int item2 = 20;
106+
int item3 = 30;
107+
int item4 = 40;
108+
int item5 = 50;
109+
110+
puava_vector_push(vector, &item1);
111+
puava_vector_push(vector, &item2);
112+
puava_vector_push(vector, &item3);
113+
puava_vector_push(vector, &item4);
114+
puava_vector_push(vector, &item5);
115+
ASSERT_EQ(puava_vector_size(vector), 5);
116+
ASSERT_EQ(puava_vector_capacity(vector), 16);
117+
118+
// Test Prepend
119+
int item6 = 60;
120+
puava_vector_prepend(vector, &item6);
121+
ASSERT_EQ(puava_vector_size(vector), 6);
122+
ASSERT_EQ(puava_vector_capacity(vector), 16); // Still 16
123+
124+
// Test Find
125+
int index = puava_vector_find(vector, &item3);
126+
ASSERT_EQ(index, 3);
127+
index = puava_vector_find(vector, &item6);
128+
ASSERT_EQ(index, 0);
129+
130+
puava_vector_free(vector);
131+
}
132+
133+
TEST(PuavaVectorTest, RemoveAndEmpty) {
134+
PuavaVector* vector = puava_vector_new(10);
135+
ASSERT_NE(vector, nullptr);
136+
ASSERT_EQ(puava_vector_size(vector), 0);
137+
ASSERT_EQ(puava_vector_capacity(vector), 16);
138+
int item1 = 10;
139+
int item2 = 20;
140+
int item3 = 30;
141+
int item4 = 40;
142+
int item5 = 50;
143+
144+
puava_vector_push(vector, &item1);
145+
puava_vector_push(vector, &item2);
146+
puava_vector_push(vector, &item3);
147+
puava_vector_push(vector, &item4);
148+
puava_vector_push(vector, &item5);
149+
ASSERT_EQ(puava_vector_size(vector), 5);
150+
ASSERT_EQ(puava_vector_capacity(vector), 16);
151+
152+
// Test Remove
153+
puava_vector_remove(vector, &item3);
154+
ASSERT_EQ(puava_vector_size(vector), 4);
155+
ASSERT_EQ(puava_vector_capacity(vector), 8);
156+
ASSERT_EQ(puava_vector_at(vector, 2), &item4);
157+
158+
// Test Empty
159+
ASSERT_EQ(puava_vector_empty(vector), 0);
160+
161+
puava_vector_pop(vector);
162+
puava_vector_pop(vector);
163+
puava_vector_pop(vector);
164+
puava_vector_pop(vector);
165+
ASSERT_EQ(puava_vector_size(vector), 0);
166+
ASSERT_EQ(puava_vector_capacity(vector), 2);
167+
ASSERT_EQ(puava_vector_empty(vector), 1);
168+
169+
puava_vector_free(vector);
170+
}

0 commit comments

Comments
 (0)