summaryrefslogtreecommitdiff
path: root/utils/ring.h
blob: 42fd676ebdb697b5c95120c04cfaf364091d62cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * Copyright 2006, 2007 Daniel Silverstone <dsilvers@digital-scurf.org>
 *
 * This file is part of NetSurf, http://www.netsurf-browser.org/
 *
 * NetSurf is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * NetSurf is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/** \file
 * Ring list structure.
 *
 * Rings are structures which have an r_next pointer and an r_prev
 * pointer which are always initialised and always point at the next
 * or previous element respectively.
 *
 * The degenerate case of a single element in the ring simply points
 * at itself in both directions. A zero element ring is NULL.
 *
 * Some of the ring functions are specific to the fetcher but may be
 * of use to others and are thus included here.
 */

#ifndef _NETSURF_UTILS_RING_H_
#define _NETSURF_UTILS_RING_H_


/** Insert the given item into the specified ring.
 * Assumes that the element is zeroed as appropriate.
 */
#define RING_INSERT(ring,element) \
	/*LOG(("RING_INSERT(%s, %p(%s))", #ring, element, element->host));*/ \
	if (ring) { \
		element->r_next = ring; \
		element->r_prev = ring->r_prev; \
		ring->r_prev = element; \
		element->r_prev->r_next = element; \
	} else \
		ring = element->r_prev = element->r_next = element

/** Remove the given element from the specified ring.
 * Will zero the element as needed
 */
#define RING_REMOVE(ring, element) \
	/*LOG(("RING_REMOVE(%s, %p(%s)", #ring, element, element->host));*/ \
	if (element->r_next != element ) { \
		/* Not the only thing in the ring */ \
		element->r_next->r_prev = element->r_prev; \
		element->r_prev->r_next = element->r_next; \
		if (ring == element) ring = element->r_next; \
	} else { \
		/* Only thing in the ring */ \
		ring = 0; \
	} \
	element->r_next = element->r_prev = 0

/** Find the element (by hostname) in the given ring, leave it in the
 * provided element variable
 */
#define RING_FINDBYHOST(ring, element, hostname) \
	/*LOG(("RING_FINDBYHOST(%s, %s)", #ring, hostname));*/ \
	if (ring) { \
		bool found = false; \
		element = ring; \
		do { \
			if (strcasecmp(element->host, hostname) == 0) { \
				found = true; \
				break; \
			} \
			element = element->r_next; \
		} while (element != ring); \
		if (!found) element = 0; \
	} else element = 0

/** Find the element (by hostname) in the given ring, leave it in the
 * provided element variable
 */
#define RING_FINDBYLWCHOST(ring, element, lwc_hostname) \
	/*LOG(("RING_FINDBYHOST(%s, %s)", #ring, hostname));*/ \
	if (ring) { \
		bool found = false; \
		element = ring; \
		do { \
			if (lwc_string_isequal(element->host, lwc_hostname, \
					&found) == lwc_error_ok && \
					found == true) { \
				break; \
			} \
			element = element->r_next; \
		} while (element != ring); \
		if (!found) element = 0; \
	} else element = 0

/** Measure the size of a ring and put it in the supplied variable */
#define RING_GETSIZE(ringtype, ring, sizevar) \
	/*LOG(("RING_GETSIZE(%s)", #ring));*/ \
	if (ring) { \
		ringtype *p = ring; \
		sizevar = 0; \
		do { \
			sizevar++; \
			p = p->r_next; \
		} while (p != ring); \
	} else sizevar = 0

/** Count the number of elements in the ring which match the provided hostname */
#define RING_COUNTBYHOST(ringtype, ring, sizevar, hostname) \
	/*LOG(("RING_COUNTBYHOST(%s, %s)", #ring, hostname));*/ \
	if (ring) { \
		ringtype *p = ring; \
		sizevar = 0; \
		do { \
			if (strcasecmp(p->host, hostname) == 0) \
				sizevar++; \
			p = p->r_next; \
		} while (p != ring); \
	} else sizevar = 0

/** Count the number of elements in the ring which match the provided lwc_hostname */
#define RING_COUNTBYLWCHOST(ringtype, ring, sizevar, lwc_hostname) \
	/*LOG(("RING_COUNTBYHOST(%s, %s)", #ring, hostname));*/ \
	if (ring) { \
		ringtype *p = ring; \
		sizevar = 0; \
		do { \
			bool matches = false; \
			/* nsurl guarantees lowercase host */ \
			if (lwc_string_isequal(p->host, lwc_hostname, \
					&matches) == lwc_error_ok) \
                		if (matches) \
					sizevar++; \
			p = p->r_next; \
		} while (p != ring); \
	} else sizevar = 0

/*
 * Ring iteration works as follows:
 *
 * RING_ITERATE_START(ringtype, ring, iteratorptr) {
 *    code_using(iteratorptr);
 * } RING_ITERATE_END(ring, iteratorptr);
 *
 * If you want to stop iterating (e.g. you found your answer)
 * RING_ITERATE_STOP(ring, iteratorptr);
 * You *MUST* abort the iteration if you do something to modify
 * the ring such as deleting or adding an element.
 */

#define RING_ITERATE_START(ringtype, ring, iteratorptr) \
	if (ring != NULL) {				\
		ringtype *iteratorptr = ring;		\
		do {					\
			do {				\
			
#define RING_ITERATE_STOP(ring, iteratorptr)	\
	goto iteration_end_ring##_##iteratorptr

#define RING_ITERATE_END(ring, iteratorptr)		\
			} while (false);		\
			iteratorptr = iteratorptr->r_next;	\
		} while (iteratorptr != ring);		\
	}						\
	iteration_end_ring##_##iteratorptr:

#endif