erase() function takes iter range
This commit is contained in:
+38
-25
@@ -7,24 +7,12 @@
|
||||
|
||||
/*
|
||||
* All functions needed
|
||||
* Ones that start with '>' I have completed
|
||||
*
|
||||
* > at() Returns an indexed element from a vector
|
||||
* > back() Returns the last element of a vector
|
||||
* > begin() Returns an iterator pointing to the beginning of a vector
|
||||
* > capacity() Returns the number of elements that a vector's reserved memory is able to store
|
||||
* > front() Returns the first element of a vector
|
||||
* > end() Returns an iterator pointing to the end of a vector
|
||||
* > push_back() Adds an element to the end of a vector
|
||||
* > size() Returns the number of elements in a vector
|
||||
* > clear() Removes all of the contents of a vector
|
||||
* > empty() Checks whether a vector is empty or not
|
||||
*
|
||||
* assign() Fills a vector with multiple values
|
||||
* data() Returns a pointer to the block of memory where a vector's elements are
|
||||
* stored erase() Removes
|
||||
* a number of elements from a vector insert() Inserts a number of elements
|
||||
* into a vector max_size() Returns the maximum number of elements that a
|
||||
* stored
|
||||
* erase() Removes a number of elements from a vector
|
||||
* insert() Inserts a number of elements into a vector
|
||||
* max_size() Returns the maximum number of elements that a
|
||||
* vector can have pop_back() Removes the last element of a vector rbegin()
|
||||
* Returns a reverse iterator pointing to the last element of a vector rend()
|
||||
* Returns a reverse iterator pointing to a position right before the first
|
||||
@@ -93,7 +81,7 @@ delete(Vec8_t* vec)
|
||||
Vec8_t
|
||||
clear(Vec8_t* vec)
|
||||
{
|
||||
if (vec != nullptr && vec->capacity > 0)
|
||||
if (vec != nullptr && vec->size > 0)
|
||||
{
|
||||
for(int i = 0; i < vec->size; i++) {
|
||||
if(!vec->arr) continue;
|
||||
@@ -126,14 +114,28 @@ at(const Vec8_t* vec, const int idx)
|
||||
return -1;
|
||||
}
|
||||
|
||||
Vec8_t*
|
||||
__attribute__((overloadable)) Vec8_t*
|
||||
erase(Vec8_t* vec, const int iter) {
|
||||
if(vec == nullptr) return nullptr;
|
||||
if(vec->arr == nullptr) return nullptr;
|
||||
if(iter >= vec->size) return nullptr;
|
||||
vec->arr[iter] = 0;
|
||||
memmove(&vec->arr[iter], &vec->arr[iter + 1], (vec->size - iter - 1) * sizeof(char));
|
||||
vec->size--;
|
||||
memmove(&vec->arr[iter], &vec->arr[iter + 1], (vec->size - iter) * sizeof(char));
|
||||
vec->arr[iter] = 0;
|
||||
return vec;
|
||||
}
|
||||
|
||||
__attribute__((overloadable)) Vec8_t*
|
||||
erase(Vec8_t* vec, const int iter_start, const int iter_end) {
|
||||
if(vec == nullptr) return nullptr;
|
||||
if(vec->arr == nullptr) return nullptr;
|
||||
if(iter_start < 0 && iter_end >= vec->size) return nullptr;
|
||||
int diff = iter_end - iter_start;
|
||||
vec->size -= diff;
|
||||
memmove(&vec->arr[iter_start], &vec->arr[iter_end], (vec->size - 1) * sizeof(char));
|
||||
for(int i = 0; i < diff; i++) {
|
||||
vec->arr[iter_start + i] = 0;
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
@@ -223,11 +225,22 @@ main()
|
||||
vec = add_back(&vec, '6');
|
||||
vec = add_back(&vec, '8');
|
||||
vec = add_back(&vec, '6');
|
||||
vec = *erase(&vec, begin(&vec) + 2);
|
||||
// for(int i = 0; i < vec.size; i++) {
|
||||
// printf("%i\n", at(&vec, i));
|
||||
// }
|
||||
print_vec(&vec);
|
||||
|
||||
size_t size = vec.size;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if(vec.arr[i] == 0) printf("0");
|
||||
printf("%c ", vec.arr[i]);
|
||||
}
|
||||
printf("\n");
|
||||
// print_vec(&vec);
|
||||
// vec = *erase(&vec, begin(&vec) + 2);
|
||||
vec = *erase(&vec, begin(&vec) + 2, begin(&vec) + 4);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if(vec.arr[i] == 0) printf("0");
|
||||
printf("%c ", vec.arr[i]);
|
||||
}
|
||||
printf("\n");
|
||||
// print_vec(&vec);
|
||||
// printf("%c", at(nullptr, 0));
|
||||
|
||||
delete(&vec);
|
||||
|
||||
Binary file not shown.
+12
-16
@@ -82,7 +82,7 @@ erase(Vec8_t* vec, const int iter)
|
||||
if (iter >= vec->size)
|
||||
return nullptr;
|
||||
vec->arr[iter] = 0;
|
||||
memmove(&vec->arr[iter], &vec->arr[iter + 1], (vec->size * sizeof(char)) - 1);
|
||||
memmove(&vec->arr[iter], &vec->arr[iter + 1], (vec->size - iter - 1) * sizeof(char));
|
||||
vec->size--;
|
||||
return vec;
|
||||
}
|
||||
@@ -165,13 +165,13 @@ test_erase_basic_correctness(void)
|
||||
|
||||
erase(&vec, 2);
|
||||
|
||||
test("erase: arr[2] set to 0", vec.arr[2] == 0);
|
||||
test("erase: size decremented to 4", vec.size == 4);
|
||||
|
||||
int elements_intact = (vec.arr[0] == 'A') && (vec.arr[1] == 'B')
|
||||
&& (vec.arr[3] == 'E');
|
||||
test("erase: remaining elements intact after shift", elements_intact);
|
||||
&& (vec.arr[2] == 'D') && (vec.arr[3] == 'E');
|
||||
test("erase: elements shifted correctly A B D E", elements_intact);
|
||||
|
||||
test("erase: element at idx 3 now holds original idx 4", vec.arr[3] == 'E');
|
||||
test("erase: element at idx 2 now holds original idx 3 ('D')", vec.arr[2] == 'D');
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
@@ -650,18 +650,14 @@ test_erase_clear_performance_comparison(void)
|
||||
void
|
||||
test_pseudo_code_bug_analysis(void)
|
||||
{
|
||||
printf("\n--- BUG ANALYSIS: Pseudo Code ---\n");
|
||||
printf(" FIXED:\n");
|
||||
printf(" - Container count decremented after removal\n");
|
||||
printf(" - Container count reset after zeroing all elements\n");
|
||||
printf(" - Index validated against count before removal\n");
|
||||
|
||||
printf("\n REMAINING - erase() memmove length:\n");
|
||||
printf(" Container holds array pointer, count, and capacity.\n");
|
||||
printf("\n--- BUG ANALYSIS: All Previously Detected Bugs Now Fixed ---\n");
|
||||
printf(" Container with array pointer, count, and capacity.\n");
|
||||
printf(" Remove at index I by shifting remaining left.\n");
|
||||
printf(" Wrong: move bytes = (count * element_size) - 1\n");
|
||||
printf(" Right: move bytes = (count - I - 1) * element_size\n");
|
||||
printf(" Effect: overwrites beyond intended range\n");
|
||||
printf(" Move bytes must account for already-deleted elements:\n");
|
||||
printf(" bytes = (count - I - 1) * element_size\n");
|
||||
printf(" Count must be decremented after removal.\n");
|
||||
printf(" Count must be reset after zeroing all elements.\n");
|
||||
printf(" Index must be validated against count before removal.\n");
|
||||
|
||||
test("bug analysis documented", 1);
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,912 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/resource.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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
vec->size = 0;
|
||||
}
|
||||
return *vec;
|
||||
}
|
||||
|
||||
char
|
||||
at(const Vec8_t* vec, const int idx)
|
||||
{
|
||||
if (vec == nullptr)
|
||||
return -2;
|
||||
if (vec->arr == nullptr)
|
||||
return -3;
|
||||
if (vec->size <= (size_t)idx)
|
||||
return -4;
|
||||
if (vec != nullptr && vec->arr != nullptr && vec->size > (size_t)idx)
|
||||
return vec->arr[idx];
|
||||
return -1;
|
||||
}
|
||||
|
||||
Vec8_t*
|
||||
erase(Vec8_t* vec, const int iter)
|
||||
{
|
||||
if (vec == nullptr)
|
||||
return nullptr;
|
||||
if (vec->arr == nullptr)
|
||||
return nullptr;
|
||||
if (iter < 0 || (size_t)iter >= vec->size)
|
||||
return nullptr;
|
||||
vec->arr[iter] = 0;
|
||||
memmove(&vec->arr[iter], &vec->arr[iter + 1], (vec->size - (size_t)iter - 1) * sizeof(char));
|
||||
vec->size--;
|
||||
return vec;
|
||||
}
|
||||
|
||||
void
|
||||
print_vec(const Vec8_t* vec)
|
||||
{
|
||||
for (int i = 0; i < vec->size; i++) {
|
||||
if (vec->arr[i]) {
|
||||
printf("%c ", at(vec, i));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int
|
||||
begin(const Vec8_t* vec)
|
||||
{
|
||||
if (vec != nullptr && vec->arr != nullptr && vec->size > 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
end(const Vec8_t* vec)
|
||||
{
|
||||
if (vec != nullptr && vec->arr != nullptr && vec->size > 0)
|
||||
return (int)(vec->size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char
|
||||
front(const Vec8_t* vec)
|
||||
{
|
||||
return at(vec, 0);
|
||||
}
|
||||
|
||||
char
|
||||
back(const Vec8_t* vec)
|
||||
{
|
||||
if (vec)
|
||||
return at(vec, (int)vec->size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
empty(const Vec8_t* vec)
|
||||
{
|
||||
if (vec->size > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
size_t
|
||||
get_mem_mb(void)
|
||||
{
|
||||
struct rusage ru;
|
||||
getrusage(RUSAGE_SELF, &ru);
|
||||
return (size_t)(ru.ru_maxrss / 1024);
|
||||
}
|
||||
|
||||
void
|
||||
fill_vec(Vec8_t* vec, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
*vec = add_back(vec, (char)(i % 256));
|
||||
}
|
||||
|
||||
int
|
||||
verify_range(const Vec8_t* vec, size_t start, size_t end)
|
||||
{
|
||||
for (size_t i = start; i < end; i++) {
|
||||
if (vec->arr[i] != (char)(i % 256))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
t_all_functions_correctness(void)
|
||||
{
|
||||
printf("\n=== ALL FUNCTIONS: Correctness ===\n");
|
||||
|
||||
Vec8_t vec = create(nullptr);
|
||||
test("create: size=0", vec.size == 0);
|
||||
test("create: capacity=1024", vec.capacity == 1024);
|
||||
test("create: arr not null", vec.arr != nullptr);
|
||||
|
||||
test("empty on new vec: returns 0", empty(&vec) == 0);
|
||||
test("begin on empty: returns -1", begin(&vec) == -1);
|
||||
test("end on empty: returns -1", end(&vec) == -1);
|
||||
|
||||
vec = add_back(&vec, 'A');
|
||||
test("add_back: size=1", vec.size == 1);
|
||||
test("add_back: capacity still 1024", vec.capacity == 1024);
|
||||
test("at idx 0: returns 'A'", at(&vec, 0) == 'A');
|
||||
test("front: returns 'A'", front(&vec) == 'A');
|
||||
test("back: returns 'A'", back(&vec) == 'A');
|
||||
test("empty after add: returns 1", empty(&vec) == 1);
|
||||
test("begin: returns 0", begin(&vec) == 0);
|
||||
test("end: returns 0", end(&vec) == 0);
|
||||
|
||||
vec = add_back(&vec, 'B');
|
||||
vec = add_back(&vec, 'C');
|
||||
vec = add_back(&vec, 'D');
|
||||
vec = add_back(&vec, 'E');
|
||||
test("5 elements: size=5", vec.size == 5);
|
||||
test("at idx 2: 'C'", at(&vec, 2) == 'C');
|
||||
test("at idx 4: 'E'", at(&vec, 4) == 'E');
|
||||
test("front: 'A'", front(&vec) == 'A');
|
||||
test("back: 'E'", back(&vec) == 'E');
|
||||
test("begin: 0", begin(&vec) == 0);
|
||||
test("end: 4", end(&vec) == 4);
|
||||
|
||||
(void)erase(&vec, 2);
|
||||
test("erase idx 2: size=4", vec.size == 4);
|
||||
test("erase idx 2: arr[2]='D'", vec.arr[2] == 'D');
|
||||
test("erase idx 2: arr[3]='E'", vec.arr[3] == 'E');
|
||||
test("front after erase: 'A'", front(&vec) == 'A');
|
||||
test("back after erase: 'E'", back(&vec) == 'E');
|
||||
|
||||
(void)erase(&vec, 0);
|
||||
test("erase idx 0: size=3", vec.size == 3);
|
||||
test("erase idx 0: front now 'B'", front(&vec) == 'B');
|
||||
test("erase idx 0: back still 'E'", back(&vec) == 'E');
|
||||
test("begin after erase: 0", begin(&vec) == 0);
|
||||
test("end after erase: 2", end(&vec) == 2);
|
||||
|
||||
(void)erase(&vec, 2);
|
||||
test("erase last: size=2", vec.size == 2);
|
||||
test("erase last: back now 'D'", back(&vec) == 'D');
|
||||
|
||||
clear(&vec);
|
||||
test("clear: size=0", vec.size == 0);
|
||||
test("clear: arr[0]=0", vec.arr[0] == 0);
|
||||
test("empty after clear: returns 0", empty(&vec) == 0);
|
||||
test("begin after clear: -1", begin(&vec) == -1);
|
||||
test("end after clear: -1", end(&vec) == -1);
|
||||
|
||||
test("at out of bounds: returns -4", at(&vec, 0) == -4);
|
||||
test("front empty: returns -4", front(&vec) == -4);
|
||||
test("back empty: returns -4", back(&vec) == -4);
|
||||
|
||||
vec = add_back(&vec, 'X');
|
||||
test("add after clear: size=1", vec.size == 1);
|
||||
test("add after clear: front='X'", front(&vec) == 'X');
|
||||
|
||||
test("erase out of bounds: nullptr", erase(&vec, 5) == nullptr);
|
||||
test("erase negative index: nullptr", erase(&vec, -1) == nullptr);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_all_null_safety(void)
|
||||
{
|
||||
printf("\n=== ALL FUNCTIONS: NULL Safety ===\n");
|
||||
|
||||
test("at(nullptr): -2", at(nullptr, 0) == -2);
|
||||
test("front(nullptr): -2", front(nullptr) == -2);
|
||||
test("back(nullptr): -1", back(nullptr) == -1);
|
||||
test("begin(nullptr): -1", begin(nullptr) == -1);
|
||||
test("end(nullptr): -1", end(nullptr) == -1);
|
||||
test("erase(nullptr): nullptr", erase(nullptr, 0) == nullptr);
|
||||
|
||||
Vec8_t vec;
|
||||
vec.arr = nullptr;
|
||||
vec.size = 5;
|
||||
vec.capacity = 10;
|
||||
test("at null arr: -3", at(&vec, 0) == -3);
|
||||
test("erase null arr: nullptr", erase(&vec, 0) == nullptr);
|
||||
test("clear null arr: no crash", 1);
|
||||
test("empty null arr (size>0): 1", empty(&vec) == 1);
|
||||
|
||||
vec.size = 0;
|
||||
test("empty null arr (size=0): 0", empty(&vec) == 0);
|
||||
test("begin null arr: -1", begin(&vec) == -1);
|
||||
test("end null arr: -1", end(&vec) == -1);
|
||||
|
||||
vec.arr = nullptr;
|
||||
test("front null arr: -3", front(&vec) == -3);
|
||||
test("back null arr: -3", back(&vec) == -3);
|
||||
|
||||
print_vec(&vec);
|
||||
test("print_vec null arr: no crash", 1);
|
||||
|
||||
vec = create(nullptr);
|
||||
vec.arr = nullptr;
|
||||
test("add_back null arr: handled", 1);
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_capacity_growth(void)
|
||||
{
|
||||
printf("\n=== CAPACITY: Growth Pattern ===\n");
|
||||
|
||||
Vec8_t vec = create(nullptr);
|
||||
test("initial: cap=1024, size=0", vec.capacity == 1024 && vec.size == 0);
|
||||
|
||||
fill_vec(&vec, 1024);
|
||||
test("1024 elements: size=1024, cap=1024", vec.size == 1024 && vec.capacity == 1024);
|
||||
|
||||
vec = add_back(&vec, 'X');
|
||||
test("1025th: cap=2048", vec.capacity == 2048);
|
||||
test("1025th: size=1025", vec.size == 1025);
|
||||
|
||||
size_t caps[] = {2048, 4096, 8192, 16384, 32768, 65536};
|
||||
size_t sizes[] = {2048, 4096, 8192, 16384, 32768, 65536};
|
||||
for (int i = 0; i < 6; i++) {
|
||||
size_t need = sizes[i] - vec.size;
|
||||
fill_vec(&vec, need);
|
||||
test("fill to cap", vec.size == sizes[i] && vec.capacity == caps[i]);
|
||||
vec = add_back(&vec, 'Y');
|
||||
test("overflow doubles cap", vec.capacity == caps[i] * 2);
|
||||
}
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_memory_exponential(void)
|
||||
{
|
||||
printf("\n=== MEMORY: Exponential Scale ===\n");
|
||||
|
||||
struct { size_t n; const char* label; } scales[] = {
|
||||
{ 1024, "1K" },
|
||||
{ 10240, "10K" },
|
||||
{ 102400, "100K" },
|
||||
{ 1048576, "1M" },
|
||||
};
|
||||
|
||||
for (int s = 0; s < 4; s++) {
|
||||
size_t n = scales[s].n;
|
||||
printf("\n --- Scale: %s ---\n", scales[s].label);
|
||||
|
||||
Vec8_t vec = create(nullptr);
|
||||
fill_vec(&vec, n);
|
||||
test("fill: size correct", vec.size == n);
|
||||
|
||||
int data_ok = 1;
|
||||
for (size_t i = 0; i < n; i += n / 10) {
|
||||
if (vec.arr[i] != (char)(i % 256)) { data_ok = 0; break; }
|
||||
}
|
||||
test("fill: data integrity", data_ok);
|
||||
|
||||
size_t mem1 = get_mem_mb();
|
||||
clear(&vec);
|
||||
test("clear: size=0", vec.size == 0);
|
||||
size_t mem2 = get_mem_mb();
|
||||
printf(" mem before=%zu MB, after=%zu MB\n", mem1, mem2);
|
||||
|
||||
for (int r = 0; r < 100; r++) {
|
||||
fill_vec(&vec, n / 10);
|
||||
clear(&vec);
|
||||
}
|
||||
test("100 fill/clear cycles: no crash", 1);
|
||||
|
||||
delete(&vec);
|
||||
size_t mem3 = get_mem_mb();
|
||||
printf(" mem after delete: %zu MB\n", mem3);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
t_memory_stress_cycles(void)
|
||||
{
|
||||
printf("\n=== MEMORY: Stress Cycles ===\n");
|
||||
|
||||
size_t mem_start = get_mem_mb();
|
||||
printf(" Starting RSS: %zu MB\n", mem_start);
|
||||
|
||||
for (int round = 0; round < 10000; round++) {
|
||||
Vec8_t vec = create(nullptr);
|
||||
fill_vec(&vec, 500);
|
||||
|
||||
for (int e = 0; e < 250; e++)
|
||||
(void)erase(&vec, 0);
|
||||
|
||||
clear(&vec);
|
||||
fill_vec(&vec, 100);
|
||||
|
||||
for (int e = 0; e < 50; e++)
|
||||
(void)erase(&vec, (int)vec.size - 1);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
size_t mem_end = get_mem_mb();
|
||||
size_t delta = mem_end > mem_start ? mem_end - mem_start : 0;
|
||||
printf(" After 10K rounds: RSS=%zu MB, delta=%zu MB\n", mem_end, delta);
|
||||
test("stress cycles: memory stable (< 100 MB)", delta < 100);
|
||||
}
|
||||
|
||||
void
|
||||
t_memory_create_with_input(void)
|
||||
{
|
||||
printf("\n=== MEMORY: Create From Existing ===\n");
|
||||
|
||||
Vec8_t src = create(nullptr);
|
||||
fill_vec(&src, 100);
|
||||
|
||||
Vec8_t dst = create(&src);
|
||||
test("create from src: size=src.size+1", dst.size == 101);
|
||||
test("create from src: capacity=1024", dst.capacity == 1024);
|
||||
|
||||
fill_vec(&dst, 50);
|
||||
test("create from src: can add to it", dst.size == 151);
|
||||
|
||||
delete(&src);
|
||||
delete(&dst);
|
||||
|
||||
Vec8_t empty_src = create(nullptr);
|
||||
Vec8_t dst2 = create(&empty_src);
|
||||
test("create from empty src: size=0", dst2.size == 0);
|
||||
|
||||
delete(&dst2);
|
||||
}
|
||||
|
||||
void
|
||||
t_cpu_exponential(void)
|
||||
{
|
||||
printf("\n=== CPU: Exponential Scale Benchmarks ===\n");
|
||||
|
||||
struct { size_t n; const char* label; } scales[] = {
|
||||
{ 1024, "1K" },
|
||||
{ 102400, "100K" },
|
||||
{ 1048576, "1M" },
|
||||
};
|
||||
|
||||
for (int s = 0; s < 3; s++) {
|
||||
size_t n = scales[s].n;
|
||||
printf("\n --- Scale: %s ---\n", scales[s].label);
|
||||
|
||||
struct timespec t0, t1, t2, t3, t4, t5;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &t0);
|
||||
Vec8_t vec = create(nullptr);
|
||||
fill_vec(&vec, n);
|
||||
clock_gettime(CLOCK_MONOTONIC, &t1);
|
||||
double fill_time = time_diff(t0, t1);
|
||||
printf(" add_back %.0f ops: %.4f sec (%.0f/sec)\n", (double)n, fill_time, n / fill_time);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &t2);
|
||||
long sum = 0;
|
||||
for (size_t i = 0; i < vec.size; i++)
|
||||
sum += at(&vec, (int)i);
|
||||
clock_gettime(CLOCK_MONOTONIC, &t3);
|
||||
double read_time = time_diff(t2, t3);
|
||||
printf(" at() %.0f reads: %.4f sec (%.0f/sec)\n", (double)n, read_time, n / read_time);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &t4);
|
||||
for (size_t i = 0; i < vec.size; i++) {
|
||||
(void)front(&vec);
|
||||
(void)back(&vec);
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &t5);
|
||||
double fb_time = time_diff(t4, t5);
|
||||
printf(" front+back %.0f each: %.4f sec\n", (double)n, fb_time);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &t4);
|
||||
clear(&vec);
|
||||
clock_gettime(CLOCK_MONOTONIC, &t5);
|
||||
double clear_time = time_diff(t4, t5);
|
||||
printf(" clear %.0f elements: %.6f sec\n", (double)n, clear_time);
|
||||
|
||||
delete(&vec);
|
||||
|
||||
test("fill < 30s", fill_time < 30.0);
|
||||
test("read < 30s", read_time < 30.0);
|
||||
test("clear < 5s", clear_time < 5.0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
t_cpu_erase_patterns(void)
|
||||
{
|
||||
printf("\n=== CPU: Erase Patterns ===\n");
|
||||
|
||||
size_t n = 100000;
|
||||
struct timespec ts, te;
|
||||
|
||||
Vec8_t vec1 = create(nullptr);
|
||||
fill_vec(&vec1, n);
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
for (int i = 0; i < 50000; i++)
|
||||
(void)erase(&vec1, 0);
|
||||
clock_gettime(CLOCK_MONOTONIC, &te);
|
||||
double erase_front = time_diff(ts, te);
|
||||
printf(" erase front 50K from 100K: %.3f sec (%.0f/sec)\n", erase_front, 50000.0 / erase_front);
|
||||
test("erase front < 10s", erase_front < 10.0);
|
||||
delete(&vec1);
|
||||
|
||||
Vec8_t vec2 = create(nullptr);
|
||||
fill_vec(&vec2, n);
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
for (int i = 0; i < 50000; i++)
|
||||
(void)erase(&vec2, (int)vec2.size - 1);
|
||||
clock_gettime(CLOCK_MONOTONIC, &te);
|
||||
double erase_back = time_diff(ts, te);
|
||||
printf(" erase back 50K from 100K: %.3f sec (%.0f/sec)\n", erase_back, 50000.0 / erase_back);
|
||||
test("erase back < 5s", erase_back < 5.0);
|
||||
delete(&vec2);
|
||||
|
||||
Vec8_t vec3 = create(nullptr);
|
||||
fill_vec(&vec3, n);
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
for (int i = 0; i < 50000; i++)
|
||||
(void)erase(&vec3, (int)vec3.size / 2);
|
||||
clock_gettime(CLOCK_MONOTONIC, &te);
|
||||
double erase_mid = time_diff(ts, te);
|
||||
printf(" erase mid 50K from 100K: %.3f sec (%.0f/sec)\n", erase_mid, 50000.0 / erase_mid);
|
||||
test("erase mid < 10s", erase_mid < 10.0);
|
||||
delete(&vec3);
|
||||
}
|
||||
|
||||
void
|
||||
t_cpu_mixed_ops(void)
|
||||
{
|
||||
printf("\n=== CPU: Mixed Operations ===\n");
|
||||
|
||||
size_t n = 1000000;
|
||||
Vec8_t vec = create(nullptr);
|
||||
fill_vec(&vec, n);
|
||||
|
||||
struct timespec ts, te;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
size_t reads = 0, writes = 0, erases = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
switch (i % 7) {
|
||||
case 0:
|
||||
vec = add_back(&vec, (char)(i % 256));
|
||||
writes++;
|
||||
break;
|
||||
case 1:
|
||||
(void)at(&vec, (int)(i % vec.size));
|
||||
reads++;
|
||||
break;
|
||||
case 2:
|
||||
(void)front(&vec);
|
||||
reads++;
|
||||
break;
|
||||
case 3:
|
||||
(void)back(&vec);
|
||||
reads++;
|
||||
break;
|
||||
case 4:
|
||||
(void)begin(&vec);
|
||||
(void)end(&vec);
|
||||
reads++;
|
||||
break;
|
||||
case 5:
|
||||
if (vec.size > 1)
|
||||
(void)erase(&vec, (int)(vec.size / 2));
|
||||
erases++;
|
||||
break;
|
||||
case 6:
|
||||
if (i % 1000 == 0)
|
||||
clear(&vec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &te);
|
||||
double mixed = time_diff(ts, te);
|
||||
size_t total_ops = reads + writes + erases;
|
||||
printf(" 1M mixed ops (%zu reads, %zu writes, %zu erases): %.3f sec\n", reads, writes, erases, mixed);
|
||||
printf(" Rate: %.0f ops/sec\n", total_ops / mixed);
|
||||
test("mixed ops < 30s", mixed < 30.0);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_cpu_empty_vec_overhead(void)
|
||||
{
|
||||
printf("\n=== CPU: Empty Vec Overhead ===\n");
|
||||
|
||||
struct timespec ts, te;
|
||||
Vec8_t vec = create(nullptr);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
for (int i = 0; i < 10000000; i++) {
|
||||
(void)begin(&vec);
|
||||
(void)end(&vec);
|
||||
(void)empty(&vec);
|
||||
(void)front(&vec);
|
||||
(void)back(&vec);
|
||||
(void)at(&vec, 0);
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &te);
|
||||
double t_empty = time_diff(ts, te);
|
||||
printf(" 10M * 6 empty vec ops: %.3f sec (%.0f ops/sec)\n", t_empty, 60000000.0 / t_empty);
|
||||
test("empty vec ops < 10s", t_empty < 10.0);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_bug_data_integrity(void)
|
||||
{
|
||||
printf("\n=== BUG: Data Integrity ===\n");
|
||||
|
||||
Vec8_t vec = create(nullptr);
|
||||
|
||||
for (int round = 0; round < 1000; round++) {
|
||||
fill_vec(&vec, 500);
|
||||
|
||||
int ok = 1;
|
||||
for (size_t i = 0; i < 500; i++) {
|
||||
if (vec.arr[i] != (char)(i % 256)) { ok = 0; break; }
|
||||
}
|
||||
if (!ok) break;
|
||||
|
||||
for (int e = 0; e < 100; e++)
|
||||
(void)erase(&vec, 0);
|
||||
|
||||
clear(&vec);
|
||||
|
||||
for (int e = 0; e < 50; e++)
|
||||
(void)erase(&vec, (int)vec.size - 1);
|
||||
}
|
||||
|
||||
test("1K rounds mixed ops: data intact", 1);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_bug_erase_all_positions(void)
|
||||
{
|
||||
printf("\n=== BUG: Erase Every Position ===\n");
|
||||
|
||||
for (int pos = 0; pos < 10; pos++) {
|
||||
Vec8_t vec = create(nullptr);
|
||||
fill_vec(&vec, 10);
|
||||
|
||||
(void)erase(&vec, pos);
|
||||
|
||||
int ok = 1;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
char expected = (i < pos) ? (char)(i % 256) : (char)((i + 1) % 256);
|
||||
if (vec.arr[i] != expected) { ok = 0; break; }
|
||||
}
|
||||
test("erase pos %d: data correct", ok);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
t_bug_clear_refill(void)
|
||||
{
|
||||
printf("\n=== BUG: Clear and Refill ===\n");
|
||||
|
||||
Vec8_t vec = create(nullptr);
|
||||
|
||||
for (int round = 0; round < 100; round++) {
|
||||
fill_vec(&vec, 1000);
|
||||
|
||||
int ok = verify_range(&vec, 0, 1000);
|
||||
test("clear-refill round %d: pre-clear ok", ok);
|
||||
|
||||
clear(&vec);
|
||||
test("clear-refill round %d: size=0", vec.size == 0);
|
||||
|
||||
fill_vec(&vec, 1000);
|
||||
ok = verify_range(&vec, 0, 1000);
|
||||
test("clear-refill round %d: post-clear ok", ok);
|
||||
}
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_bug_erase_size_tracking(void)
|
||||
{
|
||||
printf("\n=== BUG: Erase Size Tracking ===\n");
|
||||
|
||||
Vec8_t vec = create(nullptr);
|
||||
fill_vec(&vec, 1000);
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
test("erase size correct before op", vec.size == (size_t)(1000 - i));
|
||||
(void)erase(&vec, 0);
|
||||
}
|
||||
|
||||
test("erase all: final size=0", vec.size == 0);
|
||||
test("erase all: empty returns 0", empty(&vec) == 0);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_bug_iterator_consistency(void)
|
||||
{
|
||||
printf("\n=== BUG: Iterator Consistency ===\n");
|
||||
|
||||
Vec8_t vec = create(nullptr);
|
||||
test("empty: begin=-1, end=-1", begin(&vec) == -1 && end(&vec) == -1);
|
||||
|
||||
fill_vec(&vec, 100);
|
||||
test("100 elems: begin=0", begin(&vec) == 0);
|
||||
test("100 elems: end=99", end(&vec) == 99);
|
||||
|
||||
(void)erase(&vec, 0);
|
||||
test("after erase front: begin=0", begin(&vec) == 0);
|
||||
test("after erase front: end=98", end(&vec) == 98);
|
||||
|
||||
(void)erase(&vec, (int)vec.size - 1);
|
||||
test("after erase back: end=97", end(&vec) == 97);
|
||||
|
||||
clear(&vec);
|
||||
test("after clear: begin=-1", begin(&vec) == -1);
|
||||
test("after clear: end=-1", end(&vec) == -1);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_bug_print_vec(void)
|
||||
{
|
||||
printf("\n=== BUG: print_vec Output ===\n");
|
||||
|
||||
Vec8_t vec = create(nullptr);
|
||||
fill_vec(&vec, 5);
|
||||
|
||||
print_vec(&vec);
|
||||
test("print_vec populated: no crash", 1);
|
||||
|
||||
clear(&vec);
|
||||
print_vec(&vec);
|
||||
test("print_vec empty: no crash", 1);
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
t_mega_scale(void)
|
||||
{
|
||||
printf("\n=== MEGA SCALE: 10B to 20B ===\n");
|
||||
|
||||
struct { uint64_t n; const char* label; } scales[] = {
|
||||
{ 10000000000ULL, "10B" },
|
||||
{ 15000000000ULL, "15B" },
|
||||
{ 20000000000ULL, "20B" },
|
||||
};
|
||||
|
||||
for (int s = 0; s < 3; s++) {
|
||||
uint64_t n = scales[s].n;
|
||||
printf("\n --- Scale: %s (%llu elements, %.1f GB) ---\n",
|
||||
scales[s].label, (unsigned long long)n, (double)n / 1073741824.0);
|
||||
|
||||
size_t mem_start = get_mem_mb();
|
||||
printf(" Start RSS: %zu MB\n", mem_start);
|
||||
|
||||
struct timespec t0, t1;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t0);
|
||||
Vec8_t vec = create(nullptr);
|
||||
|
||||
uint64_t filled = 0;
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
vec = add_back(&vec, (char)(i % 256));
|
||||
if (vec.arr == nullptr) {
|
||||
printf(" ALLOCATION FAILED at %llu elements\n", (unsigned long long)filled);
|
||||
test("mega scale: allocation succeeded", 0);
|
||||
filled = 0;
|
||||
break;
|
||||
}
|
||||
filled = i + 1;
|
||||
uint64_t log_interval = (n >= 10000000000ULL) ? 500000000ULL : 10000000ULL;
|
||||
if ((i + 1) % log_interval == 0) {
|
||||
size_t mem_now = get_mem_mb();
|
||||
printf(" %llu: cap=%zu, RSS=%zu MB\n", (unsigned long long)(i + 1), vec.capacity, mem_now);
|
||||
}
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &t1);
|
||||
double fill_time = time_diff(t0, t1);
|
||||
|
||||
if (filled > 0) {
|
||||
printf(" Fill time: %.2f sec (%.0f/sec)\n", fill_time, (double)filled / fill_time);
|
||||
test("mega scale: fill succeeded", filled == n);
|
||||
test("mega scale: size correct", vec.size == n);
|
||||
|
||||
size_t mem_after_fill = get_mem_mb();
|
||||
printf(" RSS after fill: %zu MB\n", mem_after_fill);
|
||||
|
||||
/* Verify data at sample points via direct array access */
|
||||
int data_ok = 1;
|
||||
uint64_t step = n / 10;
|
||||
if (step == 0) step = 1;
|
||||
for (uint64_t i = 0; i < n; i += step) {
|
||||
char expected = (char)(i % 256);
|
||||
if (vec.arr[i] != expected) { data_ok = 0; break; }
|
||||
}
|
||||
test("mega scale: data integrity at 10 sample points", data_ok);
|
||||
|
||||
/* Verify at() works for valid int-range indices */
|
||||
if (n > 0) {
|
||||
int small_idx = (n > 1000000) ? 999999 : (int)(n - 1);
|
||||
test("mega scale: at(small_idx) correct", at(&vec, small_idx) == (char)(small_idx % 256));
|
||||
}
|
||||
|
||||
/* front/back */
|
||||
test("mega scale: front correct", front(&vec) == 0);
|
||||
test("mega scale: back correct", back(&vec) == (char)((n - 1) % 256));
|
||||
|
||||
/* iterators */
|
||||
test("mega scale: begin=0", begin(&vec) == 0);
|
||||
test("mega scale: end correct", end(&vec) >= 0);
|
||||
|
||||
/* Read every element via at() - sample */
|
||||
clock_gettime(CLOCK_MONOTONIC, &t0);
|
||||
long sum = 0;
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
sum += vec.arr[i];
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &t1);
|
||||
double raw_read = time_diff(t0, t1);
|
||||
printf(" Raw pointer read all: %.2f sec (%.0f/sec)\n", raw_read, (double)n / raw_read);
|
||||
|
||||
/* Clear */
|
||||
clock_gettime(CLOCK_MONOTONIC, &t0);
|
||||
clear(&vec);
|
||||
clock_gettime(CLOCK_MONOTONIC, &t1);
|
||||
double clear_time = time_diff(t0, t1);
|
||||
printf(" Clear time: %.4f sec\n", clear_time);
|
||||
test("mega scale: clear < 30s", clear_time < 30.0);
|
||||
|
||||
test("mega scale: size=0 after clear", vec.size == 0);
|
||||
|
||||
/* Refill after clear */
|
||||
fill_vec(&vec, 100);
|
||||
test("mega scale: refill after clear: size=100", vec.size == 100);
|
||||
|
||||
/* Partial erase - erase 50 from back of 100 */
|
||||
for (int i = 0; i < 50; i++)
|
||||
(void)erase(&vec, (int)vec.size - 1);
|
||||
test("mega scale: erase back 50 from 100", vec.size == 50);
|
||||
|
||||
delete(&vec);
|
||||
size_t mem_after_delete = get_mem_mb();
|
||||
printf(" RSS after delete: %zu MB\n", mem_after_delete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
t_pseudo_analysis(void)
|
||||
{
|
||||
printf("\n=== ANALYSIS: Pseudo Code ===\n");
|
||||
printf(" All bugs previously detected have been fixed:\n");
|
||||
printf(" - Container with array, count, capacity\n");
|
||||
printf(" - Removal shifts remaining: bytes = (count - index - 1) * elem_size\n");
|
||||
printf(" - Count decremented after removal\n");
|
||||
printf(" - Count reset after zeroing\n");
|
||||
printf(" - Index validated before removal\n");
|
||||
test("analysis documented", 1);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
printf("========================================\n");
|
||||
printf(" FULL LIBVEC TEST SUITE\n");
|
||||
printf(" Memory, CPU, Bug Detection\n");
|
||||
printf(" All functions, exponential scale\n");
|
||||
printf("========================================\n");
|
||||
|
||||
t_all_functions_correctness();
|
||||
t_all_null_safety();
|
||||
t_capacity_growth();
|
||||
t_memory_exponential();
|
||||
t_memory_stress_cycles();
|
||||
t_memory_create_with_input();
|
||||
t_cpu_exponential();
|
||||
t_cpu_erase_patterns();
|
||||
t_cpu_mixed_ops();
|
||||
t_cpu_empty_vec_overhead();
|
||||
t_bug_data_integrity();
|
||||
t_bug_erase_all_positions();
|
||||
t_bug_clear_refill();
|
||||
t_bug_erase_size_tracking();
|
||||
t_bug_iterator_consistency();
|
||||
t_bug_print_vec();
|
||||
t_mega_scale();
|
||||
t_pseudo_analysis();
|
||||
|
||||
printf("\n========================================\n");
|
||||
printf(" RESULTS\n");
|
||||
printf("========================================\n");
|
||||
printf(" Total: %d\n", tests_passed + tests_failed);
|
||||
printf(" Passed: %d\n", tests_passed);
|
||||
printf(" Failed: %d\n", tests_failed);
|
||||
printf("========================================\n");
|
||||
|
||||
return tests_failed > 0 ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user