erase() should really now set proper values to 0 after move
This commit is contained in:
@@ -0,0 +1,418 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#define CAPACITY 1024
|
||||
#define nullptr ((void*)0)
|
||||
|
||||
typedef struct {
|
||||
char* arr;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
} Vec8_t;
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
// Exact copy of src/main.c single erase (lines 128-137)
|
||||
__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;
|
||||
memmove(&vec->arr[iter], &vec->arr[iter + 1], (vec->size - iter - 1) * sizeof(char));
|
||||
vec->arr[vec->size - 1] = 0;
|
||||
vec->size--;
|
||||
return vec;
|
||||
}
|
||||
|
||||
// Exact copy of src/main.c range erase (lines 139-152)
|
||||
__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;
|
||||
if(iter_start >= iter_end) return nullptr;
|
||||
size_t diff = iter_end - iter_start;
|
||||
memmove(&vec->arr[iter_start], &vec->arr[iter_end], (vec->size - iter_end) * sizeof(char));
|
||||
for(size_t i = vec->size - 1; i > iter_end; i--) {
|
||||
vec->arr[i] = 0;
|
||||
}
|
||||
vec->size -= diff;
|
||||
return vec;
|
||||
}
|
||||
|
||||
void print_vec(const Vec8_t* vec) {
|
||||
for (int i = 0; i < vec->size; i++) printf("%c ", vec->arr[i]);
|
||||
printf("(size=%zu)\n", vec->size);
|
||||
}
|
||||
|
||||
// Test 1: Basic single erase
|
||||
void test_single_erase_basic() {
|
||||
printf("Test: Single erase basic\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i);
|
||||
|
||||
erase(&vec, 2); // Erase 'c'
|
||||
|
||||
assert(vec.size == 9);
|
||||
assert(vec.arr[0] == 'a');
|
||||
assert(vec.arr[1] == 'b');
|
||||
assert(vec.arr[2] == 'd'); // Shifted correctly
|
||||
assert(vec.arr[8] == 'j'); // Last element correct
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 2: Single erase at boundaries
|
||||
void test_single_erase_boundaries() {
|
||||
printf("Test: Single erase at boundaries\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 5; i++) add_back(&vec, 'a' + i);
|
||||
|
||||
// Erase first element
|
||||
erase(&vec, 0);
|
||||
assert(vec.size == 4);
|
||||
assert(vec.arr[0] == 'b');
|
||||
printf("Erase first: PASS\n");
|
||||
|
||||
// Reset
|
||||
delete(&vec);
|
||||
vec = create(nullptr);
|
||||
for (int i = 0; i < 5; i++) add_back(&vec, 'a' + i);
|
||||
|
||||
// Erase last element
|
||||
erase(&vec, 4);
|
||||
assert(vec.size == 4);
|
||||
assert(vec.arr[3] == 'd');
|
||||
printf("Erase last: PASS\n");
|
||||
|
||||
delete(&vec);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Test 3: Single erase invalid inputs
|
||||
void test_single_erase_invalid() {
|
||||
printf("Test: Single erase invalid inputs\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 5; i++) add_back(&vec, 'a' + i);
|
||||
|
||||
// Erase with negative index
|
||||
assert(erase(&vec, -1) == nullptr);
|
||||
|
||||
// Erase with out-of-bounds index
|
||||
assert(erase(&vec, 10) == nullptr);
|
||||
assert(erase(&vec, 5) == nullptr);
|
||||
|
||||
// Erase on null vector
|
||||
assert(erase(nullptr, 0) == nullptr);
|
||||
|
||||
// Erase on vector with null arr
|
||||
Vec8_t vec2 = { .arr = nullptr, .size = 0, .capacity = 0 };
|
||||
assert(erase(&vec2, 0) == nullptr);
|
||||
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 4: Range erase basic
|
||||
void test_range_erase_basic() {
|
||||
printf("Test: Range erase basic\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i);
|
||||
|
||||
erase(&vec, 2, 4); // Erase [2,4) -> 'c','d'
|
||||
|
||||
printf("After erase(2,4): ");
|
||||
print_vec(&vec);
|
||||
|
||||
assert(vec.size == 8);
|
||||
assert(vec.arr[0] == 'a');
|
||||
assert(vec.arr[1] == 'b');
|
||||
assert(vec.arr[2] == 'e'); // Shifted correctly
|
||||
assert(vec.arr[7] == 'j'); // Last element correct
|
||||
|
||||
// Check that valid data is not zeroed incorrectly
|
||||
for (int i = 0; i < vec.size; i++) {
|
||||
assert(vec.arr[i] != 0); // Valid positions should not be zero
|
||||
}
|
||||
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 5: Range erase - verify zeroing works correctly now
|
||||
void test_range_erase_zeroing_fixed() {
|
||||
printf("Test: Range erase zeroing verification\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i);
|
||||
|
||||
erase(&vec, 2, 4);
|
||||
|
||||
printf("After erase(2,4): ");
|
||||
print_vec(&vec);
|
||||
|
||||
// Verify valid data is not zeroed
|
||||
for (int i = 0; i < vec.size; i++) {
|
||||
assert(vec.arr[i] != 0); // Valid positions should not be zero
|
||||
}
|
||||
|
||||
// Verify that positions beyond new size are zeroed
|
||||
// (The zeroing loop should zero from vec.size-1 down to iter_end)
|
||||
printf("Zeroing verification: ");
|
||||
int all_valid = 1;
|
||||
for (int i = 0; i < vec.size; i++) {
|
||||
if (vec.arr[i] == 0) {
|
||||
printf("BUG: arr[%d] is zero but should be valid! ", i);
|
||||
all_valid = 0;
|
||||
}
|
||||
}
|
||||
if (all_valid) printf("PASS");
|
||||
|
||||
printf("\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 6: Range erase to end
|
||||
void test_range_erase_to_end() {
|
||||
printf("Test: Range erase to end\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i);
|
||||
|
||||
Vec8_t* res = erase(&vec, 2, 10); // Erase [2,10)
|
||||
assert(res != nullptr);
|
||||
assert(vec.size == 2);
|
||||
assert(vec.arr[0] == 'a');
|
||||
assert(vec.arr[1] == 'b');
|
||||
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 7: Range erase invalid inputs
|
||||
void test_range_erase_invalid() {
|
||||
printf("Test: Range erase invalid inputs\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 5; i++) add_back(&vec, 'a' + i);
|
||||
|
||||
// Invalid start
|
||||
assert(erase(&vec, -1, 3) == nullptr);
|
||||
|
||||
// Invalid end (>= size now, not just >)
|
||||
assert(erase(&vec, 0, 5) == nullptr); // 5 >= size (5)
|
||||
|
||||
// Start >= end now returns nullptr
|
||||
assert(erase(&vec, 3, 2) == nullptr); // start >= end
|
||||
assert(erase(&vec, 2, 2) == nullptr); // start == end
|
||||
|
||||
// Null vector
|
||||
assert(erase(nullptr, 0, 1) == nullptr);
|
||||
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 8: Large vector single erase
|
||||
void test_large_single_erase() {
|
||||
printf("Test: Large vector single erase (100k elements)\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 100000; i++) add_back(&vec, (char)(i % 256));
|
||||
|
||||
erase(&vec, 0); // Erase front
|
||||
assert(vec.size == 99999);
|
||||
assert(vec.arr[0] == 1);
|
||||
|
||||
erase(&vec, 50000); // Erase middle
|
||||
assert(vec.size == 99998);
|
||||
assert(vec.arr[50000] == 2); // After erasing index 1 (value 1), index 50000 is now value 2
|
||||
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 9: Large vector range erase
|
||||
void test_large_range_erase() {
|
||||
printf("Test: Large vector range erase (100k elements, erase 10k)\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 100000; i++) add_back(&vec, (char)(i % 256));
|
||||
|
||||
erase(&vec, 10000, 20000); // Erase 10k elements
|
||||
assert(vec.size == 90000);
|
||||
assert(vec.arr[10000] == (char)(20000 % 256)); // First element after erased range
|
||||
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 10: Repeated single erasures
|
||||
void test_repeated_single_erase() {
|
||||
printf("Test: Repeated single erasures until empty\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 100; i++) add_back(&vec, 'a' + (i % 26));
|
||||
|
||||
size_t initial_size = vec.size;
|
||||
for (int i = 0; i < initial_size; i++) {
|
||||
erase(&vec, 0); // Always erase first element
|
||||
}
|
||||
|
||||
assert(vec.size == 0);
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 11: Stress - random erasures
|
||||
void test_random_erasures() {
|
||||
printf("Test: Random erasures (1000 rounds)\n");
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
for (int round = 0; round < 1000; round++) {
|
||||
Vec8_t vec = create(nullptr);
|
||||
int num_elements = rand() % 1000 + 10;
|
||||
for (int i = 0; i < num_elements; i++) add_back(&vec, (char)(rand() % 256));
|
||||
|
||||
int num_erasures = rand() % 50;
|
||||
for (int j = 0; j < num_erasures && vec.size > 0; j++) {
|
||||
int idx = rand() % vec.size;
|
||||
erase(&vec, idx);
|
||||
}
|
||||
|
||||
// Verify integrity
|
||||
for (int i = 0; i < vec.size; i++) {
|
||||
// Just check that we can access without crashing
|
||||
char val = vec.arr[i];
|
||||
(void)val;
|
||||
}
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
printf("PASS\n\n");
|
||||
}
|
||||
|
||||
// Test 12: Stress - random range erasures
|
||||
void test_random_range_erasures() {
|
||||
printf("Test: Random range erasures (1000 rounds)\n");
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
for (int round = 0; round < 1000; round++) {
|
||||
Vec8_t vec = create(nullptr);
|
||||
int num_elements = rand() % 1000 + 10;
|
||||
for (int i = 0; i < num_elements; i++) add_back(&vec, (char)(rand() % 256));
|
||||
|
||||
int num_erasures = rand() % 20;
|
||||
for (int j = 0; j < num_erasures && vec.size > 1; j++) {
|
||||
int start = rand() % (vec.size - 1);
|
||||
int end = start + rand() % (vec.size - start) + 1;
|
||||
if (end > vec.size) end = vec.size;
|
||||
erase(&vec, start, end);
|
||||
}
|
||||
|
||||
// Verify integrity
|
||||
for (int i = 0; i < vec.size; i++) {
|
||||
char val = vec.arr[i];
|
||||
(void)val;
|
||||
}
|
||||
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
printf("PASS\n\n");
|
||||
}
|
||||
|
||||
// Test 13: Erase all elements one by one
|
||||
void test_erase_all_single() {
|
||||
printf("Test: Erase all elements one by one\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 1000; i++) add_back(&vec, 'a' + (i % 26));
|
||||
|
||||
while (vec.size > 0) {
|
||||
erase(&vec, 0);
|
||||
}
|
||||
|
||||
assert(vec.size == 0);
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 14: Erase all elements with range erase
|
||||
void test_erase_all_range() {
|
||||
printf("Test: Erase all elements with range erase\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
for (int i = 0; i < 1000; i++) add_back(&vec, 'a' + (i % 26));
|
||||
|
||||
erase(&vec, 0, vec.size);
|
||||
|
||||
assert(vec.size == 0);
|
||||
printf("PASS\n\n");
|
||||
delete(&vec);
|
||||
}
|
||||
|
||||
// Test 15: Memory stress - large vector, erase in middle repeatedly
|
||||
void test_memory_stress() {
|
||||
printf("Test: Memory stress - large vector, repeated middle erasure\n");
|
||||
Vec8_t vec = create(nullptr);
|
||||
|
||||
// Add 1 million elements
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
add_back(&vec, (char)(i % 256));
|
||||
}
|
||||
|
||||
printf(" Created vector with %zu elements\n", vec.size);
|
||||
|
||||
// Erase from middle repeatedly
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
if (vec.size == 0) break;
|
||||
int idx = vec.size / 2;
|
||||
erase(&vec, idx);
|
||||
}
|
||||
|
||||
printf(" After 10k middle erasures, size = %zu\n", vec.size);
|
||||
|
||||
delete(&vec);
|
||||
printf("PASS\n\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("=== ERASE STRESS TEST SUITE ===\n\n");
|
||||
|
||||
test_single_erase_basic();
|
||||
test_single_erase_boundaries();
|
||||
test_single_erase_invalid();
|
||||
test_range_erase_basic();
|
||||
test_range_erase_zeroing_fixed();
|
||||
test_range_erase_to_end();
|
||||
test_range_erase_invalid();
|
||||
test_large_single_erase();
|
||||
test_large_range_erase();
|
||||
test_repeated_single_erase();
|
||||
test_random_erasures();
|
||||
test_random_range_erasures();
|
||||
test_erase_all_single();
|
||||
test_erase_all_range();
|
||||
test_memory_stress();
|
||||
|
||||
printf("=== ALL TESTS COMPLETED ===\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user