diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..67c9429 Binary files /dev/null and b/.DS_Store differ diff --git a/src/main.c b/src/main.c index 91b5028..0c6a9ae 100644 --- a/src/main.c +++ b/src/main.c @@ -3,7 +3,7 @@ * dmm.dev@icloud.com * No LICENSE * Vector Library For C -*/ + */ /* * Types Wanted: @@ -13,7 +13,17 @@ * String */ -// Absolutely no AI is permitted when writing code. +/* Absolutely no AI is permitted when writing code. + * AI is and can be used to generate tests for code; however, the test results + * and the AI can not give code as to how to fix the source aside from psuedo + * code that has no clear relation to the source aside from a recreation of the + * problem in a different way entirely + * + * Any code comments below are just used for my purposes with short term memory. + * It also serves as a way to remember what needs to be changed to be readable + * and not need comments in the first place. + */ +#include #include #include #include @@ -23,17 +33,35 @@ typedef struct { char* arr; size_t size; + size_t capacity; } Vec8_t; +/* Takes in a temporary cpy of a vec + * - Can be nullptr to not have size incrementation and have a size of 0 (Create + * an empty vector) + * + * - Can be a vec to have size incrementation and size of base vec + 1 (Create a + * vector for modifying an old vector) + * + * */ Vec8_t -create(size_t init_size) +create(const Vec8_t* input) { - Vec8_t vec = { .arr = nullptr, .size = 0 }; - if (init_size > 0) + Vec8_t vec = { .arr = nullptr, .size = 0, .capacity = 4 }; + if (input == nullptr) { - vec.arr = malloc(init_size * sizeof(char)); - vec.size = init_size; + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; } + if (input->size > 0) + { + vec.size = input->size + 1; + } + if (input->capacity >= vec.capacity) + { + vec.capacity = 2 * input->capacity; + } + vec.arr = calloc(vec.capacity, sizeof(char)); return vec; } @@ -47,11 +75,22 @@ delete(Vec8_t* vec) vec->arr = nullptr; } - char -at(Vec8_t* vec, int idx) +at(const Vec8_t* vec, const int idx) { - if (vec->arr != nullptr && vec->size >= 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]; } @@ -59,27 +98,32 @@ at(Vec8_t* vec, int idx) } void -print_vec(Vec8_t* vec) { - for(int i = 0; i < vec->size; i++) { - printf("%c ", at(vec, i)); - } - printf("\n"); +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(Vec8_t* vec) +begin(const Vec8_t* vec) { - if (vec->arr != nullptr && vec->size > 0) + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) { - return 1; + return 0; } return -1; } int -end(Vec8_t* vec) +end(const Vec8_t* vec) { - if (vec->arr != nullptr && vec->size > 0) + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) { return (int)(vec->size - 1); } @@ -87,60 +131,77 @@ end(Vec8_t* vec) } char -front(Vec8_t* vec) +front(const Vec8_t* vec) { - if (vec->arr != nullptr && vec->size > 0) - { - return vec->arr[0]; - } - return -1; + return at(vec, 0); } char -back(Vec8_t* vec) +back(const Vec8_t* vec) { - if (vec->arr != nullptr && vec->size > 0) + if (vec) { - return vec->arr[vec->size - 1]; + return at(vec, (int)vec->size - 1); } return -1; } +/* Return a Vector + * if below capacity + * + * + * */ Vec8_t -add_back(Vec8_t* vec, char val) +add_back(Vec8_t* vec, const char val) { - Vec8_t nvec = create(vec->size + 1); - memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); - if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) + Vec8_t ret = { .arr = nullptr, .capacity = 0, .size = 0 }; + if (vec->size < vec->capacity) { - nvec.arr[vec->size] = val; + vec->arr[vec->size] = val; + vec->size++; + return *vec; } - return nvec; + + if (vec->size >= vec->capacity) + { + Vec8_t nvec = create(vec); + memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); + if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) + { + nvec.arr[vec->size] = val; + } + free(vec->arr); + return nvec; + } + return ret; } -Vec8_t -add_front(Vec8_t* vec, char val) -{ - Vec8_t nvec = create(vec->size + 1); - memcpy(&nvec.arr[1], &vec->arr[0], vec->size * sizeof(char)); - if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) - { - nvec.arr[0] = val; - } - return nvec; -} +// Vec8_t +// add_front(Vec8_t* vec, char val) +// { +// Vec8_t nvec = create(vec->size + 1); +// memcpy(&nvec.arr[1], &vec->arr[0], vec->size * sizeof(char)); +// if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) +// { +// nvec.arr[0] = val; +// } +// return nvec; +// } int main() { - Vec8_t vec = create(0); + Vec8_t vec = create(nullptr); vec = add_back(&vec, '3'); vec = add_back(&vec, '4'); vec = add_back(&vec, '5'); vec = add_back(&vec, '6'); - print_vec(&vec); - vec = add_front(&vec, 'c'); - print_vec(&vec); + vec = add_back(&vec, '7'); + print_vec(&vec); + // vec = add_back(&vec, '6'); + // vec = add_front(&vec, 'c'); + // print_vec(&vec); + // printf("%c", at(nullptr, 0)); delete(&vec); return 0; diff --git a/tests/cpu_stress b/tests/cpu_stress new file mode 100755 index 0000000..06a92d7 Binary files /dev/null and b/tests/cpu_stress differ diff --git a/tests/cpu_stress.c b/tests/cpu_stress.c new file mode 100644 index 0000000..88f020f --- /dev/null +++ b/tests/cpu_stress.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +Vec8_t create(Vec8_t* input) { + Vec8_t vec = { .arr = nullptr, .size = 0, .capacity = 4 }; + if(input == nullptr) { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) { + vec.size = input->size + 1; + } + if (input->capacity >= vec.capacity) { + vec.capacity = 2 * input->capacity; + } + 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(Vec8_t* vec, 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; +} + +int begin(Vec8_t* vec) { + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) return 0; + return -1; +} + +int end(Vec8_t* vec) { + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) return (int)(vec->size - 1); + return -1; +} + +char front(Vec8_t* vec) { + return at(vec, 0); +} + +char back(Vec8_t* vec) { + if (vec) return at(vec, (int)vec->size - 1); + return -1; +} + +Vec8_t add_back(Vec8_t* vec, char val) { + Vec8_t ret = { .arr = nullptr, .capacity = 0, .size = 0 }; + if (vec->size < vec->capacity) { + vec->arr[vec->size] = val; + vec->size++; + return *vec; + } + if (vec->size >= vec->capacity) { + Vec8_t nvec = create(vec); + memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); + if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) { + nvec.arr[vec->size] = val; + } + free(vec->arr); + return nvec; + } + return ret; +} + +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() { + struct timespec start, end_t; + Vec8_t vec; + + printf("=== CPU Stress Tests ===\n\n"); + + // Test 1: Rapid fire inserts (tight loop) + printf("--- Test 1: Rapid Fire (100M tight loop) ---\n"); + vec = create(nullptr); + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < 100000000; i++) { + vec = add_back(&vec, (char)i); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t1 = time_diff(start, end_t); + printf(" Time: %.3f sec\n", t1); + printf(" Rate: %.0f/sec\n", 100000000.0 / t1); + delete(&vec); + + // Test 2: Read-heavy (iteration + at()) + printf("\n--- Test 2: Read Every Element (100M at() calls) ---\n"); + vec = create(nullptr); + for (int i = 0; i < 100000000; i++) vec = add_back(&vec, (char)i); + long sum = 0; + clock_gettime(CLOCK_MONOTONIC, &start); + for (size_t i = 0; i < vec.size; i++) { + sum += at(&vec, (int)i); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t2 = time_diff(start, end_t); + printf(" Time: %.3f sec\n", t2); + printf(" Sum: %ld\n", sum); + printf(" Rate: %.0f reads/sec\n", 100000000.0 / t2); + delete(&vec); + + // Test 3: Mixed operations + printf("\n--- Test 3: Mixed Operations (50M each) ---\n"); + vec = create(nullptr); + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < 50000000; i++) { + vec = add_back(&vec, (char)i); + char f = front(&vec); + char b = back(&vec); + at(&vec, i / 2); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t3 = time_diff(start, end_t); + printf(" Time: %.3f sec\n", t3); + printf(" Rate: %.0f ops/sec\n", 50000000.0 * 3 / t3); + delete(&vec); + + // Test 4: Cache thrashing (random access) + printf("\n--- Test 4: Random Access (100M random at() calls) ---\n"); + vec = create(nullptr); + for (int i = 0; i < 100000000; i++) vec = add_back(&vec, (char)i); + srand(12345); + clock_gettime(CLOCK_MONOTONIC, &start); + sum = 0; + for (int i = 0; i < 100000000; i++) { + int idx = rand() % (int)vec.size; + sum += at(&vec, idx); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t4 = time_diff(start, end_t); + printf(" Time: %.3f sec\n", t4); + printf(" Sum: %ld\n", sum); + printf(" Rate: %.0f random reads/sec\n", 100000000.0 / t4); + delete(&vec); + + // Test 5: Sequential scan (raw pointer access) + printf("\n--- Test 5: Sequential Scan (raw pointer, 500M bytes) ---\n"); + vec = create(nullptr); + for (int i = 0; i < 500000000; i++) vec = add_back(&vec, (char)(i % 256)); + sum = 0; + clock_gettime(CLOCK_MONOTONIC, &start); + char* ptr = vec.arr; + for (size_t i = 0; i < vec.size; i++) { + sum += ptr[i]; + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t5 = time_diff(start, end_t); + printf(" Time: %.3f sec\n", t5); + printf(" Throughput: %.1f GB/sec\n", (vec.size / 1e9) / t5); + printf(" Sum: %ld\n", sum); + delete(&vec); + + // Test 6: Create/delete cycles (memory allocation stress) + printf("\n--- Test 6: Create/Delete Cycles (1M vectors) ---\n"); + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < 1000000; i++) { + vec = create(nullptr); + for (int j = 0; j < 100; j++) vec = add_back(&vec, (char)j); + delete(&vec); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t6 = time_diff(start, end_t); + printf(" Time: %.3f sec\n", t6); + printf(" Rate: %.0f create/delete cycles/sec\n", 1000000.0 / t6); + + printf("\n=== CPU Stress Complete ===\n"); + return 0; +} diff --git a/tests/edge_case_test b/tests/edge_case_test new file mode 100755 index 0000000..2757645 Binary files /dev/null and b/tests/edge_case_test differ diff --git a/tests/edge_case_test.c b/tests/edge_case_test.c new file mode 100644 index 0000000..13c770c --- /dev/null +++ b/tests/edge_case_test.c @@ -0,0 +1,317 @@ +#include +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +Vec8_t create(Vec8_t* input) { + Vec8_t vec = { .arr = nullptr, .size = 0, .capacity = 4 }; + if(input == nullptr) { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) { + vec.size = input->size + 1; + } + if (input->capacity >= vec.capacity) { + vec.capacity = 2 * input->capacity; + } + 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(Vec8_t* vec, 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; +} + +int begin(Vec8_t* vec) { + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) return 0; + return -1; +} + +int end(Vec8_t* vec) { + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) return (int)(vec->size - 1); + return -1; +} + +char front(Vec8_t* vec) { + return at(vec, 0); +} + +char back(Vec8_t* vec) { + if (vec) return at(vec, (int)vec->size - 1); + return -1; +} + +Vec8_t add_back(Vec8_t* vec, char val) { + Vec8_t ret = { .arr = nullptr, .capacity = 0, .size = 0 }; + if (vec->size < vec->capacity) { + vec->arr[vec->size] = val; + vec->size++; + return *vec; + } + if (vec->size >= vec->capacity) { + Vec8_t nvec = create(vec); + memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); + if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) { + nvec.arr[vec->size] = val; + } + free(vec->arr); + return nvec; + } + return ret; +} + +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++; + } +} + +int main() { + printf("=== EDGE CASE BRUTAL TESTS ===\n\n"); + + Vec8_t vec; + char* ptr; + + // === Test 1: Use after reallocation (expected behavior) === + printf("--- Reallocation Behavior ---\n"); + + vec = create(nullptr); + for (int i = 0; i < 10; i++) vec = add_back(&vec, (char)('A' + i)); + ptr = vec.arr; // save pointer (will be freed on next realloc) + + for (int i = 0; i < 100; i++) vec = add_back(&vec, (char)('0' + (i % 10))); + + // Pointer changes after reallocation - this is expected + test("after reallocation, vec.arr is new", ptr != vec.arr); + test("data preserved in new vec", vec.arr[0] == 'A' && vec.arr[9] == 'J'); + test("vec must be reassigned: vec = add_back()", 1); + delete(&vec); + + // === Test 2: Stack-allocated struct (not created via create) === + printf("\n--- Stack-Allocated Struct ---\n"); + + Vec8_t stack_vec; + stack_vec.arr = nullptr; + stack_vec.size = 0; + stack_vec.capacity = 0; + + // This will fail because capacity starts at 0, not 4 + // and there's no way to use add_back properly + // BUG: User can't easily use functions without calling create() + test("stack vec: add_back modifies nothing (capacity 0)", 1); // informational + + // === Test 3: Integer overflow potential === + printf("\n--- Integer Overflow ---\n"); + + // If someone passes SIZE_MAX or near-max to create + // The doubling could overflow + vec = create(nullptr); + vec.capacity = (size_t)-1; // max size_t + vec.size = 0; + vec.arr = calloc(1, 1); // tiny allocation + + // BUG: 2 * capacity overflows to 0 + size_t doubled = 2 * vec.capacity; + test("2 * SIZE_MAX overflows (demonstrates overflow)", 1); // informational + + free(vec.arr); + + // === Test 4: Negative index with signed int === + printf("\n--- Signed/Unsigned Mixing ---\n"); + + vec = create(nullptr); + vec = add_back(&vec, 'X'); + + int neg_idx = -1; + // BUG: -1 as unsigned is huge, causing out-of-bounds access + char result = at(&vec, neg_idx); + test("at() with negative -1 returns error", result == -4); + + neg_idx = -2147483648; + result = at(&vec, neg_idx); + test("at() with INT_MIN returns error", result == -4); + + delete(&vec); + + // === Test 5: Size very large === + printf("\n--- Huge Size Values ---\n"); + + vec = create(nullptr); + vec.size = 1000000; // manually corrupt size (bad user code) + vec.capacity = 4; + vec.arr = calloc(4, 1); + + // BUG: size > capacity, add_back will try to create with size+1 = 1000001 + // which allocates based on old logic + result = at(&vec, 0); + // Should still work for valid indices within actual capacity + test("at() works for valid idx despite bad size", result == 0); + + delete(&vec); + + // === Test 6: Uninitialized struct === + printf("\n--- Uninitialized Struct ---\n"); + + Vec8_t uninit; + // BUG: arr, size, capacity contain garbage + // Any function call is undefined behavior + printf(" Calling at() on uninitialized struct...\n"); + printf(" This is undefined behavior - results unpredictable!\n"); + test("uninitialized: expect garbage or crash (UB)", 1); // informational + + // === Test 7: Capacity not matching allocation === + printf("\n--- Capacity Mismatch ---\n"); + + vec = create(nullptr); + vec.arr = realloc(vec.arr, 1000); // manually grow + vec.capacity = 1000; // but don't tell anyone + + for (int i = 0; i < 50; i++) vec = add_back(&vec, (char)i); + test("manual realloc: capacity grows (add_back doesn't know)", 1); // informational + + delete(&vec); + + // === Test 8: memcpy with null === + printf("\n--- Memcpy Edge Cases ---\n"); + + vec = create(nullptr); + vec.size = 0; + // BUG: memcpy(&vec.arr[0], &vec.arr[0], 0) - this is actually fine (no-op) + for (int i = 0; i < 5; i++) vec = add_back(&vec, (char)('A' + i)); + test("empty memcpy edge case: works fine", vec.size == 5); + delete(&vec); + + // === Test 9: Return value ignored === + printf("\n--- Ignored Return Values ---\n"); + + vec = create(nullptr); + add_back(&vec, 'X'); // Modifies in-place when capacity available + test("add_back modifies in-place when capacity available", vec.size == 1); + test("data stored correctly", vec.arr[0] == 'X'); + + // Fill to capacity (4): size goes 1->4 + for (int i = 0; i < 3; i++) vec = add_back(&vec, (char)('A' + i)); + // Now size=4, cap=4 + + // Add more: this triggers reallocation (size >= capacity) + char* old_ptr = vec.arr; + vec = add_back(&vec, 'Z'); // reallocates! size becomes 5, cap becomes 8 + test("reallocation triggered", old_ptr != vec.arr); + test("realloc: data preserved in new vec", vec.arr[4] == 'Z'); + delete(&vec); + + // === Test 10: Multiple vectors, aliasing === + printf("\n--- Aliasing Issues ---\n"); + + Vec8_t v1 = create(nullptr); + Vec8_t v2 = create(nullptr); + + for (int i = 0; i < 5; i++) v1 = add_back(&v1, (char)('A' + i)); + for (int i = 0; i < 5; i++) v2 = add_back(&v2, (char)('1' + i)); + + test("v1 and v2 are separate", v1.arr != v2.arr); + test("v1 data correct", v1.arr[0] == 'A'); + test("v2 data correct", v2.arr[0] == '1'); + + delete(&v1); + delete(&v2); + + // === Test 11: Freeing already-freed memory === + printf("\n--- Double Free ---\n"); + + vec = create(nullptr); + vec = add_back(&vec, 'X'); + char* data = vec.arr; + delete(&vec); + free(data); // BUG: double free! + printf(" Double free detected (would crash with sanitizers)\n"); + test("double free: undefined behavior", 1); // informational + + // === Test 12: Realloc failure === + printf("\n--- Realloc Failure ---\n"); + + // Hard to test without mocking, but conceptually: + // If malloc/calloc fails, the library doesn't check + // BUG: nvec.arr could be NULL, then memcpy with NULL crashes + printf(" If realloc fails: nvec.arr is NULL, memcpy crashes\n"); + test("no malloc failure check in create()", 1); // informational + + // === Test 13: Reading freed memory === + printf("\n--- Use After Delete ---\n"); + + vec = create(nullptr); + for (int i = 0; i < 10; i++) vec = add_back(&vec, (char)i); + delete(&vec); + + // BUG: vec.arr is nullptr, vec.size is still 10 + // User might expect size to be 0 after delete + test("after delete: arr is null", vec.arr == nullptr); + test("after delete: size is still 10 (not cleared)", vec.size == 10); + test("after delete: accessing returns error", at(&vec, 0) == -3); + + // === Test 14: Size 0 with capacity 0 === + printf("\n--- Size/Capacity Edge ---\n"); + + vec.arr = malloc(100); + vec.size = 0; + vec.capacity = 100; + + // BUG: begin() checks size > 0, so returns -1 even though we have capacity + test("begin() returns -1 when size=0", begin(&vec) == -1); + test("end() returns -1 when size=0", end(&vec) == -1); + test("front() returns -4 when size=0", front(&vec) == -4); + test("back() returns -4 when size=0", back(&vec) == -4); + + free(vec.arr); + + // === Test 15: Concurrent modification (conceptual) === + printf("\n--- Iterator Invalidation Concept ---\n"); + + vec = create(nullptr); + for (int i = 0; i < 10; i++) vec = add_back(&vec, (char)('A' + i)); + + // If user iterates while adding: + // for (int i = 0; i < 1000; i++) { + // if (i == 10) vec = add_back(&vec, 'Z'); // reallocation! + // use vec.arr[i]; // BUG: pointer invalid after realloc + // } + printf(" Iteration + reallocation invalidates pointers\n"); + test("conceptual: iteration during add_back is unsafe", 1); + delete(&vec); + + // === Summary === + printf("\n=== Summary ===\n"); + printf("Passed: %d\n", tests_passed); + printf("Failed: %d\n", tests_failed); + printf("Note: 'informational' tests always pass, real bugs above\n"); + + return 0; +} diff --git a/tests/memory_stress b/tests/memory_stress new file mode 100755 index 0000000..d3edd05 Binary files /dev/null and b/tests/memory_stress differ diff --git a/tests/memory_stress.c b/tests/memory_stress.c new file mode 100644 index 0000000..821e262 --- /dev/null +++ b/tests/memory_stress.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; +} Vec8_t; + +Vec8_t create(size_t init_size) { + Vec8_t vec = { .arr = nullptr, .size = 0 }; + if (init_size > 0) { + vec.arr = malloc(init_size * sizeof(char)); + vec.size = init_size; + } + return vec; +} + +void delete(Vec8_t* vec) { + if (vec->arr != nullptr) free(vec->arr); + vec->arr = nullptr; +} + +int main(int argc, char* argv[]) { + size_t count = 100000000; // 100M + int vec_count = 1; + + if (argc > 1) count = atoll(argv[1]); + if (argc > 2) vec_count = atoi(argv[2]); + + size_t total = count * (size_t)vec_count; + printf("=== Direct Allocation Memory Test ===\n"); + printf("Elements per vector: %zu\n", count); + printf("Number of vectors: %d\n", vec_count); + printf("Total elements: %zu\n", total); + printf("Total memory: %.1f GB\n", (total * sizeof(char)) / (1024.0 * 1024.0 * 1024.0)); + printf("\n"); + + struct timespec start, end; + Vec8_t* vecs = malloc(vec_count * sizeof(Vec8_t)); + + clock_gettime(CLOCK_MONOTONIC, &start); + + printf("Allocating %d vectors of %zu elements each...\n", vec_count, count); + for (int v = 0; v < vec_count; v++) { + vecs[v] = create(count); + if (vecs[v].arr == nullptr) { + printf(" ERROR: Failed to allocate vector %d!\n", v); + return 1; + } + } + + clock_gettime(CLOCK_MONOTONIC, &end); + double alloc_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9; + printf("Allocation time: %.2f seconds\n", alloc_time); + + printf("\nFilling vectors...\n"); + clock_gettime(CLOCK_MONOTONIC, &start); + + for (int v = 0; v < vec_count; v++) { + for (size_t i = 0; i < count; i++) { + vecs[v].arr[i] = (char)(i % 256); + } + } + + clock_gettime(CLOCK_MONOTONIC, &end); + double fill_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9; + printf("Fill time: %.2f seconds\n", fill_time); + + printf("\nVerifying...\n"); + int errors = 0; + for (int v = 0; v < vec_count; v++) { + if (vecs[v].size != count) errors++; + if (vecs[v].arr[0] != 0) errors++; + if (vecs[v].arr[count - 1] != (char)((count - 1) % 256)) errors++; + } + printf("Errors: %d\n", errors); + + printf("\nFreeing...\n"); + clock_gettime(CLOCK_MONOTONIC, &start); + for (int v = 0; v < vec_count; v++) { + delete(&vecs[v]); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double free_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9; + printf("Free time: %.2f seconds\n", free_time); + + free(vecs); + + printf("\n=== Complete ===\n"); + printf("Total time: %.2f seconds\n", alloc_time + fill_time + free_time); + + return errors > 0 ? 1 : 0; +} diff --git a/tests/reliability_test b/tests/reliability_test new file mode 100755 index 0000000..a78214c Binary files /dev/null and b/tests/reliability_test differ diff --git a/tests/reliability_test.c b/tests/reliability_test.c new file mode 100644 index 0000000..d3cef1e --- /dev/null +++ b/tests/reliability_test.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +Vec8_t create(Vec8_t* input) { + Vec8_t vec = { .arr = nullptr, .size = 0, .capacity = 4 }; + if(input == nullptr) { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) { + vec.size = input->size + 1; + } + if (input->capacity >= vec.capacity) { + vec.capacity = 2 * input->capacity; + } + 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(Vec8_t* vec, 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; +} + +int begin(Vec8_t* vec) { + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) return 0; + return -1; +} + +int end(Vec8_t* vec) { + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) return (int)(vec->size - 1); + return -1; +} + +char front(Vec8_t* vec) { + return at(vec, 0); +} + +char back(Vec8_t* vec) { + if (vec) return at(vec, (int)vec->size - 1); + return -1; +} + +Vec8_t add_back(Vec8_t* vec, char val) { + Vec8_t ret = { .arr = nullptr, .capacity = 0, .size = 0 }; + if (vec->size < vec->capacity) { + vec->arr[vec->size] = val; + vec->size++; + return *vec; + } + if (vec->size >= vec->capacity) { + Vec8_t nvec = create(vec); + memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); + if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) { + nvec.arr[vec->size] = val; + } + free(vec->arr); + return nvec; + } + return ret; +} + +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++; + } +} + +int main() { + printf("=== Reliability Tests ===\n\n"); + + Vec8_t vec; + + // === Basic Initialization === + printf("--- Initialization ---\n"); + + vec = create(nullptr); + test("create(nullptr) returns valid vec", vec.arr != nullptr); + test("create(nullptr) capacity = 4", vec.capacity == 4); + test("create(nullptr) size = 0", vec.size == 0); + delete(&vec); + + // === Empty Vector Operations === + printf("\n--- Empty Vector Operations ---\n"); + + vec = create(nullptr); + test("at() on empty returns error", at(&vec, 0) == -4); + test("at() on empty (neg idx) returns error", at(&vec, -1) == -4); + test("at() on empty (large idx) returns error", at(&vec, 100) == -4); + test("front() on empty returns error", front(&vec) == -4); + test("back() on empty returns error", back(&vec) == -4); + test("begin() on empty returns -1", begin(&vec) == -1); + test("end() on empty returns -1", end(&vec) == -1); + delete(&vec); + + // === Single Element === + printf("\n--- Single Element ---\n"); + + vec = create(nullptr); + vec = add_back(&vec, 'X'); + test("single element: size = 1", vec.size == 1); + test("single element: at(0) = 'X'", at(&vec, 0) == 'X'); + test("single element: front() = 'X'", front(&vec) == 'X'); + test("single element: back() = 'X'", back(&vec) == 'X'); + test("single element: begin() = 0", begin(&vec) == 0); + test("single element: end() = 0", end(&vec) == 0); + delete(&vec); + + // === Capacity Boundaries === + printf("\n--- Capacity Boundaries ---\n"); + + vec = create(nullptr); + for (int i = 0; i < 4; i++) vec = add_back(&vec, (char)('A' + i)); + test("at capacity (4): size = 4", vec.size == 4); + test("at capacity (4): capacity = 4", vec.capacity == 4); + + vec = add_back(&vec, 'E'); + test("at capacity (4): size = 5", vec.size == 5); + test("at capacity (4): capacity doubled = 8", vec.capacity == 8); + test("at capacity (4): arr[4] = 'E'", vec.arr[4] == 'E'); + delete(&vec); + + // === Data Integrity === + printf("\n--- Data Integrity ---\n"); + + vec = create(nullptr); + for (int i = 0; i < 100; i++) vec = add_back(&vec, (char)i); + test("data integrity: size = 100", vec.size == 100); + for (int i = 0; i < 100; i++) { + test("data integrity: arr[i] = i", vec.arr[i] == (char)i); + } + delete(&vec); + + // === Large Capacity === + printf("\n--- Large Capacity ---\n"); + + vec = create(nullptr); + for (int i = 0; i < 1000; i++) vec = add_back(&vec, (char)(i % 256)); + test("large vec: size = 1000", vec.size == 1000); + test("large vec: capacity >= size", vec.capacity >= 1000); + test("large vec: first preserved", vec.arr[0] == 0); + test("large vec: last preserved", vec.arr[999] == (char)(999 % 256)); + delete(&vec); + + // === NULL Safety === + printf("\n--- 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); + + // === Memory Leak Check (basic) === + printf("\n--- Memory Leak Check ---\n"); + + for (int round = 0; round < 100; round++) { + vec = create(nullptr); + for (int i = 0; i < 50; i++) vec = add_back(&vec, (char)i); + delete(&vec); + } + test("100 create/delete cycles: no crash", 1); + + // === Double Delete === + printf("\n--- Double Delete Safety ---\n"); + + vec = create(nullptr); + vec = add_back(&vec, 'T'); + delete(&vec); + delete(&vec); // Should not crash + test("double delete: no crash", 1); + + // === Delete Then Access === + printf("\n--- Delete Then Access ---\n"); + + vec = create(nullptr); + vec = add_back(&vec, 'A'); + vec = add_back(&vec, 'B'); + delete(&vec); + test("after delete: at() returns error", at(&vec, 0) == -3); + test("after delete: front() returns error", front(&vec) == -3); + test("after delete: back() returns -3 (size still 2)", back(&vec) == -3); + + // === Extreme Values === + printf("\n--- Extreme Values ---\n"); + + vec = create(nullptr); + vec = add_back(&vec, 0); + vec = add_back(&vec, 127); + vec = add_back(&vec, -128); + test("extreme: zero preserved", vec.arr[0] == 0); + test("extreme: max char preserved", vec.arr[1] == 127); + test("extreme: min char preserved", vec.arr[2] == -128); + delete(&vec); + + // === Rapid Small Operations === + printf("\n--- Rapid Small Operations ---\n"); + + for (int round = 0; round < 10; round++) { + vec = create(nullptr); + for (int i = 0; i < 10; i++) vec = add_back(&vec, (char)('A' + i)); + test("rapid small: round preserves data", + vec.arr[0] == 'A' && vec.arr[9] == 'J'); + delete(&vec); + } + + // === Alternating Add/Read === + printf("\n--- Alternating Add/Read ---\n"); + + vec = create(nullptr); + for (int i = 0; i < 50; i++) { + vec = add_back(&vec, (char)('A' + i)); + test("alternating: read during add", + at(&vec, i) == (char)('A' + i)); + } + delete(&vec); + + // === Capacity Exact Match === + printf("\n--- Capacity Exact Match ---\n"); + + vec = create(nullptr); + for (int i = 0; i < 8; i++) vec = add_back(&vec, (char)i); + test("exact cap: size = 8", vec.size == 8); + test("exact cap: capacity = 8", vec.capacity == 8); + vec = add_back(&vec, 'X'); + test("exact cap +1: size = 9", vec.size == 9); + test("exact cap +1: capacity = 16", vec.capacity == 16); + delete(&vec); + + // === Summary === + printf("\n=== Summary ===\n"); + printf("Passed: %d\n", tests_passed); + printf("Failed: %d\n", tests_failed); + printf("Total: %d\n", tests_passed + tests_failed); + + return tests_failed > 0 ? 1 : 0; +} diff --git a/tests/stress_test b/tests/stress_test new file mode 100755 index 0000000..4f4c9bd Binary files /dev/null and b/tests/stress_test differ diff --git a/tests/stress_test.c b/tests/stress_test.c new file mode 100644 index 0000000..ec642b9 --- /dev/null +++ b/tests/stress_test.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +Vec8_t create(Vec8_t* input) { + Vec8_t vec = { .arr = nullptr, .size = 0, .capacity = 4 }; + if(input == nullptr) { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) { + vec.size = input->size + 1; + } + if (input->capacity >= vec.capacity) { + vec.capacity = 2 * input->capacity; + } + 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(Vec8_t* vec, 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; +} + +int begin(Vec8_t* vec) { + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) return 0; + return -1; +} + +int end(Vec8_t* vec) { + if (vec != nullptr && vec->arr != nullptr && vec->size > 0) return (int)(vec->size - 1); + return -1; +} + +char front(Vec8_t* vec) { + return at(vec, 0); +} + +char back(Vec8_t* vec) { + if (vec) return at(vec, (int)vec->size - 1); + return -1; +} + +Vec8_t add_back(Vec8_t* vec, char val) { + Vec8_t ret = { .arr = nullptr, .capacity = 0, .size = 0 }; + if (vec->size < vec->capacity) { + vec->arr[vec->size] = val; + vec->size++; + return *vec; + } + if (vec->size >= vec->capacity) { + Vec8_t nvec = create(vec); + memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); + if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) { + nvec.arr[vec->size] = val; + } + free(vec->arr); + return nvec; + } + return ret; +} + +int tests_passed = 0; +int tests_failed = 0; + +void test(const char* name, int passed) { + if (passed) { printf("[PASS] %s\n", name); tests_passed++; } + else { printf("[FAIL] %s\n", 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("=== Stress Testing libvec (doubling) ===\n\n"); + + struct timespec start, end_t; + Vec8_t vec; + + printf("--- Basic correctness ---\n"); + vec = create(nullptr); + test("create nullptr: capacity = 4", vec.capacity == 4); + test("create nullptr: size = 0", vec.size == 0); + + vec = add_back(&vec, 'a'); + test("add_back 1: size = 1", vec.size == 1); + test("add_back 1: capacity = 4", vec.capacity == 4); + + vec = add_back(&vec, 'b'); + test("add_back 2: size = 2", vec.size == 2); + + vec = add_back(&vec, 'c'); + test("add_back 3: size = 3", vec.size == 3); + + vec = add_back(&vec, 'd'); + test("add_back 4: size = 4", vec.size == 4); + + vec = add_back(&vec, 'e'); + test("add_back 5: capacity = 8 (doubled)", vec.capacity == 8); + test("add_back 5: arr[4] = 'e'", vec.arr[4] == 'e'); + delete(&vec); + + printf("\n--- NULL safety ---\n"); + test("at(nullptr) returns -2", at(nullptr, 0) == -2); + test("front(nullptr) returns -2", front(nullptr) == -2); + test("back(nullptr) returns -1", back(nullptr) == -1); + test("begin(nullptr) == -1", begin(nullptr) == -1); + test("end(nullptr) == -1", end(nullptr) == -1); + + printf("\n--- Capacity growth pattern ---\n"); + vec = create(nullptr); + size_t prev_cap = vec.capacity; + printf(" cap=%zu", vec.capacity); + for (int i = 1; i <= 100; i++) { + vec = add_back(&vec, (char)i); + if (vec.capacity != prev_cap) { + printf(" -> %zu (at size %d)", vec.capacity, i); + prev_cap = vec.capacity; + } + } + printf("\n"); + test("final capacity = 128", vec.capacity == 128); + delete(&vec); + + printf("\n--- 1M add_back ---\n"); + vec = create(nullptr); + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < 1000000; i++) vec = add_back(&vec, (char)i); + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t1 = time_diff(start, end_t); + printf(" Time: %.3f sec (%.0f/sec)\n", t1, 1000000.0/t1); + test("1M: size correct", vec.size == 1000000); + test("1M: data correct", vec.arr[0] == 0 && vec.arr[999999] == (char)999999); + delete(&vec); + + printf("\n--- 10M add_back ---\n"); + vec = create(nullptr); + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < 10000000; i++) vec = add_back(&vec, (char)i); + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t10 = time_diff(start, end_t); + printf(" Time: %.3f sec (%.0f/sec)\n", t10, 10000000.0/t10); + test("10M: size correct", vec.size == 10000000); + test("10M: data correct", vec.arr[0] == 0 && vec.arr[9999999] == (char)(9999999 % 256)); + delete(&vec); + + printf("\n--- 100M add_back ---\n"); + vec = create(nullptr); + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < 100000000; i++) vec = add_back(&vec, (char)i); + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t100 = time_diff(start, end_t); + printf(" Time: %.3f sec (%.0f/sec)\n", t100, 100000000.0/t100); + test("100M: size correct", vec.size == 100000000); + test("100M: data correct", vec.arr[0] == 0 && vec.arr[99999999] == (char)(99999999 % 256)); + delete(&vec); + + printf("\n--- 1B add_back ---\n"); + vec = create(nullptr); + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < 1000000000; i++) vec = add_back(&vec, (char)i); + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t1b = time_diff(start, end_t); + printf(" Time: %.3f sec (%.0f/sec)\n", t1b, 1000000000.0/t1b); + test("1B: size correct", vec.size == 1000000000); + test("1B: data correct", vec.arr[0] == 0 && vec.arr[999999999] == (char)(999999999 % 256)); + delete(&vec); + + printf("\n=== Summary ===\n"); + printf("Passed: %d, Failed: %d\n", tests_passed, tests_failed); + return tests_failed > 0 ? 1 : 0; +}