The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
27 RCSID("$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:444
#define unlikely(_x)
Definition: build.h:378
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
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
fr_dcursor_iter_t iter
Iterator function.
Definition: dcursor.h:97
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
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
Definition: dcursor.h:233