PreviousUpNext

15.4.887  src/lib/src/int-hashtable.pkg

## int-hashtable.pkg
## AUTHOR:   John Reppy
##          Bell Labs
##          Murray Hill, NJ 07974
##          jhr@research.bell-labs.com

# Compiled by:
#     src/lib/std/standard.lib

# A specialization of the hashtable generic to integer keys.




#                          "If it is not beautiful, it is not done."



package int_hashtable
:
Typelocked_Hashtable            # Typelocked_Hashtable  is from   src/lib/src/typelocked-hashtable.api
where
    key::Hash_Key == Int
=
package {

    package key {

        Hash_Key = Int;

        fun same_key (a:  Int, b)
            =
            a == b;

        fun hash_value a
            =
            unt::from_int a;
    };

    include key;

    package htrep= hashtable_representation;    # hashtable_representation      is from   src/lib/src/hashtable-rep.pkg

    Hashtable X
        =
        HASHTABLE  {
            not_found_exception:  Exception,
            table:  Ref( htrep::Table( Hash_Key, X ) ),
            n_items:  Ref( Int )
        };

    fun index (i, size)
        =
        unt::to_int_x( unt::bitwise_and( i, unt::from_int size - 0u1));

    # Create a new table;
    # The int is a size hint and the exception
    # is to be raised by find.
    #
    fun make_hashtable { size_hint, not_found_exception }
        =
        HASHTABLE {
            not_found_exception,
            table     => REF (htrep::alloc size_hint),
            n_items   => REF 0
        };

    # Remove all elements from the table: 
    #
    fun clear (HASHTABLE { table, n_items, ... } )
        =
        {   htrep::clear *table;
            n_items := 0;
        };

    # Insert an item.
    #
    # If the key already has an
    # item associated with it,
    # then the old item is discarded.
    #
    fun set (my_table as HASHTABLE { table, n_items, ... } ) (key, item)
        =
        {
            arr = *table;
            size = rw_vector::length arr;
            hash = hash_value key;
            index = index (hash, size);

            fun get htrep::NIL
                    =>
                    {   rw_vector::set (arr, index, htrep::BUCKET (hash, key, item, rw_vector::get (arr, index)));
                        n_items := *n_items + 1;
                        htrep::grow_table_if_needed (table, *n_items);
                        htrep::NIL;
                    };
                get (htrep::BUCKET (h, k, v, r))
                    =>
                    if   (hash == h   and   same_key (key, k))
                         htrep::BUCKET (hash, key, item, r);
                    else
                         case (get  r)
                              htrep::NIL =>  htrep::NIL;
                              rest       =>  htrep::BUCKET (h, k, v, rest);
                         esac;
                    fi;
            end;
          
            case (get (rw_vector::get (arr, index)))
              
                 htrep::NIL =>  ();
                 b          =>  rw_vector::set (arr, index, b);
            esac;

        };

    #  Return TRUE, if the key is in the domain of the table: 
    #
    fun contains_key (HASHTABLE { table, ... } ) key
        =
        get' (rw_vector::get (arr, index))
        where
            arr   =  *table;
            hash  =  hash_value key;

            index =  index (hash, rw_vector::length arr);

            fun get' htrep::NIL
                    =>
                    FALSE;

                get' (htrep::BUCKET (h, k, v, r))
                    => 
                    ((hash == h) and same_key (key, k))
                    or
                    get' r;
            end;
        end;

    # Find an item, the table's exception
    # is raised if the item doesn't exist:
    #
    fun get (HASHTABLE { table, not_found_exception, ... } ) key
        =
        get' (rw_vector::get (arr, index))
        where

            arr = *table;
            hash = hash_value key;
            index = index (hash, rw_vector::length arr);

            fun get' htrep::NIL
                    =>
                    raise exception not_found_exception;

                get' (htrep::BUCKET (h, k, v, r))
                    =>
                    if (hash == h  and  same_key (key, k))   v;
                    else                                     get' r;
                    fi;
            end;
        end;

    # Look up for an item,
    # return NULL if the item doesn't exist: 
    #
    fun find (HASHTABLE { table, ... } ) key
        =
        get' (rw_vector::get (arr, index))
        where
         
            arr = *table;
            size = rw_vector::length arr;
            hash = hash_value key;
            index = index (hash, size);

            fun get' htrep::NIL
                    =>
                    NULL;

                get' (htrep::BUCKET (h, k, v, r))
                    =>
                    if (hash == h and same_key (key, k))   THE v;
                    else                                   get' r;
                    fi;
            end;
        end;

    # Remove an item.  The table's exception is raised if
    # the item doesn't exist.
    #
    fun remove (HASHTABLE { not_found_exception, table, n_items } ) key
        =
        {
            arr = *table;
            size = rw_vector::length arr;
            hash = hash_value key;
            index = index (hash, size);

            fun get' htrep::NIL
                    =>
                    raise exception not_found_exception;

                get' (htrep::BUCKET (h, k, v, r))
                    =>
                    if (hash == h and same_key (key, k))
                         (v, r);
                    else
                         my (item, r') = get' r;
                         (item, htrep::BUCKET (h, k, v, r'));
                    fi;
            end;

            my (item, bucket) = get' (rw_vector::get (arr, index));

            rw_vector::set (arr, index, bucket);
            n_items := *n_items - 1;
            item;
        };

   # Return the number of items in the table:
   #
   fun vals_count (HASHTABLE { n_items, ... } ) = *n_items;

    # Return a list of the items in the table:
    #
    fun vals_list (HASHTABLE { table => REF arr, n_items, ... } )
        =
        htrep::vals_list (arr, n_items);

    fun keyvals_list (HASHTABLE { table => REF arr, n_items, ... } )
        =
        htrep::keyvals_list (arr, n_items);

    # Apply a function to the entries of the table:
    #
    fun keyed_apply f (HASHTABLE { table, ... } ) = htrep::keyed_apply f *table;
    fun apply f (HASHTABLE { table, ... } ) = htrep::apply f *table;

    # Map a table to a new table
    # that has the same keys and exception: 
    #
    fun keyed_map f (HASHTABLE { table, n_items, not_found_exception } )
        =
        HASHTABLE {
            table => REF (htrep::keyed_map f *table),
            n_items => REF *n_items,
            not_found_exception
          };

    fun map f (HASHTABLE { table, n_items, not_found_exception } )
        =
        HASHTABLE {
            table => REF (htrep::map f *table),
            n_items => REF *n_items,
            not_found_exception
        };

    # Fold a function over the entries of the table:
    #
    fun foldi f init (HASHTABLE { table, ... } ) =  htrep::foldi f init *table;
    fun fold f  init (HASHTABLE { table, ... } ) =  htrep::fold  f init *table;

    # Modify the hashtable items in place:
    #
    fun modifyi f (HASHTABLE { table, ... } ) =  htrep::modifyi f *table;
    fun modify  f (HASHTABLE { table, ... } ) =  htrep::modify  f *table;

    # Remove any hashtable items that
    # do not satisfy the given predicate:
    #
    fun keyed_filter prior (HASHTABLE { table, n_items, ... } )
        =
        n_items := htrep::keyed_filter prior *table;

    fun filter prior (HASHTABLE { table, n_items, ... } )
        = 
        n_items := htrep::filter prior *table;

    # Create a copy of a hashtable 
    #
    fun copy (HASHTABLE { table, n_items, not_found_exception } )
        =
        HASHTABLE {
          table   =>  REF (htrep::copy *table),
          n_items =>  REF *n_items,
          not_found_exception
        };

    # Return a list of the sizes of the various buckets.  This is to
    # allow users to gauge the quality of their hashing function.
    #
    fun bucket_sizes (HASHTABLE { table, ... } )
            =
            htrep::bucket_sizes *table;

};      # package int_hashtable_g 


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext