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 
51 /******************************************************************************
52  * TYPES
53  ******************************************************************************/
54 
55 typedef struct cf_ll_s cf_ll;
56 typedef struct cf_ll_element_s cf_ll_element;
57 
58 typedef int (*cf_ll_reduce_fn) (cf_ll_element * e, void *udata);
59 typedef void (*cf_ll_destructor) (cf_ll_element * e);
60 
61 /**
62  * cf_ll_element
63  * The element that must be included in structures
64  * This element should be the FIRST element in the structure where it is being included
65  */
66 struct cf_ll_element_s {
67  cf_ll_element * next;
68  cf_ll_element * prev;
69 };
70 
71 /**
72  * cf_ll
73  * the linked list container
74  */
75 struct cf_ll_s {
76  cf_ll_element * head;
77  cf_ll_element * tail;
79  uint32_t sz;
80  bool uselock;
81 #ifdef EXTERNAL_LOCKS
82  void * LOCK;
83 #else
84  pthread_mutex_t LOCK;
85 #endif //EXTERNAL_LOCKS
86 };
87 
88 /******************************************************************************
89  * INLINE FUNCTIONS
90  ******************************************************************************/
91 
92 static inline cf_ll_element *cf_ll_get_head(cf_ll *ll) {
93  return(ll->head);
94 }
95 
96 static inline cf_ll_element *cf_ll_get_tail(cf_ll *ll) {
97  return(ll->tail);
98 }
99 
100 static inline cf_ll_element *cf_ll_get_next(cf_ll_element *e) {
101  return(e->next);
102 }
103 
104 static inline cf_ll_element *cf_ll_get_prev(cf_ll_element *e) {
105  return(e->prev);
106 }
107 
108 /******************************************************************************
109  * FUNCTIONS
110  ******************************************************************************/
111 
112 /**
113  * Insert to head
114  */
115 void cf_ll_prepend(cf_ll *ll, cf_ll_element *e );
116 
117 /**
118  * Insert to tail
119  */
120 void cf_ll_append(cf_ll *ll, cf_ll_element *e );
121 
122 /**
123  * Insert after element !! warning! consider threadsafety before using this call!
124  */
125 void cf_ll_insert_after(cf_ll *ll, cf_ll_element *cur, cf_ll_element *ins);
126 
127 /**
128  * Insert before element !! warning! consider threadsafey before using this call!
129  */
130 void cf_ll_insert_before(cf_ll *ll, cf_ll_element *cur, cf_ll_element *ins);
131 
132 /**
133  * delete element - the real joy of a doubly linked list
134  * If a destructor function has been set, call it as well
135  */
136 void cf_ll_delete(cf_ll *ll, cf_ll_element *e );
137 
138 uint32_t cf_ll_size(cf_ll *ll);
139 
140 /**
141  * The way these reduces work:
142  * ** If you're reducing and you want to delete this element, return CF_LL_REDUCE_DELETE
143  * and it'll be removed from the list - but iteration will not halt
144  * ** If you return a negative value, the reduction will terminate immediatly and that
145  * return value will be passed to the reducer
146  * ** The 'forward' parameter specifies whether you want to traverse from front to back,
147  * pass in 'false' to go tail-to-head
148  */
149 int cf_ll_reduce( cf_ll *ll, bool forward, cf_ll_reduce_fn fn, void *udata);
150 
151 /**
152  * Insert-before
153  * Sometimes you want to iterate a list, and insert before a certain element.
154  * Common when you're trying to keep a sorted list and you have some knowledge
155  * that either the list is short, or you're doing inserts of a particular pattern
156  * so that a sorted-table is not the right answer.
157  *
158  * Similar to the reduce function: if you want to bail out of the insert, return a negative
159  * If you want to insert "here", return the special code
160  * At the end of the list, you will be passed a null element (thus meaning you'll always
161  * be called at least once)
162  */
163 int cf_ll_insert_reduce(cf_ll *ll, cf_ll_element *e, bool forward, cf_ll_reduce_fn fn, void *udata);
164 
165 /**
166  * Call this function on a head structure to initialize it to empty
167  * Call with whether you want a locked version of a lockfree version
168  * if you're handling your own locks
169  *
170  * If you're using a standard delete methodology, then don't need a destructor function,
171  * and can leave it blank. But if you're using the reduce / delete pattern, then
172  * there's not an easy way for the application-level delete to occur, because you can't
173  * free the structure first then call delete. (you could insert the element on a queue,
174  * but it would have to carefully be a reference counted object, and then you'd still
175  * need the linked-list-reduceor to decrement the linked list....)
176  * In that case, you need to have a destructor
177  * function that gets fired every time a removal from the list occurs. even on explicit
178  * deletes it's called, just to be fancy.
179  *
180  * Note that when the destructor is called, the lock for the linked list is held
181  * (if you've allocated the linked list with a lock)
182  */
183 int cf_ll_init(cf_ll *ll, cf_ll_destructor destroy_fn, bool uselock);
184 
185 /******************************************************************************/
186 
187 #ifdef __cplusplus
188 } // end extern "C"
189 #endif
void cf_ll_append(cf_ll *ll, cf_ll_element *e)
cf_ll_element * head
uint32_t cf_ll_size(cf_ll *ll)
cf_ll_element * tail
static cf_ll_element * cf_ll_get_head(cf_ll *ll)
cf_ll_destructor destroy_fn
int cf_ll_reduce(cf_ll *ll, bool forward, cf_ll_reduce_fn fn, void *udata)
void cf_ll_insert_after(cf_ll *ll, cf_ll_element *cur, cf_ll_element *ins)
static cf_ll_element * cf_ll_get_next(cf_ll_element *e)
void cf_ll_insert_before(cf_ll *ll, cf_ll_element *cur, cf_ll_element *ins)
void(* cf_ll_destructor)(cf_ll_element *e)
static cf_ll_element * cf_ll_get_tail(cf_ll *ll)
static cf_ll_element * cf_ll_get_prev(cf_ll_element *e)
void cf_ll_delete(cf_ll *ll, cf_ll_element *e)
void cf_ll_prepend(cf_ll *ll, cf_ll_element *e)
int(* cf_ll_reduce_fn)(cf_ll_element *e, void *udata)
int cf_ll_insert_reduce(cf_ll *ll, cf_ll_element *e, bool forward, cf_ll_reduce_fn fn, void *udata)
pthread_mutex_t LOCK
int cf_ll_init(cf_ll *ll, cf_ll_destructor destroy_fn, bool uselock)