Merge lp:~jamesodhunt/libnih/iterators into lp:libnih/1.0

Proposed by James Hunt on 2011-05-08
Status: Needs review
Proposed branch: lp:~jamesodhunt/libnih/iterators
Merge into: lp:libnih/1.0
Diff against target: 952 lines (+738/-8)
11 files modified
ChangeLog (+10/-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)
To merge this branch: bzr merge lp:~jamesodhunt/libnih/iterators
Reviewer Review Type Date Requested Status
Scott James Remnant (Canonical) 2011-05-08 Pending
Review via email: mp+60308@code.launchpad.net

Description of the change

* New functions:
  - nih_list_foreach()
  - nih_hash_foreach()
  - nih_tree_foreach()
  - nih_list_count()
  - nih_hash_count()
  - nih_tree_count()

These functions will be marginally slower to run than the corresponding NIH_LIST_FOREACH(), NIH_HASH_FOREACH() and NIH_TREE_FOREACH_*() macros, but have the advantage of being (more easily) callable from within a debugger. Additionally, trivial handlers can be created by apps using nih which also simplifies debug.

For example, we could change Upstart to include functions like this:

init/conf.c:
#ifdef DEBUG
  int conf_sources_handler (ConfSource *source, void *data)
      __attribute__((unused));

  int
  conf_sources_handler (ConfSource *source, void *data)
  {
    nih_assert (source);
    return TRUE;
  }
#endif

This minimal handler is enough such that from within gdb, we can then say:

(gdb) b conf_sources_handler
(gdb) call nih_list_foreach (conf_sources, NULL, (NihListHandler)conf_sources_handler, NULL)
(gdb) r

And then when the breakpoint is hit...

(gdb) p source

This avoids cluttering our applications source code with horrid hard-coded functions to print out data structures - we can rely on gdb to do that for us.

To post a comment you must log in.

Unmerged revisions

1049. By James Hunt on 2011-05-08

* 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
=== modified file 'ChangeLog'
--- ChangeLog 2010-12-23 22:06:15 +0000
+++ ChangeLog 2011-05-08 11:56:38 +0000
@@ -1,3 +1,13 @@
12011-05-08 James Hunt <james.hunt@ubuntu.com>
2
3 * New functions:
4 - nih_list_foreach()
5 - nih_hash_foreach()
6 - nih_tree_foreach()
7 - nih_list_count()
8 - nih_hash_count()
9 - nih_tree_count()
10
12010-12-23 Scott James Remnant <scott@netsplit.com>112010-12-23 Scott James Remnant <scott@netsplit.com>
212
3 * configure.ac: Bump version to 1.0.413 * configure.ac: Bump version to 1.0.4
414
=== modified file 'nih/hash.c'
--- nih/hash.c 2009-06-23 09:29:37 +0000
+++ nih/hash.c 2011-05-08 11:56:38 +0000
@@ -397,3 +397,65 @@
397397
398 return strcmp (key1, key2);398 return strcmp (key1, key2);
399}399}
400
401/**
402 * nih_hash_foreach:
403 *
404 * @hash: hash,
405 * @len: optional output parameter that will contain count of hash entries,
406 * @handler: optional function called for each hash entry,
407 * @data: optional data to pass to handler along with hash entry.
408 *
409 * Iterate over specified hash.
410 *
411 * One of @len or @handler may be NULL.
412 * If @handler is NULL, count of hash entries will still be returned in @len.
413 * If @handler returns 1, @len will be set to the number of hash entries
414 * processed successfully up to that point.
415 *
416 * Returns 0 on success (and when both @len and @handler are NULL),
417 * or -1 if handler returns an error.
418 **/
419int
420nih_hash_foreach (const NihHash *hash, size_t *len,
421 NihListHandler handler, void *data)
422{
423 int ret;
424
425 nih_assert (hash);
426
427 if (len) *len = 0;
428
429 if (!len && !handler) return 0;
430
431 NIH_HASH_FOREACH (hash, iter) {
432 if (handler) {
433 ret = handler (iter, data);
434 if (ret == FALSE) return -1;
435 }
436 if (len) ++*len;
437 }
438
439 return 0;
440}
441
442/**
443 * nih_hash_count:
444 *
445 * @hash: hash.
446 *
447 * Returns count of number of entries in @hash.
448 **/
449size_t
450nih_hash_count (const NihHash *hash)
451{
452 size_t len = 0;
453 int ret;
454
455 nih_assert (hash);
456
457 ret = nih_hash_foreach (hash, &len, NULL, NULL);
458
459 return (ret == -1 ? 0 : len);
460}
461
400462
=== modified file 'nih/hash.h'
--- nih/hash.h 2011-01-06 09:28:39 +0000
+++ nih/hash.h 2011-05-08 11:56:38 +0000
@@ -217,6 +217,13 @@
217uint32_t nih_hash_string_hash (const char *key);217uint32_t nih_hash_string_hash (const char *key);
218int nih_hash_string_cmp (const char *key1, const char *key2);218int nih_hash_string_cmp (const char *key1, const char *key2);
219219
220int nih_hash_foreach (const NihHash *hash, size_t *len,
221 NihListHandler handler, void *data)
222 __attribute__((unused));
223
224size_t nih_hash_count (const NihHash *hash)
225 __attribute__((warn_unused_result, unused));
226
220NIH_END_EXTERN227NIH_END_EXTERN
221228
222#endif /* NIH_HASH_H */229#endif /* NIH_HASH_H */
223230
=== modified file 'nih/list.c'
--- nih/list.c 2009-06-23 09:29:37 +0000
+++ nih/list.c 2011-05-08 11:56:38 +0000
@@ -249,3 +249,62 @@
249249
250 return 0;250 return 0;
251}251}
252
253/**
254 * nih_list_foreach:
255 * @list: list,
256 * @len: optional output parameter that will contain length of list,
257 * @handler: optional function called for each list entry,
258 * @data: optional data to pass to handler along with list entry.
259 *
260 * Iterate over specified list.
261 *
262 * One of @len or @handler may be NULL.
263 * If @handler is NULL, list length will still be returned in @len.
264 * If @handler returns 1, @len will be set to the number of list entries
265 * processed successfully up to that point.
266 *
267 * Returns 0 on success (and when both @len and @handler are NULL),
268 * or -1 if handler returns an error.
269 **/
270int
271nih_list_foreach (const NihList *list, size_t *len,
272 NihListHandler handler, void *data)
273{
274 int ret;
275
276 nih_assert (list);
277
278 if (len) *len = 0;
279
280 if (!len && !handler) return 0;
281
282 NIH_LIST_FOREACH (list, iter) {
283 if (handler) {
284 ret = handler (iter, data);
285 if (ret == FALSE) return -1;
286 }
287 if (len) ++*len;
288 }
289
290 return 0;
291}
292
293/**
294 * nih_list_count:
295 * @list: list.
296 *
297 * Returns count of number of entries in @list.
298 **/
299size_t
300nih_list_count (const NihList *list)
301{
302 size_t len = 0;
303 int ret;
304
305 nih_assert (list);
306
307 ret = nih_list_foreach (list, &len, NULL, NULL);
308
309 return (ret == -1 ? 0 : len);
310}
252311
=== modified file 'nih/list.h'
--- nih/list.h 2011-01-06 09:28:39 +0000
+++ nih/list.h 2011-05-08 11:56:38 +0000
@@ -110,6 +110,17 @@
110 };110 };
111} NihListEntry;111} NihListEntry;
112112
113/**
114 * NihListHandler:
115 * @entry: list entry being visited,
116 * @data: data pointer.
117 *
118 * A list handler is a function called for each list entry
119 * when iterating over a list.
120 *
121 * Returns: TRUE if list entry process correctly, else FALSE.
122 **/
123typedef int (*NihListHandler) (NihList *entry, void *data);
113124
114/**125/**
115 * NIH_LIST_EMPTY:126 * NIH_LIST_EMPTY:
@@ -208,6 +219,13 @@
208NihList * nih_list_remove (NihList *entry);219NihList * nih_list_remove (NihList *entry);
209int nih_list_destroy (NihList *entry);220int nih_list_destroy (NihList *entry);
210221
222int nih_list_foreach (const NihList *list, size_t *len,
223 NihListHandler handler, void *data)
224 __attribute__((unused));
225
226size_t nih_list_count (const NihList *list)
227 __attribute__((warn_unused_result, unused));
228
211NIH_END_EXTERN229NIH_END_EXTERN
212230
213#endif /* NIH_LIST_H */231#endif /* NIH_LIST_H */
214232
=== modified file 'nih/tests/test_hash.c'
--- nih/tests/test_hash.c 2009-06-23 09:29:37 +0000
+++ nih/tests/test_hash.c 2011-05-08 11:56:38 +0000
@@ -25,6 +25,11 @@
25#include <nih/alloc.h>25#include <nih/alloc.h>
26#include <nih/list.h>26#include <nih/list.h>
27#include <nih/hash.h>27#include <nih/hash.h>
28#include <nih/string.h>
29
30#define HASH_HANDLER_DATA_VALUE 42
31#define LIST_ENTRIES 4
32#define ERROR_ON_ENTRY 3
2833
2934
30typedef struct hash_entry {35typedef struct hash_entry {
@@ -514,7 +519,7 @@
514 * in the hash in the order we expect them to come out in, but add519 * in the hash in the order we expect them to come out in, but add
515 * them in a different order for sanity.520 * them in a different order for sanity.
516 */521 */
517 TEST_FUNCTION ("NIH_HASH_FOREACH");522 TEST_FUNCTION ("NIH_HASH_FOREACH macro");
518 hash = nih_hash_string_new (NULL, 0);523 hash = nih_hash_string_new (NULL, 0);
519 entry0 = entry[2] = new_entry (hash, "entry 1");524 entry0 = entry[2] = new_entry (hash, "entry 1");
520 entry1 = entry[1] = new_entry (hash, "entry 2");525 entry1 = entry[1] = new_entry (hash, "entry 2");
@@ -542,6 +547,173 @@
542 nih_free (hash);547 nih_free (hash);
543}548}
544549
550int
551hash_handler1 (NihList *entry, int *data)
552{
553 TEST_NE_P (entry, NULL);
554 TEST_NE_P (data, NULL);
555
556 TEST_EQ (*data, HASH_HANDLER_DATA_VALUE);
557
558 return TRUE;
559}
560
561int
562hash_handler2 (NihList *entry, int *data)
563{
564 static size_t i = 0;
565
566 TEST_NE_P (entry, NULL);
567 TEST_NE_P (data, NULL);
568
569 ++i;
570 *data = i;
571
572 return TRUE;
573}
574
575int
576hash_handler3 (NihList *entry, void *data)
577{
578 static size_t i = 0;
579
580 TEST_NE_P (entry, NULL);
581 TEST_NE_P (data, NULL);
582
583 ++i;
584 *(int *)data = i;
585
586 if (i == ERROR_ON_ENTRY)
587 return FALSE;
588
589 return TRUE;
590}
591
592void
593test_foreach_func (void)
594{
595 NihHash *hash;
596 NihList *entry[LIST_ENTRIES];
597 NihList *entry0, *entry1, *entry2, *entry3;
598 size_t len = 0;
599 int data1 = HASH_HANDLER_DATA_VALUE;
600 size_t data2 = 0;
601 int ret;
602
603 TEST_FUNCTION ("nih_hash_foreach");
604
605 hash = nih_hash_string_new (NULL, 0);
606 TEST_NE_P (hash, NULL);
607
608
609 TEST_FEATURE ("with no handler, length or data params");
610 TEST_EQ (nih_hash_foreach (hash, NULL, NULL, NULL), 0);
611
612
613 TEST_FEATURE ("with length param, but no handler");
614
615 ret = nih_hash_foreach (hash, &len, NULL, NULL);
616 TEST_EQ (ret, 0);
617 TEST_EQ (len, 0);
618
619
620 TEST_FEATURE ("with data and handler reading a value, but no len");
621
622 entry0 = entry[0] = new_entry (hash, "entry 1");
623 entry1 = entry[1] = new_entry (hash, "entry 2");
624 entry2 = entry[2] = new_entry (hash, "entry 3");
625 entry3 = entry[3] = new_entry (hash, "entry 4");
626
627 nih_hash_add (hash, entry0);
628 nih_hash_add (hash, entry1);
629 nih_hash_add (hash, entry2);
630 nih_hash_add (hash, entry3);
631
632 ret = nih_hash_foreach (hash, NULL,
633 (NihListHandler)hash_handler1, &data1);
634
635 TEST_EQ (ret, 0);
636 TEST_EQ (data1, HASH_HANDLER_DATA_VALUE);
637
638
639 TEST_FEATURE ("with len, data and handler reading a value");
640
641 ret = nih_hash_foreach (hash, &len,
642 (NihListHandler)hash_handler1, &data1);
643
644 TEST_EQ (ret, 0);
645 TEST_EQ (data1, HASH_HANDLER_DATA_VALUE);
646 TEST_EQ (len, LIST_ENTRIES);
647
648
649 TEST_FEATURE ("with len, data and hander changing a value");
650
651 len = 0;
652 data2 = 0;
653 ret = nih_hash_foreach (hash, &len,
654 (NihListHandler)hash_handler2, &data2);
655
656 TEST_EQ (ret, 0);
657 TEST_EQ (len, LIST_ENTRIES);
658 TEST_EQ (data2, LIST_ENTRIES);
659
660
661 TEST_FEATURE ("with handler returning error");
662
663 len = 0;
664 data2 = 0;
665 ret = nih_hash_foreach (hash, &len,
666 (NihListHandler)hash_handler3, &data2);
667 TEST_EQ (ret, -1);
668 TEST_EQ (len, ERROR_ON_ENTRY-1);
669}
670
671void
672test_count (void)
673{
674 NihHash *hash;
675 NihList *entry[LIST_ENTRIES];
676 nih_local char *key;
677 NihList *e;
678 size_t i;
679
680 TEST_FUNCTION ("nih_hash_count");
681
682 hash = nih_hash_string_new (NULL, 0);
683 TEST_NE_P (hash, NULL);
684
685 i = 0;
686 TEST_FEATURE ("with no initial entries");
687 TEST_EQ (nih_hash_count (hash), i);
688
689 entry[0] = new_entry (hash, "entry 1");
690 entry[1] = new_entry (hash, "entry 2");
691 entry[2] = new_entry (hash, "entry 3");
692 entry[3] = new_entry (hash, "entry 4");
693
694 TEST_FEATURE ("with increasing number of entries");
695
696 for (i=0; i < LIST_ENTRIES; ++i) {
697 nih_hash_add (hash, entry[i]);
698 TEST_EQ (nih_hash_count (hash), i+1);
699 }
700
701 TEST_FEATURE ("with decreasing number of entries");
702
703 for (i=LIST_ENTRIES; i > 0; --i) {
704 key = nih_sprintf (NULL, "entry %d", i);
705 TEST_NE_P (key, NULL);
706
707 e = nih_hash_lookup (hash, key);
708 TEST_NE_P (e, NULL);
709 nih_free (nih_list_remove (e));
710 TEST_EQ (nih_hash_count (hash), i-1);
711 }
712
713 TEST_FEATURE ("with no entries");
714 TEST_EQ (nih_hash_count (hash), 0);
715}
716
545void717void
546test_foreach_safe (void)718test_foreach_safe (void)
547{719{
@@ -553,7 +725,7 @@
553 * order, visiting each entry in each bin; and that it's safe to725 * order, visiting each entry in each bin; and that it's safe to
554 * remove the entries while doing so.726 * remove the entries while doing so.
555 */727 */
556 TEST_FUNCTION ("NIH_HASH_FOREACH_SAFE");728 TEST_FUNCTION ("NIH_HASH_FOREACH_SAFE macro");
557 hash = nih_hash_string_new (NULL, 0);729 hash = nih_hash_string_new (NULL, 0);
558 entry0 = entry[2] = new_entry (hash, "entry 1");730 entry0 = entry[2] = new_entry (hash, "entry 1");
559 entry1 = entry[1] = new_entry (hash, "entry 2");731 entry1 = entry[1] = new_entry (hash, "entry 2");
@@ -619,6 +791,8 @@
619 test_lookup ();791 test_lookup ();
620 test_foreach ();792 test_foreach ();
621 test_foreach_safe ();793 test_foreach_safe ();
794 test_foreach_func ();
795 test_count ();
622 test_string_key ();796 test_string_key ();
623797
624 return 0;798 return 0;
625799
=== modified file 'nih/tests/test_list.c'
--- nih/tests/test_list.c 2009-06-23 09:29:37 +0000
+++ nih/tests/test_list.c 2011-05-08 11:56:38 +0000
@@ -25,6 +25,9 @@
25#include <nih/alloc.h>25#include <nih/alloc.h>
26#include <nih/list.h>26#include <nih/list.h>
2727
28#define LIST_HANDLER_DATA_VALUE 42
29#define LIST_ENTRIES 3
30#define ERROR_ON_ENTRY 2
2831
29void32void
30test_init (void)33test_init (void)
@@ -251,7 +254,7 @@
251{254{
252 NihList *list, *entry;255 NihList *list, *entry;
253256
254 TEST_FUNCTION ("NIH_LIST_EMPTY");257 TEST_FUNCTION ("NIH_LIST_EMPTY macro");
255258
256 /* Check that NIH_LIST_EMPTY is TRUE on an empty list */259 /* Check that NIH_LIST_EMPTY is TRUE on an empty list */
257 TEST_FEATURE ("with empty list");260 TEST_FEATURE ("with empty list");
@@ -281,7 +284,7 @@
281 /* Check that NIH_LIST_FOREACH iterates the list correctly in284 /* Check that NIH_LIST_FOREACH iterates the list correctly in
282 * order, visiting each entry.285 * order, visiting each entry.
283 */286 */
284 TEST_FUNCTION ("NIH_LIST_FOREACH");287 TEST_FUNCTION ("NIH_LIST_FOREACH macro");
285 list = nih_list_new (NULL);288 list = nih_list_new (NULL);
286 entry[0] = nih_list_add (list, nih_list_new (NULL));289 entry[0] = nih_list_add (list, nih_list_new (NULL));
287 entry[1] = nih_list_add (list, nih_list_new (NULL));290 entry[1] = nih_list_add (list, nih_list_new (NULL));
@@ -306,13 +309,159 @@
306 nih_free (entry[2]);309 nih_free (entry[2]);
307}310}
308311
312int
313list_handler1 (NihList *entry, int *data)
314{
315 TEST_NE_P (entry, NULL);
316 TEST_NE_P (data, NULL);
317
318 TEST_EQ (*data, LIST_HANDLER_DATA_VALUE);
319
320 return TRUE;
321}
322
323int
324list_handler2 (NihList *entry, int *data)
325{
326 static size_t i = 0;
327
328 TEST_NE_P (entry, NULL);
329 TEST_NE_P (data, NULL);
330
331 ++i;
332 *data = i;
333
334 return TRUE;
335}
336
337int
338list_handler3 (NihList *entry, void *data)
339{
340 static size_t i = 0;
341
342 TEST_NE_P (entry, NULL);
343 TEST_NE_P (data, NULL);
344
345 ++i;
346 *(int *)data = i;
347
348 if (i == ERROR_ON_ENTRY)
349 return FALSE;
350
351 return TRUE;
352}
353
354void
355test_foreach_func (void)
356{
357 NihList *list, *entry[LIST_ENTRIES];
358 size_t len = 0;
359 int data1 = LIST_HANDLER_DATA_VALUE;
360 size_t data2 = 0;
361 int ret;
362
363 TEST_FUNCTION ("nih_list_foreach");
364
365 list = nih_list_new (NULL);
366 TEST_NE_P (list, NULL);
367
368
369 TEST_FEATURE ("with no handler, length or data params");
370
371 ret = nih_list_foreach (list, NULL, NULL, NULL);
372 TEST_EQ (ret, 0);
373
374 TEST_FEATURE ("with length param, but no handler");
375 ret = nih_list_foreach (list, &len, NULL, NULL);
376 TEST_EQ (ret, 0);
377 TEST_EQ (len, 0);
378
379
380 TEST_FEATURE ("with data and handler reading a value, but no len");
381
382 entry[0] = nih_list_add (list, nih_list_new (NULL));
383 entry[1] = nih_list_add (list, nih_list_new (NULL));
384 entry[2] = nih_list_add (list, nih_list_new (NULL));
385
386 ret = nih_list_foreach (list, NULL,
387 (NihListHandler)list_handler1, &data1);
388
389 TEST_EQ (ret, 0);
390 TEST_EQ (data1, LIST_HANDLER_DATA_VALUE);
391
392
393 TEST_FEATURE ("with len, data and handler reading a value");
394
395 ret = nih_list_foreach (list, &len,
396 (NihListHandler)list_handler1, &data1);
397
398 TEST_EQ (ret, 0);
399 TEST_EQ (len, LIST_ENTRIES);
400 TEST_EQ (data1, LIST_HANDLER_DATA_VALUE);
401
402
403 TEST_FEATURE ("with len, data and hander changing a value");
404
405 len = 0;
406 data2 = 0;
407 ret = nih_list_foreach (list, &len,
408 (NihListHandler)list_handler2, &data2);
409 TEST_EQ (ret, 0);
410 TEST_EQ (len, LIST_ENTRIES);
411 TEST_EQ (data2, LIST_ENTRIES);
412
413
414 TEST_FEATURE ("with handler returning error");
415
416 len = 0;
417 data2 = 0;
418 ret = nih_list_foreach (list, &len,
419 (NihListHandler)list_handler3, &data2);
420 TEST_EQ (ret, -1);
421 TEST_EQ (len, ERROR_ON_ENTRY-1);
422}
423
424void
425test_count (void)
426{
427 NihList *list, *entry[3];
428 size_t i;
429
430 TEST_FUNCTION ("nih_list_count");
431
432 list = nih_list_new (NULL);
433 TEST_NE_P (list, NULL);
434
435 TEST_FEATURE ("with no initial entries");
436 TEST_EQ (nih_list_count (list), 0);
437 TEST_EQ (NIH_LIST_EMPTY (list), TRUE);
438
439 TEST_FEATURE ("with increasing number of entries");
440 for (i=0; i < LIST_ENTRIES; ++i) {
441 entry[i] = nih_list_add (list, nih_list_new (NULL));
442 TEST_EQ (nih_list_count (list), i+1);
443 }
444
445 TEST_FEATURE ("with decreasing number of entries");
446
447 for (i=LIST_ENTRIES; i > 0; --i) {
448 nih_free (nih_list_remove (list->next));
449 TEST_EQ (nih_list_count (list), i-1);
450 }
451
452 TEST_FEATURE ("with no entries");
453 TEST_EQ (nih_list_count (list), 0);
454 TEST_EQ (NIH_LIST_EMPTY (list), TRUE);
455
456}
457
309void458void
310test_foreach_safe (void)459test_foreach_safe (void)
311{460{
312 NihList *list, *entry[3];461 NihList *list, *entry[3];
313 int i;462 int i;
314463
315 TEST_FUNCTION ("NIH_LIST_FOREACH_SAFE");464 TEST_FUNCTION ("NIH_LIST_FOREACH_SAFE macro");
316465
317 /* Check that NIH_LIST_FOREACH_SAFE iterates the list correctly in466 /* Check that NIH_LIST_FOREACH_SAFE iterates the list correctly in
318 * order, visiting each entry.467 * order, visiting each entry.
@@ -503,6 +652,8 @@
503 test_empty ();652 test_empty ();
504 test_foreach ();653 test_foreach ();
505 test_foreach_safe ();654 test_foreach_safe ();
655 test_foreach_func ();
656 test_count ();
506 test_remove ();657 test_remove ();
507 test_destroy ();658 test_destroy ();
508659
509660
=== modified file 'nih/tests/test_tree.c'
--- nih/tests/test_tree.c 2009-06-23 09:29:37 +0000
+++ nih/tests/test_tree.c 2011-05-08 11:56:38 +0000
@@ -25,6 +25,9 @@
25#include <nih/alloc.h>25#include <nih/alloc.h>
26#include <nih/tree.h>26#include <nih/tree.h>
2727
28#define TREE_HANDLER_DATA_VALUE 42
29#define NODE_COUNT 4
30#define ERROR_ON_NODE 3
2831
29void32void
30test_init (void)33test_init (void)
@@ -508,7 +511,7 @@
508 NihTree *node[12], *expect[13];511 NihTree *node[12], *expect[13];
509 int i;512 int i;
510513
511 TEST_FUNCTION ("NIH_TREE_FOREACH");514 TEST_FUNCTION ("NIH_TREE_FOREACH macro");
512 for (i = 0; i < 12; i++)515 for (i = 0; i < 12; i++)
513 node[i] = nih_tree_new (NULL);516 node[i] = nih_tree_new (NULL);
514517
@@ -589,6 +592,170 @@
589 nih_free (node[i]);592 nih_free (node[i]);
590}593}
591594
595int
596tree_handler1 (NihTree *node, void *data)
597{
598 TEST_NE_P (node, NULL);
599 TEST_NE_P (data, NULL);
600
601 TEST_EQ (*(int *)data, TREE_HANDLER_DATA_VALUE);
602
603 return TRUE;
604}
605
606int
607tree_handler2 (NihTree *node, void *data)
608{
609 static size_t count = 0;
610
611 TEST_NE_P (node, NULL);
612 TEST_NE_P (data, NULL);
613
614 ++count;
615 *(int *)data = count;
616
617 return TRUE;
618}
619
620int
621tree_handler3 (NihTree *node, void *data)
622{
623 static size_t i = 0;
624
625 TEST_NE_P (node, NULL);
626 TEST_NE_P (data, NULL);
627
628 ++i;
629 *(int *)data = i;
630
631 if (i == ERROR_ON_NODE)
632 return FALSE;
633
634 return TRUE;
635}
636
637void
638test_foreach_func (void)
639{
640 NihTree *tree, *node1, *node2, *node3;
641 int data1 = TREE_HANDLER_DATA_VALUE;
642 size_t data2 = 0;
643 int ret;
644 size_t len;
645
646 TEST_FUNCTION ("nih_tree_foreach function");
647
648 tree = nih_tree_new (NULL);
649
650
651 TEST_FEATURE ("with no handler, length or data params");
652 TEST_EQ (nih_tree_foreach (tree, NULL, NULL, NULL), 0);
653
654
655 TEST_FEATURE ("with length param, but no handler");
656
657 ret = nih_tree_foreach (tree, &len, NULL, NULL);
658 TEST_EQ (ret, 0);
659 TEST_EQ (len, 1);
660
661 node1 = nih_tree_new (tree);
662 node2 = nih_tree_new (tree);
663 node3 = nih_tree_new (tree);
664
665 nih_tree_add (tree, node1, NIH_TREE_LEFT);
666 ret = nih_tree_foreach (tree, &len, NULL, NULL);
667 TEST_EQ (ret, 0);
668 TEST_EQ (len, 2);
669
670 nih_tree_add (tree, node2, NIH_TREE_RIGHT);
671 ret = nih_tree_foreach (tree, &len, NULL, NULL);
672 TEST_EQ (ret, 0);
673 TEST_EQ (len, 3);
674
675 nih_tree_add (node1, node3, NIH_TREE_RIGHT);
676
677 ret = nih_tree_foreach (tree, &len, NULL, NULL);
678 TEST_EQ (ret, 0);
679 TEST_EQ (len, 4);
680
681
682 TEST_FEATURE ("with data and handler reading a value, but no len");
683
684 ret = nih_tree_foreach (tree, NULL,
685 (NihTreeHandler)tree_handler1, &data1);
686
687 TEST_EQ (ret, 0);
688 TEST_EQ (data1, TREE_HANDLER_DATA_VALUE);
689
690 TEST_FEATURE ("with len, data and handler reading a value");
691
692 ret = nih_tree_foreach (tree, &len,
693 (NihTreeHandler)tree_handler1, &data1);
694
695 TEST_EQ (ret, 0);
696 TEST_EQ (data1, TREE_HANDLER_DATA_VALUE);
697 TEST_EQ (len, NODE_COUNT);
698
699 TEST_FEATURE ("with len, data and handler changing a value");
700
701 data2 = 0;
702 ret = nih_tree_foreach (tree, &len,
703 (NihTreeHandler)tree_handler2, &data2);
704
705 TEST_EQ (ret, 0);
706 TEST_EQ (len, NODE_COUNT);
707 TEST_EQ (data2, NODE_COUNT);
708
709 TEST_FEATURE ("with handler returning error");
710
711 len = 0;
712 data2 = 0;
713 ret = nih_tree_foreach (tree, &len,
714 (NihTreeHandler)tree_handler3, &data2);
715
716 TEST_EQ (ret, -1);
717 TEST_EQ (len, ERROR_ON_NODE-1);
718}
719
720void
721test_count (void)
722{
723 NihTree *tree, *node1, *node2, *node3;
724
725 TEST_FUNCTION ("nih_tree_count");
726
727 tree = nih_tree_new (NULL);
728 node1 = nih_tree_new (tree);
729 node2 = nih_tree_new (tree);
730 node3 = nih_tree_new (tree);
731
732 TEST_FEATURE ("with one initial entry");
733 TEST_EQ (nih_tree_count (tree), 1);
734
735 TEST_FEATURE ("with increasing number of entries");
736
737 nih_tree_add (tree, node1, NIH_TREE_LEFT);
738 TEST_EQ (nih_tree_count (tree), 2);
739
740 nih_tree_add (tree, node2, NIH_TREE_RIGHT);
741 TEST_EQ (nih_tree_count (tree), 3);
742
743 nih_tree_add (node1, node3, NIH_TREE_RIGHT);
744 TEST_EQ (nih_tree_count (tree), 4);
745
746 TEST_FEATURE ("with decreasing number of entries");
747 nih_tree_remove (node3);
748 TEST_EQ (nih_tree_count (tree), 3);
749
750 nih_tree_remove (node2);
751 TEST_EQ (nih_tree_count (tree), 2);
752
753 nih_tree_remove (node1);
754
755 TEST_FEATURE ("with one final entry");
756 TEST_EQ (nih_tree_count (tree), 1);
757}
758
592void759void
593test_prev (void)760test_prev (void)
594{761{
@@ -2214,6 +2381,8 @@
2214 test_destroy ();2381 test_destroy ();
2215 test_next ();2382 test_next ();
2216 test_foreach ();2383 test_foreach ();
2384 test_foreach_func ();
2385 test_count ();
2217 test_prev ();2386 test_prev ();
2218 test_next_pre ();2387 test_next_pre ();
2219 test_foreach_pre ();2388 test_foreach_pre ();
22202389
=== modified file 'nih/tree.c'
--- nih/tree.c 2009-06-23 09:29:37 +0000
+++ nih/tree.c 2011-05-08 11:56:38 +0000
@@ -619,3 +619,65 @@
619 prev = tmp;619 prev = tmp;
620 }620 }
621}621}
622
623/**
624 * nih_tree_foreach:
625 *
626 * @tree: tree,
627 * @len: optional output parameter that will contain count of tree nodes,
628 * @handler: optional function called for each tree node,
629 * @data: optional data to pass to handler along with tree node.
630 *
631 * Iterate over specified tree.
632 *
633 * One of @len or @handler may be NULL.
634 * If @handler is NULL and @len is non-NULL, count of tree nodes will
635 * still be returned in @len.
636 * If @handler returns 1, @len will be set to the number of tree nodes
637 * processed successfully up to that point.
638 *
639 * Returns 0 on success (and when both @len and @handler are NULL),
640 * or -1 if handler returns an error.
641 **/
642int
643nih_tree_foreach (NihTree *tree, size_t *len,
644 NihTreeHandler handler, void *data)
645{
646 int ret;
647
648 nih_assert (tree);
649
650 if (len) *len = 0;
651
652 if (!len && !handler) return 0;
653
654 NIH_TREE_FOREACH_FULL (tree, iter, NULL, data) {
655 if (handler) {
656 ret = handler (iter, data);
657 if (!ret) return -1;
658 }
659 if (len) ++*len;
660 }
661
662 return 0;
663}
664
665/**
666 * nih_tree_count:
667 *
668 * @tree: tree.
669 *
670 * Returns count of number of entries in @tree.
671 **/
672size_t
673nih_tree_count (NihTree *tree)
674{
675 size_t len = 0;
676 int ret;
677
678 nih_assert (tree);
679
680 ret = nih_tree_foreach (tree, &len, NULL, NULL);
681
682 return (ret == -1 ? 0 : len);
683}
622684
=== modified file 'nih/tree.h'
--- nih/tree.h 2009-06-23 09:29:37 +0000
+++ nih/tree.h 2011-05-08 11:56:38 +0000
@@ -138,6 +138,17 @@
138 **/138 **/
139typedef int (*NihTreeFilter) (void *data, NihTree *node);139typedef int (*NihTreeFilter) (void *data, NihTree *node);
140140
141/**
142 * NihTreeHandler:
143 * @node: tree entry being visited,
144 * @data: data pointer.
145 *
146 * A tree handler is a function called for each tree node
147 * when iterating over a tree.
148 *
149 * Returns: TRUE if tree entry process correctly, else FALSE.
150 **/
151typedef int (*NihTreeHandler) (NihTree *node, void *data);
141152
142/**153/**
143 * NIH_TREE_FOREACH_FULL:154 * NIH_TREE_FOREACH_FULL:
@@ -370,6 +381,13 @@
370NihTree * nih_tree_prev_post_full (NihTree *tree, NihTree *node,381NihTree * nih_tree_prev_post_full (NihTree *tree, NihTree *node,
371 NihTreeFilter filter, void *data);382 NihTreeFilter filter, void *data);
372383
384int nih_tree_foreach (NihTree *tree, size_t *len,
385 NihTreeHandler handler, void *data)
386 __attribute__((unused));
387
388size_t nih_tree_count (NihTree *tree)
389 __attribute__((warn_unused_result, unused));
390
373NIH_END_EXTERN391NIH_END_EXTERN
374392
375#endif /* NIH_TREE_H */393#endif /* NIH_TREE_H */
376394
=== modified file 'po/libnih.pot'
--- po/libnih.pot 2010-12-23 22:04:08 +0000
+++ po/libnih.pot 2011-05-08 11:56:38 +0000
@@ -6,9 +6,9 @@
6#, fuzzy6#, fuzzy
7msgid ""7msgid ""
8msgstr ""8msgstr ""
9"Project-Id-Version: libnih 1.0.3\n"9"Project-Id-Version: libnih 1.0.4\n"
10"Report-Msgid-Bugs-To: libnih-bugs@netsplit.com\n"10"Report-Msgid-Bugs-To: libnih-bugs@netsplit.com\n"
11"POT-Creation-Date: 2010-12-23 21:53+0000\n"11"POT-Creation-Date: 2011-05-08 12:30+0100\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"

Subscribers

People subscribed via source and target branches

to all changes:
to status/vote changes: