Merge lp:~jamesodhunt/libnih/iterators into lp:~upstart-devel/libnih/nih

Proposed by Dimitri John Ledkov
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
Reviewer Review Type Date Requested Status
Steve Langasek Needs Fixing
Review via email: mp+140151@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Steve Langasek (vorlon) wrote :

merge conflict to be resolved here.

review: Needs Fixing

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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"

Subscribers

People subscribed via source and target branches

to all changes: