Beispiel #1
0
static int
save_visit_node(struct save_data *save_data,
                ipset_node_id node_id, serialized_id *dest)
{
    /* Check whether we've already serialized this node. */

    struct cork_hash_table_entry  *entry;
    bool  is_new;
    entry = cork_hash_table_get_or_create
        (save_data->serialized_ids, (void *) (uintptr_t) node_id, &is_new);

    if (!is_new) {
        *dest = (intptr_t) entry->value;
        return 0;
    } else {
        if (ipset_node_get_type(node_id) == IPSET_TERMINAL_NODE) {
            /* For terminals, there isn't really anything to do — we
             * just output the terminal node and use its value as the
             * serialized ID. */

            ipset_value  value = ipset_terminal_value(node_id);

            DEBUG("Writing terminal(%d)", value);
            rii_check(save_data->write_terminal(save_data, value));
            entry->value = (void *) (intptr_t) value;
            *dest = value;
            return 0;
        } else {
            /* For nonterminals, we drill down into the node's children
             * first, then output the nonterminal node. */

            struct ipset_node  *node =
                ipset_node_cache_get_nonterminal(save_data->cache, node_id);
            DEBUG("Visiting node %u nonterminal(x%u? %u: %u)",
                  node_id, node->variable, node->high, node->low);

            /* Output the node's nonterminal children before we output
             * the node itself. */
            serialized_id  serialized_low;
            serialized_id  serialized_high;
            rii_check(save_visit_node(save_data, node->low, &serialized_low));
            rii_check(save_visit_node(save_data, node->high, &serialized_high));

            /* Output the nonterminal */
            serialized_id  result = save_data->next_serialized_id--;
            DEBUG("Writing node %u as serialized node %d = (x%u? %d: %d)",
                  node_id, result,
                  node->variable, serialized_low, serialized_high);

            entry->value = (void *) (intptr_t) result;
            *dest = result;
            return save_data->write_nonterminal
                (save_data, result, node->variable,
                 serialized_low, serialized_high);
        }
    }
}
Beispiel #2
0
static int
write_footer_v1(struct save_data *save_data,
                struct ipset_node_cache *cache, ipset_node_id root)
{
    /* If the root is a terminal node, then we output the terminal value
     * in place of the (nonexistent) list of nonterminal nodes. */

    if (ipset_node_get_type(root) == IPSET_TERMINAL_NODE) {
        ipset_value  value = ipset_terminal_value(root);
        return write_uint32(save_data->stream, value);
    }

    return 0;
}
Beispiel #3
0
/**
 * Add the given node ID to the node stack, and trace down from it
 * until we find a terminal node.  Assign values to the variables for
 * each nonterminal that encounter along the way.  We check low edges
 * first, so each new variable we encounter will be assigned FALSE.
 * (The high edges will be checked eventually by a call to the
 * ipset_bdd_iterator_advance() function.)
 */
static void
add_node(struct ipset_bdd_iterator *iterator, ipset_node_id node_id)
{
    /* Keep tracing down low edges until we reach a terminal. */
    while (ipset_node_get_type(node_id) == IPSET_NONTERMINAL_NODE) {
        /* Add this nonterminal node to the stack, and trace down
         * further into the tree.  We check low edges first, so set the
         * node's variable to FALSE in the assignment. */
        struct ipset_node  *node =
            ipset_node_cache_get_nonterminal(iterator->cache, node_id);

        cork_array_append(&iterator->stack, node_id);
        ipset_assignment_set(iterator->assignment, node->variable, false);

        node_id = node->low;
    }

    /* Once we find a terminal node, save it away in the iterator result
     * and return. */
    iterator->value = ipset_terminal_value(node_id);
}
static ipset_node_id_t
cached_ite(ipset_node_cache_t *cache,
           ipset_node_id_t f,
           ipset_node_id_t g,
           ipset_node_id_t h)
{
    g_d_debug("Applying ITE(%p,%p,%p)", f, g, h);

    /*
     * Some trivial cases first.
     */

    /*
     * If F is a terminal, then we're in one of the following two
     * cases:
     *
     *   ITE(1,G,H) = G
     *   ITE(0,G,H) = H
     */

    if (ipset_node_get_type(f) == IPSET_TERMINAL_NODE)
    {
        ipset_range_t  f_value = ipset_terminal_value(f);
        ipset_node_id_t  result = (f_value == 0)? h: g;
        g_d_debug("Trivial result = %p", result);
        return result;
    }

    /*
     * ITE(F,G,G) == G
     */

    if (g == h)
    {
        g_d_debug("Trivial result = %p", g);
        return g;
    }

    /*
     * ITE(F,1,0) = F
     */

    if ((ipset_node_get_type(g) == IPSET_TERMINAL_NODE) &&
        (ipset_node_get_type(h) == IPSET_TERMINAL_NODE))
    {
        ipset_range_t  g_value = ipset_terminal_value(g);
        ipset_range_t  h_value = ipset_terminal_value(h);

        if ((g_value == 1) && (h_value == 0))
        {
            g_d_debug("Trivial result = %p", f);
            return f;
        }
    }

    /*
     * Check to see if we've already performed the operation on these
     * operands.
     */

    ipset_trinary_key_t  search_key;
    ipset_trinary_key_init(&search_key, f, g, h);

    gpointer  found_key;
    gpointer  found_result;
    gboolean  node_exists =
        g_hash_table_lookup_extended(cache->ite_cache,
                                     &search_key,
                                     &found_key,
                                     &found_result);

    if (node_exists)
    {
        /*
         * There's a result in the cache, so return it.
         */

        g_d_debug("Existing result = %p", found_result);
        return found_result;
    } else {
        /*
         * This result doesn't exist yet.  Allocate a permanent copy
         * of the key.  Apply the operator, add the result to the
         * cache, and then return it.
         */

        ipset_trinary_key_t  *real_key =
            g_slice_new(ipset_trinary_key_t);
        memcpy(real_key, &search_key, sizeof(ipset_trinary_key_t));

        ipset_node_id_t  result =
            apply_ite(cache, f, g, h);
        g_d_debug("NEW result = %p", result);

        g_hash_table_insert(cache->ite_cache, real_key, result);
        return result;
    }
}