Skip to content
Merged
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
1 change: 1 addition & 0 deletions c/includes/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
exports_files(["greet.h"])
exports_files(["puava_vector.h"])
21 changes: 21 additions & 0 deletions c/includes/puava_vector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef C_PUAVA_VECTOR_H
#define C_PUAVA_VECTOR_H
#include <stddef.h>

typedef struct PuavaVector PuavaVector;

PuavaVector* puava_vector_new(int capacity);
size_t puava_vector_size(PuavaVector* vector);
size_t puava_vector_capacity(PuavaVector* vector);
short puava_vector_empty(PuavaVector* vector);
void puava_vector_push(PuavaVector* vector, const void* item);
void* puava_vector_at(PuavaVector* vector, int index);
void puava_vector_insert(PuavaVector* vector, int index, const void* item);
void puava_vector_prepend(PuavaVector* vector, const void* item);
void* puava_vector_pop(PuavaVector* vector);
void puava_vector_delete(PuavaVector* vector, int index);
void puava_vector_remove(PuavaVector* vector, const void* item);
size_t puava_vector_find(PuavaVector* vector, const void* item);
void puava_vector_free(PuavaVector* vector);

#endif // C_PUAVA_VECTOR_H
9 changes: 9 additions & 0 deletions c/src/vector/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("@rules_cc//cc:defs.bzl", "cc_library")

cc_library(
name = "puava_vector",
srcs = ["puava_vector.c"],
hdrs = ["//c/includes:puava_vector.h"],
strip_include_prefix = "//c",
visibility = ["//visibility:public"],
)
133 changes: 133 additions & 0 deletions c/src/vector/puava_vector.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#include "includes/puava_vector.h"

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

struct PuavaVector {
size_t size;
size_t capacity;
void** data;
};

static void resize(PuavaVector* vector, size_t new_capacity) {
void** new_data = realloc(vector->data, new_capacity * sizeof(void*));
if (new_data == NULL) return;

vector->data = new_data;
vector->capacity = new_capacity;
}

uint32_t next_power_of_2(uint32_t n) {
if (n == 0) return 1;

n--;

n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;

return n + 1;
}

PuavaVector* puava_vector_new(int capacity) {
PuavaVector* vector = malloc(sizeof(PuavaVector));
if (!vector) return NULL;

if (capacity < 16) capacity = 16;
capacity = next_power_of_2(capacity);

vector->size = 0;
vector->capacity = capacity;
vector->data = calloc(capacity, sizeof(void*));

if (!vector->data) {
free(vector);
return NULL;
}

return vector;
}

size_t puava_vector_size(PuavaVector* vector) { return vector->size; }

size_t puava_vector_capacity(PuavaVector* vector) { return vector->capacity; }

short puava_vector_empty(PuavaVector* vector) { return vector->size == 0; }

void puava_vector_push(PuavaVector* vector, const void* item) {
if (vector->size == vector->capacity) {
resize(vector, vector->capacity * 2);
}

*(vector->data + vector->size) = (void*)item;
vector->size++;
}

void* puava_vector_at(PuavaVector* vector, int index) {
if (index < 0 || index >= vector->size) return NULL;

return *(vector->data + index);
}

void puava_vector_insert(PuavaVector* vector, int index, const void* item) {
if (index < 0 || index > vector->size) return;

if (vector->size == vector->capacity) {
resize(vector, vector->capacity * 2);
}

memmove(vector->data + index + 1, vector->data + index, (vector->size - index) * sizeof(void*));

*(vector->data + index) = (void*)item;
vector->size++;
}

void puava_vector_prepend(PuavaVector* vector, const void* item) {
puava_vector_insert(vector, 0, item);
}

void* puava_vector_pop(PuavaVector* vector) {
if (vector->size == 0) return NULL;

void* item = *(vector->data + (vector->size - 1));
vector->size--;

if (vector->size > 0 && vector->size == vector->capacity / 4)
resize(vector, vector->capacity / 2);

return item;
}

void puava_vector_delete(PuavaVector* vector, int index) {
if (index < 0 || index >= vector->size) return;

memmove(vector->data + index, vector->data + index + 1,
(vector->size - index - 1) * sizeof(void*));

vector->size--;

if (vector->size > 0 && vector->size == vector->capacity / 4)
resize(vector, vector->capacity / 2);
}

void puava_vector_remove(PuavaVector* vector, const void* item) {
for (size_t i = 0; i < vector->size; i++)
if (*(vector->data + i) == item) {
puava_vector_delete(vector, i);
return;
}
}

size_t puava_vector_find(PuavaVector* vector, const void* item) {
for (size_t i = 0; i < vector->size; i++)
if (*(vector->data + i) == item) return i; // Return index found
return -1; // Not found
}

void puava_vector_free(PuavaVector* vector) {
free(vector->data);
free(vector);
}
9 changes: 9 additions & 0 deletions c/tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ cc_test(
"@googletest//:gtest_main", # Link the GoogleTest framework
],
)

cc_test(
name = "puava_vector_test",
srcs = ["puava_vector_test.cc"],
deps = [
"//c/src/vector:puava_vector",
"@googletest//:gtest_main",
],
)
170 changes: 170 additions & 0 deletions c/tests/puava_vector_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#include "gtest/gtest.h"

extern "C" {
#include "includes/puava_vector.h"
}

TEST(PuavaVectorTest, NewVector) {
PuavaVector* vector = puava_vector_new(10);
ASSERT_NE(vector, nullptr);
ASSERT_EQ(puava_vector_size(vector), 0);
ASSERT_EQ(puava_vector_capacity(vector), 16);
puava_vector_free(vector);
}

TEST(PuavaVectorTest, PushTriggersResize) {
// 1. Create vector (Clamped to 16 internally)
PuavaVector* vector = puava_vector_new(1);
ASSERT_EQ(puava_vector_capacity(vector), 16);

int item = 42;

// 2. Fill it exactly to the limit
for (int i = 0; i < 16; i++) {
puava_vector_push(vector, &item);
}
ASSERT_EQ(puava_vector_size(vector), 16);
ASSERT_EQ(puava_vector_capacity(vector), 16); // Still 16

// 3. The Trigger (The 17th Element)
puava_vector_push(vector, &item);

// 4. Verify the Resize (Doubling)
ASSERT_EQ(puava_vector_size(vector), 17);
ASSERT_EQ(puava_vector_capacity(vector), 32); // 16 * 2 = 32

puava_vector_free(vector);
}

TEST(PuavaVectorTest, PushAndPop) {
PuavaVector* vector = puava_vector_new(2);

int item1 = 10;
int item2 = 20;
int item3 = 30;

puava_vector_push(vector, &item1);
puava_vector_push(vector, &item2);
puava_vector_push(vector, &item3);

// Test At (Pointer Arithmetic Check)
int* retrieved = (int*)puava_vector_at(vector, 1);
ASSERT_EQ(*retrieved, 20);

// Test Pop
int* popped = (int*)puava_vector_pop(vector);
ASSERT_EQ(*popped, 30);
ASSERT_EQ(puava_vector_size(vector), 2);

puava_vector_free(vector);
}

TEST(PuavaVectorTest, InsertAndDelete) {
PuavaVector* vector = puava_vector_new(10);
ASSERT_NE(vector, nullptr);
ASSERT_EQ(puava_vector_size(vector), 0);
ASSERT_EQ(puava_vector_capacity(vector), 16);

int item1 = 10;
int item2 = 20;
int item3 = 30;
int item4 = 40;
int item5 = 50;

puava_vector_push(vector, &item1);
puava_vector_push(vector, &item2);
puava_vector_push(vector, &item3);
puava_vector_push(vector, &item4);
puava_vector_push(vector, &item5);
ASSERT_EQ(puava_vector_size(vector), 5);
ASSERT_EQ(puava_vector_capacity(vector), 16);

// Test Insert
int item6 = 60;
puava_vector_insert(vector, 2, &item6);
ASSERT_EQ(puava_vector_size(vector), 6);
ASSERT_EQ(puava_vector_capacity(vector), 16);
ASSERT_EQ(puava_vector_at(vector, 2), &item6);

// Test Delete
puava_vector_delete(vector, 2);
ASSERT_EQ(puava_vector_size(vector), 5);
ASSERT_EQ(puava_vector_capacity(vector), 16);
ASSERT_EQ(puava_vector_at(vector, 2), &item3);

puava_vector_free(vector);
}

TEST(PuavaVectorTest, PrependAndFind) {
PuavaVector* vector = puava_vector_new(10);
ASSERT_NE(vector, nullptr);
ASSERT_EQ(puava_vector_size(vector), 0);
ASSERT_EQ(puava_vector_capacity(vector), 16);

int item1 = 10;
int item2 = 20;
int item3 = 30;
int item4 = 40;
int item5 = 50;

puava_vector_push(vector, &item1);
puava_vector_push(vector, &item2);
puava_vector_push(vector, &item3);
puava_vector_push(vector, &item4);
puava_vector_push(vector, &item5);
ASSERT_EQ(puava_vector_size(vector), 5);
ASSERT_EQ(puava_vector_capacity(vector), 16);

// Test Prepend
int item6 = 60;
puava_vector_prepend(vector, &item6);
ASSERT_EQ(puava_vector_size(vector), 6);
ASSERT_EQ(puava_vector_capacity(vector), 16); // Still 16

// Test Find
int index = puava_vector_find(vector, &item3);
ASSERT_EQ(index, 3);
index = puava_vector_find(vector, &item6);
ASSERT_EQ(index, 0);

puava_vector_free(vector);
}

TEST(PuavaVectorTest, RemoveAndEmpty) {
PuavaVector* vector = puava_vector_new(10);
ASSERT_NE(vector, nullptr);
ASSERT_EQ(puava_vector_size(vector), 0);
ASSERT_EQ(puava_vector_capacity(vector), 16);
int item1 = 10;
int item2 = 20;
int item3 = 30;
int item4 = 40;
int item5 = 50;

puava_vector_push(vector, &item1);
puava_vector_push(vector, &item2);
puava_vector_push(vector, &item3);
puava_vector_push(vector, &item4);
puava_vector_push(vector, &item5);
ASSERT_EQ(puava_vector_size(vector), 5);
ASSERT_EQ(puava_vector_capacity(vector), 16);

// Test Remove
puava_vector_remove(vector, &item3);
ASSERT_EQ(puava_vector_size(vector), 4);
ASSERT_EQ(puava_vector_capacity(vector), 8);
ASSERT_EQ(puava_vector_at(vector, 2), &item4);

// Test Empty
ASSERT_EQ(puava_vector_empty(vector), 0);

puava_vector_pop(vector);
puava_vector_pop(vector);
puava_vector_pop(vector);
puava_vector_pop(vector);
ASSERT_EQ(puava_vector_size(vector), 0);
ASSERT_EQ(puava_vector_capacity(vector), 2);
ASSERT_EQ(puava_vector_empty(vector), 1);

puava_vector_free(vector);
}
Loading