613 lines
16 KiB
C++
613 lines
16 KiB
C++
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_HASH_TABLE_KERNEl_2_
|
|
#define DLIB_HASH_TABLE_KERNEl_2_
|
|
|
|
#include "hash_table_kernel_abstract.h"
|
|
#include "../general_hash/general_hash.h"
|
|
#include "../algs.h"
|
|
#include "../interfaces/map_pair.h"
|
|
#include "../interfaces/enumerable.h"
|
|
#include "../interfaces/remover.h"
|
|
#include "../assert.h"
|
|
#include "../serialize.h"
|
|
#include <functional>
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager = default_memory_manager,
|
|
typename compare = std::less<domain>
|
|
>
|
|
class hash_table_kernel_2 : public enumerable<map_pair<domain,range> >,
|
|
public pair_remover<domain,range>
|
|
{
|
|
|
|
/*!
|
|
REQUIREMENTS ON bst_base
|
|
bst_base is instantiated with domain and range and
|
|
implements binray_search_tree/binary_search_tree_kernel_abstract.h
|
|
|
|
INITIAL VALUE
|
|
hash_size == 0
|
|
table == pointer to an array of num_of_buckets bst_base objects
|
|
num_of_buckets == the number of buckets in the hash table
|
|
current_bucket == 0
|
|
at_start_ == true
|
|
|
|
CONVENTION
|
|
current_element_valid() == (current_bucket != 0)
|
|
element() == current_bucket->element()
|
|
at_start_ == at_start()
|
|
|
|
mask == num_of_buckets-1
|
|
|
|
for all integers i where &table[i] != current_bucket
|
|
table[i].at_start() == true
|
|
|
|
|
|
hash_size = size() == the number of elements in the hash_table and
|
|
table == pointer to an array of num_of_buckets bst_base objects
|
|
num_of_buckets == the number of buckets in the hash table and
|
|
the elements in this hash table are stored in the bst_base objects in the
|
|
array table
|
|
|
|
!*/
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef domain domain_type;
|
|
typedef range range_type;
|
|
typedef compare compare_type;
|
|
typedef mem_manager mem_manager_type;
|
|
|
|
explicit hash_table_kernel_2(
|
|
unsigned long expnum
|
|
);
|
|
|
|
virtual ~hash_table_kernel_2(
|
|
)
|
|
{ pool.deallocate_array(table); }
|
|
|
|
void clear(
|
|
);
|
|
|
|
unsigned long count (
|
|
const domain& item
|
|
) const;
|
|
|
|
inline void add (
|
|
domain& d,
|
|
range& r
|
|
);
|
|
|
|
void destroy (
|
|
const domain& d
|
|
);
|
|
|
|
void remove (
|
|
const domain& d,
|
|
domain& d_copy,
|
|
range& r
|
|
);
|
|
|
|
const range* operator[] (
|
|
const domain& item
|
|
) const;
|
|
|
|
range* operator[] (
|
|
const domain& item
|
|
);
|
|
|
|
inline void swap (
|
|
hash_table_kernel_2& item
|
|
);
|
|
|
|
// functions from the remover interface
|
|
void remove_any (
|
|
domain& d,
|
|
range& r
|
|
);
|
|
|
|
// functions from the enumerable interface
|
|
inline size_t size (
|
|
) const;
|
|
|
|
inline bool at_start (
|
|
) const;
|
|
|
|
inline void reset (
|
|
) const;
|
|
|
|
bool current_element_valid (
|
|
) const;
|
|
|
|
inline const map_pair<domain,range>& element (
|
|
) const;
|
|
|
|
inline map_pair<domain,range>& element (
|
|
);
|
|
|
|
bool move_next (
|
|
) const;
|
|
|
|
private:
|
|
|
|
// data members
|
|
typename mem_manager::template rebind<bst_base>::other pool;
|
|
unsigned long mask;
|
|
unsigned long hash_size;
|
|
unsigned long num_of_buckets;
|
|
bst_base* table;
|
|
general_hash<domain> hash;
|
|
mutable bst_base* current_bucket;
|
|
mutable bool at_start_;
|
|
compare comp;
|
|
|
|
// restricted functions
|
|
hash_table_kernel_2(hash_table_kernel_2&);
|
|
hash_table_kernel_2& operator=(hash_table_kernel_2&);
|
|
|
|
};
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
inline void swap (
|
|
hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& a,
|
|
hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& b
|
|
) { a.swap(b); }
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
void deserialize (
|
|
hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& item,
|
|
std::istream& in
|
|
)
|
|
{
|
|
try
|
|
{
|
|
item.clear();
|
|
unsigned long size;
|
|
deserialize(size,in);
|
|
domain d;
|
|
range r;
|
|
for (unsigned long i = 0; i < size; ++i)
|
|
{
|
|
deserialize(d,in);
|
|
deserialize(r,in);
|
|
item.add(d,r);
|
|
}
|
|
}
|
|
catch (serialization_error& e)
|
|
{
|
|
item.clear();
|
|
throw serialization_error(e.info + "\n while deserializing object of type hash_table_kernel_2");
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// member function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
hash_table_kernel_2(
|
|
unsigned long expnum
|
|
) :
|
|
hash_size(0),
|
|
current_bucket(0),
|
|
at_start_(true)
|
|
{
|
|
|
|
num_of_buckets = 1;
|
|
while (expnum != 0)
|
|
{
|
|
--expnum;
|
|
num_of_buckets <<= 1;
|
|
}
|
|
mask = num_of_buckets-1;
|
|
|
|
table = pool.allocate_array(num_of_buckets);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
clear(
|
|
)
|
|
{
|
|
if (hash_size != 0)
|
|
{
|
|
hash_size = 0;
|
|
for (unsigned long i = 0; i < num_of_buckets; ++i)
|
|
table[i].clear();
|
|
}
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
size_t hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
size(
|
|
) const
|
|
{
|
|
return hash_size;
|
|
}
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
unsigned long hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
count(
|
|
const domain& item
|
|
) const
|
|
{
|
|
return table[hash(item)&mask].count(item);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
destroy(
|
|
const domain& item
|
|
)
|
|
{
|
|
table[hash(item)&mask].destroy(item);
|
|
--hash_size;
|
|
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
add(
|
|
domain& d,
|
|
range& r
|
|
)
|
|
{
|
|
table[hash(d)&mask].add(d,r);
|
|
++hash_size;
|
|
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
remove(
|
|
const domain& d,
|
|
domain& d_copy,
|
|
range& r
|
|
)
|
|
{
|
|
table[hash(d)&mask].remove(d,d_copy,r);
|
|
--hash_size;
|
|
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
remove_any(
|
|
domain& d,
|
|
range& r
|
|
)
|
|
{
|
|
unsigned long i = 0;
|
|
while (table[i].size() == 0)
|
|
{
|
|
++i;
|
|
}
|
|
table[i].remove_any(d,r);
|
|
--hash_size;
|
|
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
const range* hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
operator[](
|
|
const domain& d
|
|
) const
|
|
{
|
|
return table[hash(d)&mask][d];
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
range* hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
operator[](
|
|
const domain& d
|
|
)
|
|
{
|
|
return table[hash(d)&mask][d];
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
swap(
|
|
hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& item
|
|
)
|
|
{
|
|
pool.swap(item.pool);
|
|
exchange(mask,item.mask);
|
|
exchange(hash_size,item.hash_size);
|
|
exchange(num_of_buckets,item.num_of_buckets);
|
|
exchange(table,item.table);
|
|
exchange(current_bucket,item.current_bucket);
|
|
exchange(at_start_,item.at_start_);
|
|
exchange(comp,item.comp);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// enumerable function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
at_start (
|
|
) const
|
|
{
|
|
return at_start_;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
reset (
|
|
) const
|
|
{
|
|
at_start_ = true;
|
|
if (current_bucket != 0)
|
|
{
|
|
current_bucket->reset();
|
|
current_bucket = 0;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
current_element_valid (
|
|
) const
|
|
{
|
|
return (current_bucket != 0);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
const map_pair<domain,range>& hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
element (
|
|
) const
|
|
{
|
|
return current_bucket->element();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
map_pair<domain,range>& hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
element (
|
|
)
|
|
{
|
|
return current_bucket->element();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename domain,
|
|
typename range,
|
|
typename bst_base,
|
|
typename mem_manager,
|
|
typename compare
|
|
>
|
|
bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
|
|
move_next (
|
|
) const
|
|
{
|
|
if (at_start_)
|
|
{
|
|
at_start_ = false;
|
|
// if the queue is empty then there is nothing to do
|
|
if (hash_size == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// find the first element in the hash table
|
|
current_bucket = table;
|
|
while (current_bucket->size() == 0)
|
|
{
|
|
++current_bucket;
|
|
}
|
|
|
|
current_bucket->move_next();
|
|
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if we have already enumerated every element
|
|
if (current_bucket == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (current_bucket->move_next())
|
|
{
|
|
// if there is another element in this current bucket then use that
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// find the next bucket
|
|
bst_base* end = table + num_of_buckets;
|
|
current_bucket->reset();
|
|
|
|
while (true)
|
|
{
|
|
++current_bucket;
|
|
// if we ran out of buckets and didn't find anything
|
|
if (current_bucket == end)
|
|
{
|
|
current_bucket = 0;
|
|
return false;
|
|
}
|
|
if (current_bucket->size() > 0)
|
|
{
|
|
current_bucket->move_next();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_HASH_TABLE_KERNEl_2_
|
|
|