Compare commits
10 Commits
c4e7627d1f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
4238d73749
|
|||
|
a8cd5fb7a8
|
|||
|
09e1a360fd
|
|||
| 60f9f88af2 | |||
|
e5e4d75e2c
|
|||
|
10251039d5
|
|||
| 8c6e7e035b | |||
|
e48aecf36a
|
|||
| 2061eeaf4f | |||
|
ff26be2e75
|
@@ -6,7 +6,7 @@ UseTab: Never
|
||||
|
||||
ColumnLimit: 100
|
||||
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeBraces: Attach
|
||||
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
@@ -19,4 +19,4 @@ SortIncludes: true
|
||||
|
||||
IndentCaseLabels: true
|
||||
|
||||
AlignEscapedNewlines: Left
|
||||
AlignEscapedNewlines: Right
|
||||
|
||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -16,9 +16,7 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache and install APT packages
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1
|
||||
with:
|
||||
packages: cmake build-essential
|
||||
run: sudo apt update && sudo apt install -y cmake build-essential
|
||||
|
||||
- name: Configure project
|
||||
run: make configure
|
||||
@@ -34,8 +32,4 @@ jobs:
|
||||
|
||||
- name: Verify installation
|
||||
run: |
|
||||
ls -la ${{ runner.temp }}/install/lib/
|
||||
ls -la ${{ runner.temp }}/install/include/
|
||||
|
||||
|
||||
|
||||
|
||||
116
README.md
116
README.md
@@ -9,21 +9,22 @@ A simple, educational C implementation of a dynamic array (vector-like) data str
|
||||
This library provides a basic dynamic array implementation in C, similar to C++'s `std::vector` or Python's lists. It demonstrates fundamental concepts in systems programming:
|
||||
|
||||
- **Memory management** — allocation, reallocation, deallocation
|
||||
- **Generic programming** — using `void*` pointers
|
||||
- **Type-safe macros** — for type casting and operations
|
||||
- **Generic programming** — type-agnostic macros that work with any pointer type
|
||||
- **Unit testing** — with the Unity C testing framework
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- **Dynamic resizing** — Automatically grows as elements are added
|
||||
- **Type-safe operations** — Macros for working with typed elements
|
||||
- **Simple API** — Easy-to-use functions for common operations
|
||||
- **Header-only** — just include `dynamic_array.h`, no compilation step needed
|
||||
- **Dynamic resizing** — automatically grows as elements are added
|
||||
- **Type-safe** — macros operate on typed pointers; direct indexing is fully typed
|
||||
- **Simple API** — a small set of macros for common operations
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
test-meson/
|
||||
dynamic_array/
|
||||
├── src/
|
||||
│ ├── dynamic_array.c # Implementation
|
||||
│ ├── dynamic_array.h # Public API header
|
||||
│ ├── dynamic_array.h # Header-only implementation (public API)
|
||||
│ ├── test_dynamic_array.c # Unit tests
|
||||
│ └── CMakeLists.txt # Build configuration
|
||||
├── submodules/
|
||||
@@ -33,6 +34,7 @@ test-meson/
|
||||
├── Makefile # Build automation
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## 🔧 Prerequisites
|
||||
|
||||
**Linux-only project**
|
||||
@@ -41,6 +43,7 @@ test-meson/
|
||||
- **C compiler** (GCC recommended, Clang supported)
|
||||
- **Make** (optional, but recommended)
|
||||
- **build-essential** (on Ubuntu/Debian): `sudo apt-get install build-essential`
|
||||
|
||||
## 🔨 Building
|
||||
|
||||
### Using the Makefile (Recommended)
|
||||
@@ -63,6 +66,7 @@ ctest --output-on-failure
|
||||
cmake --install .
|
||||
cd .. && rm -rf build
|
||||
```
|
||||
|
||||
## 💡 Usage
|
||||
|
||||
### Including the Library
|
||||
@@ -70,72 +74,70 @@ cd .. && rm -rf build
|
||||
```c
|
||||
#include "dynamic_array.h"
|
||||
|
||||
// Create an array of integers
|
||||
ArrayCreateOptions opts = {
|
||||
.initial_size = 10,
|
||||
.element_size = sizeof(int)
|
||||
};
|
||||
Array *my_array = array_create(&opts);
|
||||
// Create a typed array (works with any pointer type)
|
||||
int *arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
// Add elements
|
||||
int value = 42;
|
||||
array_set_value(my_array, 0, &value);
|
||||
array_push_value(arr, 10);
|
||||
array_push_value(arr, 20);
|
||||
array_push_value(arr, 30);
|
||||
|
||||
// Retrieve elements
|
||||
int *retrieved = (int*)array_get_value(my_array, 0);
|
||||
// Access elements directly via indexing
|
||||
int first = arr[0]; // 10
|
||||
|
||||
// Using type-safe macros
|
||||
int result = array_set_value_as(int, my_array, 1, 100);
|
||||
// Remove the last element
|
||||
array_pop(arr);
|
||||
|
||||
// Get size and capacity
|
||||
size_t size = array_get_size(my_array);
|
||||
size_t capacity = array_get_capacity(my_array);
|
||||
// Inspect size and capacity via the header
|
||||
const ArrayHeader *header = array_get_header(arr);
|
||||
size_t size = header->size; // current number of elements
|
||||
size_t capacity = header->capacity; // allocated capacity
|
||||
|
||||
// Cleanup
|
||||
array_deconstructor(&my_array);
|
||||
array_destroy(arr); // frees memory and sets arr to NULL
|
||||
```
|
||||
|
||||
## 📖 API Reference
|
||||
|
||||
### Structures
|
||||
|
||||
#### `Array`
|
||||
#### `ArrayHeader`
|
||||
|
||||
Stored immediately before the array data in memory. Retrieve it with `array_get_header`.
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
void *value; // Pointer to element data
|
||||
size_t element_size; // Size of each element
|
||||
size_t size; // Current number of elements
|
||||
size_t capacity; // Allocated capacity
|
||||
} Array;
|
||||
size_t size; // Current number of elements
|
||||
size_t capacity; // Allocated capacity
|
||||
} ArrayHeader;
|
||||
```
|
||||
|
||||
#### `ArrayCreateOptions`
|
||||
Memory layout:
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
int initial_size; // Initial capacity
|
||||
size_t element_size; // Size of each element type
|
||||
} ArrayCreateOptions;
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `Array *array_create(const ArrayCreateOptions *options)` | Creates a new dynamic array |
|
||||
| `void array_deconstructor(Array **pp_array)` | Frees allocated memory and sets pointer to NULL |
|
||||
| `void array_resize(Array *p_array, size_t new_size)` | Resizes the array's capacity |
|
||||
| `void *array_get_value(const Array *p_array, size_t index)` | Retrieves a pointer to the element at index |
|
||||
| `void array_set_value(Array *p_array, size_t index, const void *value)` | Sets the element at index |
|
||||
| `size_t array_get_size(const Array *p_array)` | Returns the current number of elements |
|
||||
| `size_t array_get_capacity(const Array *p_array)` | Returns the allocated capacity |
|
||||
[ ArrayHeader | elem 0 | elem 1 | ... ]
|
||||
↑
|
||||
pointer returned by array_create (and all macros)
|
||||
```
|
||||
|
||||
### Macros
|
||||
|
||||
| Macro | Description |
|
||||
|-------|-------------|
|
||||
| `array_get_value_as(type, arr, idx)` | Type-safe retrieval of elements |
|
||||
| `array_set_value_as(type, arr, idx, value)` | Type-safe setting of elements (with type checking) |
|
||||
| `array_create(arr)` | Allocates a new array; sets `arr` to point to the first element |
|
||||
| `array_destroy(arr)` | Frees the array and sets `arr` to `NULL` |
|
||||
| `array_get_header(arr)` | Returns a pointer to the `ArrayHeader` for `arr` |
|
||||
| `array_push_value(arr, value)` | Appends `value`; grows the array automatically if needed |
|
||||
| `array_pop(arr)` | Removes the last element by decrementing `size` |
|
||||
|
||||
### Constants
|
||||
|
||||
| Constant | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE` | `10` | Initial capacity allocated by `array_create` |
|
||||
| `DYNAMIC_ARRAY_CAPACITY_FACTOR` | `2` | Growth multiplier applied on resize |
|
||||
|
||||
## ✅ Testing
|
||||
|
||||
Tests are written using the [Unity](http://www.throwtheswitch.org/unity) C testing framework.
|
||||
@@ -149,6 +151,7 @@ Or directly with ctest:
|
||||
```bash
|
||||
cd build && ctest --output-on-failure
|
||||
```
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
### Default Installation
|
||||
@@ -158,7 +161,6 @@ make install
|
||||
```
|
||||
|
||||
This installs to `~/.local/bin/dynamic_array/`:
|
||||
- **Library:** `lib/libdynamic_array.a`
|
||||
- **Header:** `include/dynamic_array.h`
|
||||
|
||||
### Custom Installation Directory
|
||||
@@ -173,20 +175,26 @@ Or set it as an environment variable:
|
||||
export INSTALL_PREFIX=$HOME/.local
|
||||
make install
|
||||
```
|
||||
|
||||
## ⚠️ Known Issues & Limitations
|
||||
|
||||
- ⚠️ No bounds checking in release builds
|
||||
- ⚠️ No bounds checking
|
||||
- ⚠️ `array_pop` does not return the removed element (use `arr[header->size - 1]` before popping)
|
||||
- ⚠️ Simple reallocation strategy (not optimized for performance)
|
||||
- ⚠️ Not thread-safe
|
||||
- ⚠️ Limited error handling
|
||||
- ⚠️ `realloc` failure is not propagated to the caller
|
||||
- ⚠️ Educational purpose only — use established libraries for production
|
||||
|
||||
## 🚀 Future Improvements
|
||||
|
||||
- [ ] Return value from `array_pop`
|
||||
- [ ] Propagate allocation failures
|
||||
- [ ] Add more comprehensive error handling
|
||||
- [ ] Implement shrinking functionality
|
||||
- [ ] Implement shrinking / `array_reserve`
|
||||
- [ ] Add iterator support
|
||||
- [ ] Optimize memory allocation strategy
|
||||
- [ ] Add more test coverage
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is for educational purposes.
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
# Library Configuration
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
# Library Configuration
|
||||
add_library(dynamic_array INTERFACE)
|
||||
target_include_directories(dynamic_array INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
target_include_directories(dynamic_array INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set_target_properties(dynamic_array PROPERTIES PUBLIC_HEADER dynamic_array.h)
|
||||
|
||||
|
||||
# Install the library to a specific directory (e.g., 'lib') relative to the install prefix
|
||||
install(TARGETS dynamic_array
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # Installs shared libs to <prefix>/lib
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # Installs static libs to <prefix>/lib
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # Installs associated executables to <prefix>/bin
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # Installs headers to <prefix>/include
|
||||
)
|
||||
|
||||
|
||||
# Install the exported target and public header
|
||||
install(TARGETS dynamic_array)
|
||||
install(FILES dynamic_array.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
|
||||
# Testing
|
||||
|
||||
add_executable(test_dynamic_array test_dynamic_array.c)
|
||||
target_link_libraries(test_dynamic_array PRIVATE dynamic_array unity::framework)
|
||||
|
||||
|
||||
add_test(NAME test_dynamic_array COMMAND test_dynamic_array)
|
||||
@@ -1,10 +1,12 @@
|
||||
#ifndef DYNAMIC_ARRAY_H
|
||||
#define DYNAMIC_ARRAY_H
|
||||
|
||||
#define DYNAMIC_ARRAY_VERSION_MAJOR 0
|
||||
#define DYNAMIC_ARRAY_VERSION_MINOR 1
|
||||
#define DYNAMIC_ARRAY_VERSION_BUILD 0
|
||||
#define DYNAMIC_ARRAY_VERSION ((DYNAMIC_ARRAY_VERSION_MAJOR << 16) | (DYNAMIC_ARRAY_VERSION_MINOR << 8) | DYNAMIC_ARRAY_VERSION_BUILD)
|
||||
#define DYNAMIC_ARRAY_VERSION_MAJOR 0
|
||||
#define DYNAMIC_ARRAY_VERSION_MINOR 1
|
||||
#define DYNAMIC_ARRAY_VERSION_BUILD 0
|
||||
#define DYNAMIC_ARRAY_VERSION \
|
||||
((DYNAMIC_ARRAY_VERSION_MAJOR << 16) | (DYNAMIC_ARRAY_VERSION_MINOR << 8) | \
|
||||
DYNAMIC_ARRAY_VERSION_BUILD)
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
@@ -12,8 +14,6 @@
|
||||
#define DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE 10
|
||||
#define DYNAMIC_ARRAY_CAPACITY_FACTOR 2
|
||||
|
||||
|
||||
|
||||
// [ HEADER | ARRAY ELEMENTS ]
|
||||
// ↑
|
||||
// THIS IS THE POINTER RETURNED BY ALL MACROS
|
||||
@@ -22,49 +22,65 @@ typedef struct {
|
||||
size_t capacity;
|
||||
} ArrayHeader;
|
||||
|
||||
|
||||
#define array_create(arr) \
|
||||
do { \
|
||||
ArrayHeader *header = malloc(sizeof(*arr) * DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE + sizeof(ArrayHeader)); \
|
||||
header->size = 0; \
|
||||
header->capacity = DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE; \
|
||||
\
|
||||
arr = (void *)(header + 1); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define array_get_header(arr) ((ArrayHeader*)(arr) - 1)
|
||||
|
||||
|
||||
#define array_destroy(arr) \
|
||||
do { \
|
||||
free(array_get_header(arr)); \
|
||||
arr = NULL; \
|
||||
#define array_create(arr) \
|
||||
do { \
|
||||
ArrayHeader* header = \
|
||||
malloc(sizeof(*(arr)) * DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE + sizeof(ArrayHeader)); \
|
||||
if (header == NULL) { \
|
||||
abort(); \
|
||||
} \
|
||||
header->size = 0; \
|
||||
header->capacity = DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE; \
|
||||
\
|
||||
(arr) = (void*)(header + 1); \
|
||||
} while (0)
|
||||
|
||||
#define array_get_header(arr) ((arr) ? ((ArrayHeader*)(arr) - 1) : NULL)
|
||||
|
||||
#define array_push_value(arr, value) \
|
||||
do { \
|
||||
ArrayHeader *header = array_get_header(arr); \
|
||||
if (header->size + 1 > header->capacity) { \
|
||||
size_t new_capacity = header->capacity * DYNAMIC_ARRAY_CAPACITY_FACTOR; \
|
||||
ArrayHeader *new_header = realloc(header, sizeof(*arr) * new_capacity + sizeof(ArrayHeader)); \
|
||||
if (new_header != NULL) { \
|
||||
header = new_header; \
|
||||
} \
|
||||
header->capacity = new_capacity; \
|
||||
arr = (void *)(header + 1); \
|
||||
} \
|
||||
arr[header->size] = value; \
|
||||
header->size++; \
|
||||
#define array_destroy(arr) \
|
||||
do { \
|
||||
if ((arr) == NULL) { \
|
||||
break; \
|
||||
} \
|
||||
free(array_get_header(arr)); \
|
||||
(arr) = NULL; \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define array_pop(arr) \
|
||||
do { \
|
||||
ArrayHeader *header = array_get_header(arr); \
|
||||
header->size--; \
|
||||
#define array_push_value(arr, value) \
|
||||
do { \
|
||||
if ((arr) == NULL) { \
|
||||
array_create(arr); \
|
||||
} \
|
||||
ArrayHeader* header = array_get_header(arr); \
|
||||
if (header->size >= header->capacity) { \
|
||||
size_t new_capacity = header->capacity * DYNAMIC_ARRAY_CAPACITY_FACTOR; \
|
||||
ArrayHeader* new_header = \
|
||||
realloc(header, sizeof(*(arr)) * new_capacity + sizeof(ArrayHeader)); \
|
||||
if (new_header == NULL) { \
|
||||
abort(); \
|
||||
} \
|
||||
header = new_header; \
|
||||
header->capacity = new_capacity; \
|
||||
(arr) = (void*)(header + 1); \
|
||||
} \
|
||||
(arr)[header->size] = (value); \
|
||||
header->size++; \
|
||||
} while (0)
|
||||
|
||||
#define array_pop(arr) \
|
||||
do { \
|
||||
if ((arr) == NULL) { \
|
||||
break; \
|
||||
} \
|
||||
ArrayHeader* header = array_get_header(arr); \
|
||||
if (header->size == 0) { \
|
||||
break; \
|
||||
} \
|
||||
header->size--; \
|
||||
} while (0)
|
||||
|
||||
#define array_size(arr) ((arr) ? array_get_header(arr)->size : 0)
|
||||
|
||||
#define array_capacity(arr) ((arr) ? array_get_header(arr)->capacity : 0)
|
||||
|
||||
#endif
|
||||
@@ -2,33 +2,31 @@
|
||||
|
||||
#include "dynamic_array.h"
|
||||
|
||||
void setUp(void) {
|
||||
}
|
||||
|
||||
void setUp(void) {}
|
||||
|
||||
void tearDown(void) {}
|
||||
|
||||
void tearDown(void) {
|
||||
}
|
||||
|
||||
void test_array_create_without_options(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
const ArrayHeader *header = array_get_header(arr);
|
||||
const ArrayHeader* header = array_get_header(arr);
|
||||
TEST_ASSERT_EQUAL(DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE, header->capacity);
|
||||
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
|
||||
void test_array_destroy(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
array_destroy(arr);
|
||||
TEST_ASSERT_NULL(arr);
|
||||
}
|
||||
|
||||
|
||||
void test_array_size_initial(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, array_get_header(arr)->size);
|
||||
@@ -36,9 +34,8 @@ void test_array_size_initial(void) {
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
|
||||
void test_array_push_value(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
array_push_value(arr, 42);
|
||||
@@ -49,9 +46,8 @@ void test_array_push_value(void) {
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
|
||||
void test_array_push_multiple_values(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
array_push_value(arr, 10);
|
||||
@@ -66,9 +62,8 @@ void test_array_push_multiple_values(void) {
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
|
||||
void test_array_pop_decrements_size(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
array_push_value(arr, 42);
|
||||
@@ -80,9 +75,25 @@ void test_array_pop_decrements_size(void) {
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
void test_array_pop_on_empty_is_noop(void) {
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
array_push_value(arr, 99);
|
||||
TEST_ASSERT_EQUAL(1, array_get_header(arr)->size);
|
||||
TEST_ASSERT_EQUAL(99, arr[0]);
|
||||
|
||||
array_pop(arr);
|
||||
TEST_ASSERT_EQUAL(0, array_get_header(arr)->size);
|
||||
|
||||
array_pop(arr); // should not underflow
|
||||
TEST_ASSERT_EQUAL(0, array_get_header(arr)->size);
|
||||
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
void test_array_get_capacity_default(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
TEST_ASSERT_EQUAL(DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE, array_get_header(arr)->capacity);
|
||||
@@ -90,25 +101,23 @@ void test_array_get_capacity_default(void) {
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
|
||||
void test_array_size_capacity_relationship(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
array_push_value(arr, 1);
|
||||
array_push_value(arr, 2);
|
||||
array_push_value(arr, 3);
|
||||
|
||||
const ArrayHeader *header = array_get_header(arr);
|
||||
const ArrayHeader* header = array_get_header(arr);
|
||||
TEST_ASSERT_EQUAL(3, header->size);
|
||||
TEST_ASSERT_LESS_OR_EQUAL(header->capacity, header->size);
|
||||
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
|
||||
void test_array_push_beyond_capacity(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
const int num_elements = DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE * 2;
|
||||
@@ -116,16 +125,15 @@ void test_array_push_beyond_capacity(void) {
|
||||
array_push_value(arr, i);
|
||||
}
|
||||
|
||||
const ArrayHeader *header = array_get_header(arr);
|
||||
const ArrayHeader* header = array_get_header(arr);
|
||||
TEST_ASSERT_EQUAL(num_elements, header->size);
|
||||
TEST_ASSERT_GREATER_THAN(DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE, header->capacity);
|
||||
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
|
||||
void test_array_values_correct_after_growth(void) {
|
||||
int *arr = NULL;
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
const int num_elements = 1000;
|
||||
@@ -141,9 +149,84 @@ void test_array_values_correct_after_growth(void) {
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
void test_array_looping(void) {
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const int num_elements = DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE * 2;
|
||||
for (int i = 0; i < num_elements; i++) {
|
||||
array_push_value(arr, i);
|
||||
}
|
||||
|
||||
const ArrayHeader* header = array_get_header(arr);
|
||||
TEST_ASSERT_EQUAL(num_elements, header->size);
|
||||
|
||||
for (int i = 0; i < header->size; i++) {
|
||||
TEST_ASSERT_EQUAL(i, arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- array_get_header branch: NULL arr → returns NULL --- */
|
||||
void test_array_get_header_on_null_returns_null(void) {
|
||||
int* arr = NULL;
|
||||
TEST_ASSERT_NULL(array_get_header(arr));
|
||||
}
|
||||
|
||||
/* --- array_destroy branch: NULL arr → no-op, does not crash --- */
|
||||
void test_array_destroy_on_null_is_noop(void) {
|
||||
int* arr = NULL;
|
||||
array_destroy(arr);
|
||||
TEST_ASSERT_NULL(arr);
|
||||
}
|
||||
|
||||
/* --- array_push_value branch: NULL arr → auto-creates the array --- */
|
||||
void test_array_push_value_on_null_auto_creates(void) {
|
||||
int* arr = NULL;
|
||||
array_push_value(arr, 7);
|
||||
TEST_ASSERT_NOT_NULL(arr);
|
||||
TEST_ASSERT_EQUAL(7, arr[0]);
|
||||
TEST_ASSERT_EQUAL(1, array_get_header(arr)->size);
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
/* --- array_pop branch: NULL arr → no-op, does not crash --- */
|
||||
void test_array_pop_on_null_is_noop(void) {
|
||||
int* arr = NULL;
|
||||
array_pop(arr);
|
||||
TEST_ASSERT_NULL(arr);
|
||||
}
|
||||
|
||||
/* --- array_size branch: NULL arr → 0 --- */
|
||||
void test_array_size_on_null_returns_zero(void) {
|
||||
int* arr = NULL;
|
||||
TEST_ASSERT_EQUAL(0, array_size(arr));
|
||||
}
|
||||
|
||||
/* --- array_size branch: non-NULL arr → current size --- */
|
||||
void test_array_size_returns_current_size(void) {
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
array_push_value(arr, 1);
|
||||
array_push_value(arr, 2);
|
||||
TEST_ASSERT_EQUAL(2, array_size(arr));
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
/* --- array_capacity branch: NULL arr → 0 --- */
|
||||
void test_array_capacity_on_null_returns_zero(void) {
|
||||
int* arr = NULL;
|
||||
TEST_ASSERT_EQUAL(0, array_capacity(arr));
|
||||
}
|
||||
|
||||
/* --- array_capacity branch: non-NULL arr → current capacity --- */
|
||||
void test_array_capacity_returns_current_capacity(void) {
|
||||
int* arr = NULL;
|
||||
array_create(arr);
|
||||
TEST_ASSERT_EQUAL(DYNAMIC_ARRAY_DEFAULT_ARRAY_SIZE, array_capacity(arr));
|
||||
array_destroy(arr);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_array_create_without_options);
|
||||
@@ -152,10 +235,21 @@ int main(void)
|
||||
RUN_TEST(test_array_push_value);
|
||||
RUN_TEST(test_array_push_multiple_values);
|
||||
RUN_TEST(test_array_pop_decrements_size);
|
||||
RUN_TEST(test_array_pop_on_empty_is_noop);
|
||||
RUN_TEST(test_array_get_capacity_default);
|
||||
RUN_TEST(test_array_size_capacity_relationship);
|
||||
RUN_TEST(test_array_push_beyond_capacity);
|
||||
RUN_TEST(test_array_values_correct_after_growth);
|
||||
RUN_TEST(test_array_looping);
|
||||
|
||||
RUN_TEST(test_array_get_header_on_null_returns_null);
|
||||
RUN_TEST(test_array_destroy_on_null_is_noop);
|
||||
RUN_TEST(test_array_push_value_on_null_auto_creates);
|
||||
RUN_TEST(test_array_pop_on_null_is_noop);
|
||||
RUN_TEST(test_array_size_on_null_returns_zero);
|
||||
RUN_TEST(test_array_size_returns_current_size);
|
||||
RUN_TEST(test_array_capacity_on_null_returns_zero);
|
||||
RUN_TEST(test_array_capacity_returns_current_capacity);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
Reference in New Issue
Block a user