1.1 --- a/src/cx/iterator.h Wed Nov 23 22:40:55 2022 +0100 1.2 +++ b/src/cx/iterator.h Sat Nov 26 16:58:41 2022 +0100 1.3 @@ -40,26 +40,53 @@ 1.4 #include "common.h" 1.5 1.6 /** 1.7 - * Internal iterator struct - use CxIterator. 1.8 + * The base of mutating and non-mutating iterators. 1.9 */ 1.10 -struct cx_iterator_s { 1.11 +struct cx_iterator_base_s { 1.12 /** 1.13 * True iff the iterator points to valid data. 1.14 */ 1.15 __attribute__ ((__nonnull__)) 1.16 - bool (*valid)(struct cx_iterator_s const *); 1.17 + bool (*valid)(void const *); 1.18 1.19 /** 1.20 * Returns a pointer to the current element. 1.21 */ 1.22 __attribute__ ((__nonnull__)) 1.23 - void *(*current)(struct cx_iterator_s const *); 1.24 + void *(*current)(void const *); 1.25 1.26 /** 1.27 * Advances the iterator. 1.28 */ 1.29 __attribute__ ((__nonnull__)) 1.30 - void (*next)(struct cx_iterator_s *); 1.31 + void (*next)(void *); 1.32 + 1.33 + /** 1.34 + * Flag current element for removal, if possible. 1.35 + */ 1.36 + __attribute__ ((__nonnull__)) 1.37 + bool (*flag_removal)(void *); 1.38 + 1.39 + /** 1.40 + * Indicates whether this iterator is muting. 1.41 + */ 1.42 + bool mutating; 1.43 + 1.44 + /** 1.45 + * Internal flag for removing the current element when advancing. 1.46 + */ 1.47 + bool remove; 1.48 +}; 1.49 + 1.50 +/** 1.51 + * Internal iterator struct - use CxMutIterator. 1.52 + */ 1.53 +struct cx_mut_iterator_s { 1.54 + 1.55 + /** 1.56 + * The base properties of this iterator. 1.57 + */ 1.58 + struct cx_iterator_base_s base; 1.59 1.60 /** 1.61 * Handle for the current element, if required. 1.62 @@ -79,7 +106,7 @@ 1.63 /** 1.64 * A pointer to the key. 1.65 */ 1.66 - void *key; 1.67 + void const *key; 1.68 /** 1.69 * A pointer to the value. 1.70 */ 1.71 @@ -97,13 +124,70 @@ 1.72 * Otherwise, this field is usually uninitialized. 1.73 */ 1.74 size_t index; 1.75 +}; 1.76 + 1.77 +/** 1.78 + * Mutating iterator value type. 1.79 + * 1.80 + * An iterator points to a certain element in an (possibly unbounded) chain of elements. 1.81 + * Iterators that are based on collections (which have a defined "first" element), are supposed 1.82 + * to be "position-aware", which means that they keep track of the current index within the collection. 1.83 + * 1.84 + * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the 1.85 + * iterator is based on a collection and the underlying collection is mutated by other means than this iterator 1.86 + * (e.g. elements added or removed), the iterator becomes invalid (regardless of what cxIteratorValid() returns) 1.87 + * and MUST be re-obtained from the collection. 1.88 + * 1.89 + * @see CxIterator 1.90 + */ 1.91 +typedef struct cx_mut_iterator_s CxMutIterator; 1.92 + 1.93 +/** 1.94 + * Internal iterator struct - use CxIterator. 1.95 + */ 1.96 +struct cx_iterator_s { 1.97 1.98 /** 1.99 - * Users may set this to true, if the current element shall be removed from the underlying collection 1.100 - * when the iterator advances. 1.101 - * Has no effect on iterators that are not based on a collection. 1.102 + * The base properties of this iterator. 1.103 */ 1.104 - bool remove; 1.105 + struct cx_iterator_base_s base; 1.106 + 1.107 + /** 1.108 + * Handle for the current element, if required. 1.109 + */ 1.110 + void *elem_handle; 1.111 + 1.112 + /** 1.113 + * Handle for the source collection, if any. 1.114 + */ 1.115 + void const *src_handle; 1.116 + 1.117 + /** 1.118 + * Field for storing a key-value pair. 1.119 + * May be used by iterators that iterate over k/v-collections. 1.120 + */ 1.121 + struct { 1.122 + /** 1.123 + * A pointer to the key. 1.124 + */ 1.125 + void const *key; 1.126 + /** 1.127 + * A pointer to the value. 1.128 + */ 1.129 + void *value; 1.130 + } kv_data; 1.131 + 1.132 + /** 1.133 + * Field for storing a slot number. 1.134 + * May be used by iterators that iterate over multi-bucket collections. 1.135 + */ 1.136 + size_t slot; 1.137 + 1.138 + /** 1.139 + * If the iterator is position-aware, contains the index of the element in the underlying collection. 1.140 + * Otherwise, this field is usually uninitialized. 1.141 + */ 1.142 + size_t index; 1.143 }; 1.144 1.145 /** 1.146 @@ -112,10 +196,11 @@ 1.147 * Iterators that are based on collections (which have a defined "first" element), are supposed 1.148 * to be "position-aware", which means that they keep track of the current index within the collection. 1.149 * 1.150 - * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the 1.151 - * iterator is based on a collection and the underlying collection is mutated (elements added or removed), 1.152 - * the iterator becomes invalid (regardless of what cxIteratorValid() returns) and MUST be re-obtained 1.153 - * from the collection. 1.154 + * @note Objects that are pointed to by an iterator are always mutable through that iterator. However, 1.155 + * this iterator cannot mutate the collection itself (add or remove elements) and any mutation of the 1.156 + * collection by other means make this iterator invalid (regardless of what cxIteratorValid() returns). 1.157 + * 1.158 + * @see CxMutIterator 1.159 */ 1.160 typedef struct cx_iterator_s CxIterator; 1.161 1.162 @@ -124,36 +209,35 @@ 1.163 * 1.164 * This is especially false for past-the-end iterators. 1.165 * 1.166 - * @param iter a pointer to the iterator 1.167 + * @param iter the iterator 1.168 * @return true iff the iterator points to valid data 1.169 */ 1.170 -__attribute__ ((__nonnull__)) 1.171 -static inline bool cxIteratorValid(CxIterator const *iter) { 1.172 - return iter->valid(iter); 1.173 -} 1.174 +#define cxIteratorValid(iter) (iter).base.valid(&(iter)) 1.175 1.176 /** 1.177 * Returns a pointer to the current element. 1.178 * 1.179 * The behavior is undefined if this iterator is invalid. 1.180 * 1.181 - * @param iter a pointer to the iterator 1.182 + * @param iter the iterator 1.183 * @return a pointer to the current element 1.184 */ 1.185 -__attribute__ ((__nonnull__)) 1.186 -static inline void *cxIteratorCurrent(CxIterator const *iter) { 1.187 - return iter->current(iter); 1.188 -} 1.189 +#define cxIteratorCurrent(iter) (iter).base.current(&iter) 1.190 1.191 /** 1.192 * Advances the iterator to the next element. 1.193 * 1.194 - * @param iter a pointer to the iterator 1.195 + * @param iter the iterator 1.196 */ 1.197 -__attribute__ ((__nonnull__)) 1.198 -static inline void cxIteratorNext(CxIterator *iter) { 1.199 - iter->next(iter); 1.200 -} 1.201 +#define cxIteratorNext(iter) (iter).base.next(&iter) 1.202 + 1.203 +/** 1.204 + * Flags the current element for removal. 1.205 + * 1.206 + * @param iter the iterator 1.207 + * @return false if this iterator cannot remove the element 1.208 + */ 1.209 +#define cxIteratorFlagRemoval(iter) (iter).base.flag_removal(&iter) 1.210 1.211 /** 1.212 * Loops over an iterator. 1.213 @@ -162,6 +246,6 @@ 1.214 * @param iter the iterator 1.215 */ 1.216 #define cx_foreach(type, elem, iter) \ 1.217 -for (type elem; cxIteratorValid(&iter) && (elem = (type)cxIteratorCurrent(&iter)) != NULL ; cxIteratorNext(&iter)) // NOLINT(bugprone-macro-parentheses) 1.218 +for (type elem; cxIteratorValid(iter) && (elem = (type)cxIteratorCurrent(iter)) != NULL ; cxIteratorNext(iter)) 1.219 1.220 #endif // UCX_ITERATOR_H