/*****************************************************************************

  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
  more contributor license agreements.  See the NOTICE file distributed
  with this work for additional information regarding copyright ownership.
  Accellera licenses this file to you under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with the
  License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  implied.  See the License for the specific language governing
  permissions and limitations under the License.

 *****************************************************************************/

/*****************************************************************************

  sc_hash.cpp -- Implementation of a chained hash table with MTF
                 (move-to-front).

  Original Author: Stan Y. Liao, Synopsys, Inc.

  CHANGE LOG AT END OF FILE
 *****************************************************************************/

#ifndef SC_HASH_H
#define SC_HASH_H

#include "sysc/kernel/sc_simcontext.h"

namespace sc_core {

extern SC_API unsigned default_int_hash_fn(const void*);
extern SC_API unsigned default_ptr_hash_fn(const void*);
extern SC_API unsigned default_str_hash_fn(const void*);

class sc_phash_elem;
class sc_phash_base_iter;
template<class K, class C>  //template class
class sc_pdhash_iter;       //decl. -- Amit

const int    PHASH_DEFAULT_MAX_DENSITY     = 5;
const int    PHASH_DEFAULT_INIT_TABLE_SIZE = 11;
extern SC_API const double PHASH_DEFAULT_GROW_FACTOR;
const bool   PHASH_DEFAULT_REORDER_FLAG    = true;

class SC_API sc_phash_base {
    friend class sc_phash_base_iter;

    typedef sc_phash_base_iter iterator;

public:
    typedef unsigned (*hash_fn_t)(const void*);
    typedef int (*cmpr_fn_t)(const void*, const void*);

protected:
    void*    default_value;
    int      num_bins;
    int      num_entries;
    int      max_density;
    int      reorder_flag;
    double   grow_factor;

    sc_phash_elem** bins;

    hash_fn_t hash;
    cmpr_fn_t cmpr;

    void rehash();
    unsigned do_hash(const void* key) const { return (*hash)(key) % num_bins; }

    sc_phash_elem* add_direct(void* key, void* contents, unsigned hash_val);
    sc_phash_elem* find_entry_c(unsigned hv, const void* k, sc_phash_elem*** plast);
    sc_phash_elem* find_entry_q(unsigned hv, const void* k, sc_phash_elem*** plast);
    sc_phash_elem* find_entry(unsigned hv, const void* k, sc_phash_elem*** plast=0) const
    {
      /* Got rid of member func. pointer and replaced with if-else  */
      /* Amit (5/14/99)                                             */
      if( cmpr == 0 )
        return ((sc_phash_base*)this)->find_entry_q( hv, k, plast );
      else
	return ((sc_phash_base*)this)->find_entry_c( hv, k, plast );
    }

public:
    sc_phash_base( void* def       = 0,
                   int    size     = PHASH_DEFAULT_INIT_TABLE_SIZE,
                   int    density  = PHASH_DEFAULT_MAX_DENSITY,
                   double grow     = PHASH_DEFAULT_GROW_FACTOR,
                   bool   reorder  = PHASH_DEFAULT_REORDER_FLAG,
                   hash_fn_t hash_fn = default_ptr_hash_fn,
                   cmpr_fn_t cmpr_fn = 0                             );
    ~sc_phash_base();

    void set_cmpr_fn(cmpr_fn_t);
    void set_hash_fn(hash_fn_t);

    bool empty() const { return (num_entries == 0); }
    unsigned count() const { return num_entries; }

    void erase();
    void erase(void (*kfree)(void*));
    void copy( const sc_phash_base* );
    void copy( const sc_phash_base& b ) { copy(&b); }
    void copy( const sc_phash_base& b, void* (*kdup)(const void*), void (*kfree)(void*));
    int insert( void* k, void* c );
    int insert( void* k ) { return insert(k, default_value); }
    int insert( void* k, void* c, void* (*kdup)(const void*) );
    int insert_if_not_exists(void* k, void* c);
    int insert_if_not_exists(void* k) { return insert_if_not_exists(k, default_value); }
    int insert_if_not_exists(void* k, void* c, void* (*kdup)(const void*));
    int remove(const void* k);
    int remove(const void* k, void** pk, void** pc);
    int remove(const void* k, void (*kfree)(void*));
    int remove_by_contents(const void* c);
    int remove_by_contents(bool (*predicate)(const void*, void*), void* arg);
    int remove_by_contents(const void* c, void (*kfree)(void*));
    int remove_by_contents(bool (*predicate)(const void*, void*), void* arg, void (*kfree)(void*));
    int lookup(const void* k, void** pc) const;
    bool contains(const void* k) const { return (lookup(k, 0) != 0); }
    void* operator[](const void* key) const;
};

class SC_API sc_phash_base_iter {
protected:
    sc_phash_base*  table;
    sc_phash_elem*  entry;
    sc_phash_elem*  next;
    sc_phash_elem** last;
    int             index;

public:
    void reset(sc_phash_base* t);
    void reset(sc_phash_base& t) { reset(&t); }

    sc_phash_base_iter(sc_phash_base* t)
    : table(t), entry(0), next(0), last(0), index(0)
        { reset(t); }
    sc_phash_base_iter(sc_phash_base& t)
    : table(&t), entry(0), next(0), last(0), index(0)
        { reset(t); }
    ~sc_phash_base_iter() { }

    bool empty() const;
    void step();
    void operator++(int) { step(); }
    void remove();
    void remove(void (*kfree)(void*));
    void* key() const;
    void* contents() const;
    void* set_contents(void* c);
};

template< class K, class C >
class sc_phash_iter;

template< class K, class C >
class sc_phash : public sc_phash_base {
    friend class sc_phash_iter<K,C>;

public:
    typedef sc_phash_iter<K,C> iterator;

    sc_phash( C def = (C) 0,
              int size    = PHASH_DEFAULT_INIT_TABLE_SIZE,
              int density = PHASH_DEFAULT_MAX_DENSITY,
              double grow = PHASH_DEFAULT_GROW_FACTOR,
              bool reorder = PHASH_DEFAULT_REORDER_FLAG,
              hash_fn_t hash_fn = default_ptr_hash_fn,
              cmpr_fn_t cmpr_fn = 0                          )
        : sc_phash_base((void*) def, size, density, grow, reorder, hash_fn, cmpr_fn) { }
    ~sc_phash() { }

    void copy(const sc_phash<K,C>* b) { sc_phash_base::copy(b); }
    void copy(const sc_phash<K,C>& b) { sc_phash_base::copy(b); }
    void copy(const sc_phash<K,C>& b, void* (*kdup)(const void*), void (*kfree)(void*)) { sc_phash_base::copy(b, kdup, kfree); }

    int insert(K k, C c) { return sc_phash_base::insert((void*) k, (void*) c); }
    int insert(K k) { return sc_phash_base::insert((void*) k, default_value); }
    int insert(K k, C c, void* (*kdup)(const void*)) { return sc_phash_base::insert((void*) k, (void*) c, kdup); }
    int insert_if_not_exists(K k, C c)
    {
        return sc_phash_base::insert_if_not_exists((void*) k, (void*) c);
    }
    int insert_if_not_exists(K k)
    {
        return sc_phash_base::insert_if_not_exists((void*) k, default_value);
    }
    int insert_if_not_exists(K k, C c, void* (*kdup)(const void*))
    {
        return sc_phash_base::insert_if_not_exists((void*) k, (void*) c, kdup);
    }
    int remove(K k) { return sc_phash_base::remove((const void*) k); }
    int remove(K k, K* pk, C* pc)
    {
        return sc_phash_base::remove((const void*) k, (void**) pk, (void**) pc);
    }
    int remove(K k, void (*kfree)(void*))
    {
        return sc_phash_base::remove((const void*) k, kfree);
    }
    int remove_by_contents(C c)
    {
        return sc_phash_base::remove_by_contents((const void*) c);
    }
    int remove_by_contents(bool (*predicate)(const void*, void*), void* arg)
    {
        return sc_phash_base::remove_by_contents(predicate, arg);
    }
    int remove_by_contents(const void* c, void (*kfree)(void*))
    {
        return sc_phash_base::remove_by_contents(c, kfree);
    }
    int remove_by_contents(bool (*predicate)(const void*, void*), void* arg, void (*kfree)(void*))
    {
        return sc_phash_base::remove_by_contents(predicate, arg, kfree);
    }
    int lookup(K k, C* pc) const
    {
        return sc_phash_base::lookup((const void*) k, (void**) pc);
    }
    bool contains(K k) const
    {
        return sc_phash_base::contains((const void*) k);
    }
    C operator[](K k) const
    {
        return (C) sc_phash_base::operator[]((const void*) k);
    }
};


template< class K, class C >
class sc_phash_iter : public sc_phash_base_iter {
public:
    sc_phash_iter(sc_phash<K,C>* t) : sc_phash_base_iter(t) { }
    sc_phash_iter(sc_phash<K,C>& t) : sc_phash_base_iter(t) { }
    ~sc_phash_iter() { }

    void reset(sc_phash<K,C>* t) { sc_phash_base_iter::reset(t); }
    void reset(sc_phash<K,C>& t) { sc_phash_base_iter::reset(t); }

    K key()      const { return (K) sc_phash_base_iter::key();      }
    C contents() const { return (C) sc_phash_base_iter::contents(); }
    C set_contents(C c)
    {
        return (C) sc_phash_base_iter::set_contents((void*) c);
    }
};





template< class K, class C >
class sc_pdhash : public sc_phash_base {
    friend class sc_pdhash_iter<K,C>;

private:
    void* (*kdup)(const void*); //eliminated braces around void* -- Amit
    void (*kfree)(void*);

public:
    typedef sc_pdhash_iter<K,C> iterator;
    sc_pdhash( C def = (C) 0,
              int size    = PHASH_DEFAULT_INIT_TABLE_SIZE,
              int density = PHASH_DEFAULT_MAX_DENSITY,
              double grow = PHASH_DEFAULT_GROW_FACTOR,
              bool reorder = PHASH_DEFAULT_REORDER_FLAG,
              hash_fn_t hash_fn = (hash_fn_t) 0, // defaults added --
              cmpr_fn_t cmpr_fn = (cmpr_fn_t) 0, // Amit
              void* (*kdup_fn)(const void*) = 0,
              void (*kfree_fn)(void*)  = 0 )
        : sc_phash_base((void*) def, size, density, grow, reorder, hash_fn, cmpr_fn)
    {
        kdup = kdup_fn;
        kfree = kfree_fn;
    }
    ~sc_pdhash()
    {
        erase();
    }
    void erase()
    {
        sc_phash_base::erase(kfree);
    }
    void copy(const sc_pdhash<K,C>& b) { sc_phash_base::copy(b, kdup, kfree); }
    int insert(K k, C c) { return sc_phash_base::insert((void*) k, (void*) c, kdup); }
    int insert(K k) { return sc_phash_base::insert((void*) k, default_value, kdup); }
    int insert_if_not_exists(K k, C c)
    {
        return sc_phash_base::insert_if_not_exists((void*) k, (void*) c, kdup);
    }
    int insert_if_not_exists(K k)
    {
        return sc_phash_base::insert_if_not_exists((void*) k, default_value, kdup);
    }
    int remove(K k) { return sc_phash_base::remove((const void*) k, kfree); }
    int remove(K k, K* pk, C* pc)
    {
        return sc_phash_base::remove((const void*) k, (void**) pk, (void**) pc);
    }
    int remove_by_contents(C c)
    {
        return sc_phash_base::remove_by_contents((const void*) c, kfree);
    }
    int remove_by_contents(bool (*predicate)(const void*, void*), void* arg)
    {
        return sc_phash_base::remove_by_contents(predicate, arg, kfree);
    }
    int lookup(K k, C* pc) const
    {
        return sc_phash_base::lookup((const void*) k, (void**) pc);
    }
    bool contains(K k) const
    {
        return sc_phash_base::contains((const void*) k);
    }
    C operator[](K k) const
    {
        return (C) sc_phash_base::operator[]((const void*) k);
    }
};

template< class K, class C >
class sc_pdhash_iter : public sc_phash_base_iter {
public:
    sc_pdhash_iter(sc_pdhash<K,C>* t) : sc_phash_base_iter(t) { }
    sc_pdhash_iter(sc_pdhash<K,C>& t) : sc_phash_base_iter(t) { }
    ~sc_pdhash_iter() { }

    void reset(sc_pdhash<K,C>* t) { sc_phash_base_iter::reset(t); }
    void reset(sc_pdhash<K,C>& t) { sc_phash_base_iter::reset(t); }

    void remove() { sc_phash_base_iter::remove(((sc_pdhash<K,C>*) table)->kfree); }
    K key()      const { return (K) sc_phash_base_iter::key();      }
    C contents() const { return (C) sc_phash_base_iter::contents(); }
    C set_contents(C c)
    {
        return (C) sc_phash_base_iter::set_contents((void*) c);
    }
};

extern SC_API int sc_strhash_cmp( const void*, const void* );
extern SC_API void sc_strhash_kfree(void*);
extern SC_API void* sc_strhash_kdup(const void*);

template< class C >      // template class decl.
class sc_strhash_iter;   // --Amit

template< class C >
class sc_strhash : public sc_phash_base {
    friend class sc_strhash_iter<C>;

public:
    typedef sc_strhash_iter<C> iterator;

    sc_strhash( C def = (C) 0,
                int size    = PHASH_DEFAULT_INIT_TABLE_SIZE,
                int density = PHASH_DEFAULT_MAX_DENSITY,
                double grow = PHASH_DEFAULT_GROW_FACTOR,
                bool reorder = PHASH_DEFAULT_REORDER_FLAG,
                unsigned (*hash_fn)(const void*) = default_str_hash_fn,
                int (*cmpr_fn)(const void*, const void*) = sc_strhash_cmp )
        : sc_phash_base((void*) def, size, density, grow, reorder, hash_fn, cmpr_fn)
    {

    }
    ~sc_strhash()
    {
        erase();
    }

    void erase() { sc_phash_base::erase(sc_strhash_kfree); }
    void copy(const sc_strhash<C>* b) { sc_phash_base::copy(*b, sc_strhash_kdup, sc_strhash_kfree); }
    void copy(const sc_strhash<C>& b) { sc_phash_base::copy(b, sc_strhash_kdup, sc_strhash_kfree); }

    int insert(char* k, C c) { return sc_phash_base::insert((void*) k, (void*) c, sc_strhash_kdup); }
    int insert(char* k) { return sc_phash_base::insert((void*) k, default_value, sc_strhash_kdup); }
    int insert_if_not_exists(char* k, C c)
    {
        return sc_phash_base::insert_if_not_exists((void*) k, (void*) c, sc_strhash_kdup);
    }
    int insert_if_not_exists(char* k)
    {
        return sc_phash_base::insert_if_not_exists((void*) k, default_value, sc_strhash_kdup);
    }
    int remove(const char* k) { return sc_phash_base::remove((const void*) k, sc_strhash_kfree); }
    int remove(const char* k, char** pk, C* pc)
    {
        return sc_phash_base::remove((const void*) k, (void**) pk, (void**) pc);
    }
    int remove_by_contents(C c)
    {
        return sc_phash_base::remove_by_contents((const void*) c, sc_strhash_kfree);
    }
    int remove_by_contents(bool (*predicate)(const void*, void*), void* arg)
    {
        return sc_phash_base::remove_by_contents(predicate, arg, sc_strhash_kfree);
    }
    int lookup(const char* k, C* pc) const
    {
        return sc_phash_base::lookup((const void*) k, (void** )pc);
    }
    bool contains(const char* k) const
    {
        return sc_phash_base::contains((const void*) k);
    }
    C operator[](const char* k) const
    {
        return (C) sc_phash_base::operator[]((const void*) k);
    }
};

template<class C>
class sc_strhash_iter : public sc_phash_base_iter {
public:
    sc_strhash_iter ( sc_strhash<C>* t ) : sc_phash_base_iter(t) { }
    sc_strhash_iter ( sc_strhash<C>& t ) : sc_phash_base_iter(t) { }
    ~sc_strhash_iter() { }

    void reset ( sc_strhash<C>* t ) { sc_phash_base_iter::reset(t); }
    void reset ( sc_strhash<C>& t ) { sc_phash_base_iter::reset(t); }

    void remove() { sc_phash_base_iter::remove(sc_strhash_kfree); }
    const char* key()   { return (const char*) sc_phash_base_iter::key(); }
    C contents()  { return (C) sc_phash_base_iter::contents(); }
    C set_contents(C c)
    {
        return (C) sc_phash_base_iter::set_contents((void*) c);
    }
};

} // namespace sc_core

// $Log: sc_hash.h,v $
// Revision 1.5  2011/08/29 18:04:32  acg
//  Philipp A. Hartmann: miscellaneous clean ups.
//
// Revision 1.4  2011/08/26 20:46:16  acg
//  Andy Goodrich: moved the modification log to the end of the file to
//  eliminate source line number skew when check-ins are done.
//
// Revision 1.3  2011/08/24 22:05:56  acg
//  Torsten Maehne: initialization changes to remove warnings.
//
// Revision 1.2  2011/02/18 20:38:43  acg
//  Andy Goodrich: Updated Copyright notice.
//
// Revision 1.1.1.1  2006/12/15 20:20:06  acg
// SystemC 2.3
//
// Revision 1.3  2006/01/13 18:53:10  acg
// Andy Goodrich: Added $Log command so that CVS comments are reproduced in
// the source.

#endif
