Safer push_back and faster push_back (I went from 0(n^2) to 0(1))
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user