/*
** Copyright (C) 2004-2007 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract F19628-00-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/
#ifndef _BAGTREE_H
#define _BAGTREE_H

#include "silk.h"

RCSIDENTVAR(rcsID_BAGTREE_H, "$SiLK: bagtree.h 7514 2007-06-14 12:20:54Z mthomas $");


/*
**  bagtree.h
**
**  Christopher Lee
**  2004-11-04
**
**  A Bag is a static (but variable) depth tree, where a key is
**  encoded into the tree structure, and blocks of counters are stored
**  in the leaf nodes.
**
**  It would be nice to have more-variable size keys and values, but
**  that has not been worked out.
*/

#include "utils.h"
#include "skstream.h"


/* DEFINES AND TYPEDEFS */

/* Return codes */
typedef enum skBag_err_e {
    SKBAG_OK = 0,
    SKBAG_ERR_MEMORY = 1,
    SKBAG_ERR_KEY_NOT_FOUND = 2,
    SKBAG_ERR_INPUT = 3,
    SKBAG_ERR_OP_BOUNDS = 4,
    SKBAG_ERR_OUTPUT = 5
} skBag_err_t;

/* the number of a level */
typedef uint8_t skBag_level_t;

/* the number of bits encoded on a level */
typedef uint8_t skBag_levelsize_t;

/* the number of entries in a node/leaf */
typedef uint32_t skBag_blocksize_t;

/* a key encoded in the tree */
typedef uint32_t skBag_key_t;

/* a counter */
typedef uint64_t skBag_counter_t;

/* A node either points to another node or to a counter */
union _skBag_node;
typedef union _skBag_node skBag_node_t;
union _skBag_node {
    skBag_node_t       *child;
    skBag_counter_t    *leaf;
};

/* Forward declaration of statistics about the bag data structure */
struct _skBag_stats;
typedef struct _skBag_stats skBag_stats_t;

/* The SiLK Bag */
typedef struct _skBag_header {
    /* the root of the bag */
    skBag_node_t        root;
    /* number of levels in the tree */
    skBag_level_t       levels;
    /* array of length "levels", each entry is the number of bits
     * encoded in a level. */
    skBag_levelsize_t  *level_size;
    /* the offset at every level: the sum of the offsets at every
     * level below this one. */
    skBag_levelsize_t  *level_offset;
    /* statistics about the bag */
    skBag_stats_t      *stats;
} skBag_header_t;


/* Structure used to iterate over bags */
struct _skBag_iterator;
typedef struct _skBag_iterator skBag_iterator_t;


#define SKBAG_KEY_MIN       ((skBag_key_t)0)
#define SKBAG_KEY_MAX       (~((skBag_key_t)0))
#define SKBAG_COUNTER_MIN   ((skBag_counter_t)0)
#define SKBAG_COUNTER_MAX   (~((skBag_counter_t)0))



/* FUNCTION DECLARATIONS */

/*
 *  status = skBag_alloc(&bag, num_levels, level_sizes);
 *
 *    Allocate memory for a new bag, and set '*bag' to point to it.
 *    The new bag should be 'num_levels' levels deep (counting leaf
 *    nodes), and each level 'i' should encode 'level_sizes[i]' bits
 *    of data.
 *
 *    For example, to create a 9/9/9/5 IP space tree:
 *
 *        skBag_header_t *bag;
 *        skBag_levelsize_t level_sizes[4] = { 9, 9, 9, 5 };
 *        skBag_alloc(&bag, 4, level_sizes);
 */
skBag_err_t skBag_alloc(
    skBag_header_t            **bag,
    skBag_level_t               levels,
    const skBag_levelsize_t    *level_sizes);


/*
 *  status = skBag_create(&bag);
 *
 *    Allocate memory for a new Bag and set '*bag' to point to it.
 *    The bag is created with 4 levels, with 9/9/9/5 IPs each.
 */
skBag_err_t skBag_create(
    skBag_header_t            **bag);


/*
 *  status = skBag_free(bag);
 *
 *   Free all memory associated with the bag 'bag'.  It is an error if
 *   bag is NULL.
 */
skBag_err_t skBag_free(
    skBag_header_t         *bag);


/*
 *  status = skBag_addToCounter(bag, &key, &value_add);
 *
 *    Given 'key', a pointer to a key, increment the counter
 *    associated with that key in the bag 'bag' by the value in
 *    '*value_add'.  Creates the key if it does not exist in the bag.
 *
 *    Will return SKBAG_ERR_OP_BOUNDS if the addition would exceed the
 *    counter size and cause it to overflow.
 */
skBag_err_t skBag_addToCounter(
    skBag_header_t         *bag,
    const skBag_key_t      *key,
    const skBag_counter_t  *value_add);


/*
 *  status = skBag_getCounter(bag, &key, &counter);
 *
 *   Get the counter associated with key stored in 'key' from the bag
 *   'bag', and put its value into 'counter'.
 */
skBag_err_t skBag_getCounter(
    const skBag_header_t   *bag,
    const skBag_key_t      *key,
    skBag_counter_t        *counter);


/*
 *  status = skBag_incrCounter(bag, &key);
 *
 *    Given 'key', a pointer to a key, increment the counter
 *    associated with that key in the bag 'bag' by one.  Creates the
 *    key if it does not exist in the bag.
 */
skBag_err_t skBag_incrCounter(
    skBag_header_t         *bag,
    const skBag_key_t      *key);


/*
 *  status = skBag_setCounter(bag, &key, &value);
 *
 *    Given 'key', a pointer to a key, set the counter associated with
 *    that key in the bag 'bag' to the value specified in '*value'.
 *    Creates the key if it does not exist in the bag.
 */
skBag_err_t skBag_setCounter(
    skBag_header_t         *bag,
    const skBag_key_t      *key,
    const skBag_counter_t  *value);


/*
 *  status = skBag_subtractFromCounter(bag, &key, &value_sub);
 *
 *    Given 'key', a pointer to a key, decrement the counter
 *    associated with that key in the bag 'bag' by the value in
 *    '*value_sub'.  The key must exist in the bag.
 *
 *    Will return SKBAG_ERR_OP_BOUNDS if the subtraction would cause
 *    the counter to become negative
 */
skBag_err_t skBag_subtractFromCounter(
    skBag_header_t         *bag,
    const skBag_key_t      *key,
    const skBag_counter_t  *value_sub);


/*
 *
 *   BAG ITERATOR API FUNCTIONS
 *
 */


/*
 *  status = skBag_allocIterator(bag, &iter);
 *
 *    Create a new iterator to iterate over the bag 'bag' and store
 *    the iterator in '*iter'.  The iterator is initialized so that
 *    the first call to skBag_getNext will return the counter
 *    associated with the first key
 */
skBag_err_t skBag_allocIterator(
    const skBag_header_t   *bag,
    skBag_iterator_t      **iter);


/*
 *  status = skBag_freeIterator(iter);
 *
 *    Deallocate all memory associated with the bag iterator 'iter'.
 */
skBag_err_t skBag_freeIterator(
    skBag_iterator_t       *iter);


/*
 *  status = skBag_resetIterator(iter);
 *
 *    Reset the iterator at 'iter' so the next call to skBag_getNext
 *    will return the counter associated with the first key.
 */
skBag_err_t skBag_resetIterator(
    skBag_iterator_t       *iter);


/*
 *  status = skBag_getNext(iter, &key, &counter);
 *
 *    Get the next key/counter pair associated with the given
 *    iterator, 'iter', and store them in the memory pointed at by
 *    'key' and 'counter', respectively.
 */
skBag_err_t skBag_getNext(
    skBag_iterator_t       *iter,
    skBag_key_t            *key,
    skBag_counter_t        *counter);


/*
 *
 *    EXPORTED BAG I/O API FUNCTIONS
 *
 */


/*
 *  status = skBag_printTreeStats(bag, stream);
 *
 *    Print to the stream 'stream' metadata on how the bag 'bag' is
 *    performing.
 */
skBag_err_t skBag_printTreeStats(
    const skBag_header_t   *bag,
    skstream_t             *stream_out);


/*
 *  status = skBag_writeArray(counter_array, num_keys, stream);
 *
 *    Create a Bag file from an array by writing 'counter_array', an
 *    array of skBag_counter_t values indexed from 0 to 'num_keys'-1,
 *    to the output stream 'stream'.  The caller may set the
 *    compression method of 'stream' before calling this function.
 */
skBag_err_t skBag_writeArray(
    const skBag_counter_t  *counter_data,
    skBag_key_t             num_keys,
    skstream_t             *stream);


/*
 *  status = skBag_writeBinary(bag, stream);
 *
 *    Serialize the bag 'bag' to the output stream 'stream'.  The
 *    caller may set the compression method of 'stream' before calling
 *    this function.
 */
skBag_err_t skBag_writeBinary(
    const skBag_header_t   *bag,
    skstream_t             *stream_out);


/*
 *  status = skBag_readBinary(&bag, stream);
 *
 *    Create a new bag at '*bag' and read a serialized bag from the
 *    input stream 'stream' into the new bag.
 */
skBag_err_t skBag_readBinary(
    skBag_header_t        **bag,
    skstream_t             *stream_in);


/*
 *  status = skBag_addBinary(&bag, stream);
 *
 *    Read a serialized bag from the input stream 'stream' and add
 *    it's key/counter pairs to the existing bag 'bag'.  New keys will
 *    be created if required; existing keys will value their values
 *    summed.
 */
skBag_err_t skBag_addBinary(
    skBag_header_t         *bag,
    skstream_t             *stream_in);


/*
 *  error_string = skBag_strerror(code);
 *
 *    Return a static string describing the skBag_err_t value 'code'.
 */
const char *skBag_strerror(
    skBag_err_t             err_code);
 

#endif /* _BAGTREE_H */


/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/
