[asterisk-commits] rmudgett: branch rmudgett/ao2_enhancements r360709 - /team/rmudgett/ao2_enhan...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Mar 28 11:07:45 CDT 2012


Author: rmudgett
Date: Wed Mar 28 11:07:38 2012
New Revision: 360709

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=360709
Log:
Change posted to reviewboard review 1835.

Modified:
    team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h

Modified: team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h?view=diff&rev=360709&r1=360708&r2=360709
==============================================================================
--- team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h (original)
+++ team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h Wed Mar 28 11:07:38 2012
@@ -722,7 +722,7 @@
     OBJ_MULTIPLE - don't stop at first match
     OBJ_POINTER - if set, 'arg' is an object pointer, and a hash table
                   search will be done. If not, a traversal is done.
-    OBJ_KEY - if set, 'arg', is a hashable item that is not an object.
+    OBJ_KEY - if set, 'arg', is a container key item that is not an object.
               Similar to OBJ_POINTER and mutually exclusive.
 
   -  \b ao2_callback(c, flags, fn, arg)
@@ -737,7 +737,7 @@
          OBJ_POINTER  - if set, 'arg' is an object pointer, and a hash table
                         search will be done. If not, a traversal is done through
                         all the hash table 'buckets'..
-         OBJ_KEY      - if set, 'arg', is a hashable item that is not an object.
+         OBJ_KEY      - if set, 'arg', is a container key item that is not an object.
                         Similar to OBJ_POINTER and mutually exclusive.
       - fn is a func that returns int, and takes 3 args:
         (void *obj, void *arg, int flags);
@@ -795,32 +795,6 @@
  */
 
 /*! \brief
- * Type of a generic callback function
- * \param obj  pointer to the (user-defined part) of an object.
- * \param arg callback argument from ao2_callback()
- * \param flags flags from ao2_callback()
- *
- * The return values are a combination of enum _cb_results.
- * Callback functions are used to search or manipulate objects in a container.
- */
-typedef int (ao2_callback_fn)(void *obj, void *arg, int flags);
-
-/*! \brief
- * Type of a generic callback function
- * \param obj pointer to the (user-defined part) of an object.
- * \param arg callback argument from ao2_callback()
- * \param data arbitrary data from ao2_callback()
- * \param flags flags from ao2_callback()
- *
- * The return values are a combination of enum _cb_results.
- * Callback functions are used to search or manipulate objects in a container.
- */
-typedef int (ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags);
-
-/*! \brief a very common callback is one that matches by address. */
-ao2_callback_fn ao2_match_by_addr;
-
-/*! \brief
  * A callback function will return a combination of CMP_MATCH and CMP_STOP.
  * The latter will terminate the search in a container.
  */
@@ -830,7 +804,7 @@
 };
 
 /*! \brief
- * Flags passed to ao2_callback() and ao2_hash_fn() to modify its behaviour.
+ * Flags passed to ao2_callback(), ao2_hash_fn(), and ao2_sort_fn() to modify its behaviour.
  */
 enum search_flags {
 	/*! Unlink the object for which the callback function
@@ -875,25 +849,136 @@
 	 */
 	OBJ_NOLOCK = (1 << 5),
 	/*!
-	 * \brief The data is hashable, but is not an object.
+	 * \brief The data is a container key, but is not an object.
 	 *
 	 * \details
 	 * This can be used when you want to be able to pass custom data
-	 * to the container's stored ao2_hash_fn and ao2_find
+	 * to the container's stored ao2_hash_fn, ao2_sort_fn, and ao2_find
 	 * ao2_callback_fn functions that is not a full object, but
 	 * perhaps just a string.
 	 *
 	 * \note OBJ_KEY and OBJ_POINTER are mutually exclusive options.
 	 */
 	OBJ_KEY = (1 << 6),
+	/*! \brief Traverse in ascending order (First to last container object) */
+	OBJ_ORDER_ASCENDING = (0 << 7),
+	/*! \brief Traverse in decending order (Last to first container object) */
+	OBJ_ORDER_DECENDING = (1 << 7),
+	/*! \brief Traverse in pre-order (Node then childeren, for tree container) */
+	OBJ_ORDER_PRE = (2 << 7),
+	/*! \brief Traverse in post-order (Childeren then node, for tree container) */
+	OBJ_ORDER_POST = (3 << 7),
+	OBJ_ORDER_MASK = (3 << 7),
 };
 
 /*!
+ * \brief Options available when allocating an ao2 container object.
+ *
+ * \note Each option is open to some interpretation by the
+ * container type as long as it makes sence with the option
+ * name.
+ */
+enum ao2_container_opts {
+	/*!
+	 * \brief Insert objects at the end of the container.
+	 *
+	 * \note If an ao2_sort_fn is provided, the object is inserted
+	 * after any duplicates.
+	 *
+	 * \note Hash containers insert the object in the computed hash
+	 * bucket in the indicated manner.
+	 */
+	AO2_CONTAINER_ALLOC_OPT_INSERT_END = (0 << 0),
+	/*!
+	 * \brief Insert objects at the beginning of the container.
+	 *
+	 * \note If an ao2_sort_fn is provided, the object is inserted
+	 * before any duplicates.
+	 *
+	 * \note Hash containers insert the object in the computed hash
+	 * bucket in the indicated manner.
+	 */
+	AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN = (1 << 0),
+
+	/*!
+	 * \brief Allow duplicate keyed objects in container.
+	 */
+	AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW = (0 << 1),
+	/*!
+	 * \brief Reject duplicate keyed objects in container.
+	 */
+	AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT = (1 << 1),
+	/*!
+	 * \brief Reject duplicate objects in container.
+	 *
+	 * \details Don't link the same object into the container twice.
+	 * However, you can link a different object with the same key.
+	 *
+	 * \note It is assumed that the objects are located where the
+	 * container key says they should be located.
+	 */
+	AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT = (2 << 1),
+	/*!
+	 * \brief Replace duplicate keyed objects in container.
+	 *
+	 * \details The existing duplicate object is removed and the new
+	 * object takes the old object's place.
+	 */
+	AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE = (3 << 1),
+	/*! \brief The ao2 container object duplicate option field mask. */
+	AO2_CONTAINER_ALLOC_OPT_DUPS_MASK = (3 << 1),
+};
+
+/*! \brief
+ * Type of a generic callback function
+ * \param obj  pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * The return values are a combination of enum _cb_results.
+ * Callback functions are used to search or manipulate objects in a container.
+ */
+typedef int (ao2_callback_fn)(void *obj, void *arg, int flags);
+
+/*! \brief A common ao2_callback is one that matches by address. */
+int ao2_match_by_addr(void *obj, void *arg, int flags);
+
+/*! \brief
+ * Type of a generic callback function
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param data arbitrary data from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * The return values are a combination of enum _cb_results.
+ * Callback functions are used to search or manipulate objects in a container.
+ */
+typedef int (ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags);
+
+/*!
  * Type of a generic function to generate a hash value from an object.
- * flags is ignored at the moment. Eventually, it will include the
- * value of OBJ_POINTER passed to ao2_callback().
- */
-typedef int (ao2_hash_fn)(const void *obj, const int flags);
+ *
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param flags flags from ao2_callback()
+ *   OBJ_KEY - if set, 'obj', is a container key item that is not an object.
+ *
+ * \return Computed hash value.
+ */
+typedef int (ao2_hash_fn)(const void *obj, int flags);
+
+/*!
+ * \brief Type of generic container sort function.
+ *
+ * \param obj_left pointer to the (user-defined part) of an object.
+ * \param obj_right pointer to the (user-defined part) of an object.
+ * \param flags flags from ao2_callback()
+ *   OBJ_KEY - if set, 'obj_right', is a container key item that is not an object.
+ *
+ * \retval <0 if obj_left < obj_right
+ * \retval =0 if obj_left == obj_right
+ * \retval >0 if obj_left > obj_right
+ */
+typedef int (ao2_sort_fn)(const void *obj_left, const void *obj_right, int flags);
 
 /*! \name Object Containers
  * Here start declarations of containers.
@@ -910,57 +995,142 @@
  *
  * \param options Container ao2 object options (See enum ao2_alloc_opts)
  * \param n_buckets Number of buckets for hash
- * \param hash_fn Pointer to a function computing a hash value.
+ * \param hash_fn Pointer to a function computing a hash value. (NULL if everyting goes in first bucket.)
  * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
  * \param tag used for debugging.
  *
  * \return A pointer to a struct container.
  *
  * \note Destructor is set implicitly.
- */
-
-#if defined(REF_DEBUG)
+ * \note This is legacy container creation that is mapped to the new method.
+ */
 
 #define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
-	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+	ao2_t_container_alloc_hash((options), 0, (n_buckets), (hash_fn), NULL, (cmp_fn), (tag))
 #define ao2_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
-	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+	ao2_container_alloc_hash((options), 0, (n_buckets), (hash_fn), NULL, (cmp_fn))
 
 #define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
-	__ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+	ao2_t_container_alloc_options(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), (tag))
 #define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
-	__ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
-
-#elif defined(__AST_DEBUG_MALLOC)
-
-#define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
-	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-#define ao2_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
-	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-
-#define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
-	__ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-#define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
-	__ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-
-#else
-
-#define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
-	__ao2_container_alloc((options), (n_buckets), (hash_fn), (cmp_fn))
-#define ao2_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
-	__ao2_container_alloc((options), (n_buckets), (hash_fn), (cmp_fn))
-
-#define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
-	__ao2_container_alloc(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn))
-#define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
-	__ao2_container_alloc(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn))
-
-#endif
-
+	ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn))
+
+/* BUGBUG for legacy precompiled modules. Should be able to remove since it is trunk. */
 struct ao2_container *__ao2_container_alloc(unsigned int options,
 	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn);
 struct ao2_container *__ao2_container_alloc_debug(unsigned int options,
 	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
+	const char *tag, const char *file, int line, const char *funcname, int ref_debug);
+
+/*!
+ * \brief Allocate and initialize a hash container with the desired number of buckets.
+ *
+ * \details
+ * We allocate space for a struct astobj_container, struct container
+ * and the buckets[] array.
+ *
+ * \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
+ * \param container_options Container behaviour options (See enum ao2_container_opts)
+ * \param n_buckets Number of buckets for hash
+ * \param hash_fn Pointer to a function computing a hash value. (NULL if everyting goes in first bucket.)
+ * \param sort_fn Pointer to a sort function. (NULL if buckets not sorted.)
+ * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
+ * \param tag used for debugging.
+ *
+ * \return A pointer to a struct container.
+ *
+ * \note Destructor is set implicitly.
+ */
+
+#if defined(REF_DEBUG)
+
+#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
+	__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
+	__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+
+#elif defined(__AST_DEBUG_MALLOC)
+
+#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
+	__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
+	__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+
+#else
+
+#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
+	__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn))
+#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
+	__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn))
+
+#endif
+
+struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options, unsigned int container_options,
+	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn);
+struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options, unsigned int container_options,
+	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
+	const char *tag, const char *file, int line, const char *funcname, int ref_debug);
+
+/*!
+ * \brief Allocate and initialize a list container.
+ *
+ * \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
+ * \param container_options Container behaviour options (See enum ao2_container_opts)
+ * \param sort_fn Pointer to a sort function. (NULL if list not sorted.)
+ * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
+ * \param tag used for debugging.
+ *
+ * \return A pointer to a struct container.
+ *
+ * \note Destructor is set implicitly.
+ * \note Implemented as a degenerate hash table.
+ */
+#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
+	ao2_t_container_alloc_hash((ao2_options), (container_options), 1, NULL, (sort_fn), (cmp_fn), (tag))
+#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
+	ao2_container_alloc_hash((ao2_options), (container_options), 1, NULL, (sort_fn), (cmp_fn))
+
+/*!
+ * \brief Allocate and initialize a red-black tree container.
+ *
+ * \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
+ * \param container_options Container behaviour options (See enum ao2_container_opts)
+ * \param sort_fn Pointer to a sort function. (NULL if buckets not sorted.)
+ * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
+ * \param tag used for debugging.
+ *
+ * \return A pointer to a struct container.
+ *
+ * \note Destructor is set implicitly.
+ */
+
+#if defined(REF_DEBUG)
+
+#define ao2_t_container_alloc_tree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
+	__ao2_container_alloc_tree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+#define ao2_container_alloc_tree(ao2_options, container_options, , sort_fn, cmp_fn) \
+	__ao2_container_alloc_tree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+
+#elif defined(__AST_DEBUG_MALLOC)
+
+#define ao2_t_container_alloc_tree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
+	__ao2_container_alloc_tree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_container_alloc_tree(ao2_options, container_options, sort_fn, cmp_fn) \
+	__ao2_container_alloc_tree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+
+#else
+
+#define ao2_t_container_alloc_tree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
+	__ao2_container_alloc_tree((ao2_options), (container_options), (sort_fn), (cmp_fn))
+#define ao2_container_alloc_tree(ao2_options, container_options, sort_fn, cmp_fn) \
+	__ao2_container_alloc_tree((ao2_options), (container_options), (sort_fn), (cmp_fn))
+
+#endif
+
+struct ao2_container *__ao2_container_alloc_tree(unsigned int ao2_options, unsigned int container_options,
+	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn);
+struct ao2_container *__ao2_container_alloc_tree_debug(unsigned int ao2_options, unsigned int container_options,
+	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
 	const char *tag, const char *file, int line, const char *funcname, int ref_debug);
 
 /*! \brief
@@ -1121,10 +1291,10 @@
  *  the callback.
  *   - If OBJ_NODATA is set, ao2_callback will return NULL. No refcounts
  *     of any of the traversed objects will be incremented.
- *     On the converse, if it is NOT set (the default), The ref count
- *     of each object for which CMP_MATCH was set will be incremented,
- *     and you will have no way of knowing which those are, until
- *     the multiple-object-return functionality is implemented.
+ *     On the converse, if it is NOT set (the default), the ref count
+ *     of the first matching object will be incremented and returned.  If
+ *     OBJ_MULTIPLE is set, the ref count of all matching objects will
+ *     be incremented in an iterator for a temporary container and returned.
  *   - If OBJ_POINTER is set, the traversed items will be restricted
  *     to the objects in the bucket that the object key hashes to.
  * \param cb_fn A function pointer, that will be called on all
@@ -1143,7 +1313,7 @@
  * \param tag used for debugging.
  * \return when OBJ_MULTIPLE is not included in the flags parameter,
  *         the return value will be either the object found or NULL if no
- *         no matching object was found. if OBJ_MULTIPLE is included,
+ *         no matching object was found.  If OBJ_MULTIPLE is included,
  *         the return value will be a pointer to an ao2_iterator object,
  *         which must be destroyed with ao2_iterator_destroy() when the
  *         caller no longer needs it.
@@ -1165,11 +1335,11 @@
  * on objects according on flags passed.
  * XXX describe better
  * The comparison is done calling the compare function set implicitly.
- * The p pointer can be a pointer to an object or to a key,
+ * The arg pointer can be a pointer to an object or to a key,
  * we can say this looking at flags value.
- * If p points to an object we will search for the object pointed
+ * If arg points to an object we will search for the object pointed
  * by this value, otherwise we search for a key value.
- * If the key is not unique we only find the first matching valued.
+ * If the key is not unique we only find the first matching value.
  *
  * The use of flags argument is the follow:
  *
@@ -1180,7 +1350,7 @@
  *      OBJ_MULTIPLE            return multiple matches
  *                              Default is no.
  *      OBJ_POINTER             the pointer is an object pointer
- *      OBJ_KEY                 the pointer is to a hashable key
+ *      OBJ_KEY                 the pointer is to a container key
  *
  * \note When the returned object is no longer in use, ao2_ref() should
  * be used to free the additional reference possibly created by this function.
@@ -1384,15 +1554,22 @@
 	 * locked already.
 	 */
 	AO2_ITERATOR_DONTLOCK = (1 << 0),
-	/*! Indicates that the iterator was dynamically allocated by
+	/*!
+	 * Indicates that the iterator was dynamically allocated by
 	 * astobj2 API and should be freed by ao2_iterator_destroy().
 	 */
 	AO2_ITERATOR_MALLOCD = (1 << 1),
-	/*! Indicates that before the iterator returns an object from
+	/*!
+	 * Indicates that before the iterator returns an object from
 	 * the container being iterated, the object should be unlinked
 	 * from the container.
 	 */
 	AO2_ITERATOR_UNLINK = (1 << 2),
+	/*!
+	 * Iterate in decending order (Last to first container object)
+	 * (Otherwise ascending order)
+	 */
+	AO2_ITERATOR_DECENDING = (1 << 3),
 };
 
 /*!




More information about the asterisk-commits mailing list