|
|
|
|
|
#ifndef DLIB_HASH_TABLE_KERNEl_1_ |
|
#define DLIB_HASH_TABLE_KERNEl_1_ |
|
|
|
#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 mem_manager = default_memory_manager, |
|
typename compare = std::less<domain> |
|
> |
|
class hash_table_kernel_1 : public enumerable<map_pair<domain, range> >, |
|
public pair_remover<domain,range> |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct node |
|
{ |
|
node* next; |
|
domain d; |
|
range r; |
|
}; |
|
|
|
|
|
class mpair : public map_pair<domain,range> |
|
{ |
|
public: |
|
const domain* d; |
|
range* r; |
|
|
|
const domain& key( |
|
) const { return *d; } |
|
|
|
const range& value( |
|
) const { return *r; } |
|
|
|
range& value( |
|
) { return *r; } |
|
}; |
|
|
|
|
|
public: |
|
|
|
typedef domain domain_type; |
|
typedef range range_type; |
|
typedef compare compare_type; |
|
typedef mem_manager mem_manager_type; |
|
|
|
explicit hash_table_kernel_1( |
|
unsigned long expnum |
|
); |
|
|
|
virtual ~hash_table_kernel_1( |
|
); |
|
|
|
void clear( |
|
); |
|
|
|
unsigned long count ( |
|
const domain& item |
|
) const; |
|
|
|
void add ( |
|
domain& d, |
|
range& r |
|
); |
|
|
|
void remove ( |
|
const domain& d, |
|
domain& d_copy, |
|
range& r |
|
); |
|
|
|
void destroy ( |
|
const domain& d |
|
); |
|
|
|
const range* operator[] ( |
|
const domain& d |
|
) const; |
|
|
|
range* operator[] ( |
|
const domain& d |
|
); |
|
|
|
void swap ( |
|
hash_table_kernel_1& item |
|
); |
|
|
|
|
|
void remove_any ( |
|
domain& d, |
|
range& r |
|
); |
|
|
|
|
|
inline size_t size ( |
|
) const; |
|
|
|
bool at_start ( |
|
) const; |
|
|
|
inline void reset ( |
|
) const; |
|
|
|
bool current_element_valid ( |
|
) const; |
|
|
|
const map_pair<domain,range>& element ( |
|
) const; |
|
|
|
map_pair<domain,range>& element ( |
|
); |
|
|
|
bool move_next ( |
|
) const; |
|
|
|
private: |
|
|
|
|
|
typename mem_manager::template rebind<node>::other pool; |
|
typename mem_manager::template rebind<node*>::other ppool; |
|
unsigned long hash_size; |
|
node** table; |
|
general_hash<domain> hash; |
|
unsigned long num_of_buckets; |
|
unsigned long mask; |
|
|
|
mutable mpair p; |
|
|
|
mutable unsigned long current_bucket; |
|
mutable node* current_element; |
|
mutable bool at_start_; |
|
compare comp; |
|
|
|
|
|
hash_table_kernel_1(hash_table_kernel_1&); |
|
hash_table_kernel_1& operator=(hash_table_kernel_1&); |
|
|
|
}; |
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
inline void swap ( |
|
hash_table_kernel_1<domain,range,mem_manager,compare>& a, |
|
hash_table_kernel_1<domain,range,mem_manager,compare>& b |
|
) { a.swap(b); } |
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
void deserialize ( |
|
hash_table_kernel_1<domain,range,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_1"); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
hash_table_kernel_1( |
|
unsigned long expnum |
|
) : |
|
hash_size(0), |
|
current_element(0), |
|
at_start_(true) |
|
{ |
|
|
|
num_of_buckets = 1; |
|
while (expnum != 0) |
|
{ |
|
--expnum; |
|
num_of_buckets <<= 1; |
|
} |
|
mask = num_of_buckets-1; |
|
|
|
table = ppool.allocate_array(num_of_buckets); |
|
for (unsigned long i = 0; i < num_of_buckets; ++i) |
|
{ |
|
table[i] = 0; |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
~hash_table_kernel_1( |
|
) |
|
{ |
|
for (unsigned long i = 0; i < num_of_buckets; ++i) |
|
{ |
|
|
|
node* temp = table[i]; |
|
while (temp) |
|
{ |
|
node* t = temp; |
|
temp = temp->next; |
|
pool.deallocate(t); |
|
} |
|
table[i] = 0; |
|
} |
|
ppool.deallocate_array(table); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
void hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
clear( |
|
) |
|
{ |
|
if (hash_size > 0) |
|
{ |
|
for (unsigned long i = 0; i < num_of_buckets; ++i) |
|
{ |
|
|
|
node* temp = table[i]; |
|
while (temp) |
|
{ |
|
node* t = temp; |
|
temp = temp->next; |
|
pool.deallocate(t); |
|
} |
|
table[i] = 0; |
|
} |
|
hash_size = 0; |
|
} |
|
|
|
reset(); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
size_t hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
size( |
|
) const |
|
{ |
|
return hash_size; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
unsigned long hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
count( |
|
const domain& d |
|
) const |
|
{ |
|
unsigned long items_found = 0; |
|
node* temp = table[hash(d)&mask]; |
|
|
|
while (temp != 0) |
|
{ |
|
|
|
if ( !(comp(temp->d , d) || comp(d , temp->d)) ) |
|
{ |
|
++items_found; |
|
} |
|
temp = temp->next; |
|
} |
|
|
|
return items_found; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
void hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
add( |
|
domain& d, |
|
range& r |
|
) |
|
{ |
|
unsigned long hash_value = hash(d)&mask; |
|
|
|
|
|
node& temp = *(pool.allocate()); |
|
exchange(d,temp.d); |
|
exchange(r,temp.r); |
|
|
|
|
|
temp.next = table[hash_value]; |
|
table[hash_value] = &temp; |
|
|
|
++hash_size; |
|
|
|
|
|
reset(); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
void hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
destroy( |
|
const domain& d |
|
) |
|
{ |
|
node* last; |
|
const unsigned long hash_value = hash(d)&mask; |
|
node* temp = table[hash_value]; |
|
|
|
|
|
if (temp->next != 0) |
|
{ |
|
|
|
last = temp; |
|
temp = temp->next; |
|
while (true) |
|
{ |
|
|
|
|
|
if (temp == 0) |
|
{ |
|
temp = table[hash_value]; |
|
table[hash_value] = temp->next; |
|
|
|
break; |
|
} |
|
|
|
|
|
if ( !(comp(temp->d , d) || comp(d , temp->d)) ) |
|
{ |
|
|
|
last->next = temp->next; |
|
break; |
|
} |
|
|
|
last = temp; |
|
temp = temp->next; |
|
} |
|
|
|
} |
|
|
|
else |
|
{ |
|
table[hash_value] = 0; |
|
} |
|
|
|
pool.deallocate(temp); |
|
|
|
--hash_size; |
|
|
|
|
|
reset(); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
void hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
remove( |
|
const domain& d, |
|
domain& d_copy, |
|
range& r |
|
) |
|
{ |
|
node* last; |
|
const unsigned long hash_value = hash(d)&mask; |
|
node* temp = table[hash_value]; |
|
|
|
|
|
if (temp->next != 0) |
|
{ |
|
|
|
last = temp; |
|
temp = temp->next; |
|
while (true) |
|
{ |
|
|
|
|
|
if (temp == 0) |
|
{ |
|
temp = table[hash_value]; |
|
table[hash_value] = temp->next; |
|
|
|
break; |
|
} |
|
|
|
|
|
if ( !(comp(temp->d , d) || comp(d , temp->d)) ) |
|
{ |
|
|
|
last->next = temp->next; |
|
break; |
|
} |
|
|
|
last = temp; |
|
temp = temp->next; |
|
} |
|
|
|
} |
|
|
|
else |
|
{ |
|
table[hash_value] = 0; |
|
} |
|
|
|
|
|
exchange(d_copy,temp->d); |
|
exchange(r,temp->r); |
|
pool.deallocate(temp); |
|
|
|
--hash_size; |
|
|
|
|
|
reset(); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
void hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
remove_any( |
|
domain& d, |
|
range& r |
|
) |
|
{ |
|
unsigned long i = 0; |
|
|
|
|
|
while (table[i] == 0) |
|
{ |
|
++i; |
|
} |
|
|
|
|
|
node& temp = *(table[i]); |
|
|
|
exchange(temp.d,d); |
|
exchange(temp.r,r); |
|
table[i] = temp.next; |
|
|
|
pool.deallocate(&temp); |
|
|
|
--hash_size; |
|
|
|
|
|
reset(); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
const range* hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
operator[]( |
|
const domain& d |
|
) const |
|
{ |
|
node* temp = table[hash(d)&mask]; |
|
|
|
while (temp != 0) |
|
{ |
|
|
|
if ( !(comp(temp->d , d) || comp(d , temp->d)) ) |
|
return &(temp->r); |
|
|
|
temp = temp->next; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
range* hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
operator[]( |
|
const domain& d |
|
) |
|
{ |
|
node* temp = table[hash(d)&mask]; |
|
|
|
while (temp != 0) |
|
{ |
|
|
|
if ( !(comp(temp->d , d) || comp(d , temp->d)) ) |
|
return &(temp->r); |
|
|
|
temp = temp->next; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
void hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
swap( |
|
hash_table_kernel_1<domain,range,mem_manager,compare>& item |
|
) |
|
{ |
|
exchange(mask,item.mask); |
|
exchange(table,item.table); |
|
exchange(hash_size,item.hash_size); |
|
exchange(num_of_buckets,item.num_of_buckets); |
|
exchange(current_bucket,item.current_bucket); |
|
exchange(current_element,item.current_element); |
|
exchange(at_start_,item.at_start_); |
|
pool.swap(item.pool); |
|
ppool.swap(item.ppool); |
|
exchange(p,item.p); |
|
exchange(comp,item.comp); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
bool hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
at_start ( |
|
) const |
|
{ |
|
return at_start_; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
void hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
reset ( |
|
) const |
|
{ |
|
at_start_ = true; |
|
current_element = 0; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
bool hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
current_element_valid ( |
|
) const |
|
{ |
|
return (current_element != 0); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
const map_pair<domain,range>& hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
element ( |
|
) const |
|
{ |
|
p.d = &(current_element->d); |
|
p.r = &(current_element->r); |
|
return p; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
map_pair<domain,range>& hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
element ( |
|
) |
|
{ |
|
p.d = &(current_element->d); |
|
p.r = &(current_element->r); |
|
return p; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename domain, |
|
typename range, |
|
typename mem_manager, |
|
typename compare |
|
> |
|
bool hash_table_kernel_1<domain,range,mem_manager,compare>:: |
|
move_next ( |
|
) const |
|
{ |
|
if (at_start_) |
|
{ |
|
at_start_ = false; |
|
|
|
if (hash_size == 0) |
|
{ |
|
return false; |
|
} |
|
else |
|
{ |
|
|
|
for (current_bucket = 0; true ; ++current_bucket) |
|
{ |
|
if (table[current_bucket] != 0) |
|
{ |
|
current_element = table[current_bucket]; |
|
break; |
|
} |
|
} |
|
return true; |
|
} |
|
} |
|
else |
|
{ |
|
|
|
if (current_element == 0) |
|
{ |
|
return false; |
|
} |
|
else |
|
{ |
|
|
|
if (current_element->next != 0) |
|
{ |
|
current_element = current_element->next; |
|
return true; |
|
} |
|
else |
|
{ |
|
|
|
for (current_bucket+=1; current_bucket<num_of_buckets; ++current_bucket) |
|
{ |
|
if (table[current_bucket] != 0) |
|
{ |
|
|
|
current_element = table[current_bucket]; |
|
break; |
|
} |
|
} |
|
|
|
if (current_bucket == num_of_buckets) |
|
{ |
|
|
|
current_element = 0; |
|
return false; |
|
} |
|
else |
|
{ |
|
|
|
return true; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#endif |
|
|
|
|