diff options
Diffstat (limited to 'lab04/vec.h')
| -rw-r--r-- | lab04/vec.h | 1183 |
1 files changed, 1183 insertions, 0 deletions
diff --git a/lab04/vec.h b/lab04/vec.h new file mode 100644 index 0000000..d62df76 --- /dev/null +++ b/lab04/vec.h @@ -0,0 +1,1183 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +/** + * @file vec.h + * @brief A dynamically sized contiguous sequence with byte-based storage. + * + * `struct vec` stores the element size rather than a type. The caller is + * responsible for using the type associated with the initialized element size. + */ +#ifndef VEC_H +#define VEC_H + +#include <stddef.h> +#include <stdbool.h> +#include <assert.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +/** + * @brief A dynamically sized contiguous sequence. + * + * `data` points to storage for at most `capacity` elements. The first + * `size` positions contain valid elements. + */ +typedef struct vec { + void *data; + size_t size; + size_t capacity; + size_t elem_size; +} vec; + +/** + * @brief Compares two elements. + * + * @return A value less than, equal to, or greater than zero when the left + * element is less than, equal to, or greater than the right element. + */ +typedef int (*vec_compare_fn)(const void *lhs, const void *rhs); + +/** @name Initialization */ +/** @{ */ + +/** + * @brief Produces an initializer for an empty vector of the given element type. + * @param type The element type. + */ +#define VEC_INIT(type) { \ + .data = NULL, \ + .size = 0, \ + .capacity = 0, \ + .elem_size = sizeof(type), \ +} + +/** + * @brief Declares and initializes a vector for the given element type. + * @param name The vector variable name. + * @param type The element type. + */ +#define VEC(name, type) \ + struct vec name = VEC_INIT(type) + +/** + * @brief Initializes an existing vector. + * @param v A pointer to the vector. + * @param type The element type. + */ +#define vec_init(v, type) \ + (*(v) = (struct vec)VEC_INIT(type)) + +/** @} */ + +/** @name Basic properties */ +/** @{ */ + +/** @brief Returns the number of valid elements in the vector. */ +static inline size_t vec_size(const struct vec *v) +{ + return v->size; +} + +/** @brief Returns the current storage capacity of the vector. */ +static inline size_t vec_capacity(const struct vec *v) +{ + return v->capacity; +} + +/** @brief Returns the size of one element in bytes. */ +static inline size_t vec_elem_size(const struct vec *v) +{ + return v->elem_size; +} + +/** + * @brief Returns the maximum number of elements representable at this element size. + */ +static inline size_t vec_max_size(const struct vec *v) +{ + return SIZE_MAX / v->elem_size; +} + +/** @brief Tests whether the vector is empty. */ +static inline int vec_empty(const struct vec *v) +{ + return v->size == 0; +} + +/** @} */ + +/** @name Lifetime and capacity */ +/** @{ */ + +/** + * @brief Removes all valid elements from the vector. + * + * The operation does not release the allocated capacity. + */ +static inline void vec_clear(struct vec *v) +{ + v->size = 0; +} + +/** + * @brief Destroys the vector and releases its storage. + */ +static inline void vec_destroy(struct vec *v) +{ + free(v->data); + + v->data = NULL; + v->size = 0; + v->capacity = 0; + v->elem_size = 0; +} + +/** + * @brief Ensures that the vector has at least the requested capacity. + * @param v A pointer to the vector. + * @param capacity The minimum requested number of elements. + * @return `true` on success; `false` on overflow or allocation failure. + */ +static inline bool vec_reserve(struct vec *v, size_t capacity) +{ + if (!v || v->elem_size == 0) { + return false; + } + // 当前容量已满足需求,直接返回成功 + if (capacity <= v->capacity) { + return true; + } + // 乘法溢出检查 (capacity * elem_size > SIZE_MAX) + if (capacity > SIZE_MAX / v->elem_size) { + return false; + } + + size_t new_bytes = capacity * v->elem_size; + void *new_data = realloc(v->data, new_bytes); + if (!new_data) { + return false; // 分配失败,原 v->data 依然有效 + } + + v->data = new_data; + v->capacity = capacity; + return true; +} + +/** + * @brief Changes the number of valid elements in the vector. + * + * Elements added by growing the vector are uninitialized. + * + * @param v A pointer to the vector. + * @param size The new number of elements. + * @return `true` on success; `false` on allocation failure. + */ +static inline bool vec_resize(struct vec *v, size_t size) +{ + if (!v) { + return false; + } + + if (size > v->capacity) { + if (!vec_reserve(v, size)) { + return false; + } + } + v->size = size; + return true; +} + +/** + * @brief Changes the vector size and clears newly added bytes. + * + * Clearing bytes does not guarantee a type-specific zero value; it only + * guarantees that the corresponding storage bytes are zero. + */ +static inline bool vec_resize_zero(struct vec *v, size_t size) +{ + if (!v) { + return false; + } + size_t old_size = v->size; + + if (size > old_size) { + if (size > v->capacity) { + if (!vec_reserve(v, size)) { + return false; + } + } + /* 这里使用 memset 清零字节,不保证所有元素类型都得到 + * 该类型语义上的零值。 */ + char *start = (char *)v->data + (old_size * v->elem_size); + size_t zero_bytes = (size - old_size) * v->elem_size; + memset(start, 0, zero_bytes); + } + + v->size = size; + return true; +} + +/** + * @brief Attempts to reduce the capacity to the current size. + * @return `true` on success; `false` if reallocation fails. + */ +static inline bool vec_shrink_to_fit(struct vec *v) +{ + if (!v || v->elem_size == 0) { + return false; + } + // 已经完全贴合,无需缩容 + if (v->capacity == v->size) { + return true; + } + + // 当 size == 0 时,彻底归还堆内存 + if (v->size == 0) { + free(v->data); + v->data = NULL; + v->capacity = 0; + return true; + } + + // 缩容至刚好容纳 size 个元素 + size_t bytes = v->size * v->elem_size; + void *new_data = realloc(v->data, bytes); + if (!new_data) { + return false; // 极少数情况下缩容可能失败,保持原样 + } + + v->data = new_data; + v->capacity = v->size; + return true; +} + +/** @} */ + +/** @name Raw element access */ +/** @{ */ + +/** @brief Returns a writable pointer to the vector storage. */ +static inline void *vec_data(struct vec *v) +{ + return v->data; +} + +/** @brief Returns a read-only pointer to the vector storage. */ +static inline const void *vec_data_const(const struct vec *v) +{ + return v->data; +} + +/** + * @brief Tests two vectors for equality using a comparison function. + */ +static inline bool vec_equal(const struct vec *a, + const struct vec *b, + vec_compare_fn compare) +{ + if (a->elem_size != b->elem_size || a->size != b->size) { + return false; + } + + for (size_t i = 0; i < a->size; ++i) { + const void *lhs = (const unsigned char *)a->data + + i * a->elem_size; + const void *rhs = (const unsigned char *)b->data + + i * b->elem_size; + if (compare(lhs, rhs) != 0) { + return false; + } + } + return true; +} + +/** + * @brief Compares two vectors lexicographically. + * @return -1, 0, or 1 when the left vector is less than, equal to, or + * greater than the right vector. + */ +static inline int vec_compare(const struct vec *a, + const struct vec *b, + vec_compare_fn compare) +{ + size_t common_size = a->size < b->size ? a->size : b->size; + + for (size_t i = 0; i < common_size; ++i) { + const void *lhs = (const unsigned char *)a->data + + i * a->elem_size; + const void *rhs = (const unsigned char *)b->data + + i * b->elem_size; + int result = compare(lhs, rhs); + if (result < 0) { + return -1; + } + if (result > 0) { + return 1; + } + } + + if (a->size < b->size) { + return -1; + } + if (a->size > b->size) { + return 1; + } + return 0; +} + +/** + * @brief Returns a writable pointer to the element at `index`. + * @pre `index < v->size`. + */ +static inline void *vec_at(struct vec *v, size_t index) +{ + assert(index < v->size); + + return (unsigned char *)v->data + + index * v->elem_size; +} + +/** + * @brief Returns a read-only pointer to the element at `index`. + * @pre `index < v->size`. + */ +static inline const void *vec_at_const(const struct vec *v, + size_t index) +{ + assert(index < v->size); + + return (const unsigned char *)v->data + + index * v->elem_size; +} + +/** + * @brief Returns a writable pointer to the element at `index`, or `NULL` + * when `index` is out of range. + */ +static inline void *vec_at_checked(struct vec *v, size_t index) +{ + if (index >= v->size) { + return NULL; + } + + return (unsigned char *)v->data + + index * v->elem_size; +} + +/** + * @brief Returns a read-only pointer to the element at `index`, or `NULL` + * when `index` is out of range. + */ +static inline const void *vec_at_checked_const(const struct vec *v, + size_t index) +{ + if (index >= v->size) { + return NULL; + } + + return (const unsigned char *)v->data + + index * v->elem_size; +} + +/** + * @brief Returns a writable pointer to the first element. + * @pre The vector is not empty. + */ +static inline void *vec_front(struct vec *v) +{ + assert(v->size); + return v->data; +} + +/** + * @brief Returns a read-only pointer to the first element. + * @pre The vector is not empty. + */ +static inline const void *vec_front_const(const struct vec *v) +{ + assert(v->size); + return v->data; +} + +/** + * @brief Returns a writable pointer to the last element. + * @pre The vector is not empty. + */ +static inline void *vec_back(struct vec *v) +{ + assert(v->size); + return vec_at(v, v->size - 1); +} + +/** + * @brief Returns a read-only pointer to the last element. + * @pre The vector is not empty. + */ +static inline const void *vec_back_const(const struct vec *v) +{ + assert(v->size); + return vec_at_const(v, v->size - 1); +} + +/** @} */ + +/** @name Typed access macros */ +/** @{ */ + +/** @brief Converts the storage pointer to a writable pointer of `type`. */ +#define vec_data_as(v, type) \ + ((type *)vec_data(v)) + +/** @brief Converts the storage pointer to a read-only pointer of `type`. */ +#define vec_data_as_const(v, type) \ + ((const type *)vec_data_const(v)) + +/** @brief Accesses the writable element at `i` as `type`. */ +#define vec_at_as(v, type, i) \ + (*(type *)vec_at((v), (i))) + +/** @brief Accesses the read-only element at `i` as `type`. */ +#define vec_at_as_const(v, type, i) \ + (*(const type *)vec_at_const((v), (i))) + +/** @brief Accesses the first element as a writable `type`. */ +#define vec_front_as(v, type) \ + (*(type *)vec_front(v)) + +/** @brief Accesses the first element as a read-only `type`. */ +#define vec_front_as_const(v, type) \ + (*(const type *)vec_front_const(v)) + +/** @brief Accesses the last element as a writable `type`. */ +#define vec_back_as(v, type) \ + (*(type *)vec_back(v)) + +/** @brief Accesses the last element as a read-only `type`. */ +#define vec_back_as_const(v, type) \ + (*(const type *)vec_back_const(v)) + +/** @} */ + +/** @name Raw element insertion */ +/** @{ */ + +/* 内部辅助函数:按 2 倍几何级数扩容,确保至少容纳 needed 个元素 */ +static inline bool __vec_grow_to(struct vec *v, size_t needed) +{ + size_t max_elements = SIZE_MAX / v->elem_size; + if (needed > max_elements) { + return false; + } + if (needed <= v->capacity) { + return true; + } + // 初始默认给 8 个元素容量,之后每次翻倍 + size_t new_cap = v->capacity ? v->capacity : 8; + if (new_cap > max_elements) { + new_cap = max_elements; + } + while (new_cap < needed) { + // 防止翻倍超过最大元素数量 + if (new_cap > max_elements / 2) { + new_cap = max_elements; + break; + } + new_cap *= 2; + } + return vec_reserve(v, new_cap); +} + +/** + * @brief Reserves an uninitialized slot at the end of the vector. + * @return A pointer to the new slot, or `NULL` on failure. + */ +static inline void *vec_emplace_back(struct vec *v) +{ + if (!v || v->elem_size == 0) { + return NULL; + } + size_t max_elements = SIZE_MAX / v->elem_size; + if (v->size >= max_elements) { + return NULL; + } + size_t needed = v->size + 1; + /* Grow the storage when the current capacity is exhausted. */ + if (v->size >= v->capacity) { + if (!__vec_grow_to(v, needed)) { + return NULL; + } + } + void *slot = (char *)v->data + (v->size * v->elem_size); + v->size++; + return slot; +} + +static inline size_t __vec_source_index(const struct vec *v, + const void *elem) +{ + if (!v || !v->data || !elem || v->elem_size == 0) { + return SIZE_MAX; + } + + uintptr_t base = (uintptr_t)v->data; + uintptr_t address = (uintptr_t)elem; + if (address < base) { + return SIZE_MAX; + } + + uintptr_t offset = address - base; + if (offset % v->elem_size != 0) { + return SIZE_MAX; + } + + size_t index = (size_t)(offset / v->elem_size); + return index < v->size ? index : SIZE_MAX; +} + +/** + * @brief Appends one raw element to the vector. + * @param v A pointer to the vector. + * @param elem A pointer to the element to copy. + * @return `true` on success; `false` on invalid input or allocation failure. + */ +static inline bool vec_push_back(struct vec *v, + const void *elem) +{ + if (!elem) { + return false; + } + size_t source_index = __vec_source_index(v, elem); + void *slot = vec_emplace_back(v); + if (!slot) { + return false; + } + const void *source = source_index == SIZE_MAX + ? elem + : (const unsigned char *)v->data + + source_index * v->elem_size; + memcpy(slot, source, v->elem_size); + return true; +} + +/** + * @brief Reserves an uninitialized slot at `index`. + * @param v A pointer to the vector. + * @param index The insertion index in the range `[0, size]`. + * @return A pointer to the new slot, or `NULL` on failure. + */ +static inline void *vec_emplace(struct vec *v, + size_t index) +{ + if (!v || v->elem_size == 0 || index > v->size) { + return NULL; + } + size_t max_elements = SIZE_MAX / v->elem_size; + if (v->size >= max_elements) { + return NULL; + } + size_t needed = v->size + 1; + if (v->size >= v->capacity) { + if (!__vec_grow_to(v, needed)) { + return NULL; + } + } + char *slot = (char *)v->data + (index * v->elem_size); + + /* Shift the suffix when insertion is not at the end. */ + if (index < v->size) { + memmove(slot + v->elem_size, slot, (v->size - index) * v->elem_size); + } + + v->size++; + return (void *)slot; + +} + +/** + * @brief Inserts one raw element at `index`. + * @param v A pointer to the vector. + * @param index The insertion index in the range `[0, size]`. + * @param elem A pointer to the element to copy. + * @return `true` on success; `false` on invalid input or allocation failure. + */ +static inline bool vec_insert(struct vec *v, + size_t index, + const void *elem) +{ + if (!elem) { + return false; + } + size_t source_index = __vec_source_index(v, elem); + void *slot = vec_emplace(v, index); + if (!slot) { + return false; + } + if (source_index != SIZE_MAX && source_index >= index) { + source_index++; + } + const void *source = source_index == SIZE_MAX + ? elem + : (const unsigned char *)v->data + + source_index * v->elem_size; + memcpy(slot, source, v->elem_size); + return true; +} + +/** + * @brief Inserts a range of raw elements at `index`. + * + * The source range must not refer to the vector's storage. + * + * @param v A pointer to the vector. + * @param index The insertion index in the range `[0, size]`. + * @param src The source range. + * @param count The number of elements to insert. + * @return `true` on success; `false` on invalid input or allocation failure. + */ +static inline bool vec_insert_range(struct vec *v, + size_t index, + const void *src, + size_t count) +{ + /* 前置条件:src 不得指向当前 vector 的存储区, + * 这与 std::vector::insert(position, first, last) 一致。 */ + if (!v || v->elem_size == 0 || index > v->size) { + return false; + } + if (count == 0) { + return true; /* Inserting zero elements succeeds. */ + } + if (!src) { + return false; + } + /* Check for overflow in size + count. */ + if (count > SIZE_MAX - v->size) { + return false; + } + + size_t needed = v->size + count; + if (needed > v->capacity) { + if (!__vec_grow_to(v, needed)) { + return false; + } + } + + char *dest = (char *)v->data + (index * v->elem_size); + + /* Shift the suffix when insertion is not at the end. */ + if (index < v->size) { + memmove(dest + (count * v->elem_size), dest, (v->size - index) * v->elem_size); + } + + /* Copy the source range into the newly opened gap. */ + memcpy(dest, src, count * v->elem_size); + v->size += count; + return true; +} + +/** + * @brief Replaces the vector with `count` copies of one raw element. + * @param v A pointer to the vector. + * @param count The resulting number of elements. + * @param value A pointer to the value to copy. + * @return `true` on success; `false` on invalid input or allocation failure. + */ +static inline bool vec_assign_n(struct vec *v, + size_t count, + const void *value) +{ + if (!v || v->elem_size == 0) { + return false; + } + if (count == 0) { + v->size = 0; + return true; + } + if (!value || count > vec_max_size(v)) { + return false; + } + + size_t source_index = __vec_source_index(v, value); + if (count > v->capacity && !vec_reserve(v, count)) { + return false; + } + + const void *source = source_index == SIZE_MAX + ? value + : (const unsigned char *)v->data + + source_index * v->elem_size; + for (size_t i = 0; i < count; ++i) { + void *dest = (unsigned char *)v->data + i * v->elem_size; + memmove(dest, source, v->elem_size); + } + v->size = count; + return true; +} + +/** + * @brief Replaces the vector with a range of raw elements. + * + * The source range must not refer to the vector's storage. + * + * @param v A pointer to the vector. + * @param src The source range. + * @param count The number of elements to assign. + * @return `true` on success; `false` on invalid input or allocation failure. + */ +static inline bool vec_assign_range(struct vec *v, + const void *src, + size_t count) +{ + /* 前置条件:src 不得指向当前 vector 的存储区。 */ + if (!v || v->elem_size == 0) { + return false; + } + if (count == 0) { + v->size = 0; + return true; + } + if (!src || count > vec_max_size(v)) { + return false; + } + if (count > v->capacity && !vec_reserve(v, count)) { + return false; + } + + memmove(v->data, src, count * v->elem_size); + v->size = count; + return true; +} + +/** + * @brief Appends a range of raw elements to the vector. + * + * The source range must not refer to the vector's storage. + * + * @param v A pointer to the vector. + * @param src The source range. + * @param count The number of elements to append. + * @return `true` on success; `false` on invalid input or allocation failure. + */ +static inline bool vec_append(struct vec *v, + const void *src, + size_t count) +{ + /* The source must not refer to the vector's storage. */ + if (!v) { + return false; + } + /* Reuse vec_insert_range() at the current end position. */ + return vec_insert_range(v, v->size, src, count); +} + + +/** @} */ + +/** @name Value insertion wrappers */ +/** @{ */ + +/** @brief Appends a typed value after checking its size. */ +#define vec_push(v, value) ({ \ + typeof(value) __vec_tmp = (value); \ + assert(sizeof(__vec_tmp) == \ + (v)->elem_size); \ + vec_push_back((v), &__vec_tmp); \ +}) + +/** @brief Inserts a typed value after checking its size. */ +#define vec_insert_value(v, index, value) ({ \ + typeof(value) __vec_tmp = (value); \ + assert(sizeof(__vec_tmp) == \ + (v)->elem_size); \ + vec_insert((v), (index), &__vec_tmp); \ +}) + +/** @brief Reserves a typed slot at the end of the vector. */ +#define vec_emplace_back_as(v, type) \ + ((type *)vec_emplace_back(v)) + +/** @brief Reserves a typed slot at the specified index. */ +#define vec_emplace_as(v, type, index) \ + ((type *)vec_emplace((v), (index))) + + +/** @} */ + +/** @name Erasure */ +/** @{ */ + +/** @brief Removes the last element, if one exists. */ +static inline void vec_pop_back(struct vec *v) +{ + if (!v || v->size == 0) { + return; + } + v->size--; +} + +/** + * @brief Removes the last element and copies it to `out`. + * @return `true` on success; `false` when the vector is empty or `out` is null. + */ +static inline bool vec_pop_back_copy(struct vec *v, + void *out) +{ + if (!v || !out || v->size == 0) { + return false; + } + v->size--; + const char *last_elem = (const char *)v->data + (v->size * v->elem_size); + memcpy(out, last_elem, v->elem_size); + return true; +} + +/** + * @brief Removes up to `count` elements starting at `index`. + */ +static inline void vec_erase_n(struct vec *v, + size_t index, + size_t count) +{ + if (!v || index >= v->size || count == 0) { + return; + } + + /* Limit the count without allowing index + count to overflow. */ + if (count > v->size - index) { + count = v->size - index; + } + + size_t trailing_elems = v->size - (index + count); + if (trailing_elems > 0) { + char *dest = (char *)v->data + (index * v->elem_size); + const char *src = (const char *)v->data + ((index + count) * v->elem_size); + /* The source and destination overlap, so use memmove. */ + memmove(dest, src, trailing_elems * v->elem_size); + } + + v->size -= count; +} + +/** @brief Removes the element at `index`, if it exists. */ +static inline void vec_erase(struct vec *v, + size_t index) +{ + vec_erase_n(v, index, 1); +} + +/** + * @brief Removes the half-open range `[first, last)`. + * @return A pointer to the element now at `first`, or the end pointer. + */ +static inline void *vec_erase_range(struct vec *v, + size_t first, + size_t last) +{ + if (!v || first > last || last > v->size) { + return NULL; + } + + vec_erase_n(v, first, last - first); + if (first == v->size) { + if (!v->data) { + return NULL; + } + return (unsigned char *)v->data + v->size * v->elem_size; + } + return (unsigned char *)v->data + first * v->elem_size; +} + +/** @brief Exchanges the contents of two vectors. */ +static inline void vec_swap(struct vec *a, struct vec *b) +{ + struct vec tmp = *a; + *a = *b; + *b = tmp; +} + + +/** + * @brief Removes an element by replacing it with the last element. + * + * The order of the remaining elements is not preserved. + */ +static inline void vec_swap_erase(struct vec *v, + size_t index) +{ + if (!v || index >= v->size) { + return; + } + + size_t last_idx = v->size - 1; + /* Move the last element over the erased element when necessary. */ + if (index < last_idx) { + char *dest = (char *)v->data + (index * v->elem_size); + const char *src = (const char *)v->data + (last_idx * v->elem_size); + memcpy(dest, src, v->elem_size); + } + + v->size--; +} + +/** @} */ + +/** @name Forward iterators */ +/** @{ */ + +/** @brief Returns a writable iterator to the first element. */ +static inline void *vec_begin(struct vec *v) +{ + return v->data; +} + +/** @brief Returns a read-only iterator to the first element. */ +static inline const void *vec_cbegin(const struct vec *v) +{ + return v->data; +} + +/** @brief Returns a writable iterator past the last element. */ +static inline void *vec_end(struct vec *v) +{ + if (!v->data) + return NULL; + + return (unsigned char *)v->data + + v->size * v->elem_size; +} + +/** @brief Returns a read-only iterator past the last element. */ +static inline const void *vec_cend(const struct vec *v) +{ + if (!v->data) + return NULL; + + return (const unsigned char *)v->data + + v->size * v->elem_size; +} + +/** @brief Returns the first element as a typed writable iterator. */ +#define vec_begin_as(v, type) \ + ((type *)vec_begin(v)) + +/** @brief Returns the end as a typed writable iterator. */ +#define vec_end_as(v, type) \ + ((type *)vec_end(v)) + +/** @brief Returns the first element as a typed read-only iterator. */ +#define vec_cbegin_as(v, type) \ + ((const type *)vec_cbegin(v)) + +/** @brief Returns the end as a typed read-only iterator. */ +#define vec_cend_as(v, type) \ + ((const type *)vec_cend(v)) + + +/** @} */ + +/** @name Iterator helpers */ +/** @{ */ + +/** @brief Advances a pointer iterator by one element. */ +#define vec_iter_next(it) \ + (++(it)) + +/** @brief Moves a pointer iterator back by one element. */ +#define vec_iter_prev(it) \ + (--(it)) + +/** + * @brief Returns the distance between two pointer iterators. + * + * Equal iterators, including two null pointers, have distance zero. + */ +#define vec_iter_distance(first, last) ({ \ + __auto_type __vec_first = (first); \ + __auto_type __vec_last = (last); \ + __vec_first == __vec_last \ + ? 0 \ + : __vec_last - __vec_first; \ +}) + +/** + * @brief A reverse iterator over mutable vector storage. + */ +struct vec_reverse_iterator { + void *data; + size_t size; + size_t elem_size; + size_t offset; +}; + +/** + * @brief A reverse iterator over read-only vector storage. + */ +struct vec_const_reverse_iterator { + const void *data; + size_t size; + size_t elem_size; + size_t offset; +}; + +/** @brief Returns a reverse iterator to the last element. */ +static inline struct vec_reverse_iterator vec_rbegin(struct vec *v) +{ + return (struct vec_reverse_iterator){ + .data = v->data, + .size = v->size, + .elem_size = v->elem_size, + .offset = 0, + }; +} + +/** @brief Returns a reverse iterator past the first element. */ +static inline struct vec_reverse_iterator vec_rend(struct vec *v) +{ + return (struct vec_reverse_iterator){ + .data = v->data, + .size = v->size, + .elem_size = v->elem_size, + .offset = v->size, + }; +} + +/** @brief Returns a read-only reverse iterator to the last element. */ +static inline struct vec_const_reverse_iterator +vec_crbegin(const struct vec *v) +{ + return (struct vec_const_reverse_iterator){ + .data = v->data, + .size = v->size, + .elem_size = v->elem_size, + .offset = 0, + }; +} + +/** @brief Returns a read-only reverse iterator past the first element. */ +static inline struct vec_const_reverse_iterator +vec_crend(const struct vec *v) +{ + return (struct vec_const_reverse_iterator){ + .data = v->data, + .size = v->size, + .elem_size = v->elem_size, + .offset = v->size, + }; +} + +/** @brief Dereferences a mutable reverse iterator. */ +static inline void *vec_reverse_deref(struct vec_reverse_iterator it) +{ + return (unsigned char *)it.data + + (it.size - it.offset - 1) * it.elem_size; +} + +/** @brief Dereferences a read-only reverse iterator. */ +static inline const void * +vec_reverse_deref_const(struct vec_const_reverse_iterator it) +{ + return (const unsigned char *)it.data + + (it.size - it.offset - 1) * it.elem_size; +} + +/** @brief Advances a mutable reverse iterator. */ +static inline void vec_reverse_next(struct vec_reverse_iterator *it) +{ + ++it->offset; +} + +/** @brief Advances a read-only reverse iterator. */ +static inline void +vec_reverse_next_const(struct vec_const_reverse_iterator *it) +{ + ++it->offset; +} + +/** @brief Moves a mutable reverse iterator backwards. */ +static inline void vec_reverse_prev(struct vec_reverse_iterator *it) +{ + --it->offset; +} + +/** @brief Moves a read-only reverse iterator backwards. */ +static inline void +vec_reverse_prev_const(struct vec_const_reverse_iterator *it) +{ + --it->offset; +} + +/** @brief Compares two mutable reverse iterators. */ +static inline bool vec_reverse_equal(struct vec_reverse_iterator lhs, + struct vec_reverse_iterator rhs) +{ + return lhs.data == rhs.data && lhs.offset == rhs.offset; +} + +/** @brief Compares two read-only reverse iterators. */ +static inline bool +vec_reverse_equal_const(struct vec_const_reverse_iterator lhs, + struct vec_const_reverse_iterator rhs) +{ + return lhs.data == rhs.data && lhs.offset == rhs.offset; +} + +/** @brief Returns the distance between mutable reverse iterators. */ +static inline ptrdiff_t +vec_reverse_distance(struct vec_reverse_iterator first, + struct vec_reverse_iterator last) +{ + return (ptrdiff_t)last.offset - (ptrdiff_t)first.offset; +} + +/** @brief Returns the distance between read-only reverse iterators. */ +static inline ptrdiff_t +vec_reverse_distance_const(struct vec_const_reverse_iterator first, + struct vec_const_reverse_iterator last) +{ + return (ptrdiff_t)last.offset - (ptrdiff_t)first.offset; +} + + +/** @} */ + +/** @name Traversal */ +/** @{ */ + +/** + * @brief Iterates over mutable vector elements. + * + * Example: + * @code + * int *it; + * vec_for_each(it, &v, int) + * printf("%d\\n", *it); + * @endcode + */ + +#define vec_for_each(pos, v, type) \ + for ((pos) = vec_begin_as((v), type); \ + (pos) != vec_end_as((v), type); \ + ++(pos)) + +/** @brief Iterates over read-only vector elements. */ +#define vec_for_each_const(pos, v, type) \ + for ((pos) = vec_cbegin_as((v), type); \ + (pos) != vec_cend_as((v), type); \ + ++(pos)) + +/** + * @brief Iterates over vector indexes in ascending order. + */ + +#define vec_for_each_index(i, v) \ + for (size_t i = 0; i < (v)->size; ++i) + +/** @brief Iterates over vector indexes in descending order. */ +#define vec_for_each_index_reverse(i, v) \ + for (size_t i = (v)->size; i-- > 0; ) + +/** @} */ + +#endif /* VEC_H */ |
