dgraph.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /* Licensed under LGPLv2.1+ - see LICENSE file for details */
  2. #include <ccan/dgraph/dgraph.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. void dgraph_init_node(struct dgraph_node *n)
  6. {
  7. tlist_init(&n->edge[DGRAPH_FROM]);
  8. tlist_init(&n->edge[DGRAPH_TO]);
  9. }
  10. static void free_edge(struct dgraph_edge *e)
  11. {
  12. tlist_del_from(&e->n[DGRAPH_FROM]->edge[DGRAPH_FROM],
  13. e, list[DGRAPH_FROM]);
  14. tlist_del_from(&e->n[DGRAPH_TO]->edge[DGRAPH_TO],
  15. e, list[DGRAPH_TO]);
  16. free(e);
  17. }
  18. void dgraph_clear_node(struct dgraph_node *n)
  19. {
  20. struct dgraph_edge *e;
  21. unsigned int i;
  22. (void)dgraph_debug(n);
  23. for (i = DGRAPH_FROM; i <= DGRAPH_TO; i++) {
  24. while ((e = tlist_top(&n->edge[i], list[i])) != NULL) {
  25. assert(e->n[i] == n);
  26. free_edge(e);
  27. }
  28. }
  29. }
  30. void dgraph_add_edge(struct dgraph_node *from, struct dgraph_node *to)
  31. {
  32. struct dgraph_edge *e = malloc(sizeof(*e));
  33. (void)dgraph_debug(from);
  34. (void)dgraph_debug(to);
  35. e->n[DGRAPH_FROM] = from;
  36. e->n[DGRAPH_TO] = to;
  37. tlist_add(&from->edge[DGRAPH_FROM], e, list[DGRAPH_FROM]);
  38. tlist_add(&to->edge[DGRAPH_TO], e, list[DGRAPH_TO]);
  39. }
  40. bool dgraph_del_edge(struct dgraph_node *from, struct dgraph_node *to)
  41. {
  42. struct dgraph_edge *e, *next;
  43. (void)dgraph_debug(from);
  44. (void)dgraph_debug(to);
  45. dgraph_for_each_edge_safe(from, e, next, DGRAPH_FROM) {
  46. if (e->n[DGRAPH_TO] == to) {
  47. free_edge(e);
  48. return true;
  49. }
  50. }
  51. return false;
  52. }
  53. static bool traverse_depth_first(struct dgraph_node *n,
  54. enum dgraph_dir dir,
  55. bool (*fn)(struct dgraph_node *, void *),
  56. const void *data)
  57. {
  58. struct dgraph_edge *e, *next;
  59. /* dgraph_for_each_edge_safe, without dgraph_debug() */
  60. tlist_for_each_safe(&n->edge[dir], e, next, list[dir]) {
  61. if (!traverse_depth_first(e->n[!dir], dir, fn, data))
  62. return false;
  63. }
  64. return fn(n, (void *)data);
  65. }
  66. void dgraph_traverse(const struct dgraph_node *n,
  67. enum dgraph_dir dir,
  68. bool (*fn)(struct dgraph_node *, void *),
  69. const void *data)
  70. {
  71. struct dgraph_edge *e, *next;
  72. /* dgraph_for_each_edge_safe, without dgraph_debug() */
  73. tlist_for_each_safe(&n->edge[dir], e, next, list[dir]) {
  74. if (!traverse_depth_first(e->n[!dir], dir, fn, data))
  75. break;
  76. }
  77. }
  78. struct check_info {
  79. const struct dgraph_node *ret;
  80. const char *abortstr;
  81. };
  82. static bool find_backedge(const struct dgraph_node *from,
  83. const struct dgraph_node *to,
  84. enum dgraph_dir dir)
  85. {
  86. struct dgraph_edge *e;
  87. tlist_for_each(&from->edge[dir], e, list[dir]) {
  88. if (e->n[!dir] == to)
  89. return true;
  90. }
  91. return false;
  92. }
  93. static bool dgraph_check_node(struct dgraph_node *n, void *info_)
  94. {
  95. struct check_info *info = info_;
  96. unsigned int dir;
  97. struct dgraph_edge *e;
  98. for (dir = DGRAPH_FROM; dir <= DGRAPH_TO; dir++) {
  99. /* First, check edges list. */
  100. if (!tlist_check(&n->edge[dir], info->abortstr)) {
  101. info->ret = NULL;
  102. return false;
  103. }
  104. /* dgraph_for_each_edge() without check! */
  105. tlist_for_each(&n->edge[dir], e, list[dir]) {
  106. if (e->n[dir] == n) {
  107. if (find_backedge(e->n[!dir], n, !dir))
  108. continue;
  109. if (info->abortstr) {
  110. fprintf(stderr,
  111. "%s: node %p %s edge doesnt"
  112. " point back to %p\n",
  113. info->abortstr, e->n[!dir],
  114. !dir == DGRAPH_FROM
  115. ? "DGRAPH_FROM" : "DGRAPH_TO",
  116. n);
  117. abort();
  118. }
  119. info->ret = NULL;
  120. return false;
  121. }
  122. if (info->abortstr) {
  123. fprintf(stderr,
  124. "%s: node %p %s edge %p points"
  125. " to %p\n",
  126. info->abortstr, n,
  127. dir == DGRAPH_FROM
  128. ? "DGRAPH_FROM" : "DGRAPH_TO",
  129. e, e->n[dir]);
  130. abort();
  131. }
  132. info->ret = NULL;
  133. return false;
  134. }
  135. }
  136. return true;
  137. }
  138. struct dgraph_node *dgraph_check(const struct dgraph_node *n,
  139. const char *abortstr)
  140. {
  141. struct check_info info;
  142. /* This gets set to NULL by dgraph_check_node on failure. */
  143. info.ret = n;
  144. info.abortstr = abortstr;
  145. dgraph_check_node((struct dgraph_node *)info.ret, &info);
  146. if (info.ret)
  147. dgraph_traverse(n, DGRAPH_FROM, dgraph_check_node, &info);
  148. if (info.ret)
  149. dgraph_traverse(n, DGRAPH_TO, dgraph_check_node, &info);
  150. return (void *)info.ret;
  151. }