You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

83 lines
2.6 KiB

10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2010-2013, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the LICENSE.txt file in this distribution for license
  7. * details.
  8. * ----------------------------------------------------------------------
  9. */
  10. #include <libcork/core.h>
  11. #include <libcork/ds.h>
  12. #include "ipset/bdd/nodes.h"
  13. #include "ipset/logging.h"
  14. size_t
  15. ipset_node_reachable_count(const struct ipset_node_cache *cache,
  16. ipset_node_id node)
  17. {
  18. /* Create a set to track when we've visited a given node. */
  19. struct cork_hash_table *visited = cork_pointer_hash_table_new(0, 0);
  20. /* And a queue of nodes to check. */
  21. cork_array(ipset_node_id) queue;
  22. cork_array_init(&queue);
  23. if (ipset_node_get_type(node) == IPSET_NONTERMINAL_NODE) {
  24. DEBUG("Adding node %u to queue", node);
  25. cork_array_append(&queue, node);
  26. }
  27. /* And somewhere to store the result. */
  28. size_t node_count = 0;
  29. /* Check each node in turn. */
  30. while (!cork_array_is_empty(&queue)) {
  31. ipset_node_id curr = cork_array_at(&queue, --queue.size);
  32. /* We don't have to do anything if this node is already in the
  33. * visited set. */
  34. if (cork_hash_table_get(visited, (void *) (uintptr_t) curr) == NULL) {
  35. DEBUG("Visiting node %u for the first time", curr);
  36. /* Add the node to the visited set. */
  37. cork_hash_table_put
  38. (visited, (void *) (uintptr_t) curr,
  39. (void *) (uintptr_t) true, NULL, NULL, NULL);
  40. /* Increase the node count. */
  41. node_count++;
  42. /* And add the node's nonterminal children to the visit
  43. * queue. */
  44. struct ipset_node *node =
  45. ipset_node_cache_get_nonterminal(cache, curr);
  46. if (ipset_node_get_type(node->low) == IPSET_NONTERMINAL_NODE) {
  47. DEBUG("Adding node %u to queue", node->low);
  48. cork_array_append(&queue, node->low);
  49. }
  50. if (ipset_node_get_type(node->high) == IPSET_NONTERMINAL_NODE) {
  51. DEBUG("Adding node %u to queue", node->high);
  52. cork_array_append(&queue, node->high);
  53. }
  54. }
  55. }
  56. /* Return the result, freeing everything before we go. */
  57. cork_hash_table_free(visited);
  58. cork_array_done(&queue);
  59. return node_count;
  60. }
  61. size_t
  62. ipset_node_memory_size(const struct ipset_node_cache *cache,
  63. ipset_node_id node)
  64. {
  65. return ipset_node_reachable_count(cache, node) * sizeof(struct ipset_node);
  66. }