From 904c1b4d699aeb1ce170f0cd996a01d2d06812e3 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 10 Sep 2021 20:11:46 -0400 Subject: Add nullability annotations This allows clang to issue warnings at compile time when null is passed to a non-null parameter. For public entry points, also add assertions to catch such issues when the compiler does not support this. --- benchmark/tree_bench.c | 5 ++-- include/zix/attributes.h | 11 +++++++ include/zix/bitset.h | 24 ++++++++++------ include/zix/btree.h | 55 +++++++++++++++++++---------------- include/zix/digest.h | 12 ++++---- include/zix/hash.h | 74 +++++++++++++++++++++++++++--------------------- include/zix/ring.h | 24 +++++++++------- include/zix/sem.h | 41 ++++++++++++++------------- include/zix/tree.h | 58 +++++++++++++++++++------------------ meson.build | 1 + src/btree.c | 17 +++++++++++ src/hash.c | 35 +++++++++++++++++++++++ test/ring_test.c | 3 ++ 13 files changed, 230 insertions(+), 130 deletions(-) diff --git a/benchmark/tree_bench.c b/benchmark/tree_bench.c index 72f1926..6e573ee 100644 --- a/benchmark/tree_bench.c +++ b/benchmark/tree_bench.c @@ -198,8 +198,9 @@ bench_zix_btree(size_t n_elems, for (size_t i = 0; i < n_elems; i++) { r = unique_rand(i); - void* removed = NULL; - if (zix_btree_remove(t, (void*)r, &removed, NULL)) { + void* removed = NULL; + ZixBTreeIter next = zix_btree_end(t); + if (zix_btree_remove(t, (void*)r, &removed, &next)) { return test_fail("Failed to remove %" PRIuPTR "\n", r); } } diff --git a/include/zix/attributes.h b/include/zix/attributes.h index c8f77c4..255b315 100644 --- a/include/zix/attributes.h +++ b/include/zix/attributes.h @@ -74,6 +74,17 @@ # define ZIX_UNUSED(name) name #endif +// Clang nullability annotations +#if defined(__clang__) && __clang_major__ >= 7 +# define ZIX_NONNULL _Nonnull +# define ZIX_NULLABLE _Nullable +# define ZIX_ALLOCATED _Null_unspecified +#else +# define ZIX_NONNULL +# define ZIX_NULLABLE +# define ZIX_ALLOCATED +#endif + /** @} */ diff --git a/include/zix/bitset.h b/include/zix/bitset.h index ee8b805..b6e4bac 100644 --- a/include/zix/bitset.h +++ b/include/zix/bitset.h @@ -48,27 +48,35 @@ typedef uint8_t ZixBitsetTally; /// Clear a Bitset ZIX_API void -zix_bitset_clear(ZixBitset* b, ZixBitsetTally* t, size_t n_bits); +zix_bitset_clear(ZixBitset* ZIX_NONNULL b, + ZixBitsetTally* ZIX_NONNULL t, + size_t n_bits); /// Set bit `i` in `t` to 1 ZIX_API void -zix_bitset_set(ZixBitset* b, ZixBitsetTally* t, size_t i); +zix_bitset_set(ZixBitset* ZIX_NONNULL b, + ZixBitsetTally* ZIX_NONNULL t, + size_t i); /// Clear bit `i` in `t` (set to 0) ZIX_API void -zix_bitset_reset(ZixBitset* b, ZixBitsetTally* t, size_t i); +zix_bitset_reset(ZixBitset* ZIX_NONNULL b, + ZixBitsetTally* ZIX_NONNULL t, + size_t i); /// Return the `i`th bit in `t` ZIX_PURE_API bool -zix_bitset_get(const ZixBitset* b, size_t i); +zix_bitset_get(const ZixBitset* ZIX_NONNULL b, size_t i); /// Return the number of set bits in `b` up to bit `i` (non-inclusive) ZIX_PURE_API size_t -zix_bitset_count_up_to(const ZixBitset* b, const ZixBitsetTally* t, size_t i); +zix_bitset_count_up_to(const ZixBitset* ZIX_NONNULL b, + const ZixBitsetTally* ZIX_NONNULL t, + size_t i); /** Return the number of set bits in `b` up to bit `i` (non-inclusive) if bit @@ -76,9 +84,9 @@ zix_bitset_count_up_to(const ZixBitset* b, const ZixBitsetTally* t, size_t i); */ ZIX_PURE_API size_t -zix_bitset_count_up_to_if(const ZixBitset* b, - const ZixBitsetTally* t, - size_t i); +zix_bitset_count_up_to_if(const ZixBitset* ZIX_NONNULL b, + const ZixBitsetTally* ZIX_NONNULL t, + size_t i); /** @} diff --git a/include/zix/btree.h b/include/zix/btree.h index e2a5f26..3979084 100644 --- a/include/zix/btree.h +++ b/include/zix/btree.h @@ -64,9 +64,11 @@ typedef struct ZixBTreeNodeImpl ZixBTreeNode; iterators can be allocated on the stack. */ typedef struct { - ZixBTreeNode* nodes[ZIX_BTREE_MAX_HEIGHT]; ///< Parallel node pointer stack - uint16_t indexes[ZIX_BTREE_MAX_HEIGHT]; ///< Parallel child index stack - uint16_t level; ///< Current level in stack + ZixBTreeNode* ZIX_NULLABLE + nodes[ZIX_BTREE_MAX_HEIGHT]; ///< Parallel node pointer stacky + + uint16_t indexes[ZIX_BTREE_MAX_HEIGHT]; ///< Parallel child index stack + uint16_t level; ///< Current level in stack } ZixBTreeIter; /// A static end iterator for convenience @@ -85,8 +87,8 @@ static const ZixBTreeIter zix_btree_end_iter = { zix_btree_lower_bound() for details. */ ZIX_API -ZixBTree* -zix_btree_new(ZixComparator cmp, const void* cmp_data); +ZixBTree* ZIX_ALLOCATED +zix_btree_new(ZixComparator ZIX_NONNULL cmp, const void* ZIX_NULLABLE cmp_data); /** Free `t` and all the nodes it contains. @@ -96,9 +98,9 @@ zix_btree_new(ZixComparator cmp, const void* cmp_data); */ ZIX_API void -zix_btree_free(ZixBTree* t, - ZixDestroyFunc destroy, - const void* destroy_user_data); +zix_btree_free(ZixBTree* ZIX_NONNULL t, + ZixDestroyFunc ZIX_NULLABLE destroy, + const void* ZIX_NULLABLE destroy_user_data); /** Clear everything from `t`, leaving it empty. @@ -108,19 +110,19 @@ zix_btree_free(ZixBTree* t, */ ZIX_API void -zix_btree_clear(ZixBTree* t, - ZixDestroyFunc destroy, - const void* destroy_user_data); +zix_btree_clear(ZixBTree* ZIX_NONNULL t, + ZixDestroyFunc ZIX_NULLABLE destroy, + const void* ZIX_NULLABLE destroy_user_data); /// Return the number of elements in `t` ZIX_PURE_API size_t -zix_btree_size(const ZixBTree* t); +zix_btree_size(const ZixBTree* ZIX_NONNULL t); /// Insert the element `e` into `t` ZIX_API ZixStatus -zix_btree_insert(ZixBTree* t, void* e); +zix_btree_insert(ZixBTree* ZIX_NONNULL t, void* ZIX_NULLABLE e); /** Remove the value `e` from `t`. @@ -136,7 +138,10 @@ zix_btree_insert(ZixBTree* t, void* e); */ ZIX_API ZixStatus -zix_btree_remove(ZixBTree* t, const void* e, void** out, ZixBTreeIter* next); +zix_btree_remove(ZixBTree* ZIX_NONNULL t, + const void* ZIX_NULLABLE e, + void* ZIX_NULLABLE* ZIX_NONNULL out, + ZixBTreeIter* ZIX_NONNULL next); /** Set `ti` to an element exactly equal to `e` in `t`. @@ -145,7 +150,9 @@ zix_btree_remove(ZixBTree* t, const void* e, void** out, ZixBTreeIter* next); */ ZIX_API ZixStatus -zix_btree_find(const ZixBTree* t, const void* e, ZixBTreeIter* ti); +zix_btree_find(const ZixBTree* ZIX_NONNULL t, + const void* ZIX_NULLABLE e, + ZixBTreeIter* ZIX_NONNULL ti); /** Set `ti` to the smallest element in `t` that is not less than `e`. @@ -163,26 +170,26 @@ zix_btree_find(const ZixBTree* t, const void* e, ZixBTreeIter* ti); */ ZIX_API ZixStatus -zix_btree_lower_bound(const ZixBTree* t, - ZixComparator compare_key, - const void* compare_key_user_data, - const void* key, - ZixBTreeIter* ti); +zix_btree_lower_bound(const ZixBTree* ZIX_NONNULL t, + ZixComparator ZIX_NULLABLE compare_key, + const void* ZIX_NULLABLE compare_key_user_data, + const void* ZIX_NULLABLE key, + ZixBTreeIter* ZIX_NONNULL ti); /// Return the data at the given position in the tree ZIX_PURE_API -void* +void* ZIX_NULLABLE zix_btree_get(ZixBTreeIter ti); /// Return an iterator to the first (smallest) element in `t` ZIX_PURE_API ZixBTreeIter -zix_btree_begin(const ZixBTree* t); +zix_btree_begin(const ZixBTree* ZIX_NONNULL t); /// Return an iterator to the end of `t` (one past the last element) ZIX_CONST_API ZixBTreeIter -zix_btree_end(const ZixBTree* t); +zix_btree_end(const ZixBTree* ZIX_NULLABLE t); /// Return true iff `lhs` is equal to `rhs` ZIX_PURE_API @@ -199,7 +206,7 @@ zix_btree_iter_is_end(const ZixBTreeIter i) /// Increment `i` to point to the next element in the tree ZIX_API ZixStatus -zix_btree_iter_increment(ZixBTreeIter* i); +zix_btree_iter_increment(ZixBTreeIter* ZIX_NONNULL i); /// Return an iterator one past `iter` ZIX_API diff --git a/include/zix/digest.h b/include/zix/digest.h index 139a0bd..6462717 100644 --- a/include/zix/digest.h +++ b/include/zix/digest.h @@ -45,7 +45,7 @@ extern "C" { */ ZIX_PURE_API uint32_t -zix_digest32(uint32_t seed, const void* buf, size_t len); +zix_digest32(uint32_t seed, const void* ZIX_NONNULL buf, size_t len); /** Return a 32-bit hash of an aligned buffer. @@ -55,7 +55,7 @@ zix_digest32(uint32_t seed, const void* buf, size_t len); */ ZIX_PURE_API uint32_t -zix_digest32_aligned(uint32_t seed, const void* buf, size_t len); +zix_digest32_aligned(uint32_t seed, const void* ZIX_NONNULL buf, size_t len); /** Return a 64-bit hash of a buffer. @@ -64,7 +64,7 @@ zix_digest32_aligned(uint32_t seed, const void* buf, size_t len); */ ZIX_PURE_API uint64_t -zix_digest64(uint64_t seed, const void* buf, size_t len); +zix_digest64(uint64_t seed, const void* ZIX_NONNULL buf, size_t len); /** Return a 64-bit hash of an aligned buffer. @@ -74,7 +74,7 @@ zix_digest64(uint64_t seed, const void* buf, size_t len); */ ZIX_PURE_API uint64_t -zix_digest64_aligned(uint64_t seed, const void* buf, size_t len); +zix_digest64_aligned(uint64_t seed, const void* ZIX_NONNULL buf, size_t len); /** Return a pointer-sized hash of a buffer. @@ -86,7 +86,7 @@ zix_digest64_aligned(uint64_t seed, const void* buf, size_t len); */ ZIX_PURE_API size_t -zix_digest(size_t seed, const void* buf, size_t len); +zix_digest(size_t seed, const void* ZIX_NONNULL buf, size_t len); /** Return a pointer-sized hash of an aligned buffer. @@ -100,7 +100,7 @@ zix_digest(size_t seed, const void* buf, size_t len); */ ZIX_PURE_API size_t -zix_digest_aligned(size_t seed, const void* buf, size_t len); +zix_digest_aligned(size_t seed, const void* ZIX_NONNULL buf, size_t len); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/zix/hash.h b/include/zix/hash.h index 27fb39d..8be8941 100644 --- a/include/zix/hash.h +++ b/include/zix/hash.h @@ -96,17 +96,20 @@ typedef size_t ZixHashCode; typedef size_t ZixHashIter; /// User function for computing the hash of a key -typedef ZixHashCode (*ZixHashFunc)(const ZixHashKey* key); +typedef ZixHashCode (*ZixHashFunc)(const ZixHashKey* ZIX_NONNULL key); /// User function for determining if two keys are truly equal -typedef bool (*ZixKeyEqualFunc)(const ZixHashKey* a, const ZixHashKey* b); +typedef bool (*ZixKeyEqualFunc)(const ZixHashKey* ZIX_NONNULL a, + const ZixHashKey* ZIX_NONNULL b); /// User function for determining if a key matches in a custom search -typedef bool (*ZixKeyMatchFunc)(const ZixHashKey* key, - const ZixHashSearchData* user_data); +typedef bool (*ZixKeyMatchFunc)(const ZixHashKey* ZIX_NONNULL key, + const ZixHashSearchData* ZIX_NULLABLE + user_data); /// User function for getting the key of a record -typedef const ZixHashKey* (*ZixKeyFunc)(const ZixHashRecord* record); +typedef const ZixHashKey* ZIX_NONNULL (*ZixKeyFunc)( + const ZixHashRecord* ZIX_NONNULL record); /** A "plan" (position) to insert a record in a hash table. @@ -129,40 +132,40 @@ typedef struct { @param equal_func A function to test keys for equality. */ ZIX_API -ZixHash* -zix_hash_new(ZixKeyFunc key_func, - ZixHashFunc hash_func, - ZixKeyEqualFunc equal_func); +ZixHash* ZIX_ALLOCATED +zix_hash_new(ZixKeyFunc ZIX_NONNULL key_func, + ZixHashFunc ZIX_NONNULL hash_func, + ZixKeyEqualFunc ZIX_NONNULL equal_func); /// Free `hash` ZIX_API void -zix_hash_free(ZixHash* hash); +zix_hash_free(ZixHash* ZIX_NULLABLE hash); /// Return an iterator to the first record in a hash, or the end if it is empty ZIX_PURE_API ZixHashIter -zix_hash_begin(const ZixHash* hash); +zix_hash_begin(const ZixHash* ZIX_NONNULL hash); /// Return an iterator one past the last possible record in a hash ZIX_PURE_API ZixHashIter -zix_hash_end(const ZixHash* hash); +zix_hash_end(const ZixHash* ZIX_NONNULL hash); /// Return the record pointed to by an iterator ZIX_PURE_API -ZixHashRecord* -zix_hash_get(const ZixHash* hash, ZixHashIter i); +ZixHashRecord* ZIX_NULLABLE +zix_hash_get(const ZixHash* ZIX_NONNULL hash, ZixHashIter i); /// Return an iterator that has been advanced to the next record in a hash ZIX_PURE_API ZixHashIter -zix_hash_next(const ZixHash* hash, ZixHashIter i); +zix_hash_next(const ZixHash* ZIX_NONNULL hash, ZixHashIter i); /// Return the number of elements in a hash ZIX_PURE_API size_t -zix_hash_size(const ZixHash* hash); +zix_hash_size(const ZixHash* ZIX_NONNULL hash); /** Find the best position to insert a record with the given key. @@ -177,7 +180,8 @@ zix_hash_size(const ZixHash* hash); */ ZIX_API ZixHashInsertPlan -zix_hash_plan_insert(const ZixHash* hash, const ZixHashKey* key); +zix_hash_plan_insert(const ZixHash* ZIX_NONNULL hash, + const ZixHashKey* ZIX_NONNULL key); /** Find the best position to insert a record with a custom search. @@ -201,10 +205,10 @@ zix_hash_plan_insert(const ZixHash* hash, const ZixHashKey* key); */ ZIX_API ZixHashInsertPlan -zix_hash_plan_insert_prehashed(const ZixHash* hash, - ZixHashCode code, - ZixKeyMatchFunc predicate, - const ZixHashSearchData* user_data); +zix_hash_plan_insert_prehashed(const ZixHash* ZIX_NONNULL hash, + ZixHashCode code, + ZixKeyMatchFunc ZIX_NONNULL predicate, + const ZixHashSearchData* ZIX_NULLABLE user_data); /** Return the record at the given position, or null. @@ -214,8 +218,8 @@ zix_hash_plan_insert_prehashed(const ZixHash* hash, record. */ ZIX_PURE_API -ZixHashRecord* -zix_hash_record_at(const ZixHash* hash, ZixHashInsertPlan position); +ZixHashRecord* ZIX_NULLABLE +zix_hash_record_at(const ZixHash* ZIX_NONNULL hash, ZixHashInsertPlan position); /** Insert a record at a specific position. @@ -236,9 +240,9 @@ zix_hash_record_at(const ZixHash* hash, ZixHashInsertPlan position); */ ZIX_API ZixStatus -zix_hash_insert_at(ZixHash* hash, - ZixHashInsertPlan position, - ZixHashRecord* record); +zix_hash_insert_at(ZixHash* ZIX_NONNULL hash, + ZixHashInsertPlan position, + ZixHashRecord* ZIX_NONNULL record); /** Insert a record. @@ -256,7 +260,7 @@ zix_hash_insert_at(ZixHash* hash, */ ZIX_API ZixStatus -zix_hash_insert(ZixHash* hash, ZixHashRecord* record); +zix_hash_insert(ZixHash* ZIX_NONNULL hash, ZixHashRecord* ZIX_NONNULL record); /** Erase a record at a specific position. @@ -274,7 +278,9 @@ zix_hash_insert(ZixHash* hash, ZixHashRecord* record); */ ZIX_API ZixStatus -zix_hash_erase(ZixHash* hash, ZixHashIter i, ZixHashRecord** removed); +zix_hash_erase(ZixHash* ZIX_NONNULL hash, + ZixHashIter i, + ZixHashRecord* ZIX_NULLABLE* ZIX_NONNULL removed); /** Remove a record. @@ -286,7 +292,9 @@ zix_hash_erase(ZixHash* hash, ZixHashIter i, ZixHashRecord** removed); */ ZIX_API ZixStatus -zix_hash_remove(ZixHash* hash, const ZixHashKey* key, ZixHashRecord** removed); +zix_hash_remove(ZixHash* ZIX_NONNULL hash, + const ZixHashKey* ZIX_NONNULL key, + ZixHashRecord* ZIX_NULLABLE* ZIX_NONNULL removed); /** Find the position of a record with a given key. @@ -300,7 +308,8 @@ zix_hash_remove(ZixHash* hash, const ZixHashKey* key, ZixHashRecord** removed); */ ZIX_API ZixHashIter -zix_hash_find(const ZixHash* hash, const ZixHashKey* key); +zix_hash_find(const ZixHash* ZIX_NONNULL hash, + const ZixHashKey* ZIX_NONNULL key); /** Find a record with a given key. @@ -315,8 +324,9 @@ zix_hash_find(const ZixHash* hash, const ZixHashKey* key); @return A pointer to the matching record, of null if no such record exists. */ ZIX_API -ZixHashRecord* -zix_hash_find_record(const ZixHash* hash, const ZixHashKey* key); +ZixHashRecord* ZIX_NULLABLE +zix_hash_find_record(const ZixHash* ZIX_NONNULL hash, + const ZixHashKey* ZIX_NONNULL key); /** @} diff --git a/include/zix/ring.h b/include/zix/ring.h index 69803bf..b323e70 100644 --- a/include/zix/ring.h +++ b/include/zix/ring.h @@ -47,13 +47,13 @@ typedef struct ZixRingImpl ZixRing; At most `size` - 1 bytes may be stored in the ring at once. */ ZIX_MALLOC_API -ZixRing* +ZixRing* ZIX_ALLOCATED zix_ring_new(uint32_t size); /// Destroy a ring ZIX_API void -zix_ring_free(ZixRing* ring); +zix_ring_free(ZixRing* ZIX_NULLABLE ring); /** Lock the ring data into physical memory. @@ -66,7 +66,7 @@ zix_ring_free(ZixRing* ring); */ ZIX_API void -zix_ring_mlock(ZixRing* ring); +zix_ring_mlock(ZixRing* ZIX_NONNULL ring); /** Reset (empty) a ring. @@ -76,42 +76,44 @@ zix_ring_mlock(ZixRing* ring); */ ZIX_API void -zix_ring_reset(ZixRing* ring); +zix_ring_reset(ZixRing* ZIX_NONNULL ring); /// Return the number of bytes of space available for reading ZIX_CONST_API uint32_t -zix_ring_read_space(const ZixRing* ring); +zix_ring_read_space(const ZixRing* ZIX_NONNULL ring); /// Return the number of bytes of space available for writing ZIX_CONST_API uint32_t -zix_ring_write_space(const ZixRing* ring); +zix_ring_write_space(const ZixRing* ZIX_NONNULL ring); /// Return the capacity (i.e. total write space when empty) ZIX_CONST_API uint32_t -zix_ring_capacity(const ZixRing* ring); +zix_ring_capacity(const ZixRing* ZIX_NONNULL ring); /// Read from the ring without advancing the read head ZIX_API uint32_t -zix_ring_peek(ZixRing* ring, void* dst, uint32_t size); +zix_ring_peek(ZixRing* ZIX_NONNULL ring, void* ZIX_NONNULL dst, uint32_t size); /// Read from the ring and advance the read head ZIX_API uint32_t -zix_ring_read(ZixRing* ring, void* dst, uint32_t size); +zix_ring_read(ZixRing* ZIX_NONNULL ring, void* ZIX_NONNULL dst, uint32_t size); /// Skip data in the ring (advance read head without reading) ZIX_API uint32_t -zix_ring_skip(ZixRing* ring, uint32_t size); +zix_ring_skip(ZixRing* ZIX_NONNULL ring, uint32_t size); /// Write data to the ring ZIX_API uint32_t -zix_ring_write(ZixRing* ring, const void* src, uint32_t size); +zix_ring_write(ZixRing* ZIX_NONNULL ring, + const void* ZIX_NONNULL src, + uint32_t size); /** @} diff --git a/include/zix/sem.h b/include/zix/sem.h index c773ef1..7ff601b 100644 --- a/include/zix/sem.h +++ b/include/zix/sem.h @@ -17,6 +17,7 @@ #ifndef ZIX_SEM_H #define ZIX_SEM_H +#include "zix/attributes.h" #include "zix/common.h" #ifdef __APPLE__ @@ -65,11 +66,11 @@ typedef struct ZixSemImpl ZixSem; /// Create and initialize `sem` to `initial` static inline ZixStatus -zix_sem_init(ZixSem* sem, unsigned initial); +zix_sem_init(ZixSem* ZIX_NONNULL sem, unsigned initial); /// Destroy `sem` static inline void -zix_sem_destroy(ZixSem* sem); +zix_sem_destroy(ZixSem* ZIX_NONNULL sem); /** Increment and signal any waiters. @@ -77,7 +78,7 @@ zix_sem_destroy(ZixSem* sem); Realtime safe. */ static inline void -zix_sem_post(ZixSem* sem); +zix_sem_post(ZixSem* ZIX_NONNULL sem); /** Wait until count is > 0, then decrement. @@ -85,7 +86,7 @@ zix_sem_post(ZixSem* sem); Obviously not realtime safe. */ static inline ZixStatus -zix_sem_wait(ZixSem* sem); +zix_sem_wait(ZixSem* ZIX_NONNULL sem); /** Non-blocking version of wait(). @@ -93,7 +94,7 @@ zix_sem_wait(ZixSem* sem); @return true if decrement was successful (lock was acquired). */ static inline bool -zix_sem_try_wait(ZixSem* sem); +zix_sem_try_wait(ZixSem* ZIX_NONNULL sem); /** @cond @@ -106,7 +107,7 @@ struct ZixSemImpl { }; static inline ZixStatus -zix_sem_init(ZixSem* sem, unsigned val) +zix_sem_init(ZixSem* ZIX_NONNULL sem, unsigned val) { return semaphore_create( mach_task_self(), &sem->sem, SYNC_POLICY_FIFO, (int)val) @@ -115,19 +116,19 @@ zix_sem_init(ZixSem* sem, unsigned val) } static inline void -zix_sem_destroy(ZixSem* sem) +zix_sem_destroy(ZixSem* ZIX_NONNULL sem) { semaphore_destroy(mach_task_self(), sem->sem); } static inline void -zix_sem_post(ZixSem* sem) +zix_sem_post(ZixSem* ZIX_NONNULL sem) { semaphore_signal(sem->sem); } static inline ZixStatus -zix_sem_wait(ZixSem* sem) +zix_sem_wait(ZixSem* ZIX_NONNULL sem) { if (semaphore_wait(sem->sem) != KERN_SUCCESS) { return ZIX_STATUS_ERROR; @@ -136,7 +137,7 @@ zix_sem_wait(ZixSem* sem) } static inline bool -zix_sem_try_wait(ZixSem* sem) +zix_sem_try_wait(ZixSem* ZIX_NONNULL sem) { const mach_timespec_t zero = {0, 0}; return semaphore_timedwait(sem->sem, zero) == KERN_SUCCESS; @@ -149,26 +150,26 @@ struct ZixSemImpl { }; static inline ZixStatus -zix_sem_init(ZixSem* sem, unsigned initial) +zix_sem_init(ZixSem* ZIX_NONNULL sem, unsigned initial) { sem->sem = CreateSemaphore(NULL, (LONG)initial, LONG_MAX, NULL); return (sem->sem) ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR; } static inline void -zix_sem_destroy(ZixSem* sem) +zix_sem_destroy(ZixSem* ZIX_NONNULL sem) { CloseHandle(sem->sem); } static inline void -zix_sem_post(ZixSem* sem) +zix_sem_post(ZixSem* ZIX_NONNULL sem) { ReleaseSemaphore(sem->sem, 1, NULL); } static inline ZixStatus -zix_sem_wait(ZixSem* sem) +zix_sem_wait(ZixSem* ZIX_NONNULL sem) { if (WaitForSingleObject(sem->sem, INFINITE) != WAIT_OBJECT_0) { return ZIX_STATUS_ERROR; @@ -177,7 +178,7 @@ zix_sem_wait(ZixSem* sem) } static inline bool -zix_sem_try_wait(ZixSem* sem) +zix_sem_try_wait(ZixSem* ZIX_NONNULL sem) { return WaitForSingleObject(sem->sem, 0) == WAIT_OBJECT_0; } @@ -189,26 +190,26 @@ struct ZixSemImpl { }; static inline ZixStatus -zix_sem_init(ZixSem* sem, unsigned initial) +zix_sem_init(ZixSem* ZIX_NONNULL sem, unsigned initial) { return sem_init(&sem->sem, 0, initial) ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS; } static inline void -zix_sem_destroy(ZixSem* sem) +zix_sem_destroy(ZixSem* ZIX_NONNULL sem) { sem_destroy(&sem->sem); } static inline void -zix_sem_post(ZixSem* sem) +zix_sem_post(ZixSem* ZIX_NONNULL sem) { sem_post(&sem->sem); } static inline ZixStatus -zix_sem_wait(ZixSem* sem) +zix_sem_wait(ZixSem* ZIX_NONNULL sem) { while (sem_wait(&sem->sem)) { if (errno != EINTR) { @@ -221,7 +222,7 @@ zix_sem_wait(ZixSem* sem) } static inline bool -zix_sem_try_wait(ZixSem* sem) +zix_sem_try_wait(ZixSem* ZIX_NONNULL sem) { return (sem_trywait(&sem->sem) == 0); } diff --git a/include/zix/tree.h b/include/zix/tree.h index a6822e1..2ce7490 100644 --- a/include/zix/tree.h +++ b/include/zix/tree.h @@ -42,32 +42,34 @@ typedef struct ZixTreeNodeImpl ZixTreeIter; /// Create a new (empty) tree ZIX_API -ZixTree* -zix_tree_new(bool allow_duplicates, - ZixComparator cmp, - void* cmp_data, - ZixDestroyFunc destroy, - const void* destroy_user_data); +ZixTree* ZIX_ALLOCATED +zix_tree_new(bool allow_duplicates, + ZixComparator ZIX_NONNULL cmp, + void* ZIX_NULLABLE cmp_data, + ZixDestroyFunc ZIX_NULLABLE destroy, + const void* ZIX_NULLABLE destroy_user_data); /// Free `t` ZIX_API void -zix_tree_free(ZixTree* t); +zix_tree_free(ZixTree* ZIX_NULLABLE t); /// Return the number of elements in `t` ZIX_PURE_API size_t -zix_tree_size(const ZixTree* t); +zix_tree_size(const ZixTree* ZIX_NONNULL t); /// Insert the element `e` into `t` and point `ti` at the new element ZIX_API ZixStatus -zix_tree_insert(ZixTree* t, void* e, ZixTreeIter** ti); +zix_tree_insert(ZixTree* ZIX_NONNULL t, + void* ZIX_NULLABLE e, + ZixTreeIter* ZIX_NULLABLE* ZIX_NULLABLE ti); /// Remove the item pointed at by `ti` from `t` ZIX_API ZixStatus -zix_tree_remove(ZixTree* t, ZixTreeIter* ti); +zix_tree_remove(ZixTree* ZIX_NONNULL t, ZixTreeIter* ZIX_NONNULL ti); /** Set `ti` to an element equal to `e` in `t`. @@ -76,52 +78,54 @@ zix_tree_remove(ZixTree* t, ZixTreeIter* ti); */ ZIX_API ZixStatus -zix_tree_find(const ZixTree* t, const void* e, ZixTreeIter** ti); +zix_tree_find(const ZixTree* ZIX_NONNULL t, + const void* ZIX_NULLABLE e, + ZixTreeIter* ZIX_NULLABLE* ZIX_NONNULL ti); /// Return the data associated with the given tree item ZIX_PURE_API -void* -zix_tree_get(const ZixTreeIter* ti); +void* ZIX_NULLABLE +zix_tree_get(const ZixTreeIter* ZIX_NULLABLE ti); /// Return an iterator to the first (smallest) element in `t` ZIX_PURE_API -ZixTreeIter* -zix_tree_begin(ZixTree* t); +ZixTreeIter* ZIX_NULLABLE +zix_tree_begin(ZixTree* ZIX_NONNULL t); /// Return an iterator the the element one past the last element in `t` ZIX_CONST_API -ZixTreeIter* -zix_tree_end(ZixTree* t); +ZixTreeIter* ZIX_NULLABLE +zix_tree_end(ZixTree* ZIX_NONNULL t); /// Return true iff `i` is an iterator to the end of its tree ZIX_CONST_API bool -zix_tree_iter_is_end(const ZixTreeIter* i); +zix_tree_iter_is_end(const ZixTreeIter* ZIX_NULLABLE i); /// Return an iterator to the last (largest) element in `t` ZIX_PURE_API -ZixTreeIter* -zix_tree_rbegin(ZixTree* t); +ZixTreeIter* ZIX_NULLABLE +zix_tree_rbegin(ZixTree* ZIX_NONNULL t); /// Return an iterator the the element one before the first element in `t` ZIX_CONST_API -ZixTreeIter* -zix_tree_rend(ZixTree* t); +ZixTreeIter* ZIX_NULLABLE +zix_tree_rend(ZixTree* ZIX_NONNULL t); /// Return true iff `i` is an iterator to the reverse end of its tree ZIX_CONST_API bool -zix_tree_iter_is_rend(const ZixTreeIter* i); +zix_tree_iter_is_rend(const ZixTreeIter* ZIX_NULLABLE i); /// Return an iterator that points to the element one past `i` ZIX_PURE_API -ZixTreeIter* -zix_tree_iter_next(ZixTreeIter* i); +ZixTreeIter* ZIX_NULLABLE +zix_tree_iter_next(ZixTreeIter* ZIX_NULLABLE i); /// Return an iterator that points to the element one before `i` ZIX_PURE_API -ZixTreeIter* -zix_tree_iter_prev(ZixTreeIter* i); +ZixTreeIter* ZIX_NULLABLE +zix_tree_iter_prev(ZixTreeIter* ZIX_NULLABLE i); /** @} diff --git a/meson.build b/meson.build index 7b8e872..f732a5f 100644 --- a/meson.build +++ b/meson.build @@ -28,6 +28,7 @@ if get_option('strict') c_warnings = [ '-Weverything', '-Wno-bad-function-cast', + '-Wno-nullability-extension', '-Wno-padded', '-Wno-reserved-id-macro', ] diff --git a/src/btree.c b/src/btree.c index 4a8c4f6..7d967b8 100644 --- a/src/btree.c +++ b/src/btree.c @@ -97,6 +97,8 @@ zix_btree_child(const ZixBTreeNode* const node, const unsigned i) ZixBTree* zix_btree_new(const ZixComparator cmp, const void* const cmp_data) { + assert(cmp); + ZixBTree* const t = (ZixBTree*)malloc(sizeof(ZixBTree)); if (!t) { return NULL; @@ -168,6 +170,7 @@ zix_btree_clear(ZixBTree* const t, size_t zix_btree_size(const ZixBTree* const t) { + assert(t); return t->size; } @@ -422,6 +425,8 @@ zix_btree_grow_up(ZixBTree* const t) ZixStatus zix_btree_insert(ZixBTree* const t, void* const e) { + assert(t); + ZixStatus st = ZIX_STATUS_SUCCESS; // Grow up if necessary to ensure the root is not full @@ -723,6 +728,9 @@ zix_btree_remove(ZixBTree* const t, void** const out, ZixBTreeIter* const next) { + assert(t); + assert(out); + ZixBTreeNode* n = t->root; ZixBTreeIter* ti = next; ZixStatus st = ZIX_STATUS_SUCCESS; @@ -806,6 +814,9 @@ zix_btree_find(const ZixBTree* const t, const void* const e, ZixBTreeIter* const ti) { + assert(t); + assert(ti); + ZixBTreeNode* n = t->root; *ti = zix_btree_end_iter; @@ -842,6 +853,9 @@ zix_btree_lower_bound(const ZixBTree* const t, const void* const key, ZixBTreeIter* const ti) { + assert(t); + assert(ti); + *ti = zix_btree_end_iter; ZixBTreeNode* n = t->root; // Current node @@ -911,6 +925,8 @@ zix_btree_get(const ZixBTreeIter ti) ZixBTreeIter zix_btree_begin(const ZixBTree* const t) { + assert(t); + ZixBTreeIter iter = zix_btree_end_iter; if (t->size > 0u) { @@ -946,6 +962,7 @@ zix_btree_iter_equals(const ZixBTreeIter lhs, const ZixBTreeIter rhs) ZixStatus zix_btree_iter_increment(ZixBTreeIter* const i) { + assert(i); assert(!zix_btree_iter_is_end(*i)); // Move to the next value in the current node diff --git a/src/hash.c b/src/hash.c index 5bc9d60..471ccb7 100644 --- a/src/hash.c +++ b/src/hash.c @@ -44,6 +44,10 @@ zix_hash_new(const ZixKeyFunc key_func, const ZixHashFunc hash_func, const ZixKeyEqualFunc equal_func) { + assert(key_func); + assert(hash_func); + assert(equal_func); + ZixHash* const hash = (ZixHash*)malloc(sizeof(ZixHash)); if (!hash) { return NULL; @@ -77,18 +81,21 @@ zix_hash_free(ZixHash* const hash) ZixHashIter zix_hash_begin(const ZixHash* const hash) { + assert(hash); return hash->entries[0u].value ? 0u : zix_hash_next(hash, 0u); } ZixHashIter zix_hash_end(const ZixHash* const hash) { + assert(hash); return hash->n_entries; } ZixHashRecord* zix_hash_get(const ZixHash* hash, const ZixHashIter i) { + assert(hash); assert(i < hash->n_entries); return hash->entries[i].value; @@ -97,6 +104,7 @@ zix_hash_get(const ZixHash* hash, const ZixHashIter i) ZixHashIter zix_hash_next(const ZixHash* const hash, ZixHashIter i) { + assert(hash); do { ++i; } while (i < hash->n_entries && !hash->entries[i].value); @@ -107,6 +115,7 @@ zix_hash_next(const ZixHash* const hash, ZixHashIter i) size_t zix_hash_size(const ZixHash* const hash) { + assert(hash); return hash->count; } @@ -215,6 +224,9 @@ shrink(ZixHash* const hash) ZixHashIter zix_hash_find(const ZixHash* const hash, const ZixHashKey* const key) { + assert(hash); + assert(key); + const ZixHashCode h_nomod = hash->hash_func(key); const size_t h = fold_hash(h_nomod, hash->mask); const ZixHashIter i = find_entry(hash, key, h, h_nomod); @@ -225,6 +237,9 @@ zix_hash_find(const ZixHash* const hash, const ZixHashKey* const key) ZixHashRecord* zix_hash_find_record(const ZixHash* const hash, const ZixHashKey* const key) { + assert(hash); + assert(key); + const ZixHashCode h_nomod = hash->hash_func(key); const size_t h = fold_hash(h_nomod, hash->mask); @@ -237,6 +252,9 @@ zix_hash_plan_insert_prehashed(const ZixHash* const hash, const ZixKeyMatchFunc predicate, const void* const user_data) { + assert(hash); + assert(predicate); + // Calculate an ideal initial position ZixHashInsertPlan pos = {code, fold_hash(code, hash->mask)}; @@ -269,6 +287,9 @@ zix_hash_plan_insert_prehashed(const ZixHash* const hash, ZixHashInsertPlan zix_hash_plan_insert(const ZixHash* const hash, const ZixHashKey* const key) { + assert(hash); + assert(key); + return zix_hash_plan_insert_prehashed( hash, hash->hash_func(key), hash->equal_func, key); } @@ -276,6 +297,7 @@ zix_hash_plan_insert(const ZixHash* const hash, const ZixHashKey* const key) ZixHashRecord* zix_hash_record_at(const ZixHash* const hash, const ZixHashInsertPlan position) { + assert(hash); return hash->entries[position.index].value; } @@ -284,6 +306,9 @@ zix_hash_insert_at(ZixHash* const hash, const ZixHashInsertPlan position, ZixHashRecord* const record) { + assert(hash); + assert(record); + if (hash->entries[position.index].value) { return ZIX_STATUS_EXISTS; } @@ -306,6 +331,9 @@ zix_hash_insert_at(ZixHash* const hash, ZixStatus zix_hash_insert(ZixHash* const hash, ZixHashRecord* const record) { + assert(hash); + assert(record); + const ZixHashKey* const key = hash->key_func(record); const ZixHashInsertPlan position = zix_hash_plan_insert(hash, key); @@ -317,6 +345,9 @@ zix_hash_erase(ZixHash* const hash, const ZixHashIter i, ZixHashRecord** const removed) { + assert(hash); + assert(removed); + // Replace entry with a tombstone *removed = hash->entries[i].value; hash->entries[i].hash = tombstone; @@ -336,6 +367,10 @@ zix_hash_remove(ZixHash* const hash, const ZixHashKey* const key, ZixHashRecord** const removed) { + assert(hash); + assert(key); + assert(removed); + const ZixHashIter i = zix_hash_find(hash, key); return i == hash->n_entries ? ZIX_STATUS_NOT_FOUND diff --git a/test/ring_test.c b/test/ring_test.c index 49cf4f0..61a6d1f 100644 --- a/test/ring_test.c +++ b/test/ring_test.c @@ -18,6 +18,7 @@ #include "zix/ring.h" #include "zix/thread.h" +#include #include #include #include @@ -137,6 +138,7 @@ main(int argc, char** argv) size); ring = zix_ring_new(size); + assert(ring); if (zix_ring_read_space(ring) != 0) { return failure("New ring is not empty\n"); } @@ -163,6 +165,7 @@ main(int argc, char** argv) return failure("Read error\n"); } + assert(ring); zix_ring_reset(ring); if (zix_ring_read_space(ring) > 0) { return failure("Reset did not empty ring.\n"); -- cgit v1.2.1