📄 apr_ring.h
字号:
/** * Splice the sequence ep1..epN into the ring before the first element * (..hp.. becomes ..hp..ep1..epN..) * @param hp Head of the ring * @param ep1 First element in the sequence to splice in * @param epN Last element in the sequence to splice in * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_SPLICE_HEAD(hp, ep1, epN, elem, link) \ APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((hp), elem, link), \ (ep1), (epN), link)/** * Splice the sequence ep1..epN into the ring after the last element * (..hp.. becomes ..ep1..epN..hp..) * @param hp Head of the ring * @param ep1 First element in the sequence to splice in * @param epN Last element in the sequence to splice in * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_SPLICE_TAIL(hp, ep1, epN, elem, link) \ APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((hp), elem, link), \ (ep1), (epN), link)/** * Insert the element nep into the ring before the first element * (..hp.. becomes ..hp..nep..) * @param hp Head of the ring * @param nep Element to insert * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_INSERT_HEAD(hp, nep, elem, link) \ APR_RING_SPLICE_HEAD((hp), (nep), (nep), elem, link)/** * Insert the element nep into the ring after the last element * (..hp.. becomes ..nep..hp..) * @param hp Head of the ring * @param nep Element to insert * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_INSERT_TAIL(hp, nep, elem, link) \ APR_RING_SPLICE_TAIL((hp), (nep), (nep), elem, link)/** * Concatenate ring h2 onto the end of ring h1, leaving h2 empty. * @param h1 Head of the ring to concatenate onto * @param h2 Head of the ring to concatenate * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_CONCAT(h1, h2, elem, link) do { \ if (!APR_RING_EMPTY((h2), elem, link)) { \ APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((h1), elem, link), \ APR_RING_FIRST((h2)), \ APR_RING_LAST((h2)), link); \ APR_RING_INIT((h2), elem, link); \ } \ } while (0)/** * Prepend ring h2 onto the beginning of ring h1, leaving h2 empty. * @param h1 Head of the ring to prepend onto * @param h2 Head of the ring to prepend * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_PREPEND(h1, h2, elem, link) do { \ if (!APR_RING_EMPTY((h2), elem, link)) { \ APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((h1), elem, link), \ APR_RING_FIRST((h2)), \ APR_RING_LAST((h2)), link); \ APR_RING_INIT((h2), elem, link); \ } \ } while (0)/** * Unsplice a sequence of elements from a ring * @warning The unspliced sequence is left with dangling pointers at either end * @param ep1 First element in the sequence to unsplice * @param epN Last element in the sequence to unsplice * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_UNSPLICE(ep1, epN, link) do { \ APR_RING_NEXT(APR_RING_PREV((ep1), link), link) = \ APR_RING_NEXT((epN), link); \ APR_RING_PREV(APR_RING_NEXT((epN), link), link) = \ APR_RING_PREV((ep1), link); \ } while (0)/** * Remove a single element from a ring * @warning The unspliced element is left with dangling pointers at either end * @param ep Element to remove * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_REMOVE(ep, link) \ APR_RING_UNSPLICE((ep), (ep), link)/** * Iterate through a ring * @param ep The current element * @param hp The ring to iterate over * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct * @remark This is the same as either: * <pre> * ep = APR_RING_FIRST(hp); * while (ep != APR_RING_SENTINEL(hp, elem, link)) { * ... * ep = APR_RING_NEXT(ep, link); * } * OR * for (ep = APR_RING_FIRST(hp); * ep != APR_RING_SENTINEL(hp, elem, link); * ep = APR_RING_NEXT(ep, link)) { * ... * } * </pre> * @warning Be aware that you cannot change the value of ep within * the foreach loop, nor can you destroy the ring element it points to. * Modifying the prev and next pointers of the element is dangerous * but can be done if you're careful. If you change ep's value or * destroy the element it points to, then APR_RING_FOREACH * will have no way to find out what element to use for its next * iteration. The reason for this can be seen by looking closely * at the equivalent loops given in the tip above. So, for example, * if you are writing a loop that empties out a ring one element * at a time, APR_RING_FOREACH just won't work for you. Do it * by hand, like so: * <pre> * while (!APR_RING_EMPTY(hp, elem, link)) { * ep = APR_RING_FIRST(hp); * ... * APR_RING_REMOVE(ep, link); * } * </pre> * @deprecated This macro causes more headaches than it's worth. Use * one of the alternatives documented here instead; the clarity gained * in what's really going on is well worth the extra line or two of code. * This macro will be removed at some point in the future. */#define APR_RING_FOREACH(ep, hp, elem, link) \ for ((ep) = APR_RING_FIRST((hp)); \ (ep) != APR_RING_SENTINEL((hp), elem, link); \ (ep) = APR_RING_NEXT((ep), link))/** * Iterate through a ring backwards * @param ep The current element * @param hp The ring to iterate over * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct * @see APR_RING_FOREACH */#define APR_RING_FOREACH_REVERSE(ep, hp, elem, link) \ for ((ep) = APR_RING_LAST((hp)); \ (ep) != APR_RING_SENTINEL((hp), elem, link); \ (ep) = APR_RING_PREV((ep), link))/* Debugging tools: */#ifdef APR_RING_DEBUG#include <stdio.h>#include <assert.h>#define APR_RING_CHECK_ONE(msg, ptr) \ fprintf(stderr, "*** %s %p\n", msg, ptr)#define APR_RING_CHECK(hp, elem, link, msg) \ APR_RING_CHECK_ELEM(APR_RING_SENTINEL(hp, elem, link), elem, link, msg)#define APR_RING_CHECK_ELEM(ep, elem, link, msg) do { \ struct elem *start = (ep); \ struct elem *here = start; \ fprintf(stderr, "*** ring check start -- %s\n", msg); \ do { \ fprintf(stderr, "\telem %p\n", here); \ fprintf(stderr, "\telem->next %p\n", \ APR_RING_NEXT(here, link)); \ fprintf(stderr, "\telem->prev %p\n", \ APR_RING_PREV(here, link)); \ fprintf(stderr, "\telem->next->prev %p\n", \ APR_RING_PREV(APR_RING_NEXT(here, link), link)); \ fprintf(stderr, "\telem->prev->next %p\n", \ APR_RING_NEXT(APR_RING_PREV(here, link), link)); \ if (APR_RING_PREV(APR_RING_NEXT(here, link), link) != here) { \ fprintf(stderr, "\t*** elem->next->prev != elem\n"); \ break; \ } \ if (APR_RING_NEXT(APR_RING_PREV(here, link), link) != here) { \ fprintf(stderr, "\t*** elem->prev->next != elem\n"); \ break; \ } \ here = APR_RING_NEXT(here, link); \ } while (here != start); \ fprintf(stderr, "*** ring check end\n"); \ } while (0)#define APR_RING_CHECK_CONSISTENCY(hp, elem, link) \ APR_RING_CHECK_ELEM_CONSISTENCY(APR_RING_SENTINEL(hp, elem, link),\ elem, link)#define APR_RING_CHECK_ELEM_CONSISTENCY(ep, elem, link) do { \ struct elem *start = (ep); \ struct elem *here = start; \ do { \ assert(APR_RING_PREV(APR_RING_NEXT(here, link), link) == here); \ assert(APR_RING_NEXT(APR_RING_PREV(here, link), link) == here); \ here = APR_RING_NEXT(here, link); \ } while (here != start); \ } while (0)#else/** * Print a single pointer value to STDERR * (This is a no-op unless APR_RING_DEBUG is defined.) * @param msg Descriptive message * @param ptr Pointer value to print */#define APR_RING_CHECK_ONE(msg, ptr)/** * Dump all ring pointers to STDERR, starting with the head and looping all * the way around the ring back to the head. Aborts if an inconsistency * is found. * (This is a no-op unless APR_RING_DEBUG is defined.) * @param hp Head of the ring * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct * @param msg Descriptive message */#define APR_RING_CHECK(hp, elem, link, msg)/** * Loops around a ring and checks all the pointers for consistency. Pops * an assertion if any inconsistency is found. Same idea as APR_RING_CHECK() * except that it's silent if all is well. * (This is a no-op unless APR_RING_DEBUG is defined.) * @param hp Head of the ring * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_CHECK_CONSISTENCY(hp, elem, link)/** * Dump all ring pointers to STDERR, starting with the given element and * looping all the way around the ring back to that element. Aborts if * an inconsistency is found. * (This is a no-op unless APR_RING_DEBUG is defined.) * @param ep The element * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct * @param msg Descriptive message */#define APR_RING_CHECK_ELEM(ep, elem, link, msg)/** * Loops around a ring, starting with the given element, and checks all * the pointers for consistency. Pops an assertion if any inconsistency * is found. Same idea as APR_RING_CHECK_ELEM() except that it's silent * if all is well. * (This is a no-op unless APR_RING_DEBUG is defined.) * @param ep The element * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */#define APR_RING_CHECK_ELEM_CONSISTENCY(ep, elem, link)#endif/** @} */ #endif /* !APR_RING_H */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -