NetSurf
ring.h
Go to the documentation of this file.
1/*
2 * Copyright 2006, 2007 Daniel Silverstone <dsilvers@digital-scurf.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/** \file
20 * Ring list structure.
21 *
22 * Rings are structures which have an r_next pointer and an r_prev
23 * pointer which are always initialised and always point at the next
24 * or previous element respectively.
25 *
26 * The degenerate case of a single element in the ring simply points
27 * at itself in both directions. A zero element ring is NULL.
28 *
29 * Some of the ring functions are specific to the fetcher but may be
30 * of use to others and are thus included here.
31 */
32
33#ifndef _NETSURF_UTILS_RING_H_
34#define _NETSURF_UTILS_RING_H_
35
36
37/** Insert the given item into the specified ring.
38 * Assumes that the element is zeroed as appropriate.
39 */
40#define RING_INSERT(ring,element) \
41 /*LOG("RING_INSERT(%s, %p(%s))", #ring, element, element->host);*/ \
42 if (ring) { \
43 element->r_next = ring; \
44 element->r_prev = ring->r_prev; \
45 ring->r_prev = element; \
46 element->r_prev->r_next = element; \
47 } else \
48 ring = element->r_prev = element->r_next = element
49
50/** Remove the given element from the specified ring.
51 * Will zero the element as needed
52 */
53#define RING_REMOVE(ring, element) \
54 /*LOG("RING_REMOVE(%s, %p(%s)", #ring, element, element->host);*/ \
55 if (element->r_next != element ) { \
56 /* Not the only thing in the ring */ \
57 element->r_next->r_prev = element->r_prev; \
58 element->r_prev->r_next = element->r_next; \
59 if (ring == element) ring = element->r_next; \
60 } else { \
61 /* Only thing in the ring */ \
62 ring = 0; \
63 } \
64 element->r_next = element->r_prev = 0
65
66/** Find the element (by hostname) in the given ring, leave it in the
67 * provided element variable
68 */
69#define RING_FINDBYLWCHOST(ring, element, lwc_hostname) \
70 /*LOG("RING_FINDBYHOST(%s, %s)", #ring, hostname);*/ \
71 if (ring) { \
72 bool found = false; \
73 element = ring; \
74 do { \
75 if (lwc_string_isequal(element->host, lwc_hostname, \
76 &found) == lwc_error_ok && \
77 found == true) { \
78 break; \
79 } \
80 element = element->r_next; \
81 } while (element != ring); \
82 if (!found) element = 0; \
83 } else element = 0
84
85/** Measure the size of a ring and put it in the supplied variable */
86#define RING_GETSIZE(ringtype, ring, sizevar) \
87 /*LOG("RING_GETSIZE(%s)", #ring);*/ \
88 if (ring) { \
89 ringtype *p = ring; \
90 sizevar = 0; \
91 do { \
92 sizevar++; \
93 p = p->r_next; \
94 } while (p != ring); \
95 } else sizevar = 0
96
97/** Count the number of elements in the ring which match the provided lwc_hostname */
98#define RING_COUNTBYLWCHOST(ringtype, ring, sizevar, lwc_hostname) \
99 /*LOG("RING_COUNTBYHOST(%s, %s)", #ring, hostname);*/ \
100 if (ring) { \
101 ringtype *p = ring; \
102 sizevar = 0; \
103 do { \
104 bool matches = false; \
105 /* nsurl guarantees lowercase host */ \
106 if (lwc_string_isequal(p->host, lwc_hostname, \
107 &matches) == lwc_error_ok) \
108 if (matches) \
109 sizevar++; \
110 p = p->r_next; \
111 } while (p != ring); \
112 } else sizevar = 0
113
114/*
115 * Ring iteration works as follows:
116 *
117 * RING_ITERATE_START(ringtype, ring, iteratorptr) {
118 * code_using(iteratorptr);
119 * } RING_ITERATE_END(ring, iteratorptr);
120 *
121 * If you want to stop iterating (e.g. you found your answer)
122 * RING_ITERATE_STOP(ring, iteratorptr);
123 * You *MUST* abort the iteration if you do something to modify
124 * the ring such as deleting or adding an element.
125 */
126
127#define RING_ITERATE_START(ringtype, ring, iteratorptr) \
128 if (ring != NULL) { \
129 ringtype *iteratorptr = ring; \
130 do { \
131 do { \
132
133#define RING_ITERATE_STOP(ring, iteratorptr) \
134 goto iteration_end_ring##_##iteratorptr
135
136#define RING_ITERATE_END(ring, iteratorptr) \
137 } while (false); \
138 iteratorptr = iteratorptr->r_next; \
139 } while (iteratorptr != ring); \
140 } \
141 iteration_end_ring##_##iteratorptr:
142
143#endif