157 lines
4.7 KiB
C
157 lines
4.7 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <stdio.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-151)
|
|
__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;
|
|
memmove(&vec->arr[iter_start], &vec->arr[iter_end], (vec->size - iter_end) * sizeof(char));
|
|
for(size_t i = vec->size; i > iter_end; i--) {
|
|
vec->arr[i] = 0; // BUG: i starts at vec->size (out of bounds!)
|
|
}
|
|
vec->size -= diff;
|
|
return vec;
|
|
}
|
|
|
|
void test_single_erase() {
|
|
printf("=== Testing Single Erase ===\n");
|
|
Vec8_t vec = create(nullptr);
|
|
for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i);
|
|
|
|
printf("Before: ");
|
|
for (int i = 0; i < vec.size; i++) printf("%c ", vec.arr[i]);
|
|
printf("(size=%zu)\n", vec.size);
|
|
|
|
erase(&vec, 2); // Erase 'c'
|
|
|
|
printf("After erase(2): ");
|
|
for (int i = 0; i < vec.size; i++) printf("%c ", vec.arr[i]);
|
|
printf("(size=%zu)\n", vec.size);
|
|
|
|
assert(vec.size == 9);
|
|
assert(vec.arr[0] == 'a');
|
|
assert(vec.arr[1] == 'b');
|
|
assert(vec.arr[2] == 'd'); // Shifted left correctly
|
|
printf("Single erase: PASS\n\n");
|
|
delete(&vec);
|
|
}
|
|
|
|
void test_single_erase_large() {
|
|
printf("=== Testing 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); // Shifted correctly
|
|
|
|
printf("Large single erase: PASS\n\n");
|
|
delete(&vec);
|
|
}
|
|
|
|
void test_range_erase() {
|
|
printf("=== Testing Range Erase (exclusive end) ===\n");
|
|
Vec8_t vec = create(nullptr);
|
|
for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i);
|
|
|
|
printf("Before: ");
|
|
for (int i = 0; i < vec.size; i++) printf("%c ", vec.arr[i]);
|
|
printf("(size=%zu)\n", vec.size);
|
|
|
|
erase(&vec, 2, 4); // Erase [2,4) -> indices 2,3 ('c','d')
|
|
|
|
printf("After erase(2,4): ");
|
|
for (int i = 0; i < vec.size; i++) printf("%c ", vec.arr[i]);
|
|
printf("(size=%zu)\n", vec.size);
|
|
|
|
// Expected: a b e f g h i j (size=8)
|
|
assert(vec.size == 8);
|
|
assert(vec.arr[0] == 'a');
|
|
assert(vec.arr[1] == 'b');
|
|
assert(vec.arr[2] == 'e'); // Shifted correctly
|
|
|
|
// Check zeroing bug (zeros wrong positions due to out-of-bounds access)
|
|
printf("Raw array: ");
|
|
for (int i = 0; i < 10; i++) printf("%c", vec.arr[i] == 0 ? '0' : vec.arr[i]);
|
|
printf("\n");
|
|
|
|
printf("Range erase: PASS (but zeroing loop has out-of-bounds bug)\n\n");
|
|
delete(&vec);
|
|
}
|
|
|
|
void test_range_erase_to_end() {
|
|
printf("=== Testing 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) -> indices 2-9
|
|
assert(res != nullptr);
|
|
assert(vec.size == 2);
|
|
assert(vec.arr[0] == 'a');
|
|
assert(vec.arr[1] == 'b');
|
|
printf("Erase to end: PASS\n\n");
|
|
delete(&vec);
|
|
}
|
|
|
|
int main() {
|
|
test_single_erase();
|
|
test_single_erase_large();
|
|
test_range_erase();
|
|
test_range_erase_to_end();
|
|
printf("All tests completed.\n");
|
|
return 0;
|
|
}
|