diff -r eb48f716b31c -r e10457d74fe1 src/ucx/cx/iterator.h
--- a/src/ucx/cx/iterator.h	Mon Feb 10 17:44:51 2025 +0100
+++ b/src/ucx/cx/iterator.h	Sun Mar 02 18:10:52 2025 +0100
@@ -26,12 +26,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 /**
- * \file iterator.h
- * \brief Interface for iterator implementations.
- * \author Mike Becker
- * \author Olaf Wintermann
- * \version 3.0
- * \copyright 2-Clause BSD License
+ * @file iterator.h
+ * @brief Interface for iterator implementations.
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ * @copyright 2-Clause BSD License
  */
 
 #ifndef UCX_ITERATOR_H
@@ -39,51 +38,41 @@
 
 #include "common.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
- * The base of mutating and non-mutating iterators.
+ * Common data for all iterators.
  */
 struct cx_iterator_base_s {
     /**
-     * True iff the iterator points to valid data.
+     * True if the iterator points to valid data.
      */
-    __attribute__ ((__nonnull__))
-    bool (*valid)(void const *);
+    bool (*valid)(const void *);
 
     /**
      * Returns a pointer to the current element.
      *
      * When valid returns false, the behavior of this function is undefined.
      */
-    __attribute__ ((__nonnull__))
-    void *(*current)(void const *);
+    void *(*current)(const void *);
 
     /**
      * Original implementation in case the function needs to be wrapped.
      */
-    __attribute__ ((__nonnull__))
-    void *(*current_impl)(void const *);
+    void *(*current_impl)(const void *);
 
     /**
      * Advances the iterator.
      *
      * When valid returns false, the behavior of this function is undefined.
      */
-    __attribute__ ((__nonnull__))
     void (*next)(void *);
-
-    /**
-     * Flag current element for removal, if possible.
-     *
-     * When valid returns false, the behavior of this function is undefined.
-     */
-    __attribute__ ((__nonnull__))
-    bool (*flag_removal)(void *);
-
     /**
      * Indicates whether this iterator may remove elements.
      */
     bool mutating;
-
     /**
      * Internal flag for removing the current element when advancing.
      */
@@ -91,138 +80,82 @@
 };
 
 /**
- * Internal iterator struct - use CxMutIterator.
+ * Convenience type definition for the base structure of an iterator.
+ * @see #CX_ITERATOR_BASE
+ */
+typedef struct cx_iterator_base_s CxIteratorBase;
+
+/**
+ * Declares base attributes for an iterator.
+ * Must be the first member of an iterator structure.
  */
-struct cx_mut_iterator_s {
+#define CX_ITERATOR_BASE struct cx_iterator_base_s base
+
+/**
+ * Internal iterator struct - use CxIterator.
+ */
+struct cx_iterator_s {
+    /**
+     * Inherited common data for all iterators.
+     */
+    CX_ITERATOR_BASE;
 
     /**
-     * The base properties of this iterator.
-     */
-    struct cx_iterator_base_s base;
-
-    /**
-     * Handle for the current element, if required.
+     * Handle for the current element.
      */
     void *elem_handle;
 
     /**
      * Handle for the source collection, if any.
      */
-    void *src_handle;
-
-    /**
-     * Field for storing a key-value pair.
-     * May be used by iterators that iterate over k/v-collections.
-     */
-    struct {
+    union {
         /**
-         * A pointer to the key.
+         * Access for mutating iterators.
          */
-        void const *key;
+        void *m;
         /**
-         * A pointer to the value.
+         * Access for normal iterators.
          */
-        void *value;
-    } kv_data;
-
-    /**
-     * Field for storing a slot number.
-     * May be used by iterators that iterate over multi-bucket collections.
-     */
-    size_t slot;
+        const void *c;
+    } src_handle;
 
     /**
      * If the iterator is position-aware, contains the index of the element in the underlying collection.
      * Otherwise, this field is usually uninitialized.
      */
     size_t index;
+
+    /**
+     * The size of an individual element.
+     */
+    size_t elem_size;
+
+    /**
+     * May contain the total number of elements, if known.
+     * Shall be set to @c SIZE_MAX when the total number is unknown during iteration.
+     */
+    size_t elem_count;
 };
 
 /**
- * Mutating iterator value type.
- *
- * An iterator points to a certain element in an (possibly unbounded) chain of elements.
- * Iterators that are based on collections (which have a defined "first" element), are supposed
- * to be "position-aware", which means that they keep track of the current index within the collection.
- *
- * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the
- * iterator is based on a collection and the underlying collection is mutated by other means than this iterator
- * (e.g. elements added or removed), the iterator becomes invalid (regardless of what cxIteratorValid() returns)
- * and MUST be re-obtained from the collection.
+ * Iterator type.
  *
- * @see CxIterator
- */
-typedef struct cx_mut_iterator_s CxMutIterator;
-
-/**
- * Internal iterator struct - use CxIterator.
- */
-struct cx_iterator_s {
-
-    /**
-     * The base properties of this iterator.
-     */
-    struct cx_iterator_base_s base;
-
-    /**
-     * Handle for the current element, if required.
-     */
-    void *elem_handle;
-
-    /**
-     * Handle for the source collection, if any.
-     */
-    void const *src_handle;
-
-    /**
-     * Field for storing a key-value pair.
-     * May be used by iterators that iterate over k/v-collections.
-     */
-    struct {
-        /**
-         * A pointer to the key.
-         */
-        void const *key;
-        /**
-         * A pointer to the value.
-         */
-        void *value;
-    } kv_data;
-
-    /**
-     * Field for storing a slot number.
-     * May be used by iterators that iterate over multi-bucket collections.
-     */
-    size_t slot;
-
-    /**
-     * If the iterator is position-aware, contains the index of the element in the underlying collection.
-     * Otherwise, this field is usually uninitialized.
-     */
-    size_t index;
-};
-
-/**
- * Iterator value type.
  * An iterator points to a certain element in a (possibly unbounded) chain of elements.
  * Iterators that are based on collections (which have a defined "first" element), are supposed
  * to be "position-aware", which means that they keep track of the current index within the collection.
  *
  * @note Objects that are pointed to by an iterator are always mutable through that iterator. However,
- * this iterator cannot mutate the collection itself (add or remove elements) and any mutation of the
- * collection by other means makes this iterator invalid (regardless of what cxIteratorValid() returns).
- *
- * @see CxMutIterator
+ * any concurrent mutation of the collection other than by this iterator makes this iterator invalid,
+ * and it must not be used anymore.
  */
 typedef struct cx_iterator_s CxIterator;
 
 /**
  * Checks if the iterator points to valid data.
  *
- * This is especially false for past-the-end iterators.
- *
  * @param iter the iterator
- * @return true iff the iterator points to valid data
+ * @retval true if the iterator points to valid data
+ * @retval false if the iterator already moved past the end
  */
 #define cxIteratorValid(iter) (iter).base.valid(&(iter))
 
@@ -233,6 +166,7 @@
  *
  * @param iter the iterator
  * @return a pointer to the current element
+ * @see cxIteratorValid()
  */
 #define cxIteratorCurrent(iter) (iter).base.current(&iter)
 
@@ -244,15 +178,27 @@
 #define cxIteratorNext(iter) (iter).base.next(&iter)
 
 /**
- * Flags the current element for removal.
+ * Flags the current element for removal, if this iterator is mutating.
+ *
+ * Does nothing for non-mutating iterators.
  *
  * @param iter the iterator
- * @return false if this iterator cannot remove the element
  */
-#define cxIteratorFlagRemoval(iter) (iter).base.flag_removal(&iter)
+#define cxIteratorFlagRemoval(iter) (iter).base.remove |= (iter).base.mutating
+
+/**
+ * Obtains a reference to an arbitrary iterator.
+ *
+ * This is useful for APIs that expect some iterator as an argument.
+ *
+ * @param iter the iterator
+ * @return (@c struct @c cx_iterator_base_s*) a pointer to the iterator
+ */
+#define cxIteratorRef(iter) &((iter).base)
 
 /**
  * Loops over an iterator.
+ *
  * @param type the type of the elements
  * @param elem the name of the iteration variable
  * @param iter the iterator
@@ -260,4 +206,108 @@
 #define cx_foreach(type, elem, iter) \
 for (type elem; cxIteratorValid(iter) && (elem = (type)cxIteratorCurrent(iter)) != NULL ; cxIteratorNext(iter))
 
+
+/**
+ * Creates an iterator for the specified plain array.
+ *
+ * The @p array can be @c NULL in which case the iterator will be immediately
+ * initialized such that #cxIteratorValid() returns @c false.
+ *
+ * This iterator yields the addresses of the array elements.
+ * If you want to iterator over an array of pointers, you can
+ * use cxIteratorPtr() to create an iterator which directly
+ * yields the stored pointers.
+ *
+ * @param array a pointer to the array (can be @c NULL)
+ * @param elem_size the size of one array element
+ * @param elem_count the number of elements in the array
+ * @return an iterator for the specified array
+ * @see cxIteratorPtr()
+ */
+cx_attr_nodiscard
+cx_attr_export
+CxIterator cxIterator(
+        const void *array,
+        size_t elem_size,
+        size_t elem_count
+);
+
+/**
+ * Creates a mutating iterator for the specified plain array.
+ *
+ * While the iterator is in use, the array may only be altered by removing
+ * elements through #cxIteratorFlagRemoval(). Every other change to the array
+ * will bring this iterator to an undefined state.
+ *
+ * When @p remove_keeps_order is set to @c false, removing an element will only
+ * move the last element to the position of the removed element, instead of
+ * moving all subsequent elements by one. Usually, when the order of elements is
+ * not important, this parameter should be set to @c false.
+ *
+ * The @p array can be @c NULL in which case the iterator will be immediately
+ * initialized such that #cxIteratorValid() returns @c false.
+ *
+ *
+ * @param array a pointer to the array (can be @c NULL)
+ * @param elem_size the size of one array element
+ * @param elem_count the number of elements in the array
+ * @param remove_keeps_order @c true if the order of elements must be preserved
+ * when removing an element
+ * @return an iterator for the specified array
+ */
+cx_attr_nodiscard
+cx_attr_export
+CxIterator cxMutIterator(
+        void *array,
+        size_t elem_size,
+        size_t elem_count,
+        bool remove_keeps_order
+);
+
+/**
+ * Creates an iterator for the specified plain pointer array.
+ *
+ * This iterator assumes that every element in the array is a pointer
+ * and yields exactly those pointers during iteration (while in contrast
+ * an iterator created with cxIterator() would return the addresses
+ * of those pointers within the array).
+ *
+ * @param array a pointer to the array (can be @c NULL)
+ * @param elem_count the number of elements in the array
+ * @return an iterator for the specified array
+ * @see cxIterator()
+ */
+cx_attr_nodiscard
+cx_attr_export
+CxIterator cxIteratorPtr(
+        const void *array,
+        size_t elem_count
+);
+
+/**
+ * Creates a mutating iterator for the specified plain pointer array.
+ *
+ * This is the mutating variant of cxIteratorPtr(). See also
+ * cxMutIterator().
+ *
+ * @param array a pointer to the array (can be @c NULL)
+ * @param elem_count the number of elements in the array
+ * @param remove_keeps_order @c true if the order of elements must be preserved
+ * when removing an element
+ * @return an iterator for the specified array
+ * @see cxMutIterator()
+ * @see cxIteratorPtr()
+ */
+cx_attr_nodiscard
+cx_attr_export
+CxIterator cxMutIteratorPtr(
+        void *array,
+        size_t elem_count,
+        bool remove_keeps_order
+);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif // UCX_ITERATOR_H