@@ -145,6 +145,51 @@ OVS_NO_RETURN void ovs_assert_failure(const char *, const char *, const char *);
#define INIT_CONTAINER(OBJECT, POINTER, MEMBER) \
((OBJECT) = NULL, ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER))
+
+/* Multi-variable container iterators.
+ *
+ * The following macros facilitate safe iteration over data structures
+ * contained in objects. It does so by using an internal iterator variable of
+ * the type of the member object pointer (i.e: pointer to the data structure).
+ */
+
+/* Multi-variable iterator variable name.
+ * Returns the name of the internal iterator variable.
+ */
+#define ITER_VAR(NAME) NAME ## __iterator__
+
+/* Multi-variable initialization. Creates an internal iterator variable that
+ * points to the provided pointer. The type of the pointer must be that of the
+ * iterator variable, not the containing object.
+ *
+ * The _EXP version evaluates the given expressions once.
+ */
+#define INIT_MULTIVAR(VAR, MEMBER, POINTER, ...) \
+ INIT_MULTIVAR_EXP(VAR, MEMBER, POINTER, (void) 0)
+
+#define INIT_MULTIVAR_EXP(VAR, MEMBER, POINTER, ...) \
+ OVS_TYPEOF(&(VAR->MEMBER)) ITER_VAR(VAR) = ( __VA_ARGS__ , \
+ ((OVS_TYPEOF(&(VAR->MEMBER))) POINTER))
+
+/* Multi-variable condition.
+ * Evaluates the condition expression (that must be based on the internal
+ * iterator variable). Only if the result of expression is true, the OBJECT is
+ * set to the object containing the current value of the iterator variable.
+ *
+ * It is up to the caller to make sure it is safe to run OBJECT_CONTAINING on
+ * the pointers that verify the condition.
+ */
+#define CONDITION_MULTIVAR(EXPR, VAR, MEMBER) \
+ ((EXPR) ? \
+ (((VAR) = OBJECT_CONTAINING(ITER_VAR(VAR), VAR, MEMBER)), 1) : \
+ (((VAR) = NULL), 0))
+
+/* Multi-variable update.
+ * Evaluates the expresssion that is supposed to update the iterator variable.
+ */
+#define UPDATE_MULTIVAR(EXPR, VAR) \
+ ((EXPR), (VAR) = NULL)
+
/* Returns the number of elements in ARRAY. */
#define ARRAY_SIZE(ARRAY) __ARRAY_SIZE(ARRAY)
Multi-variable loop iterators avoid potential undefined behavior by using an internal iterator variable to perform the iteration and only referencing the containing object (via OBJECT_CONTAINING) if the iterator has been validated via the second expression of the for statement. That way, the user can easily implement a loop that never tries to obtain the object containing NULL or stack-allocated non-contained nodes. Signed-off-by: Adrian Moreno <amorenoz@redhat.com> --- include/openvswitch/util.h | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)