Merge lp:~jamesodhunt/libnih/iterators into lp:~upstart-devel/libnih/nih
- iterators
- Merge into nih
Status: | Work in progress |
---|---|
Proposed branch: | lp:~jamesodhunt/libnih/iterators |
Merge into: | lp:~upstart-devel/libnih/nih |
Diff against target: |
962 lines (+741/-8) (has conflicts) 11 files modified
ChangeLog (+13/-0) nih/hash.c (+62/-0) nih/hash.h (+7/-0) nih/list.c (+59/-0) nih/list.h (+18/-0) nih/tests/test_hash.c (+176/-2) nih/tests/test_list.c (+154/-3) nih/tests/test_tree.c (+170/-1) nih/tree.c (+62/-0) nih/tree.h (+18/-0) po/libnih.pot (+2/-2) Text conflict in ChangeLog |
To merge this branch: | bzr merge lp:~jamesodhunt/libnih/iterators |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Steve Langasek | Needs Fixing | ||
Review via email: mp+140151@code.launchpad.net |
Commit message
Description of the change
Unmerged revisions
- 1049. By James Hunt
-
* Changelog: Summary of new functions.
* nih/hash.c: New functions:
- nih_hash_foreach()
- nih_hash_count()
* nih/hash.h: Prototypes for new functions:
- nih_hash_foreach()
- nih_hash_count()
* nih/list.c: New functions:
- nih_list_foreach()
- nih_list_count()
* nih/list.h:
- Prototypes for new functions:
- nih_list_foreach()
- nih_list_count()
- New type: NihListHandler.
* nih/tree.c: New functions:
- nih_tree_foreach()
- nih_tree_count()
* nih/tree.h:
- Prototypes for new functions:
- nih_tree_foreach()
- nih_tree_count()
- New type: NihTreeHandler.
* nih/tests/test_hash. c:
- New functions:
- test_count()
- test_foreach_func () and supporting functions:
- hash_handler1()
- hash_handler2()
- hash_handler3()
- Updated main to call test_foreach_func() and test_count().
- Changed description for existing functions to make it clear that
NIH_HASH_FOREACH( ) is a macro.
* nih/tests/test_list. c:
- New functions:
- test_count()
- test_foreach_func() and supporting functions:
- list_handler1()
- list_handler2()
- list_handler3()
- Updated main to call test_foreach_func() and test_count().
- Changed description for existing functions to make it clear that
NIH_LIST_*() are macros.
* nih/tests/test_tree. c
- New functions:
- test_count()
- test_foreach_func () and supporting functions:
- tree_handler1()
- tree_handler2()
- tree_handler3()
- Updated main to call test_foreach_func() and test_count().
- Changed description for existing functions to make it clear that
NIH_TREE_FOREACH_ *() are macros.
Preview Diff
1 | === modified file 'ChangeLog' |
2 | --- ChangeLog 2011-09-01 18:41:03 +0000 |
3 | +++ ChangeLog 2012-12-17 09:27:29 +0000 |
4 | @@ -1,3 +1,4 @@ |
5 | +<<<<<<< TREE |
6 | 2011-08-31 James Hunt <james.hunt@ubuntu.com> |
7 | |
8 | * nih-dbus-tool/tests/test_com.netsplit.Nih.Test_object.c |
9 | @@ -33,6 +34,18 @@ |
10 | a single slash (LP:#777097). |
11 | * nih/tests/test_watch.c: Added explicit test for watch on a file. |
12 | |
13 | +======= |
14 | +2011-05-08 James Hunt <james.hunt@ubuntu.com> |
15 | + |
16 | + * New functions: |
17 | + - nih_list_foreach() |
18 | + - nih_hash_foreach() |
19 | + - nih_tree_foreach() |
20 | + - nih_list_count() |
21 | + - nih_hash_count() |
22 | + - nih_tree_count() |
23 | + |
24 | +>>>>>>> MERGE-SOURCE |
25 | 2010-12-23 Scott James Remnant <scott@netsplit.com> |
26 | |
27 | * configure.ac: Bump version to 1.0.4 |
28 | |
29 | === modified file 'nih/hash.c' |
30 | --- nih/hash.c 2009-06-23 09:29:37 +0000 |
31 | +++ nih/hash.c 2012-12-17 09:27:29 +0000 |
32 | @@ -397,3 +397,65 @@ |
33 | |
34 | return strcmp (key1, key2); |
35 | } |
36 | + |
37 | +/** |
38 | + * nih_hash_foreach: |
39 | + * |
40 | + * @hash: hash, |
41 | + * @len: optional output parameter that will contain count of hash entries, |
42 | + * @handler: optional function called for each hash entry, |
43 | + * @data: optional data to pass to handler along with hash entry. |
44 | + * |
45 | + * Iterate over specified hash. |
46 | + * |
47 | + * One of @len or @handler may be NULL. |
48 | + * If @handler is NULL, count of hash entries will still be returned in @len. |
49 | + * If @handler returns 1, @len will be set to the number of hash entries |
50 | + * processed successfully up to that point. |
51 | + * |
52 | + * Returns 0 on success (and when both @len and @handler are NULL), |
53 | + * or -1 if handler returns an error. |
54 | + **/ |
55 | +int |
56 | +nih_hash_foreach (const NihHash *hash, size_t *len, |
57 | + NihListHandler handler, void *data) |
58 | +{ |
59 | + int ret; |
60 | + |
61 | + nih_assert (hash); |
62 | + |
63 | + if (len) *len = 0; |
64 | + |
65 | + if (!len && !handler) return 0; |
66 | + |
67 | + NIH_HASH_FOREACH (hash, iter) { |
68 | + if (handler) { |
69 | + ret = handler (iter, data); |
70 | + if (ret == FALSE) return -1; |
71 | + } |
72 | + if (len) ++*len; |
73 | + } |
74 | + |
75 | + return 0; |
76 | +} |
77 | + |
78 | +/** |
79 | + * nih_hash_count: |
80 | + * |
81 | + * @hash: hash. |
82 | + * |
83 | + * Returns count of number of entries in @hash. |
84 | + **/ |
85 | +size_t |
86 | +nih_hash_count (const NihHash *hash) |
87 | +{ |
88 | + size_t len = 0; |
89 | + int ret; |
90 | + |
91 | + nih_assert (hash); |
92 | + |
93 | + ret = nih_hash_foreach (hash, &len, NULL, NULL); |
94 | + |
95 | + return (ret == -1 ? 0 : len); |
96 | +} |
97 | + |
98 | |
99 | === modified file 'nih/hash.h' |
100 | --- nih/hash.h 2011-01-06 09:28:39 +0000 |
101 | +++ nih/hash.h 2012-12-17 09:27:29 +0000 |
102 | @@ -217,6 +217,13 @@ |
103 | uint32_t nih_hash_string_hash (const char *key); |
104 | int nih_hash_string_cmp (const char *key1, const char *key2); |
105 | |
106 | +int nih_hash_foreach (const NihHash *hash, size_t *len, |
107 | + NihListHandler handler, void *data) |
108 | + __attribute__((unused)); |
109 | + |
110 | +size_t nih_hash_count (const NihHash *hash) |
111 | + __attribute__((warn_unused_result, unused)); |
112 | + |
113 | NIH_END_EXTERN |
114 | |
115 | #endif /* NIH_HASH_H */ |
116 | |
117 | === modified file 'nih/list.c' |
118 | --- nih/list.c 2009-06-23 09:29:37 +0000 |
119 | +++ nih/list.c 2012-12-17 09:27:29 +0000 |
120 | @@ -249,3 +249,62 @@ |
121 | |
122 | return 0; |
123 | } |
124 | + |
125 | +/** |
126 | + * nih_list_foreach: |
127 | + * @list: list, |
128 | + * @len: optional output parameter that will contain length of list, |
129 | + * @handler: optional function called for each list entry, |
130 | + * @data: optional data to pass to handler along with list entry. |
131 | + * |
132 | + * Iterate over specified list. |
133 | + * |
134 | + * One of @len or @handler may be NULL. |
135 | + * If @handler is NULL, list length will still be returned in @len. |
136 | + * If @handler returns 1, @len will be set to the number of list entries |
137 | + * processed successfully up to that point. |
138 | + * |
139 | + * Returns 0 on success (and when both @len and @handler are NULL), |
140 | + * or -1 if handler returns an error. |
141 | + **/ |
142 | +int |
143 | +nih_list_foreach (const NihList *list, size_t *len, |
144 | + NihListHandler handler, void *data) |
145 | +{ |
146 | + int ret; |
147 | + |
148 | + nih_assert (list); |
149 | + |
150 | + if (len) *len = 0; |
151 | + |
152 | + if (!len && !handler) return 0; |
153 | + |
154 | + NIH_LIST_FOREACH (list, iter) { |
155 | + if (handler) { |
156 | + ret = handler (iter, data); |
157 | + if (ret == FALSE) return -1; |
158 | + } |
159 | + if (len) ++*len; |
160 | + } |
161 | + |
162 | + return 0; |
163 | +} |
164 | + |
165 | +/** |
166 | + * nih_list_count: |
167 | + * @list: list. |
168 | + * |
169 | + * Returns count of number of entries in @list. |
170 | + **/ |
171 | +size_t |
172 | +nih_list_count (const NihList *list) |
173 | +{ |
174 | + size_t len = 0; |
175 | + int ret; |
176 | + |
177 | + nih_assert (list); |
178 | + |
179 | + ret = nih_list_foreach (list, &len, NULL, NULL); |
180 | + |
181 | + return (ret == -1 ? 0 : len); |
182 | +} |
183 | |
184 | === modified file 'nih/list.h' |
185 | --- nih/list.h 2011-01-06 09:28:39 +0000 |
186 | +++ nih/list.h 2012-12-17 09:27:29 +0000 |
187 | @@ -110,6 +110,17 @@ |
188 | }; |
189 | } NihListEntry; |
190 | |
191 | +/** |
192 | + * NihListHandler: |
193 | + * @entry: list entry being visited, |
194 | + * @data: data pointer. |
195 | + * |
196 | + * A list handler is a function called for each list entry |
197 | + * when iterating over a list. |
198 | + * |
199 | + * Returns: TRUE if list entry process correctly, else FALSE. |
200 | + **/ |
201 | +typedef int (*NihListHandler) (NihList *entry, void *data); |
202 | |
203 | /** |
204 | * NIH_LIST_EMPTY: |
205 | @@ -208,6 +219,13 @@ |
206 | NihList * nih_list_remove (NihList *entry); |
207 | int nih_list_destroy (NihList *entry); |
208 | |
209 | +int nih_list_foreach (const NihList *list, size_t *len, |
210 | + NihListHandler handler, void *data) |
211 | + __attribute__((unused)); |
212 | + |
213 | +size_t nih_list_count (const NihList *list) |
214 | + __attribute__((warn_unused_result, unused)); |
215 | + |
216 | NIH_END_EXTERN |
217 | |
218 | #endif /* NIH_LIST_H */ |
219 | |
220 | === modified file 'nih/tests/test_hash.c' |
221 | --- nih/tests/test_hash.c 2009-06-23 09:29:37 +0000 |
222 | +++ nih/tests/test_hash.c 2012-12-17 09:27:29 +0000 |
223 | @@ -25,6 +25,11 @@ |
224 | #include <nih/alloc.h> |
225 | #include <nih/list.h> |
226 | #include <nih/hash.h> |
227 | +#include <nih/string.h> |
228 | + |
229 | +#define HASH_HANDLER_DATA_VALUE 42 |
230 | +#define LIST_ENTRIES 4 |
231 | +#define ERROR_ON_ENTRY 3 |
232 | |
233 | |
234 | typedef struct hash_entry { |
235 | @@ -514,7 +519,7 @@ |
236 | * in the hash in the order we expect them to come out in, but add |
237 | * them in a different order for sanity. |
238 | */ |
239 | - TEST_FUNCTION ("NIH_HASH_FOREACH"); |
240 | + TEST_FUNCTION ("NIH_HASH_FOREACH macro"); |
241 | hash = nih_hash_string_new (NULL, 0); |
242 | entry0 = entry[2] = new_entry (hash, "entry 1"); |
243 | entry1 = entry[1] = new_entry (hash, "entry 2"); |
244 | @@ -542,6 +547,173 @@ |
245 | nih_free (hash); |
246 | } |
247 | |
248 | +int |
249 | +hash_handler1 (NihList *entry, int *data) |
250 | +{ |
251 | + TEST_NE_P (entry, NULL); |
252 | + TEST_NE_P (data, NULL); |
253 | + |
254 | + TEST_EQ (*data, HASH_HANDLER_DATA_VALUE); |
255 | + |
256 | + return TRUE; |
257 | +} |
258 | + |
259 | +int |
260 | +hash_handler2 (NihList *entry, int *data) |
261 | +{ |
262 | + static size_t i = 0; |
263 | + |
264 | + TEST_NE_P (entry, NULL); |
265 | + TEST_NE_P (data, NULL); |
266 | + |
267 | + ++i; |
268 | + *data = i; |
269 | + |
270 | + return TRUE; |
271 | +} |
272 | + |
273 | +int |
274 | +hash_handler3 (NihList *entry, void *data) |
275 | +{ |
276 | + static size_t i = 0; |
277 | + |
278 | + TEST_NE_P (entry, NULL); |
279 | + TEST_NE_P (data, NULL); |
280 | + |
281 | + ++i; |
282 | + *(int *)data = i; |
283 | + |
284 | + if (i == ERROR_ON_ENTRY) |
285 | + return FALSE; |
286 | + |
287 | + return TRUE; |
288 | +} |
289 | + |
290 | +void |
291 | +test_foreach_func (void) |
292 | +{ |
293 | + NihHash *hash; |
294 | + NihList *entry[LIST_ENTRIES]; |
295 | + NihList *entry0, *entry1, *entry2, *entry3; |
296 | + size_t len = 0; |
297 | + int data1 = HASH_HANDLER_DATA_VALUE; |
298 | + size_t data2 = 0; |
299 | + int ret; |
300 | + |
301 | + TEST_FUNCTION ("nih_hash_foreach"); |
302 | + |
303 | + hash = nih_hash_string_new (NULL, 0); |
304 | + TEST_NE_P (hash, NULL); |
305 | + |
306 | + |
307 | + TEST_FEATURE ("with no handler, length or data params"); |
308 | + TEST_EQ (nih_hash_foreach (hash, NULL, NULL, NULL), 0); |
309 | + |
310 | + |
311 | + TEST_FEATURE ("with length param, but no handler"); |
312 | + |
313 | + ret = nih_hash_foreach (hash, &len, NULL, NULL); |
314 | + TEST_EQ (ret, 0); |
315 | + TEST_EQ (len, 0); |
316 | + |
317 | + |
318 | + TEST_FEATURE ("with data and handler reading a value, but no len"); |
319 | + |
320 | + entry0 = entry[0] = new_entry (hash, "entry 1"); |
321 | + entry1 = entry[1] = new_entry (hash, "entry 2"); |
322 | + entry2 = entry[2] = new_entry (hash, "entry 3"); |
323 | + entry3 = entry[3] = new_entry (hash, "entry 4"); |
324 | + |
325 | + nih_hash_add (hash, entry0); |
326 | + nih_hash_add (hash, entry1); |
327 | + nih_hash_add (hash, entry2); |
328 | + nih_hash_add (hash, entry3); |
329 | + |
330 | + ret = nih_hash_foreach (hash, NULL, |
331 | + (NihListHandler)hash_handler1, &data1); |
332 | + |
333 | + TEST_EQ (ret, 0); |
334 | + TEST_EQ (data1, HASH_HANDLER_DATA_VALUE); |
335 | + |
336 | + |
337 | + TEST_FEATURE ("with len, data and handler reading a value"); |
338 | + |
339 | + ret = nih_hash_foreach (hash, &len, |
340 | + (NihListHandler)hash_handler1, &data1); |
341 | + |
342 | + TEST_EQ (ret, 0); |
343 | + TEST_EQ (data1, HASH_HANDLER_DATA_VALUE); |
344 | + TEST_EQ (len, LIST_ENTRIES); |
345 | + |
346 | + |
347 | + TEST_FEATURE ("with len, data and hander changing a value"); |
348 | + |
349 | + len = 0; |
350 | + data2 = 0; |
351 | + ret = nih_hash_foreach (hash, &len, |
352 | + (NihListHandler)hash_handler2, &data2); |
353 | + |
354 | + TEST_EQ (ret, 0); |
355 | + TEST_EQ (len, LIST_ENTRIES); |
356 | + TEST_EQ (data2, LIST_ENTRIES); |
357 | + |
358 | + |
359 | + TEST_FEATURE ("with handler returning error"); |
360 | + |
361 | + len = 0; |
362 | + data2 = 0; |
363 | + ret = nih_hash_foreach (hash, &len, |
364 | + (NihListHandler)hash_handler3, &data2); |
365 | + TEST_EQ (ret, -1); |
366 | + TEST_EQ (len, ERROR_ON_ENTRY-1); |
367 | +} |
368 | + |
369 | +void |
370 | +test_count (void) |
371 | +{ |
372 | + NihHash *hash; |
373 | + NihList *entry[LIST_ENTRIES]; |
374 | + nih_local char *key; |
375 | + NihList *e; |
376 | + size_t i; |
377 | + |
378 | + TEST_FUNCTION ("nih_hash_count"); |
379 | + |
380 | + hash = nih_hash_string_new (NULL, 0); |
381 | + TEST_NE_P (hash, NULL); |
382 | + |
383 | + i = 0; |
384 | + TEST_FEATURE ("with no initial entries"); |
385 | + TEST_EQ (nih_hash_count (hash), i); |
386 | + |
387 | + entry[0] = new_entry (hash, "entry 1"); |
388 | + entry[1] = new_entry (hash, "entry 2"); |
389 | + entry[2] = new_entry (hash, "entry 3"); |
390 | + entry[3] = new_entry (hash, "entry 4"); |
391 | + |
392 | + TEST_FEATURE ("with increasing number of entries"); |
393 | + |
394 | + for (i=0; i < LIST_ENTRIES; ++i) { |
395 | + nih_hash_add (hash, entry[i]); |
396 | + TEST_EQ (nih_hash_count (hash), i+1); |
397 | + } |
398 | + |
399 | + TEST_FEATURE ("with decreasing number of entries"); |
400 | + |
401 | + for (i=LIST_ENTRIES; i > 0; --i) { |
402 | + key = nih_sprintf (NULL, "entry %d", i); |
403 | + TEST_NE_P (key, NULL); |
404 | + |
405 | + e = nih_hash_lookup (hash, key); |
406 | + TEST_NE_P (e, NULL); |
407 | + nih_free (nih_list_remove (e)); |
408 | + TEST_EQ (nih_hash_count (hash), i-1); |
409 | + } |
410 | + |
411 | + TEST_FEATURE ("with no entries"); |
412 | + TEST_EQ (nih_hash_count (hash), 0); |
413 | +} |
414 | + |
415 | void |
416 | test_foreach_safe (void) |
417 | { |
418 | @@ -553,7 +725,7 @@ |
419 | * order, visiting each entry in each bin; and that it's safe to |
420 | * remove the entries while doing so. |
421 | */ |
422 | - TEST_FUNCTION ("NIH_HASH_FOREACH_SAFE"); |
423 | + TEST_FUNCTION ("NIH_HASH_FOREACH_SAFE macro"); |
424 | hash = nih_hash_string_new (NULL, 0); |
425 | entry0 = entry[2] = new_entry (hash, "entry 1"); |
426 | entry1 = entry[1] = new_entry (hash, "entry 2"); |
427 | @@ -619,6 +791,8 @@ |
428 | test_lookup (); |
429 | test_foreach (); |
430 | test_foreach_safe (); |
431 | + test_foreach_func (); |
432 | + test_count (); |
433 | test_string_key (); |
434 | |
435 | return 0; |
436 | |
437 | === modified file 'nih/tests/test_list.c' |
438 | --- nih/tests/test_list.c 2009-06-23 09:29:37 +0000 |
439 | +++ nih/tests/test_list.c 2012-12-17 09:27:29 +0000 |
440 | @@ -25,6 +25,9 @@ |
441 | #include <nih/alloc.h> |
442 | #include <nih/list.h> |
443 | |
444 | +#define LIST_HANDLER_DATA_VALUE 42 |
445 | +#define LIST_ENTRIES 3 |
446 | +#define ERROR_ON_ENTRY 2 |
447 | |
448 | void |
449 | test_init (void) |
450 | @@ -251,7 +254,7 @@ |
451 | { |
452 | NihList *list, *entry; |
453 | |
454 | - TEST_FUNCTION ("NIH_LIST_EMPTY"); |
455 | + TEST_FUNCTION ("NIH_LIST_EMPTY macro"); |
456 | |
457 | /* Check that NIH_LIST_EMPTY is TRUE on an empty list */ |
458 | TEST_FEATURE ("with empty list"); |
459 | @@ -281,7 +284,7 @@ |
460 | /* Check that NIH_LIST_FOREACH iterates the list correctly in |
461 | * order, visiting each entry. |
462 | */ |
463 | - TEST_FUNCTION ("NIH_LIST_FOREACH"); |
464 | + TEST_FUNCTION ("NIH_LIST_FOREACH macro"); |
465 | list = nih_list_new (NULL); |
466 | entry[0] = nih_list_add (list, nih_list_new (NULL)); |
467 | entry[1] = nih_list_add (list, nih_list_new (NULL)); |
468 | @@ -306,13 +309,159 @@ |
469 | nih_free (entry[2]); |
470 | } |
471 | |
472 | +int |
473 | +list_handler1 (NihList *entry, int *data) |
474 | +{ |
475 | + TEST_NE_P (entry, NULL); |
476 | + TEST_NE_P (data, NULL); |
477 | + |
478 | + TEST_EQ (*data, LIST_HANDLER_DATA_VALUE); |
479 | + |
480 | + return TRUE; |
481 | +} |
482 | + |
483 | +int |
484 | +list_handler2 (NihList *entry, int *data) |
485 | +{ |
486 | + static size_t i = 0; |
487 | + |
488 | + TEST_NE_P (entry, NULL); |
489 | + TEST_NE_P (data, NULL); |
490 | + |
491 | + ++i; |
492 | + *data = i; |
493 | + |
494 | + return TRUE; |
495 | +} |
496 | + |
497 | +int |
498 | +list_handler3 (NihList *entry, void *data) |
499 | +{ |
500 | + static size_t i = 0; |
501 | + |
502 | + TEST_NE_P (entry, NULL); |
503 | + TEST_NE_P (data, NULL); |
504 | + |
505 | + ++i; |
506 | + *(int *)data = i; |
507 | + |
508 | + if (i == ERROR_ON_ENTRY) |
509 | + return FALSE; |
510 | + |
511 | + return TRUE; |
512 | +} |
513 | + |
514 | +void |
515 | +test_foreach_func (void) |
516 | +{ |
517 | + NihList *list, *entry[LIST_ENTRIES]; |
518 | + size_t len = 0; |
519 | + int data1 = LIST_HANDLER_DATA_VALUE; |
520 | + size_t data2 = 0; |
521 | + int ret; |
522 | + |
523 | + TEST_FUNCTION ("nih_list_foreach"); |
524 | + |
525 | + list = nih_list_new (NULL); |
526 | + TEST_NE_P (list, NULL); |
527 | + |
528 | + |
529 | + TEST_FEATURE ("with no handler, length or data params"); |
530 | + |
531 | + ret = nih_list_foreach (list, NULL, NULL, NULL); |
532 | + TEST_EQ (ret, 0); |
533 | + |
534 | + TEST_FEATURE ("with length param, but no handler"); |
535 | + ret = nih_list_foreach (list, &len, NULL, NULL); |
536 | + TEST_EQ (ret, 0); |
537 | + TEST_EQ (len, 0); |
538 | + |
539 | + |
540 | + TEST_FEATURE ("with data and handler reading a value, but no len"); |
541 | + |
542 | + entry[0] = nih_list_add (list, nih_list_new (NULL)); |
543 | + entry[1] = nih_list_add (list, nih_list_new (NULL)); |
544 | + entry[2] = nih_list_add (list, nih_list_new (NULL)); |
545 | + |
546 | + ret = nih_list_foreach (list, NULL, |
547 | + (NihListHandler)list_handler1, &data1); |
548 | + |
549 | + TEST_EQ (ret, 0); |
550 | + TEST_EQ (data1, LIST_HANDLER_DATA_VALUE); |
551 | + |
552 | + |
553 | + TEST_FEATURE ("with len, data and handler reading a value"); |
554 | + |
555 | + ret = nih_list_foreach (list, &len, |
556 | + (NihListHandler)list_handler1, &data1); |
557 | + |
558 | + TEST_EQ (ret, 0); |
559 | + TEST_EQ (len, LIST_ENTRIES); |
560 | + TEST_EQ (data1, LIST_HANDLER_DATA_VALUE); |
561 | + |
562 | + |
563 | + TEST_FEATURE ("with len, data and hander changing a value"); |
564 | + |
565 | + len = 0; |
566 | + data2 = 0; |
567 | + ret = nih_list_foreach (list, &len, |
568 | + (NihListHandler)list_handler2, &data2); |
569 | + TEST_EQ (ret, 0); |
570 | + TEST_EQ (len, LIST_ENTRIES); |
571 | + TEST_EQ (data2, LIST_ENTRIES); |
572 | + |
573 | + |
574 | + TEST_FEATURE ("with handler returning error"); |
575 | + |
576 | + len = 0; |
577 | + data2 = 0; |
578 | + ret = nih_list_foreach (list, &len, |
579 | + (NihListHandler)list_handler3, &data2); |
580 | + TEST_EQ (ret, -1); |
581 | + TEST_EQ (len, ERROR_ON_ENTRY-1); |
582 | +} |
583 | + |
584 | +void |
585 | +test_count (void) |
586 | +{ |
587 | + NihList *list, *entry[3]; |
588 | + size_t i; |
589 | + |
590 | + TEST_FUNCTION ("nih_list_count"); |
591 | + |
592 | + list = nih_list_new (NULL); |
593 | + TEST_NE_P (list, NULL); |
594 | + |
595 | + TEST_FEATURE ("with no initial entries"); |
596 | + TEST_EQ (nih_list_count (list), 0); |
597 | + TEST_EQ (NIH_LIST_EMPTY (list), TRUE); |
598 | + |
599 | + TEST_FEATURE ("with increasing number of entries"); |
600 | + for (i=0; i < LIST_ENTRIES; ++i) { |
601 | + entry[i] = nih_list_add (list, nih_list_new (NULL)); |
602 | + TEST_EQ (nih_list_count (list), i+1); |
603 | + } |
604 | + |
605 | + TEST_FEATURE ("with decreasing number of entries"); |
606 | + |
607 | + for (i=LIST_ENTRIES; i > 0; --i) { |
608 | + nih_free (nih_list_remove (list->next)); |
609 | + TEST_EQ (nih_list_count (list), i-1); |
610 | + } |
611 | + |
612 | + TEST_FEATURE ("with no entries"); |
613 | + TEST_EQ (nih_list_count (list), 0); |
614 | + TEST_EQ (NIH_LIST_EMPTY (list), TRUE); |
615 | + |
616 | +} |
617 | + |
618 | void |
619 | test_foreach_safe (void) |
620 | { |
621 | NihList *list, *entry[3]; |
622 | int i; |
623 | |
624 | - TEST_FUNCTION ("NIH_LIST_FOREACH_SAFE"); |
625 | + TEST_FUNCTION ("NIH_LIST_FOREACH_SAFE macro"); |
626 | |
627 | /* Check that NIH_LIST_FOREACH_SAFE iterates the list correctly in |
628 | * order, visiting each entry. |
629 | @@ -503,6 +652,8 @@ |
630 | test_empty (); |
631 | test_foreach (); |
632 | test_foreach_safe (); |
633 | + test_foreach_func (); |
634 | + test_count (); |
635 | test_remove (); |
636 | test_destroy (); |
637 | |
638 | |
639 | === modified file 'nih/tests/test_tree.c' |
640 | --- nih/tests/test_tree.c 2009-06-23 09:29:37 +0000 |
641 | +++ nih/tests/test_tree.c 2012-12-17 09:27:29 +0000 |
642 | @@ -25,6 +25,9 @@ |
643 | #include <nih/alloc.h> |
644 | #include <nih/tree.h> |
645 | |
646 | +#define TREE_HANDLER_DATA_VALUE 42 |
647 | +#define NODE_COUNT 4 |
648 | +#define ERROR_ON_NODE 3 |
649 | |
650 | void |
651 | test_init (void) |
652 | @@ -508,7 +511,7 @@ |
653 | NihTree *node[12], *expect[13]; |
654 | int i; |
655 | |
656 | - TEST_FUNCTION ("NIH_TREE_FOREACH"); |
657 | + TEST_FUNCTION ("NIH_TREE_FOREACH macro"); |
658 | for (i = 0; i < 12; i++) |
659 | node[i] = nih_tree_new (NULL); |
660 | |
661 | @@ -589,6 +592,170 @@ |
662 | nih_free (node[i]); |
663 | } |
664 | |
665 | +int |
666 | +tree_handler1 (NihTree *node, void *data) |
667 | +{ |
668 | + TEST_NE_P (node, NULL); |
669 | + TEST_NE_P (data, NULL); |
670 | + |
671 | + TEST_EQ (*(int *)data, TREE_HANDLER_DATA_VALUE); |
672 | + |
673 | + return TRUE; |
674 | +} |
675 | + |
676 | +int |
677 | +tree_handler2 (NihTree *node, void *data) |
678 | +{ |
679 | + static size_t count = 0; |
680 | + |
681 | + TEST_NE_P (node, NULL); |
682 | + TEST_NE_P (data, NULL); |
683 | + |
684 | + ++count; |
685 | + *(int *)data = count; |
686 | + |
687 | + return TRUE; |
688 | +} |
689 | + |
690 | +int |
691 | +tree_handler3 (NihTree *node, void *data) |
692 | +{ |
693 | + static size_t i = 0; |
694 | + |
695 | + TEST_NE_P (node, NULL); |
696 | + TEST_NE_P (data, NULL); |
697 | + |
698 | + ++i; |
699 | + *(int *)data = i; |
700 | + |
701 | + if (i == ERROR_ON_NODE) |
702 | + return FALSE; |
703 | + |
704 | + return TRUE; |
705 | +} |
706 | + |
707 | +void |
708 | +test_foreach_func (void) |
709 | +{ |
710 | + NihTree *tree, *node1, *node2, *node3; |
711 | + int data1 = TREE_HANDLER_DATA_VALUE; |
712 | + size_t data2 = 0; |
713 | + int ret; |
714 | + size_t len; |
715 | + |
716 | + TEST_FUNCTION ("nih_tree_foreach function"); |
717 | + |
718 | + tree = nih_tree_new (NULL); |
719 | + |
720 | + |
721 | + TEST_FEATURE ("with no handler, length or data params"); |
722 | + TEST_EQ (nih_tree_foreach (tree, NULL, NULL, NULL), 0); |
723 | + |
724 | + |
725 | + TEST_FEATURE ("with length param, but no handler"); |
726 | + |
727 | + ret = nih_tree_foreach (tree, &len, NULL, NULL); |
728 | + TEST_EQ (ret, 0); |
729 | + TEST_EQ (len, 1); |
730 | + |
731 | + node1 = nih_tree_new (tree); |
732 | + node2 = nih_tree_new (tree); |
733 | + node3 = nih_tree_new (tree); |
734 | + |
735 | + nih_tree_add (tree, node1, NIH_TREE_LEFT); |
736 | + ret = nih_tree_foreach (tree, &len, NULL, NULL); |
737 | + TEST_EQ (ret, 0); |
738 | + TEST_EQ (len, 2); |
739 | + |
740 | + nih_tree_add (tree, node2, NIH_TREE_RIGHT); |
741 | + ret = nih_tree_foreach (tree, &len, NULL, NULL); |
742 | + TEST_EQ (ret, 0); |
743 | + TEST_EQ (len, 3); |
744 | + |
745 | + nih_tree_add (node1, node3, NIH_TREE_RIGHT); |
746 | + |
747 | + ret = nih_tree_foreach (tree, &len, NULL, NULL); |
748 | + TEST_EQ (ret, 0); |
749 | + TEST_EQ (len, 4); |
750 | + |
751 | + |
752 | + TEST_FEATURE ("with data and handler reading a value, but no len"); |
753 | + |
754 | + ret = nih_tree_foreach (tree, NULL, |
755 | + (NihTreeHandler)tree_handler1, &data1); |
756 | + |
757 | + TEST_EQ (ret, 0); |
758 | + TEST_EQ (data1, TREE_HANDLER_DATA_VALUE); |
759 | + |
760 | + TEST_FEATURE ("with len, data and handler reading a value"); |
761 | + |
762 | + ret = nih_tree_foreach (tree, &len, |
763 | + (NihTreeHandler)tree_handler1, &data1); |
764 | + |
765 | + TEST_EQ (ret, 0); |
766 | + TEST_EQ (data1, TREE_HANDLER_DATA_VALUE); |
767 | + TEST_EQ (len, NODE_COUNT); |
768 | + |
769 | + TEST_FEATURE ("with len, data and handler changing a value"); |
770 | + |
771 | + data2 = 0; |
772 | + ret = nih_tree_foreach (tree, &len, |
773 | + (NihTreeHandler)tree_handler2, &data2); |
774 | + |
775 | + TEST_EQ (ret, 0); |
776 | + TEST_EQ (len, NODE_COUNT); |
777 | + TEST_EQ (data2, NODE_COUNT); |
778 | + |
779 | + TEST_FEATURE ("with handler returning error"); |
780 | + |
781 | + len = 0; |
782 | + data2 = 0; |
783 | + ret = nih_tree_foreach (tree, &len, |
784 | + (NihTreeHandler)tree_handler3, &data2); |
785 | + |
786 | + TEST_EQ (ret, -1); |
787 | + TEST_EQ (len, ERROR_ON_NODE-1); |
788 | +} |
789 | + |
790 | +void |
791 | +test_count (void) |
792 | +{ |
793 | + NihTree *tree, *node1, *node2, *node3; |
794 | + |
795 | + TEST_FUNCTION ("nih_tree_count"); |
796 | + |
797 | + tree = nih_tree_new (NULL); |
798 | + node1 = nih_tree_new (tree); |
799 | + node2 = nih_tree_new (tree); |
800 | + node3 = nih_tree_new (tree); |
801 | + |
802 | + TEST_FEATURE ("with one initial entry"); |
803 | + TEST_EQ (nih_tree_count (tree), 1); |
804 | + |
805 | + TEST_FEATURE ("with increasing number of entries"); |
806 | + |
807 | + nih_tree_add (tree, node1, NIH_TREE_LEFT); |
808 | + TEST_EQ (nih_tree_count (tree), 2); |
809 | + |
810 | + nih_tree_add (tree, node2, NIH_TREE_RIGHT); |
811 | + TEST_EQ (nih_tree_count (tree), 3); |
812 | + |
813 | + nih_tree_add (node1, node3, NIH_TREE_RIGHT); |
814 | + TEST_EQ (nih_tree_count (tree), 4); |
815 | + |
816 | + TEST_FEATURE ("with decreasing number of entries"); |
817 | + nih_tree_remove (node3); |
818 | + TEST_EQ (nih_tree_count (tree), 3); |
819 | + |
820 | + nih_tree_remove (node2); |
821 | + TEST_EQ (nih_tree_count (tree), 2); |
822 | + |
823 | + nih_tree_remove (node1); |
824 | + |
825 | + TEST_FEATURE ("with one final entry"); |
826 | + TEST_EQ (nih_tree_count (tree), 1); |
827 | +} |
828 | + |
829 | void |
830 | test_prev (void) |
831 | { |
832 | @@ -2214,6 +2381,8 @@ |
833 | test_destroy (); |
834 | test_next (); |
835 | test_foreach (); |
836 | + test_foreach_func (); |
837 | + test_count (); |
838 | test_prev (); |
839 | test_next_pre (); |
840 | test_foreach_pre (); |
841 | |
842 | === modified file 'nih/tree.c' |
843 | --- nih/tree.c 2009-06-23 09:29:37 +0000 |
844 | +++ nih/tree.c 2012-12-17 09:27:29 +0000 |
845 | @@ -619,3 +619,65 @@ |
846 | prev = tmp; |
847 | } |
848 | } |
849 | + |
850 | +/** |
851 | + * nih_tree_foreach: |
852 | + * |
853 | + * @tree: tree, |
854 | + * @len: optional output parameter that will contain count of tree nodes, |
855 | + * @handler: optional function called for each tree node, |
856 | + * @data: optional data to pass to handler along with tree node. |
857 | + * |
858 | + * Iterate over specified tree. |
859 | + * |
860 | + * One of @len or @handler may be NULL. |
861 | + * If @handler is NULL and @len is non-NULL, count of tree nodes will |
862 | + * still be returned in @len. |
863 | + * If @handler returns 1, @len will be set to the number of tree nodes |
864 | + * processed successfully up to that point. |
865 | + * |
866 | + * Returns 0 on success (and when both @len and @handler are NULL), |
867 | + * or -1 if handler returns an error. |
868 | + **/ |
869 | +int |
870 | +nih_tree_foreach (NihTree *tree, size_t *len, |
871 | + NihTreeHandler handler, void *data) |
872 | +{ |
873 | + int ret; |
874 | + |
875 | + nih_assert (tree); |
876 | + |
877 | + if (len) *len = 0; |
878 | + |
879 | + if (!len && !handler) return 0; |
880 | + |
881 | + NIH_TREE_FOREACH_FULL (tree, iter, NULL, data) { |
882 | + if (handler) { |
883 | + ret = handler (iter, data); |
884 | + if (!ret) return -1; |
885 | + } |
886 | + if (len) ++*len; |
887 | + } |
888 | + |
889 | + return 0; |
890 | +} |
891 | + |
892 | +/** |
893 | + * nih_tree_count: |
894 | + * |
895 | + * @tree: tree. |
896 | + * |
897 | + * Returns count of number of entries in @tree. |
898 | + **/ |
899 | +size_t |
900 | +nih_tree_count (NihTree *tree) |
901 | +{ |
902 | + size_t len = 0; |
903 | + int ret; |
904 | + |
905 | + nih_assert (tree); |
906 | + |
907 | + ret = nih_tree_foreach (tree, &len, NULL, NULL); |
908 | + |
909 | + return (ret == -1 ? 0 : len); |
910 | +} |
911 | |
912 | === modified file 'nih/tree.h' |
913 | --- nih/tree.h 2009-06-23 09:29:37 +0000 |
914 | +++ nih/tree.h 2012-12-17 09:27:29 +0000 |
915 | @@ -138,6 +138,17 @@ |
916 | **/ |
917 | typedef int (*NihTreeFilter) (void *data, NihTree *node); |
918 | |
919 | +/** |
920 | + * NihTreeHandler: |
921 | + * @node: tree entry being visited, |
922 | + * @data: data pointer. |
923 | + * |
924 | + * A tree handler is a function called for each tree node |
925 | + * when iterating over a tree. |
926 | + * |
927 | + * Returns: TRUE if tree entry process correctly, else FALSE. |
928 | + **/ |
929 | +typedef int (*NihTreeHandler) (NihTree *node, void *data); |
930 | |
931 | /** |
932 | * NIH_TREE_FOREACH_FULL: |
933 | @@ -370,6 +381,13 @@ |
934 | NihTree * nih_tree_prev_post_full (NihTree *tree, NihTree *node, |
935 | NihTreeFilter filter, void *data); |
936 | |
937 | +int nih_tree_foreach (NihTree *tree, size_t *len, |
938 | + NihTreeHandler handler, void *data) |
939 | + __attribute__((unused)); |
940 | + |
941 | +size_t nih_tree_count (NihTree *tree) |
942 | + __attribute__((warn_unused_result, unused)); |
943 | + |
944 | NIH_END_EXTERN |
945 | |
946 | #endif /* NIH_TREE_H */ |
947 | |
948 | === modified file 'po/libnih.pot' |
949 | --- po/libnih.pot 2010-12-23 22:04:08 +0000 |
950 | +++ po/libnih.pot 2012-12-17 09:27:29 +0000 |
951 | @@ -6,9 +6,9 @@ |
952 | #, fuzzy |
953 | msgid "" |
954 | msgstr "" |
955 | -"Project-Id-Version: libnih 1.0.3\n" |
956 | +"Project-Id-Version: libnih 1.0.4\n" |
957 | "Report-Msgid-Bugs-To: libnih-bugs@netsplit.com\n" |
958 | -"POT-Creation-Date: 2010-12-23 21:53+0000\n" |
959 | +"POT-Creation-Date: 2011-05-08 12:30+0100\n" |
960 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
961 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
962 | "Language-Team: LANGUAGE <LL@li.org>\n" |
merge conflict to be resolved here.