File: list.h

package info (click to toggle)
cfengine3 3.6.2-4
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 20,256 kB
  • ctags: 9,613
  • sloc: ansic: 116,129; sh: 12,366; yacc: 1,088; makefile: 1,006; lex: 391; perl: 197; xml: 21; sed: 4
file content (317 lines) | stat: -rw-r--r-- 13,934 bytes parent folder | download | duplicates (2)
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/*
   Copyright (C) CFEngine AS

   This file is part of CFEngine 3 - written and maintained by CFEngine AS.

   This program 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 3.

   This program 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, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

  To the extent this program is licensed as part of the Enterprise
  versions of CFEngine, the applicable Commercial Open Source License
  (COSL) may apply to this file if you as a licensee so wish it. See
  included file COSL.txt.
*/

#ifndef CFENGINE_LIST_H
#define CFENGINE_LIST_H

#include <stdlib.h>
#include <refcount.h>

/**
  @brief Double linked list implementation.

  A linked list is to be used when data needs to be stored and then sequentially processed, not for quick
  lookups. Prime examples of bad usage of a linked list is for instance having a list of files and then
  iterating over the list to find a particular file based on the name. A Map will be much better for this type
  of usage. A good usage for a linked list is to store a list of files that need to be changed sequentially.
  For instance a list of files that need to change permissions.

  A linked list should not be used when fast retrieval is important, for that it is better to use a Map.
  The implementation of the list is kept intentionally opaque, so we can change it in the future. It provides a
  reference counted list with copy on write. In order for this to work the user needs to provide at least a copy
  function. The List is used at its full potential if the user provides three helper functions:
  - copy(void *source, void **destination)
  - compare(void *a, void *b)
  - destroy(void *element)

  It is highly recommend to at least implement the copy function, since that is the key for the copy on write implementation.
  The destroy function is recommended to avoid leaking memory whenever an element is destroyed. Notice that the
  list never copies the elements, so as long as the user still has access to the elements this function does not
  need to be implemented and the user then needs to delete the elements afterwards.

  The compare function is a nice to have function. It is used when the user wants to remove elements, in order to
  find the right element to delete. If this function is not provided, then the list will try to match the pointer.
  These three helper functions can assume that they will never be called with NULL pointers.

  A special note on the copy function. The copy function is analog to the copy constructor in C++, it takes a properly
  constructed element and produces a newly created element that is a copy of the previous one. The copy function
  needs to allocate memory for the new element and then fill it with the proper data. It should be avoid moving
  pointers around, it should copy the content to the new element so the new element is not tied to the previous
  element.

  The list can have many iterators, but only one mutable iterator at any given time. The difference between a normal
  iterator and a mutable iterator is the fact that with normal iterators only additions can be performed to the list
  without invalidating the iterator, while the mutable iterator allows any kind of change. Be aware that removing from
  the list, either by using remove or via the mutable iterator will invalidate all the normal iterators.

  Simple way to iterate over the list:

  ListIterator *i = ListIteratorGet(list);
  int r = 0;
  for (r = ListIteratorFirst(i); r == 0; r = ListIteratorNext(i))
  {
      MyData = ListIteratorData(i);
      ...
      Do something with the data.
      ...
  }
  */
typedef struct List List;
typedef struct ListMutableIterator ListMutableIterator;
typedef struct ListIterator ListIterator;
/**
  @brief Initialization of a linked list.
  @param compare Compare functions for the elements of the list. Same semantic as strcmp.
  @param copy Copies one element into a new element.
  @param destroy Destroys an element.
  @return A fully initialized list ready to be used or -1 in case of error.
  */
List *ListNew(int (*compare)(const void *, const void *), void (*copy)(const void *source, void **destination), void (*destroy)(void *));
/**
  @brief Destroy a linked list.
  @param list List to be destroyed. It can be a NULL pointer.
  @return 0 if destroyed, -1 otherwise.
  */
int ListDestroy(List **list);
/**
  @brief Performs a shallow copy of a linked list.
  A shallow copy is a copy that does not copy the elements but only the list structure.
  This is done by internal reference counting. If any of the lists is modified afterwards
  then a deep copy of the list is triggered and all the elements are copied.
  @param origin Original list to be copied.
  @param destination List to be copied to.
  @return 0 if copied, -1 otherwise.
  @remark If no copy function is provided, then this function returns -1.
  */
int ListCopy(List *origin, List **destination);
/**
  @brief Adds an element to the beginning of the list.
  Notice that we do not copy the element, so if the original element is free'd there will be
  a dangling pointer.
  We used to change the state of the list after adding an element, but now we don't do it.
  The reason is because adding an element is not destructive, no iterators will be affected
  by this, while removing it is destructive. An iterator might be pointing to the dark side
  of the moon after a removal operation.
  If the list is shared this will trigger a deep copy of the list.
  @param list Linked list.
  @param payload Data to be added.
  @return 0 if prepended, -1 otherwise.
  */
int ListPrepend(List *list, void *payload);
/**
  @brief Adds an element to the end of the list.
  Notice that we do not copy the element, so if the original element is free'd there will be
  a dangling pointer.
  We used to change the state of the list after adding an element, but now we don't do it.
  The reason is because adding an element is not destructive, no iterators will be affected
  by this, while removing it is destructive. An iterator might be pointing to the dark side
  of the moon after a removal operation.
  If the list is shared this will trigger a deep copy of the list.
  @param list Linked list.
  @param payload Data to be added.
  @return 0 if appended, -1 otherwise.
  */
int ListAppend(List *list, void *payload);
/**
  @brief Removes an element from the linked list.
  Removes the first element that matches the payload. It starts looking from the beginning of the list.
  Notice that this might trigger a deep copy of the list. This only happens if the list was
  copied before.
  @param list Linked list.
  @param payload Data to be removed.
  @return 0 if removed, -1 otherwise.
  */
int ListRemove(List *list, void *payload);
/**
  @brief Returns the number of elements on a given linked list.
  @param list Linked list.
  @return The number of elements on the list.
  */
int ListCount(const List *list);

/**
  @brief Gets an iterator for a given linked list.

  This iterator will be invalid if data is removed from the list. It will still be valid
  after a new addition though.
  @note After creation the iterator will be pointing to the first item of the list.
  @param list Linked list
  @param iterator Iterator.
  @return A fully initialized iterator or NULL in case of error.
  */
ListIterator *ListIteratorGet(const List *list);
/**
  @brief Releases the memory associated with an iterator.

  This function exists only to free the memory associated with the iterator, there is no strong
  connection between the iterator and the list.
  @note It is not possible to get an iterator for an empty list.
  @param iterator Iterator.
  @return 0 if released, -1 otherwise.
  */
int ListIteratorDestroy(ListIterator **iterator);
/**
  @brief Moves the iterator to the first element of the list.
  @param iterator Iterator.
  @return 0 if it was possible to move, -1 otherwise.
  */
int ListIteratorFirst(ListIterator *iterator);
/**
  @brief Moves the iterator to the last element of the list.
  @param iterator Iterator.
  @return 0 if it was possible to move, -1 otherwise.
  */
int ListIteratorLast(ListIterator *iterator);
/**
  @brief Moves the iterator to the next element of the list.
  @param iterator Iterator.
  @return 0 if it was possible to move, -1 otherwise.
  */
int ListIteratorNext(ListIterator *iterator);
/**
  @brief Moves the iterator to the previous element of the list.
  @param iterator Iterator.
  @return 0 if it was possible to move, -1 otherwise.
  */
int ListIteratorPrevious(ListIterator *iterator);
/**
  @brief Returns the data associated with the current element.
  @param iterator Iterator.
  @return Pointer to the data or NULL if it was not possible.
  */
void *ListIteratorData(const ListIterator *iterator);
/**
  @brief Checks if the iterator has a next element
  @return True if it has a next element or False if not.
  */
bool ListIteratorHasNext(const ListIterator *iterator);
/**
  @brief Checks if the iterator has a previous element
  @return True if it has a previous element or False if not.
  */
bool ListIteratorHasPrevious(const ListIterator *iterator);

/**
  @brief Creates a new mutable iterator.

  A mutable iterator can be used for the same kind of operations as a normal iterator, but it can also be
  used to add and remove elements while iterating over the list. Any removal operation will invalidate all
  the normal iterators though.

  Since there can be only one mutable iterator for a list at any given time, the creation of a second iterator
  will fail.
  @note After creation the iterator will be pointing to the first item of the list.
  @param iterator Iterator to be initialized.
  @return A fully initialized iterator or NULL in case of error.
  */
ListMutableIterator *ListMutableIteratorGet(List *list);
/**
  @brief Releases the memory associated with an iterator.

  This function has to be called for mutable iterators, otherwise the list will think there is already one mutable
  iterator and the creation of new mutable iterators will not be possible.
  @note It is not possible to get an iterator for an empty list.
  @param iterator Iterator.
  @return 0 if released, -1 otherwise.
  */
int ListMutableIteratorRelease(ListMutableIterator **iterator);
/**
  @brief Moves the iterator to the first element of the list.
  @param iterator Iterator.
  @return 0 if it was possible to move, -1 otherwise.
  */
int ListMutableIteratorFirst(ListMutableIterator *iterator);
/**
  @brief Moves the iterator to the last element of the list.
  @param iterator Iterator.
  @return 0 if it was possible to move, -1 otherwise.
  */
int ListMutableIteratorLast(ListMutableIterator *iterator);
/**
  @brief Moves the iterator to the next element of the list.
  @param iterator Iterator.
  @return 0 if it was possible to move, -1 otherwise.
  */
int ListMutableIteratorNext(ListMutableIterator *iterator);
/**
  @brief Moves the iterator to the previous element of the list.
  @param iterator Iterator.
  @return 0 if it was possible to move, -1 otherwise.
  */
int ListMutableIteratorPrevious(ListMutableIterator *iterator);
/**
  @brief Returns the data associated with the current element.
  @param iterator Iterator.
  @return Pointer to the data or NULL if it was not possible.
  */
void *ListMutableIteratorData(const ListMutableIterator *iterator);
/**
  @brief Removes the current element from the list.

  After this operation all the normal iterators are invalid. The iterator might be pointing to the next element,
  or in the case of removing the last element, to the previous element.

  Although it is supported to remove elements from the list bypassing the iterator, i.e. calling ListRemove, this
  might bring unintended side effects. The iterator might be moved to another element, therefore special care must
  be taken when mixing removal both from the list and from the iterator.
  @param iterator Iterator
  @return 0 if removed, -1 otherwise.
  */
int ListMutableIteratorRemove(ListMutableIterator *iterator);
/**
  @brief Prepends element on front of the element pointed by the iterator.

  An important clarification, the iterator still points to the same element after this operation. It is up to the user
  to move the iterator to the prepended element.

  All the light operators are still valid after this operation.
  @param iterator Iterator
  @param payload Element to be prepended.
  @return 0 if prepended, -1 in case of error.
  */
int ListMutableIteratorPrepend(ListMutableIterator *iterator, void *payload);
/**
  @brief Appends element after the element pointed by the iterator.

  An important clarification, the iterator still points to the same element after this operation. It is up to the user
  to move the iterator to the appended element.

  All the light operators are still valid after this operation.
  @param iterator Iterator
  @param payload Element to be appended.
  @return 0 if appended, -1 in case of error.
  */
int ListMutableIteratorAppend(ListMutableIterator *iterator, void *payload);
/**
  @brief Checks if the iterator has a next element
  @return True if it has a next element or False if not.
  */
bool ListMutableIteratorHasNext(const ListMutableIterator *iterator);
/**
  @brief Checks if the iterator has a previous element
  @return True if it has a previous element or False if not.
  */
bool ListMutableIteratorHasPrevious(const ListMutableIterator *iterator);

#endif // CFENGINE_LIST_H