Mon, 18 Aug 2025 23:06:27 +0200
add support for NULL in map iterators
--- a/CHANGELOG Mon Aug 18 23:00:55 2025 +0200 +++ b/CHANGELOG Mon Aug 18 23:06:27 2025 +0200 @@ -21,7 +21,7 @@ * changes grow strategy for the mempory pool to reduce reallocations * changes grow strategy for CxBuffer, which does now take the page size into account * changes the implementation of cx_strreplacen() for improved efficiency - * changes all cxListIterator() without index to also accept NULL as list argument + * changes all cxListIterator() and cxMapIterator() family of functions to also accept NULL as argument * changes insert_element member function of CxList to accept NULL source and return a pointer to the inserted element * fixes critical memory overflow in the stack-based array reallocator (this unfortunately breaks the function signature) * fixes mempool implementation not supporting NULL as argument for realloc
--- a/docs/Writerside/topics/list.h.md Mon Aug 18 23:00:55 2025 +0200 +++ b/docs/Writerside/topics/list.h.md Mon Aug 18 23:06:27 2025 +0200 @@ -290,7 +290,7 @@ The functions with `Mut` in are equivalently, except that they create a [mutating iterator](iterator.h.md#mutating-iterators). Removing elements via a mutating iterator will cause an invocation of the [destructor functions](collection.h.md#destructor-functions) for the removed element. -If is safe to specify an out-of-bounds index, or a `NULL` pointer, in which cases an iterator is returned for which `cxIteratorValid()` returns `false`, immediately. +If is safe to specify an out-of-bounds index, or a `NULL` pointer, in which cases the returned iterator will behave like an iterator over an empty list. ## Reorder
--- a/docs/Writerside/topics/map.h.md Mon Aug 18 23:00:55 2025 +0200 +++ b/docs/Writerside/topics/map.h.md Mon Aug 18 23:06:27 2025 +0200 @@ -282,6 +282,9 @@ If used, the `void*` elements the iterator yields, shall be directly the stored pointers. Otherwise, the iterator shall yield pointers to the map's memory where the value is stored. +It is always safe to call the above functions on a `NULL`-pointer. +In that case, the returned iterator will behave like an iterator over an empty map. + ## Dispose ```C
--- a/src/cx/map.h Mon Aug 18 23:00:55 2025 +0200 +++ b/src/cx/map.h Mon Aug 18 23:06:27 2025 +0200 @@ -280,12 +280,12 @@ * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored values */ -cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIteratorValues(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES); } @@ -298,12 +298,12 @@ * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored keys */ -cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIteratorKeys(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS); } @@ -316,14 +316,14 @@ * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored entries * @see cxMapIteratorKeys() * @see cxMapIteratorValues() */ -cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIterator(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS); } @@ -338,10 +338,9 @@ * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored values */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIteratorValues(CxMap *map); @@ -355,10 +354,9 @@ * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored keys */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIteratorKeys(CxMap *map); @@ -372,12 +370,11 @@ * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored entries * @see cxMapMutIteratorKeys() * @see cxMapMutIteratorValues() */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIterator(CxMap *map);