The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dcursor.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2 of the
4 * License as published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14 */
15
16/** Functions to iterate over a sets and subsets of items in dlists
17 *
18 * @file src/lib/util/dcursor.c
19 *
20 * @note Do not modify collections of items pointed to by a cursor
21 * with non fr_dcursor_* functions over the lifetime of that cursor.
22 *
23 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @copyright 2013-2016 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 * @copyright 2013-2016 The FreeRADIUS Server Project.
26 */
27RCSID("$Id: b54fca9beb8aca1564ba60ac5304ac4c59cf4c59 $")
28
29#include <string.h>
30#include <stdint.h>
31#include <freeradius-devel/util/dcursor.h>
32#include <freeradius-devel/util/pair.h>
33
34/** Return the first item matching the iterator in cursor a and cursor b
35 *
36 * If a and b are not currently set to the same item, b will be reset,
37 * and wound to the item before a's current item.
38 *
39 * @note Both cursors must operate on the same list of items.
40 *
41 * @param[in] a First cursor.
42 * @param[in] b Second cursor.
43 * @return item at the start of the list.
44 *
45 * @hidecallergraph
46 */
48{
49 void *a_item, *b_item;
50
51 if (unlikely(a->dlist != b->dlist)) return NULL;
52
53 a_item = fr_dcursor_head(a);
54 b_item = fr_dcursor_head(b);
55
56 if (a_item == b_item) return a_item;
57
58 return fr_dcursor_intersect_next(a, b);
59}
60
61/** Return the next item matching the iterator in cursor a and cursor b
62 *
63 * If a and b are not currently set to the same item, b will be reset,
64 * and wound to the item before a's current item.
65 *
66 * The purpose of this function is to return items that match both iterators.
67 *
68 * @note Both cursors must operate on the same list of items.
69 *
70 * @param[in] a First cursor.
71 * @param[in] b Second cursor.
72 * @return next item in the list.
73 *
74 * @hidecallergraph
75 */
77{
78 void *a_next, *b_next;
79
80 if (unlikely(a->dlist != b->dlist)) return NULL;
81
82 /*
83 * If either of the cursors lack an iterator
84 * just use cursor_next... i.e. return items
85 * from the list that's actually filtered.
86 */
87 if (!a->iter) return fr_dcursor_next(b);
88 if (!b->iter) return fr_dcursor_next(a);
89
90 /*
91 * Deal with the case where the two iterators
92 * are out of sync.
93 */
94 if (a->current == b->current) {
95 a_next = fr_dcursor_next(a);
96 b_next = fr_dcursor_next(b);
97
98 /*
99 * Fast path...
100 */
101 if (a_next == b_next) return a_next;
102 } else {
103 a_next = fr_dcursor_next(a);
104 }
105
106 if (!a_next) return NULL;
107
108 /*
109 * b_next doesn't match a_next, we don't know
110 * if b is ahead or behind a, so we rewind
111 * b, and compare every item to see if it
112 * matches a.
113 *
114 * This is slow and inefficient, but there's
115 * nothing else we can do for stateful
116 * iterators.
117 */
118 do {
119 for (b_next = fr_dcursor_head(b);
120 b_next;
121 b_next = fr_dcursor_next(b)) if (a_next == b_next) return b_next;
122 } while ((a_next = fr_dcursor_next(a)));
123
124 return NULL;
125}
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
void * fr_dcursor_intersect_head(fr_dcursor_t *a, fr_dcursor_t *b)
Return the first item matching the iterator in cursor a and cursor b.
Definition dcursor.c:47
void * fr_dcursor_intersect_next(fr_dcursor_t *a, fr_dcursor_t *b)
Return the next item matching the iterator in cursor a and cursor b.
Definition dcursor.c:76
fr_dcursor_iter_t iter
Iterator function.
Definition dcursor.h:97
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:288
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
Definition dcursor.h:234
void * current
The current item in the dlist.
Definition dcursor.h:95
fr_dlist_head_t * dlist
Head of the doubly linked list being iterated over.
Definition dcursor.h:94