head	1.1;
branch	1.1.1;
access;
symbols
	tonic_4:1.1.1.1
	tonic_3:1.1.1.1
	tonic_2:1.1.1.1
	demo:1.1.1.1.0.2
	design_report:1.1.1.1
	dec5:1.1.1.1
	course_staff:1.1.1;
locks; strict;
comment	@ * @;


1.1
date	95.12.05.07.25.51;	author hartmans;	state Exp;
branches
	1.1.1.1;
next	;

1.1.1.1
date	95.12.05.07.25.52;	author hartmans;	state Exp;
branches;
next	;


desc
@@



1.1
log
@Initial revision
@
text
@#ifndef _HASH_MAP_H
#define _HASH_MAP_H

// Copyright 1995 Barbara Liskov

#include <stddef.h>
#include <assert.h>
#include "basic.h"
#include "generator.h"

/*
    Maps
    ----

    This file defines three easy-to-use implementations of a
    parameterized map type, all based on the same underlying
    dynamically-resizing chained hash table.  Which precise
    implementation should be chosen depends on the choice of key and
    value types.

    "map<KEY,VALUE>": an efficient implementation using chained buckets.
        Has the weakness that each bucket is long-word aligned, possibly
        wasting space. It also generates new code for every instantiation.
    
    "ptr_map<KEY,VALUE>": on most machines, an efficient implementation for
        the case where KEY and VALUE are both pointer types. The win over
        "map" is that all "ptr_map"s share the same code.
    
    "packed_map<KEY, VALUE>": provides extremely compact storage of pairs
        by placing keys and values in their own separate arrays. The
        definition of "packed_map" is contained in "packed_map.h".

    The interface to all these map classes is the following:

    int size() const;
      // Returns the number of (k, v) pairs in the table

    void add(KEY, VALUE);
      // Checks: the table does not already contain a mapping for the key.
      // Effects: Adds a new mapping to the hash table.

    bool find(KEY k, VALUE &v) const;
      // Replace "v" with the value corresponding to "k"
      //    and return TRUE. Return FALSE if no such value exists.

    VALUE fetch(KEY k) const;
    VALUE operator[](KEY k) const;
      // Checks: there is a mapping for "k".
      // Effects: returns the value corresponding to "k".

    bool contains(KEY k) const;
      // Return whether there is a mapping for "k".

    bool store(KEY, VALUE);
      // If a mapping already exists, store the value
      //     under the specified key, replacing the existing mapping.
      //     Otherwise, add a new mapping. Return TRUE if there was
      //     an existing mapping.

    bool remove(KEY k, VALUE &v);
      // If there is a mapping for "k", remove the mapping, return TRUE,
      // and put the corresponding value in that mapping into "v".
      // Otherwise, return FALSE.

//  Performance Hints
//
//  The following operations have no effect on the correctness of the
//  map, but they allow the user to provide extra information that may
//  improve the performance of the map, or help diagnose why the performance
//  of the map is not as good as expected.

    void predict(int size);
      //    Indicate that you would like the hash table to contain "size"
      //    buckets. This is useful for obtaining optimal
      //    performance when many new mappings are being added at once. It
      //    may be an expensive operation, though it has no semantic effect.
      //    For best performance, "size" should be at least as large as the
      //    number of elements. This operation is O(size()).
        
    void allowAutoResize();
      //    Allow the hash table to rehash its mappings so that optimal
      //    performance is achieved. This operation is O(size()).
      //    The hash table will not rehash the mappings if it is
      //    at a reasonable size already.

    float estimateEfficiency() const;
      //    Return the average expected number of buckets in a bucket chain.
      //    If this number is "n", the expected number of buckets that will be
      //    looked at when a "fetch" or "remove" operation is performed is
      //    roughly "1 + n/2". Efficiency should be 1 for maximal speed.

    float estimateClumping() const;
      //    Evaluate how well the current hash function is working. This number
      //    should be close to one if the hash function is working well. If
      //    the clumping is less than 1.0, the hash function is doing better
      //    than a perfect hash function would be expected to, by magically
      //    avoiding collisions. A clumping of K means that the hash function
      //    is doing as badly as a hash function that only generates a
      //    fraction 1/K of the hash indices.

   Generators
   ----------

   To iterate over the mappings in a map, use a generator: a data
   structure that successively produces each of the keys of the map.
   A generator is used in the following fashion:

        map *m;
        ...
        generator<KEY> *g = m->keys();
        KEY k;
        while (g->get(k)) { ... }
        delete g; // necessary if you do not have garbage collection

   If the generator is declared as a "hash_generator<KEY, VALUE> *",
   the current value can be accessed with "value", and the
   current mapping can be removed from the map by calling "remove", e.g.

        map *m;
        ...
        hash_generator<KEY, VALUE> *g = m->keys();
        KEY k;
        while (g->get(k)) { if (g->value() == v2) g->remove(); }

   Any number of generators may exist for a map. While any generator
   exists, no non-const method of "map" may be called on the object that
   the generator is attached to. There are two methods for making a
   generator attached a map:

    hash_generator<KEY, VALUE> *mappings();
        // Return a hash generator, which allows the associated
        // value to be obtained easily, and also allows the current
        // mapping to be removed.

    generator<KEY> *keys() const;
        // Return an ordinary generator, which does not allow the
        // map to be modified.

   The specification of "hash_generator" is as follows:
*/

template <class KEY, class VALUE>
class hash_generator : public generator<KEY> {
    /*
        A "hash_generator" generates all key/value pairs in a hash
        table. It can be in one of three states: "readable",
        "removable", and "finished".  It also points to some element of
        the table unless it is in the "finished" state.  A new
        "hash_generator" starts in the "readable" state, pointing to the
        first element.
    */
public:
    hash_generator() {}
    virtual bool get(KEY &) = 0;
          /*
             Requires: The generator is not in the "finished" state.
             Effects: If there is another unyielded key, places it in "k"
                 enters the "removable" state, and returns TRUE.
                 Otherwise, enters the "finished" state and return FALSE.
          */
    virtual VALUE value() const = 0;
          /*
             Requires: The generator is not in the "finished" state.
             Effects: The currently pointed-to value
          */
    virtual void remove() = 0;
          /*
             Requires: The generator is in the "removable" state.
             Effects: Deletes the pointed-to element and point to the next
                 element, entering the "readable" state.
          */
};

#include "bhash.h"

/*
    The "map" class is a easy-to-use map from KEY to VALUE, i.e.
    "map<int_key, char>" is a map from integers to characters. It supports
    all the operations described above. See "bhash.h" for implementation
    details.
*/

template <class KEY, class VALUE> class map
         : public bhash<KEY, VALUE, buckets<KEY, VALUE> >
{
public:
    map(int size_hint) : bhash<KEY, VALUE,
	buckets<KEY, VALUE> >(size_hint) {}
    map() : bhash<KEY, VALUE, buckets<KEY, VALUE> >(0) {}
    VALUE fetch(KEY k) { return operator[](k); }
};

/*
    The classes "KEY" and "VALUE" must conform to the following declarations:

class KEY {
    // A key must be a hashable value. Often, a "KEY" is a wrapper class
    // that provides an inlined "hash" implementation. Ideally, the hash
    // function does not lose information about the value that is being
    // hashed: a good implementation of a hash function for an integer key
    // would be the identity function.

    KEY(KEY const &);                    // Keys can be copied
    ~KEY();                              // Keys can be destroyed. 
    operator=(KEY const &);              // Keys can be overwritten
    operator==(KEY const &key2) const;   // Returns whether they are equal
    int hash() const;                    // Returns a hash key for this value 
      
};

class VALUE {
    VALUE(VALUE const &);         // Values can be copied.
    ~VALUE();                     // Values can be destroyed.
};
*/


/*
    The following classes are useful if you want to use a primitive type
    as a key, since the primitive types do not have a built-in hash()
    function:
*/

class int_key {
public:
    int_key() : val(0) {} // need this for use with generators, annoyingly
    int_key(int a) : val(a) {}
    void operator=(int_key const &x) { val = x.val; }
    int hash() const { return val; }
    bool operator==(int_key const &x) { return (x.val == val) ? TRUE : FALSE; }
    int val;
};

class char_key {
public:
    char_key() : val(0) {} // need this for use with generators, annoyingly
    char_key(char a) : val(a) {}
    void operator=(char_key const &x) { val = x.val; }
    int hash() const { return val; }
    bool operator==(char_key const &x) { return (x.val == val) ? TRUE : FALSE; }
    char val;
};

/* A "ptr_key" is a useful class that provides a key for any pointer type.
T can be any type. */
template <class T>
class ptr_key {
public:
    ptr_key() : val(0) {}
    ptr_key(T *a) : val(a) {}
    void operator=(ptr_key<T> const &x) { val = x.val; }
    int hash() const { return int(*((ptrdiff_t *)&val) >> 2); }
    bool operator==(ptr_key<T> const &x)
        { return (x.val == val) ? TRUE : FALSE; } 
    T * val;
};

/*
    The "ptr_map" class is a easy-to-use map from KEY * to VALUE *, i.e.
    "ptr_map<int, Foo>" is a map from integer pointers to Foo *.
    "ptr_map" supports all the operations of bhash.
*/
#define _superclass bhash<ptr_key<void>,                                  \
                         void *,                                         \
                         buckets<ptr_key<void>, void *> >
#define K ptr_key<void>((void *)k)
template <class KEY, class VALUE> class ptr_map : private _superclass {
public:
    ptr_map() : _superclass(0) {}
    ptr_map(int size_hint) : _superclass(size_hint) {}
    int size() const { return _superclass::size(); }
    void add(KEY *k, VALUE *v) { _superclass::add(K, (void *)v); }
    bool find(KEY *k, VALUE *&v) { return _superclass::find(K, (void *&)v); }
    VALUE *fetch(KEY *k) const
        { return (VALUE *)_superclass::operator[](K); }
    VALUE *operator[](KEY *k) const
        { return (VALUE *)_superclass::operator[](K); }
    bool contains(KEY *k) const {return _superclass::contains(K); }
    bool store(KEY *k, VALUE *v) { return _superclass::store(K, v); }
    bool remove(KEY *k, VALUE *&v)
        { return _superclass::remove(K, (void *&)v); } 
    void predict(int size) { _superclass::predict(size); }
    void allowAutoResize() { _superclass::allowAutoResize(); }
    float estimateEfficiency() const { _superclass::estimateEfficiency(); }
    float estimateClumping() const {_superclass::estimateClumping(); }
    hash_generator<KEY *, VALUE *> *mappings()
        { return (hash_generator<KEY *, VALUE *> *)_superclass::mappings(); }
};
#undef _superclass
#undef K

#define packed_map map

#endif /* _HASH_MAP_H */
@


1.1.1.1
log
@More lossage fixup
@
text
@@
