Beispiel #1
0
size_t
ipset_node_reachable_count(const struct ipset_node_cache *cache,
                           ipset_node_id node)
{
    /* Create a set to track when we've visited a given node. */
    struct cork_hash_table  *visited = cork_pointer_hash_table_new(0, 0);

    /* And a queue of nodes to check. */
    cork_array(ipset_node_id)  queue;
    cork_array_init(&queue);

    if (ipset_node_get_type(node) == IPSET_NONTERMINAL_NODE) {
        DEBUG("Adding node %u to queue", node);
        cork_array_append(&queue, node);
    }

    /* And somewhere to store the result. */
    size_t  node_count = 0;

    /* Check each node in turn. */
    while (!cork_array_is_empty(&queue)) {
        ipset_node_id  curr = cork_array_at(&queue, --queue.size);

        /* We don't have to do anything if this node is already in the
         * visited set. */
        if (cork_hash_table_get(visited, (void *) (uintptr_t) curr) == NULL) {
            DEBUG("Visiting node %u for the first time", curr);

            /* Add the node to the visited set. */
            cork_hash_table_put
                (visited, (void *) (uintptr_t) curr,
                 (void *) (uintptr_t) true, NULL, NULL, NULL);

            /* Increase the node count. */
            node_count++;

            /* And add the node's nonterminal children to the visit
             * queue. */
            struct ipset_node  *node =
                ipset_node_cache_get_nonterminal(cache, curr);

            if (ipset_node_get_type(node->low) == IPSET_NONTERMINAL_NODE) {
                DEBUG("Adding node %u to queue", node->low);
                cork_array_append(&queue, node->low);
            }

            if (ipset_node_get_type(node->high) == IPSET_NONTERMINAL_NODE) {
                DEBUG("Adding node %u to queue", node->high);
                cork_array_append(&queue, node->high);
            }
        }
    }

    /* Return the result, freeing everything before we go. */
    cork_hash_table_free(visited);
    cork_array_done(&queue);
    return node_count;
}
Beispiel #2
0
static int
save_bdd(struct save_data *save_data,
         struct ipset_node_cache *cache, ipset_node_id root)
{
    /* First, output the file header. */

    DEBUG("Writing file header");
    rii_check(save_data->write_header(save_data, cache, root));

    /* The serialized node IDs are different than the in-memory node
     * IDs.  This means that, for our nonterminal nodes, we need a
     * mapping from internal node ID to serialized node ID. */

    DEBUG("Creating file caches");
    save_data->serialized_ids = cork_pointer_hash_table_new(0, 0);
    save_data->next_serialized_id = -1;

    /* Trace down through the BDD tree, outputting each terminal and
     * nonterminal node as they're encountered. */

    DEBUG("Writing nodes");

    serialized_id  last_serialized_id;
    ei_check(save_visit_node(save_data, root, &last_serialized_id));

    /* Finally, output the file footer and cleanup. */

    DEBUG("Writing file footer");
    ei_check(save_data->write_footer(save_data, cache, root));

    DEBUG("Freeing file caches");
    cork_hash_table_free(save_data->serialized_ids);
    return 0;

  error:
    /* If there's an error, clean up the objects that we've created
     * before returning. */
    cork_hash_table_free(save_data->serialized_ids);
    return -1;
}