All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
target/Linux-x86_64/include/citrusleaf/cf_ll.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2008-2013 by Aerospike.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  *****************************************************************************/
22 #pragma once
23 
24 /*
25  * SYNOPSIS
26  * LinkedList
27  * Sometimes the answer is a doubly linked list. It's not that frequent, but
28  * all the corner cases in a double linked list can be annoying.
29  *
30  * the current use pattern is the caller creates a structure that starts with a 'cf_ll_element',
31  * ie, can be cast to a cf_ll_element. The caller allocates and frees the memory.
32  * (There are far cooler ways to do this, so if you want to improve this, go ahead!
33  *
34  */
35 
36 #include <pthread.h>
37 #include <inttypes.h>
38 #include <citrusleaf/cf_types.h>
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /******************************************************************************
45  * CONSTANTS
46  ******************************************************************************/
47 
48 #define CF_LL_REDUCE_DELETE (1)
49 #define CF_LL_REDUCE_INSERT (2)
50 #define CF_LL_REDUCE_MATCHED (3)
51 #define CF_LL_REDUCE_NOT_MATCHED (4)
52 /******************************************************************************
53  * TYPES
54  ******************************************************************************/
55 
56 typedef struct cf_ll_s cf_ll;
57 typedef struct cf_ll_element_s cf_ll_element;
58 typedef struct cf_ll_iterator_s cf_ll_iterator;
59 typedef int (*cf_ll_reduce_fn) (cf_ll_element * e, void *udata);
60 typedef void (*cf_ll_destructor) (cf_ll_element * e);
61 
62 /**
63  * cf_ll_element
64  * The element that must be included in structures
65  * This element should be the FIRST element in the structure where it is being included
66  */
67 struct cf_ll_element_s {
68  cf_ll_element * next;
69  cf_ll_element * prev;
70 };
71 
72 /**
73  * cf_ll_iterator
74  * the linked list iterator
75  */
76 struct cf_ll_iterator_s {
77  cf_ll_element * next;
78  bool forward;
79 };
80 /**
81  * cf_ll
82  * the linked list container
83  */
84 struct cf_ll_s {
85  cf_ll_element * head;
86  cf_ll_element * tail;
88  uint32_t sz;
89  bool uselock;
90 #ifdef EXTERNAL_LOCKS
91  void * LOCK;
92 #else
93  pthread_mutex_t LOCK;
94 #endif //EXTERNAL_LOCKS
95 };
96 
97 /******************************************************************************
98  * INLINE FUNCTIONS
99  ******************************************************************************/
100 
101 static inline cf_ll_element *cf_ll_get_head(cf_ll *ll) {
102  return(ll->head);
103 }
104 
105 static inline cf_ll_element *cf_ll_get_tail(cf_ll *ll) {
106  return(ll->tail);
107 }
108 
109 static inline cf_ll_element *cf_ll_get_next(cf_ll_element *e) {
110  return(e->next);
111 }
112 
113 static inline cf_ll_element *cf_ll_get_prev(cf_ll_element *e) {
114  return(e->prev);
115 }
116 
117 /******************************************************************************
118  * FUNCTIONS
119  ******************************************************************************/
120 
121 /**
122  * Insert to head
123  */
124 void cf_ll_prepend(cf_ll *ll, cf_ll_element *e );
125 
126 /**
127  * Insert to tail
128  */
129 void cf_ll_append(cf_ll *ll, cf_ll_element *e );
130 
131 /**
132  * Insert after element !! warning! consider threadsafety before using this call!
133  */
134 void cf_ll_insert_after(cf_ll *ll, cf_ll_element *cur, cf_ll_element *ins);
135 
136 /**
137  * Insert before element !! warning! consider threadsafey before using this call!
138  */
139 void cf_ll_insert_before(cf_ll *ll, cf_ll_element *cur, cf_ll_element *ins);
140 
141 /**
142  * delete element - the real joy of a doubly linked list
143  * If a destructor function has been set, call it as well
144  */
145 void cf_ll_delete(cf_ll *ll, cf_ll_element *e );
146 
147 uint32_t cf_ll_size(cf_ll *ll);
148 /*
149  * Create a iterator for linked list. Will move from head to tail
150  * if forward is true else from tail to head
151  */
152 cf_ll_iterator * cf_ll_getIterator(cf_ll * ll, bool forward);
153 
154 /*
155  * Get next element of linked list pointed by iterator
156  */
157 cf_ll_element * cf_ll_getNext(cf_ll_iterator *iter);
158 
159 /*
160  * Release iterator
161  */
162 void cf_ll_releaseIterator(cf_ll_iterator *iter);
163 
164 /*
165  * Search an element in the linked list.
166  */
167 cf_ll_element * cf_ll_search(cf_ll *ll, cf_ll_element *e, bool forward, cf_ll_reduce_fn fn);
168 
169 /*
170  * Get the linked list element through indexing
171  */
172 cf_ll_element *cf_ll_index(cf_ll *ll, int index);
173 /**
174  * The way these reduces work:
175  * ** If you're reducing and you want to delete this element, return CF_LL_REDUCE_DELETE
176  * and it'll be removed from the list - but iteration will not halt
177  * ** If you return a negative value, the reduction will terminate immediatly and that
178  * return value will be passed to the reducer
179  * ** The 'forward' parameter specifies whether you want to traverse from front to back,
180  * pass in 'false' to go tail-to-head
181  */
182 int cf_ll_reduce( cf_ll *ll, bool forward, cf_ll_reduce_fn fn, void *udata);
183 
184 /**
185  * Insert-before
186  * Sometimes you want to iterate a list, and insert before a certain element.
187  * Common when you're trying to keep a sorted list and you have some knowledge
188  * that either the list is short, or you're doing inserts of a particular pattern
189  * so that a sorted-table is not the right answer.
190  *
191  * Similar to the reduce function: if you want to bail out of the insert, return a negative
192  * If you want to insert "here", return the special code
193  * At the end of the list, you will be passed a null element (thus meaning you'll always
194  * be called at least once)
195  */
196 int cf_ll_insert_reduce(cf_ll *ll, cf_ll_element *e, bool forward, cf_ll_reduce_fn fn, void *udata);
197 
198 /**
199  * Call this function on a head structure to initialize it to empty
200  * Call with whether you want a locked version of a lockfree version
201  * if you're handling your own locks
202  *
203  * If you're using a standard delete methodology, then don't need a destructor function,
204  * and can leave it blank. But if you're using the reduce / delete pattern, then
205  * there's not an easy way for the application-level delete to occur, because you can't
206  * free the structure first then call delete. (you could insert the element on a queue,
207  * but it would have to carefully be a reference counted object, and then you'd still
208  * need the linked-list-reduceor to decrement the linked list....)
209  * In that case, you need to have a destructor
210  * function that gets fired every time a removal from the list occurs. even on explicit
211  * deletes it's called, just to be fancy.
212  *
213  * Note that when the destructor is called, the lock for the linked list is held
214  * (if you've allocated the linked list with a lock)
215  */
216 int cf_ll_init(cf_ll *ll, cf_ll_destructor destroy_fn, bool uselock);
217 
218 /******************************************************************************/
219 
220 #ifdef __cplusplus
221 } // end extern "C"
222 #endif