summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-09-10 20:11:46 -0400
committerDavid Robillard <d@drobilla.net>2021-09-10 20:54:28 -0400
commit904c1b4d699aeb1ce170f0cd996a01d2d06812e3 (patch)
tree35a4a9f75a395a958ab0ea5fffeca81ce733bbc1
parent1f8c8118f2d42f495dbe6e3adb2a95c87a92e8e0 (diff)
downloadzix-904c1b4d699aeb1ce170f0cd996a01d2d06812e3.tar.gz
zix-904c1b4d699aeb1ce170f0cd996a01d2d06812e3.tar.bz2
zix-904c1b4d699aeb1ce170f0cd996a01d2d06812e3.zip
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.
-rw-r--r--benchmark/tree_bench.c5
-rw-r--r--include/zix/attributes.h11
-rw-r--r--include/zix/bitset.h24
-rw-r--r--include/zix/btree.h55
-rw-r--r--include/zix/digest.h12
-rw-r--r--include/zix/hash.h74
-rw-r--r--include/zix/ring.h24
-rw-r--r--include/zix/sem.h41
-rw-r--r--include/zix/tree.h58
-rw-r--r--meson.build1
-rw-r--r--src/btree.c17
-rw-r--r--src/hash.c35
-rw-r--r--test/ring_test.c3
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 <assert.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -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");