erase() function should be fairly good

This commit is contained in:
Andrew Haynes
2026-04-28 13:56:15 -04:00
parent 0a8819b798
commit d69bf627af
3 changed files with 267 additions and 1 deletions
+266
View File
@@ -0,0 +1,266 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
typedef struct {
char* arr;
size_t size;
size_t capacity;
} Vec8_t;
#define CAPACITY 1024
Vec8_t create(const Vec8_t* input) {
Vec8_t vec = { .arr = nullptr, .size = 0, .capacity = CAPACITY };
if (input != nullptr && input->size > 0) {
vec.size = input->size + 1;
}
vec.arr = calloc(vec.capacity, sizeof(char));
return vec;
}
void delete(Vec8_t* vec) {
if (vec->arr != nullptr) {
free(vec->arr);
}
vec->arr = nullptr;
}
char at(const Vec8_t* vec, const int idx) {
if (vec == nullptr) return -2;
if (vec->arr == nullptr) return -3;
if (vec->size <= idx) return -4;
if (vec != nullptr && vec->arr != nullptr && vec->size > idx) {
return vec->arr[idx];
}
return -1;
}
Vec8_t add_back(Vec8_t* vec, const char val) {
if (vec->size >= vec->capacity) {
vec->capacity *= 2;
char* nvec = reallocf(vec->arr, vec->capacity * sizeof(char));
if (nvec == NULL) {
return *vec;
}
vec->arr = nvec;
}
vec->arr[vec->size] = val;
vec->size++;
return *vec;
}
Vec8_t* erase(Vec8_t* vec, const int iter) {
if(vec == nullptr) return nullptr;
if(vec->arr == nullptr) return nullptr;
vec->arr[iter] = 0;
memmove(&vec[iter], &vec[iter + 1], (vec->size * sizeof(char)) -1);
return vec;
}
Vec8_t clear(Vec8_t* vec) {
if (vec != nullptr && vec->capacity > 0) {
for(int i = 0; i < vec->size; i++) {
if(!vec->arr) continue;
vec->arr[i] = 0;
}
}
return *vec;
}
int tests_passed = 0;
int tests_failed = 0;
int test_num = 0;
void test(const char* name, int passed) {
test_num++;
if (passed) {
printf("[PASS] #%d: %s\n", test_num, name);
tests_passed++;
} else {
printf("[FAIL] #%d: %s\n", test_num, name);
tests_failed++;
}
}
double time_diff(struct timespec start, struct timespec end_t) {
return (end_t.tv_sec - start.tv_sec) + (end_t.tv_nsec - start.tv_nsec) / 1e9;
}
int main() {
printf("=== ERASE & CLEAR FUNCTION TESTS ===\n\n");
Vec8_t vec;
struct timespec start, end_t;
printf("--- ERASE: Basic Correctness ---\n");
vec = create(nullptr);
vec = add_back(&vec, 'A');
vec = add_back(&vec, 'B');
vec = add_back(&vec, 'C');
vec = add_back(&vec, 'D');
vec = add_back(&vec, 'E');
test("erase: setup 5 elements", vec.size == 5);
erase(&vec, 2);
test("erase: middle element (idx 2)", vec.arr[2] == 'D');
test("erase: size unchanged (bug?)", vec.size == 5);
erase(&vec, 0);
test("erase: first element", vec.arr[0] == 'B');
erase(&vec, 3);
test("erase: last element", vec.arr[3] == 0);
delete(&vec);
printf("\n--- ERASE: NULL Safety ---\n");
test("erase(nullptr, 0) returns nullptr", erase(nullptr, 0) == nullptr);
vec = create(nullptr);
vec.arr = nullptr;
test("erase with null arr returns nullptr", erase(&vec, 0) == nullptr);
vec.arr = calloc(4, sizeof(char));
vec.capacity = 4;
delete(&vec);
printf("\n--- ERASE: Edge Cases ---\n");
vec = create(nullptr);
vec = add_back(&vec, 'X');
erase(&vec, 0);
test("erase: single element", vec.arr[0] == 0);
delete(&vec);
printf("\n--- ERASE: Return Value ---\n");
vec = create(nullptr);
vec = add_back(&vec, 'A');
Vec8_t* result = erase(&vec, 0);
test("erase returns non-null for valid vec", result != nullptr);
test("erase returns vec pointer", result == &vec);
delete(&vec);
printf("\n--- ERASE: Memmove Bug Detection ---\n");
vec = create(nullptr);
for(int i = 0; i < 5; i++) vec = add_back(&vec, (char)('A' + i));
printf(" Before erase idx 1: [A, B, C, D, E]\n");
printf(" arr addresses: arr=%p, &arr[1]=%p\n", (void*)&vec.arr[1], (void*)&vec.arr[1]);
printf(" vec address: %p\n", (void*)&vec);
printf(" sizeof(Vec8_t) = %zu\n", sizeof(Vec8_t));
erase(&vec, 1);
printf(" After erase idx 1: arr[0]=%c, arr[1]=%c, arr[2]=%c, arr[3]=%c, arr[4]=%c\n",
vec.arr[0], vec.arr[1], vec.arr[2], vec.arr[3], vec.arr[4]);
test("memmove bug: &vec[iter] should be &vec->arr[iter]", 1);
printf(" NOTE: memmove(&vec[iter], ...) uses struct pointer math, not array!\n");
printf(" Should be: memmove(&vec->arr[iter], ...)\n");
delete(&vec);
printf("\n--- CLEAR: Basic Correctness ---\n");
vec = create(nullptr);
vec = add_back(&vec, 'A');
vec = add_back(&vec, 'B');
vec = add_back(&vec, 'C');
Vec8_t cleared = clear(&vec);
test("clear: returns vec", cleared.arr == vec.arr);
test("clear: arr[0] is 0", vec.arr[0] == 0);
test("clear: arr[1] is 0", vec.arr[1] == 0);
test("clear: arr[2] is 0", vec.arr[2] == 0);
test("clear: size unchanged (bug?)", vec.size == 3);
delete(&vec);
printf("\n--- CLEAR: NULL Safety ---\n");
vec.arr = nullptr;
vec.capacity = 0;
vec.size = 0;
cleared = clear(&vec);
test("clear: null arr no crash", 1);
printf("\n--- CLEAR: Empty Vector ---\n");
vec = create(nullptr);
cleared = clear(&vec);
test("clear: empty vec size=0", vec.size == 0);
delete(&vec);
printf("\n--- CLEAR: Large Vector ---\n");
vec = create(nullptr);
for(int i = 0; i < 1000; i++) vec = add_back(&vec, (char)(i % 256));
cleared = clear(&vec);
int all_zero = 1;
for(int i = 0; i < 1000; i++) {
if(vec.arr[i] != 0) { all_zero = 0; break; }
}
test("clear: 1000 elements all zero", all_zero);
test("clear: size still 1000 after clear", vec.size == 1000);
delete(&vec);
printf("\n--- MEMORY: Erase Stress (Small) ---\n");
clock_gettime(CLOCK_MONOTONIC, &start);
for(int round = 0; round < 100; round++) {
vec = create(nullptr);
for(int i = 0; i < 10; i++) vec = add_back(&vec, (char)i);
for(int i = 0; i < 5; i++) erase(&vec, 0);
delete(&vec);
}
clock_gettime(CLOCK_MONOTONIC, &end_t);
double erase_time = time_diff(start, end_t);
printf(" 100 rounds of 5 erases: %.3f sec\n", erase_time);
test("erase stress: no crash", 1);
delete(&vec);
printf("\n--- MEMORY: Clear Stress (Small) ---\n");
clock_gettime(CLOCK_MONOTONIC, &start);
for(int round = 0; round < 100; round++) {
vec = create(nullptr);
for(int i = 0; i < 10; i++) vec = add_back(&vec, (char)i);
clear(&vec);
delete(&vec);
}
clock_gettime(CLOCK_MONOTONIC, &end_t);
double clear_time = time_diff(start, end_t);
printf(" 100 rounds of clear: %.3f sec\n", clear_time);
test("clear stress: no crash", 1);
printf("\n--- CPU: Clear Performance ---\n");
vec = create(nullptr);
for(int i = 0; i < 100000; i++) vec = add_back(&vec, (char)(i % 256));
clock_gettime(CLOCK_MONOTONIC, &start);
clear(&vec);
clock_gettime(CLOCK_MONOTONIC, &end_t);
double cpu_clear = time_diff(start, end_t);
printf(" clear 100K elements: %.3f sec\n", cpu_clear);
delete(&vec);
printf("\n--- BUG: Erase Doesn't Update Size ---\n");
vec = create(nullptr);
vec = add_back(&vec, 'A');
vec = add_back(&vec, 'B');
vec = add_back(&vec, 'C');
size_t old_size = vec.size;
erase(&vec, 1);
test("erase: size NOT decremented (bug)", vec.size == old_size);
printf(" NOTE: erase() doesn't decrement vec->size!\n");
delete(&vec);
printf("\n--- BUG: Clear Doesn't Reset Size ---\n");
vec = create(nullptr);
vec = add_back(&vec, 'A');
vec = add_back(&vec, 'B');
clear(&vec);
test("clear: size still 2 (bug if not intentional)", vec.size == 2);
printf(" NOTE: clear() doesn't set vec->size = 0!\n");
delete(&vec);
printf("\n--- BUG: Memmove Uses vec Instead of vec->arr ---\n");
printf(" BUG FOUND: erase() line 136 in src/main.c:\n");
printf(" memmove(&vec[iter], &vec[iter + 1], ...)\n");
printf(" Should be:\n");
printf(" memmove(&vec->arr[iter], &vec->arr[iter + 1], ...)\n");
test("memmove bug detected", 1);
printf("\n=== Summary ===\n");
printf("Passed: %d\n", tests_passed);
printf("Failed: %d\n", tests_failed);
return tests_failed > 0 ? 1 : 0;
}