2014-12-28 10:51:16 -06:00
// This is free and unencumbered software released into the public domain.
2015-07-02 04:14:30 -05:00
//
2014-12-28 10:51:16 -06:00
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// -------------------------------------------------------
2021-06-07 17:39:36 -05:00
// Written by Claire Xenia Wolf <claire@yosyshq.com> in 2014
2014-12-28 10:51:16 -06:00
// -------------------------------------------------------
# ifndef HASHLIB_H
2016-05-14 04:43:20 -05:00
# define HASHLIB_H
2014-12-26 12:28:52 -06:00
2014-12-26 14:35:22 -06:00
# include <stdexcept>
2015-01-31 17:27:07 -06:00
# include <algorithm>
2014-12-26 12:28:52 -06:00
# include <string>
2024-10-07 16:57:30 -05:00
# include <variant>
2014-12-26 12:28:52 -06:00
# include <vector>
2024-02-08 04:15:26 -06:00
# include <stdint.h>
2014-12-28 10:51:16 -06:00
namespace hashlib {
2014-12-30 06:22:33 -06:00
const int hashtable_size_trigger = 2 ;
const int hashtable_size_factor = 3 ;
2014-12-26 20:04:50 -06:00
2014-12-27 05:02:57 -06:00
// The XOR version of DJB2
2014-12-26 12:28:52 -06:00
inline unsigned int mkhash ( unsigned int a , unsigned int b ) {
return ( ( a < < 5 ) + a ) ^ b ;
}
2014-12-30 11:51:24 -06:00
// traditionally 5381 is used as starting value for the djb2 hash
const unsigned int mkhash_init = 5381 ;
2014-12-27 05:02:57 -06:00
// The ADD version of DJB2
2015-06-09 02:54:22 -05:00
// (use this version for cache locality in b)
2014-12-27 05:02:57 -06:00
inline unsigned int mkhash_add ( unsigned int a , unsigned int b ) {
return ( ( a < < 5 ) + a ) + b ;
}
2014-12-28 17:12:36 -06:00
inline unsigned int mkhash_xorshift ( unsigned int a ) {
if ( sizeof ( a ) = = 4 ) {
a ^ = a < < 13 ;
a ^ = a > > 17 ;
a ^ = a < < 5 ;
} else if ( sizeof ( a ) = = 8 ) {
a ^ = a < < 13 ;
a ^ = a > > 7 ;
a ^ = a < < 17 ;
} else
throw std : : runtime_error ( " mkhash_xorshift() only implemented for 32 bit and 64 bit ints " ) ;
return a ;
}
2014-12-26 12:28:52 -06:00
template < typename T > struct hash_ops {
2014-12-31 06:05:33 -06:00
static inline bool cmp ( const T & a , const T & b ) {
2014-12-26 12:28:52 -06:00
return a = = b ;
}
2014-12-31 06:05:33 -06:00
static inline unsigned int hash ( const T & a ) {
2014-12-26 12:28:52 -06:00
return a . hash ( ) ;
}
} ;
2015-08-12 06:37:09 -05:00
struct hash_int_ops {
2014-12-28 10:51:16 -06:00
template < typename T >
2014-12-31 06:05:33 -06:00
static inline bool cmp ( T a , T b ) {
2014-12-26 12:28:52 -06:00
return a = = b ;
}
2015-08-24 15:49:23 -05:00
} ;
2021-05-24 14:27:29 -05:00
template < > struct hash_ops < bool > : hash_int_ops
{
static inline unsigned int hash ( bool a ) {
return a ? 1 : 0 ;
}
} ;
2015-08-24 15:49:23 -05:00
template < > struct hash_ops < int32_t > : hash_int_ops
{
2015-08-12 06:37:09 -05:00
static inline unsigned int hash ( int32_t a ) {
2014-12-26 12:28:52 -06:00
return a ;
}
2015-08-24 15:49:23 -05:00
} ;
template < > struct hash_ops < int64_t > : hash_int_ops
{
2015-08-12 06:37:09 -05:00
static inline unsigned int hash ( int64_t a ) {
2016-02-13 10:31:24 -06:00
return mkhash ( ( unsigned int ) ( a ) , ( unsigned int ) ( a > > 32 ) ) ;
2015-08-12 06:37:09 -05:00
}
2014-12-26 12:28:52 -06:00
} ;
2021-11-25 13:43:58 -06:00
template < > struct hash_ops < uint32_t > : hash_int_ops
{
static inline unsigned int hash ( uint32_t a ) {
return a ;
}
} ;
2023-10-03 16:25:59 -05:00
template < > struct hash_ops < uint64_t > : hash_int_ops
{
static inline unsigned int hash ( uint64_t a ) {
return mkhash ( ( unsigned int ) ( a ) , ( unsigned int ) ( a > > 32 ) ) ;
}
} ;
2014-12-26 12:28:52 -06:00
template < > struct hash_ops < std : : string > {
2014-12-31 06:05:33 -06:00
static inline bool cmp ( const std : : string & a , const std : : string & b ) {
2014-12-26 12:28:52 -06:00
return a = = b ;
}
2014-12-31 06:05:33 -06:00
static inline unsigned int hash ( const std : : string & a ) {
2014-12-26 12:28:52 -06:00
unsigned int v = 0 ;
for ( auto c : a )
v = mkhash ( v , c ) ;
return v ;
}
} ;
2014-12-28 19:01:42 -06:00
template < typename P , typename Q > struct hash_ops < std : : pair < P , Q > > {
2014-12-31 06:05:33 -06:00
static inline bool cmp ( std : : pair < P , Q > a , std : : pair < P , Q > b ) {
2014-12-28 19:01:42 -06:00
return a = = b ;
}
2014-12-31 06:05:33 -06:00
static inline unsigned int hash ( std : : pair < P , Q > a ) {
2016-02-14 02:35:25 -06:00
return mkhash ( hash_ops < P > : : hash ( a . first ) , hash_ops < Q > : : hash ( a . second ) ) ;
2014-12-28 19:01:42 -06:00
}
} ;
2015-04-07 10:23:30 -05:00
template < typename . . . T > struct hash_ops < std : : tuple < T . . . > > {
static inline bool cmp ( std : : tuple < T . . . > a , std : : tuple < T . . . > b ) {
return a = = b ;
}
template < size_t I = 0 >
static inline typename std : : enable_if < I = = sizeof . . . ( T ) , unsigned int > : : type hash ( std : : tuple < T . . . > ) {
return mkhash_init ;
}
template < size_t I = 0 >
static inline typename std : : enable_if < I ! = sizeof . . . ( T ) , unsigned int > : : type hash ( std : : tuple < T . . . > a ) {
2016-02-14 02:35:25 -06:00
typedef hash_ops < typename std : : tuple_element < I , std : : tuple < T . . . > > : : type > element_ops_t ;
return mkhash ( hash < I + 1 > ( a ) , element_ops_t : : hash ( std : : get < I > ( a ) ) ) ;
2015-04-07 10:23:30 -05:00
}
} ;
2014-12-30 16:45:43 -06:00
template < typename T > struct hash_ops < std : : vector < T > > {
2014-12-31 06:05:33 -06:00
static inline bool cmp ( std : : vector < T > a , std : : vector < T > b ) {
2014-12-30 16:45:43 -06:00
return a = = b ;
}
2014-12-31 06:05:33 -06:00
static inline unsigned int hash ( std : : vector < T > a ) {
2014-12-30 16:45:43 -06:00
unsigned int h = mkhash_init ;
for ( auto k : a )
2015-08-24 15:49:23 -05:00
h = mkhash ( h , hash_ops < T > : : hash ( k ) ) ;
2014-12-30 16:45:43 -06:00
return h ;
}
} ;
2014-12-26 14:59:41 -06:00
struct hash_cstr_ops {
2014-12-31 06:05:33 -06:00
static inline bool cmp ( const char * a , const char * b ) {
2014-12-26 14:59:41 -06:00
for ( int i = 0 ; a [ i ] | | b [ i ] ; i + + )
if ( a [ i ] ! = b [ i ] )
return false ;
return true ;
}
2014-12-31 06:05:33 -06:00
static inline unsigned int hash ( const char * a ) {
2014-12-30 11:51:24 -06:00
unsigned int hash = mkhash_init ;
2014-12-26 14:59:41 -06:00
while ( * a )
2016-04-05 06:25:23 -05:00
hash = mkhash ( hash , * ( a + + ) ) ;
return hash ;
2014-12-26 14:59:41 -06:00
}
} ;
2014-12-26 14:35:22 -06:00
struct hash_ptr_ops {
2014-12-31 06:05:33 -06:00
static inline bool cmp ( const void * a , const void * b ) {
2014-12-26 14:35:22 -06:00
return a = = b ;
}
2014-12-31 06:05:33 -06:00
static inline unsigned int hash ( const void * a ) {
2017-07-18 10:38:19 -05:00
return ( uintptr_t ) a ;
2014-12-26 14:35:22 -06:00
}
} ;
2014-12-26 20:04:50 -06:00
struct hash_obj_ops {
2014-12-31 06:05:33 -06:00
static inline bool cmp ( const void * a , const void * b ) {
2014-12-26 20:04:50 -06:00
return a = = b ;
}
template < typename T >
2014-12-31 06:05:33 -06:00
static inline unsigned int hash ( const T * a ) {
2016-04-16 16:20:11 -05:00
return a ? a - > hash ( ) : 0 ;
2014-12-26 20:04:50 -06:00
}
} ;
2015-10-25 13:31:29 -05:00
template < typename T >
inline unsigned int mkhash ( const T & v ) {
return hash_ops < T > ( ) . hash ( v ) ;
}
2024-06-20 10:25:21 -05:00
template < > struct hash_ops < std : : monostate > {
static inline bool cmp ( std : : monostate a , std : : monostate b ) {
return a = = b ;
}
static inline unsigned int hash ( std : : monostate ) {
return mkhash_init ;
}
} ;
template < typename . . . T > struct hash_ops < std : : variant < T . . . > > {
static inline bool cmp ( std : : variant < T . . . > a , std : : variant < T . . . > b ) {
return a = = b ;
}
static inline unsigned int hash ( std : : variant < T . . . > a ) {
unsigned int h = std : : visit ( [ ] ( const auto & v ) { return mkhash ( v ) ; } , a ) ;
return mkhash ( a . index ( ) , h ) ;
}
} ;
2024-07-25 06:25:19 -05:00
template < typename T > struct hash_ops < std : : optional < T > > {
static inline bool cmp ( std : : optional < T > a , std : : optional < T > b ) {
return a = = b ;
}
static inline unsigned int hash ( std : : optional < T > a ) {
if ( a . has_value ( ) )
return mkhash ( * a ) ;
else
return 0 ;
}
} ;
2014-12-30 06:22:33 -06:00
inline int hashtable_size ( int min_size )
2014-12-26 16:21:23 -06:00
{
2024-07-01 06:30:35 -05:00
// Primes as generated by https://oeis.org/A175953
2014-12-30 20:58:29 -06:00
static std : : vector < int > zero_and_some_primes = {
0 , 23 , 29 , 37 , 47 , 59 , 79 , 101 , 127 , 163 , 211 , 269 , 337 , 431 , 541 , 677 ,
2014-12-30 06:22:33 -06:00
853 , 1069 , 1361 , 1709 , 2137 , 2677 , 3347 , 4201 , 5261 , 6577 , 8231 , 10289 ,
12889 , 16127 , 20161 , 25219 , 31531 , 39419 , 49277 , 61603 , 77017 , 96281 ,
120371 , 150473 , 188107 , 235159 , 293957 , 367453 , 459317 , 574157 , 717697 ,
897133 , 1121423 , 1401791 , 1752239 , 2190299 , 2737937 , 3422429 , 4278037 ,
5347553 , 6684443 , 8355563 , 10444457 , 13055587 , 16319519 , 20399411 ,
25499291 , 31874149 , 39842687 , 49803361 , 62254207 , 77817767 , 97272239 ,
2024-07-01 06:30:35 -05:00
121590311 , 151987889 , 189984863 , 237481091 , 296851369 , 371064217 ,
2024-07-02 02:10:18 -05:00
463830313 , 579787991 , 724735009 , 905918777 , 1132398479 , 1415498113 ,
1769372713
2014-12-30 06:22:33 -06:00
} ;
2014-12-30 20:58:29 -06:00
for ( auto p : zero_and_some_primes )
if ( p > = min_size ) return p ;
2014-12-30 06:22:33 -06:00
if ( sizeof ( int ) = = 4 )
2022-08-25 06:45:01 -05:00
throw std : : length_error ( " hash table exceeded maximum size. \n Design is likely too large for yosys to handle, if possible try not to flatten the design. " ) ;
2014-12-30 06:22:33 -06:00
2014-12-30 20:58:29 -06:00
for ( auto p : zero_and_some_primes )
2014-12-30 06:22:33 -06:00
if ( 100129 * p > min_size ) return 100129 * p ;
throw std : : length_error ( " hash table exceeded maximum size. " ) ;
2014-12-26 16:21:23 -06:00
}
2020-04-22 17:04:22 -05:00
template < typename K , typename T , typename OPS = hash_ops < K > > class dict ;
template < typename K , int offset = 0 , typename OPS = hash_ops < K > > class idict ;
template < typename K , typename OPS = hash_ops < K > > class pool ;
template < typename K , typename OPS = hash_ops < K > > class mfp ;
2015-01-18 05:12:33 -06:00
template < typename K , typename T , typename OPS >
2014-12-26 14:35:22 -06:00
class dict
2014-12-26 12:28:52 -06:00
{
struct entry_t
{
std : : pair < K , T > udata ;
2014-12-30 20:58:29 -06:00
int next ;
2014-12-26 14:35:22 -06:00
2014-12-30 20:58:29 -06:00
entry_t ( ) { }
entry_t ( const std : : pair < K , T > & udata , int next ) : udata ( udata ) , next ( next ) { }
2015-02-09 13:11:51 -06:00
entry_t ( std : : pair < K , T > & & udata , int next ) : udata ( std : : move ( udata ) ) , next ( next ) { }
2020-04-24 03:37:16 -05:00
bool operator < ( const entry_t & other ) const { return udata . first < other . udata . first ; }
2014-12-26 12:28:52 -06:00
} ;
std : : vector < int > hashtable ;
std : : vector < entry_t > entries ;
OPS ops ;
2015-02-09 13:11:51 -06:00
# ifdef NDEBUG
static inline void do_assert ( bool ) { }
# else
2014-12-30 20:58:29 -06:00
static inline void do_assert ( bool cond ) {
if ( ! cond ) throw std : : runtime_error ( " dict<> assert failed. " ) ;
2014-12-26 12:28:52 -06:00
}
2014-12-30 20:58:29 -06:00
# endif
2014-12-26 12:28:52 -06:00
2014-12-30 20:58:29 -06:00
int do_hash ( const K & key ) const
2014-12-26 14:35:22 -06:00
{
unsigned int hash = 0 ;
if ( ! hashtable . empty ( ) )
hash = ops . hash ( key ) % ( unsigned int ) ( hashtable . size ( ) ) ;
return hash ;
2014-12-26 12:28:52 -06:00
}
2014-12-30 20:58:29 -06:00
void do_rehash ( )
2014-12-29 13:24:28 -06:00
{
2014-12-30 20:58:29 -06:00
hashtable . clear ( ) ;
2016-01-31 15:50:34 -06:00
hashtable . resize ( hashtable_size ( entries . capacity ( ) * hashtable_size_factor ) , - 1 ) ;
2014-12-29 13:24:28 -06:00
2014-12-30 20:58:29 -06:00
for ( int i = 0 ; i < int ( entries . size ( ) ) ; i + + ) {
do_assert ( - 1 < = entries [ i ] . next & & entries [ i ] . next < int ( entries . size ( ) ) ) ;
int hash = do_hash ( entries [ i ] . udata . first ) ;
entries [ i ] . next = hashtable [ hash ] ;
hashtable [ hash ] = i ;
}
2014-12-29 13:24:28 -06:00
}
2014-12-30 20:58:29 -06:00
int do_erase ( int index , int hash )
2014-12-26 12:28:52 -06:00
{
2014-12-30 20:58:29 -06:00
do_assert ( index < int ( entries . size ( ) ) ) ;
if ( hashtable . empty ( ) | | index < 0 )
return 0 ;
int k = hashtable [ hash ] ;
2015-02-09 13:11:51 -06:00
do_assert ( 0 < = k & & k < int ( entries . size ( ) ) ) ;
2014-12-30 20:58:29 -06:00
if ( k = = index ) {
hashtable [ hash ] = entries [ index ] . next ;
} else {
while ( entries [ k ] . next ! = index ) {
k = entries [ k ] . next ;
do_assert ( 0 < = k & & k < int ( entries . size ( ) ) ) ;
}
entries [ k ] . next = entries [ index ] . next ;
}
2014-12-30 06:22:33 -06:00
2014-12-30 20:58:29 -06:00
int back_idx = entries . size ( ) - 1 ;
2014-12-26 12:28:52 -06:00
2014-12-30 20:58:29 -06:00
if ( index ! = back_idx )
{
int back_hash = do_hash ( entries [ back_idx ] . udata . first ) ;
2014-12-26 12:28:52 -06:00
2014-12-30 20:58:29 -06:00
k = hashtable [ back_hash ] ;
2015-02-09 13:11:51 -06:00
do_assert ( 0 < = k & & k < int ( entries . size ( ) ) ) ;
2014-12-30 20:58:29 -06:00
if ( k = = back_idx ) {
hashtable [ back_hash ] = index ;
2014-12-26 12:28:52 -06:00
} else {
2014-12-30 20:58:29 -06:00
while ( entries [ k ] . next ! = back_idx ) {
k = entries [ k ] . next ;
do_assert ( 0 < = k & & k < int ( entries . size ( ) ) ) ;
}
entries [ k ] . next = index ;
2014-12-26 12:28:52 -06:00
}
2014-12-29 13:24:28 -06:00
2014-12-30 20:58:29 -06:00
entries [ index ] = std : : move ( entries [ back_idx ] ) ;
}
entries . pop_back ( ) ;
if ( entries . empty ( ) )
hashtable . clear ( ) ;
2014-12-29 13:24:28 -06:00
2014-12-30 20:58:29 -06:00
return 1 ;
2014-12-26 12:28:52 -06:00
}
2014-12-30 20:58:29 -06:00
int do_lookup ( const K & key , int & hash ) const
2014-12-26 12:28:52 -06:00
{
2014-12-30 20:58:29 -06:00
if ( hashtable . empty ( ) )
return - 1 ;
if ( entries . size ( ) * hashtable_size_trigger > hashtable . size ( ) ) {
( ( dict * ) this ) - > do_rehash ( ) ;
hash = do_hash ( key ) ;
2014-12-26 12:28:52 -06:00
}
2014-12-30 20:58:29 -06:00
int index = hashtable [ hash ] ;
while ( index > = 0 & & ! ops . cmp ( entries [ index ] . udata . first , key ) ) {
index = entries [ index ] . next ;
do_assert ( - 1 < = index & & index < int ( entries . size ( ) ) ) ;
2014-12-26 12:28:52 -06:00
}
2014-12-30 20:58:29 -06:00
return index ;
2014-12-26 12:28:52 -06:00
}
2015-02-09 13:11:51 -06:00
int do_insert ( const K & key , int & hash )
{
if ( hashtable . empty ( ) ) {
2020-04-13 14:59:29 -05:00
entries . emplace_back ( std : : pair < K , T > ( key , T ( ) ) , - 1 ) ;
2015-02-09 13:11:51 -06:00
do_rehash ( ) ;
hash = do_hash ( key ) ;
} else {
2020-04-13 14:59:29 -05:00
entries . emplace_back ( std : : pair < K , T > ( key , T ( ) ) , hashtable [ hash ] ) ;
2015-02-09 13:11:51 -06:00
hashtable [ hash ] = entries . size ( ) - 1 ;
}
return entries . size ( ) - 1 ;
}
2014-12-30 20:58:29 -06:00
int do_insert ( const std : : pair < K , T > & value , int & hash )
2014-12-26 12:28:52 -06:00
{
2014-12-30 20:58:29 -06:00
if ( hashtable . empty ( ) ) {
2020-04-13 14:59:29 -05:00
entries . emplace_back ( value , - 1 ) ;
2014-12-30 20:58:29 -06:00
do_rehash ( ) ;
hash = do_hash ( value . first ) ;
} else {
2020-04-13 14:59:29 -05:00
entries . emplace_back ( value , hashtable [ hash ] ) ;
hashtable [ hash ] = entries . size ( ) - 1 ;
}
return entries . size ( ) - 1 ;
}
int do_insert ( std : : pair < K , T > & & rvalue , int & hash )
{
if ( hashtable . empty ( ) ) {
auto key = rvalue . first ;
entries . emplace_back ( std : : forward < std : : pair < K , T > > ( rvalue ) , - 1 ) ;
do_rehash ( ) ;
hash = do_hash ( key ) ;
} else {
entries . emplace_back ( std : : forward < std : : pair < K , T > > ( rvalue ) , hashtable [ hash ] ) ;
2014-12-30 20:58:29 -06:00
hashtable [ hash ] = entries . size ( ) - 1 ;
2014-12-26 12:28:52 -06:00
}
2014-12-30 20:58:29 -06:00
return entries . size ( ) - 1 ;
2014-12-26 12:28:52 -06:00
}
public :
2023-12-09 11:43:38 -06:00
class const_iterator
2014-12-26 12:28:52 -06:00
{
2014-12-30 21:24:04 -06:00
friend class dict ;
2014-12-30 20:58:29 -06:00
protected :
2014-12-31 07:52:46 -06:00
const dict * ptr ;
2014-12-26 12:28:52 -06:00
int index ;
2014-12-31 07:52:46 -06:00
const_iterator ( const dict * ptr , int index ) : ptr ( ptr ) , index ( index ) { }
2014-12-26 12:28:52 -06:00
public :
2023-12-09 11:43:38 -06:00
typedef std : : forward_iterator_tag iterator_category ;
typedef std : : pair < K , T > value_type ;
typedef ptrdiff_t difference_type ;
typedef std : : pair < K , T > * pointer ;
typedef std : : pair < K , T > & reference ;
2014-12-31 07:52:46 -06:00
const_iterator ( ) { }
const_iterator operator + + ( ) { index - - ; return * this ; }
2020-06-19 15:57:27 -05:00
const_iterator operator + = ( int amt ) { index - = amt ; return * this ; }
2014-12-31 07:52:46 -06:00
bool operator < ( const const_iterator & other ) const { return index > other . index ; }
bool operator = = ( const const_iterator & other ) const { return index = = other . index ; }
bool operator ! = ( const const_iterator & other ) const { return index ! = other . index ; }
2014-12-26 14:35:22 -06:00
const std : : pair < K , T > & operator * ( ) const { return ptr - > entries [ index ] . udata ; }
const std : : pair < K , T > * operator - > ( ) const { return & ptr - > entries [ index ] . udata ; }
2014-12-26 12:28:52 -06:00
} ;
2023-12-09 11:43:38 -06:00
class iterator
2014-12-26 14:35:22 -06:00
{
2014-12-30 21:24:04 -06:00
friend class dict ;
2014-12-30 20:58:29 -06:00
protected :
2014-12-31 07:52:46 -06:00
dict * ptr ;
2014-12-26 14:35:22 -06:00
int index ;
2014-12-31 07:52:46 -06:00
iterator ( dict * ptr , int index ) : ptr ( ptr ) , index ( index ) { }
2014-12-26 14:35:22 -06:00
public :
2023-12-09 11:43:38 -06:00
typedef std : : forward_iterator_tag iterator_category ;
typedef std : : pair < K , T > value_type ;
typedef ptrdiff_t difference_type ;
typedef std : : pair < K , T > * pointer ;
typedef std : : pair < K , T > & reference ;
2014-12-31 07:52:46 -06:00
iterator ( ) { }
iterator operator + + ( ) { index - - ; return * this ; }
2020-06-19 15:57:27 -05:00
iterator operator + = ( int amt ) { index - = amt ; return * this ; }
2014-12-31 07:52:46 -06:00
bool operator < ( const iterator & other ) const { return index > other . index ; }
bool operator = = ( const iterator & other ) const { return index = = other . index ; }
bool operator ! = ( const iterator & other ) const { return index ! = other . index ; }
std : : pair < K , T > & operator * ( ) { return ptr - > entries [ index ] . udata ; }
std : : pair < K , T > * operator - > ( ) { return & ptr - > entries [ index ] . udata ; }
2014-12-26 14:35:22 -06:00
const std : : pair < K , T > & operator * ( ) const { return ptr - > entries [ index ] . udata ; }
const std : : pair < K , T > * operator - > ( ) const { return & ptr - > entries [ index ] . udata ; }
2014-12-31 07:52:46 -06:00
operator const_iterator ( ) const { return const_iterator ( ptr , index ) ; }
2014-12-26 14:35:22 -06:00
} ;
2023-12-29 12:20:44 -06:00
constexpr dict ( )
2014-12-26 12:28:52 -06:00
{
}
2014-12-30 21:19:04 -06:00
dict ( const dict & other )
2014-12-26 14:35:22 -06:00
{
2014-12-30 20:58:29 -06:00
entries = other . entries ;
do_rehash ( ) ;
2014-12-26 14:35:22 -06:00
}
2014-12-30 21:19:04 -06:00
dict ( dict & & other )
2014-12-26 14:35:22 -06:00
{
swap ( other ) ;
}
2014-12-30 21:19:04 -06:00
dict & operator = ( const dict & other ) {
2014-12-30 20:58:29 -06:00
entries = other . entries ;
do_rehash ( ) ;
2014-12-26 14:35:22 -06:00
return * this ;
}
2014-12-30 21:19:04 -06:00
dict & operator = ( dict & & other ) {
2014-12-26 14:35:22 -06:00
clear ( ) ;
swap ( other ) ;
return * this ;
}
dict ( const std : : initializer_list < std : : pair < K , T > > & list )
{
for ( auto & it : list )
insert ( it ) ;
}
2014-12-26 12:28:52 -06:00
template < class InputIterator >
2014-12-26 14:35:22 -06:00
dict ( InputIterator first , InputIterator last )
2014-12-26 12:28:52 -06:00
{
insert ( first , last ) ;
}
template < class InputIterator >
void insert ( InputIterator first , InputIterator last )
{
for ( ; first ! = last ; + + first )
insert ( * first ) ;
}
2015-02-09 13:11:51 -06:00
std : : pair < iterator , bool > insert ( const K & key )
{
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
if ( i > = 0 )
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
i = do_insert ( key , hash ) ;
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
}
2014-12-28 10:51:16 -06:00
std : : pair < iterator , bool > insert ( const std : : pair < K , T > & value )
2014-12-26 12:28:52 -06:00
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( value . first ) ;
int i = do_lookup ( value . first , hash ) ;
2014-12-26 12:28:52 -06:00
if ( i > = 0 )
2014-12-28 10:51:16 -06:00
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
2014-12-30 20:58:29 -06:00
i = do_insert ( value , hash ) ;
2014-12-28 10:51:16 -06:00
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
2014-12-26 12:28:52 -06:00
}
2020-04-13 14:59:29 -05:00
std : : pair < iterator , bool > insert ( std : : pair < K , T > & & rvalue )
{
int hash = do_hash ( rvalue . first ) ;
int i = do_lookup ( rvalue . first , hash ) ;
if ( i > = 0 )
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
i = do_insert ( std : : forward < std : : pair < K , T > > ( rvalue ) , hash ) ;
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
}
2020-04-15 11:22:22 -05:00
std : : pair < iterator , bool > emplace ( K const & key , T const & value )
{
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
if ( i > = 0 )
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
i = do_insert ( std : : make_pair ( key , value ) , hash ) ;
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
}
std : : pair < iterator , bool > emplace ( K const & key , T & & rvalue )
2020-04-13 14:59:29 -05:00
{
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
if ( i > = 0 )
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
i = do_insert ( std : : make_pair ( key , std : : forward < T > ( rvalue ) ) , hash ) ;
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
}
2020-04-15 11:22:22 -05:00
std : : pair < iterator , bool > emplace ( K & & rkey , T const & value )
{
int hash = do_hash ( rkey ) ;
int i = do_lookup ( rkey , hash ) ;
if ( i > = 0 )
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
i = do_insert ( std : : make_pair ( std : : forward < K > ( rkey ) , value ) , hash ) ;
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
}
std : : pair < iterator , bool > emplace ( K & & rkey , T & & rvalue )
{
int hash = do_hash ( rkey ) ;
int i = do_lookup ( rkey , hash ) ;
if ( i > = 0 )
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
i = do_insert ( std : : make_pair ( std : : forward < K > ( rkey ) , std : : forward < T > ( rvalue ) ) , hash ) ;
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
}
2014-12-28 15:26:09 -06:00
int erase ( const K & key )
2014-12-26 12:28:52 -06:00
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( key ) ;
int index = do_lookup ( key , hash ) ;
return do_erase ( index , hash ) ;
2014-12-26 12:28:52 -06:00
}
2014-12-28 15:26:09 -06:00
iterator erase ( iterator it )
2014-12-26 14:35:22 -06:00
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( it - > first ) ;
do_erase ( it . index , hash ) ;
2014-12-28 15:26:09 -06:00
return + + it ;
2014-12-26 14:35:22 -06:00
}
int count ( const K & key ) const
2014-12-26 12:28:52 -06:00
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 12:28:52 -06:00
return i < 0 ? 0 : 1 ;
}
2014-12-31 07:52:46 -06:00
int count ( const K & key , const_iterator it ) const
{
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
return i < 0 | | i > it . index ? 0 : 1 ;
}
2014-12-26 14:35:22 -06:00
iterator find ( const K & key )
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 14:35:22 -06:00
if ( i < 0 )
return end ( ) ;
return iterator ( this , i ) ;
}
const_iterator find ( const K & key ) const
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 14:35:22 -06:00
if ( i < 0 )
return end ( ) ;
return const_iterator ( this , i ) ;
}
T & at ( const K & key )
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 14:35:22 -06:00
if ( i < 0 )
throw std : : out_of_range ( " dict::at() " ) ;
return entries [ i ] . udata . second ;
}
const T & at ( const K & key ) const
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 14:35:22 -06:00
if ( i < 0 )
throw std : : out_of_range ( " dict::at() " ) ;
return entries [ i ] . udata . second ;
}
2020-04-16 14:48:03 -05:00
const T & at ( const K & key , const T & defval ) const
2015-12-02 13:41:57 -06:00
{
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
if ( i < 0 )
return defval ;
return entries [ i ] . udata . second ;
}
2014-12-26 12:28:52 -06:00
T & operator [ ] ( const K & key )
{
2014-12-30 20:58:29 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 12:28:52 -06:00
if ( i < 0 )
2014-12-30 20:58:29 -06:00
i = do_insert ( std : : pair < K , T > ( key , T ( ) ) , hash ) ;
2014-12-26 12:28:52 -06:00
return entries [ i ] . udata . second ;
}
2015-01-23 17:13:27 -06:00
template < typename Compare = std : : less < K > >
void sort ( Compare comp = Compare ( ) )
{
std : : sort ( entries . begin ( ) , entries . end ( ) , [ comp ] ( const entry_t & a , const entry_t & b ) { return comp ( b . udata . first , a . udata . first ) ; } ) ;
do_rehash ( ) ;
}
2014-12-30 21:19:04 -06:00
void swap ( dict & other )
2014-12-26 14:35:22 -06:00
{
hashtable . swap ( other . hashtable ) ;
entries . swap ( other . entries ) ;
}
2014-12-30 21:19:04 -06:00
bool operator = = ( const dict & other ) const {
2014-12-30 20:58:29 -06:00
if ( size ( ) ! = other . size ( ) )
2014-12-26 14:35:22 -06:00
return false ;
2014-12-30 20:58:29 -06:00
for ( auto & it : entries ) {
auto oit = other . find ( it . udata . first ) ;
2015-02-09 13:11:51 -06:00
if ( oit = = other . end ( ) | | ! ( oit - > second = = it . udata . second ) )
2014-12-30 20:58:29 -06:00
return false ;
}
2014-12-26 14:35:22 -06:00
return true ;
}
2014-12-30 21:19:04 -06:00
bool operator ! = ( const dict & other ) const {
2015-02-09 13:11:51 -06:00
return ! operator = = ( other ) ;
2014-12-26 14:35:22 -06:00
}
2020-04-22 17:04:22 -05:00
unsigned int hash ( ) const {
unsigned int h = mkhash_init ;
2020-05-18 12:10:01 -05:00
for ( auto & entry : entries ) {
h ^ = hash_ops < K > : : hash ( entry . udata . first ) ;
h ^ = hash_ops < T > : : hash ( entry . udata . second ) ;
2020-04-22 17:04:22 -05:00
}
return h ;
}
2016-01-31 15:50:34 -06:00
void reserve ( size_t n ) { entries . reserve ( n ) ; }
2014-12-30 20:58:29 -06:00
size_t size ( ) const { return entries . size ( ) ; }
bool empty ( ) const { return entries . empty ( ) ; }
void clear ( ) { hashtable . clear ( ) ; entries . clear ( ) ; }
2014-12-26 14:35:22 -06:00
2014-12-30 20:58:29 -06:00
iterator begin ( ) { return iterator ( this , int ( entries . size ( ) ) - 1 ) ; }
2019-03-13 11:36:06 -05:00
iterator element ( int n ) { return iterator ( this , int ( entries . size ( ) ) - 1 - n ) ; }
2014-12-30 06:30:22 -06:00
iterator end ( ) { return iterator ( nullptr , - 1 ) ; }
2014-12-26 14:35:22 -06:00
2014-12-30 20:58:29 -06:00
const_iterator begin ( ) const { return const_iterator ( this , int ( entries . size ( ) ) - 1 ) ; }
2019-03-13 11:36:06 -05:00
const_iterator element ( int n ) const { return const_iterator ( this , int ( entries . size ( ) ) - 1 - n ) ; }
2014-12-30 06:30:22 -06:00
const_iterator end ( ) const { return const_iterator ( nullptr , - 1 ) ; }
2014-12-26 12:28:52 -06:00
} ;
2015-01-18 05:12:33 -06:00
template < typename K , typename OPS >
2014-12-26 14:59:41 -06:00
class pool
{
2015-01-18 05:12:33 -06:00
template < typename , int , typename > friend class idict ;
protected :
2014-12-26 14:59:41 -06:00
struct entry_t
{
2014-12-30 21:19:04 -06:00
K udata ;
int next ;
2014-12-26 14:59:41 -06:00
2014-12-30 21:19:04 -06:00
entry_t ( ) { }
entry_t ( const K & udata , int next ) : udata ( udata ) , next ( next ) { }
2020-04-20 00:37:10 -05:00
entry_t ( K & & udata , int next ) : udata ( std : : move ( udata ) ) , next ( next ) { }
2014-12-26 14:59:41 -06:00
} ;
std : : vector < int > hashtable ;
std : : vector < entry_t > entries ;
OPS ops ;
2015-02-09 13:11:51 -06:00
# ifdef NDEBUG
static inline void do_assert ( bool ) { }
# else
2014-12-30 21:19:04 -06:00
static inline void do_assert ( bool cond ) {
if ( ! cond ) throw std : : runtime_error ( " pool<> assert failed. " ) ;
2014-12-26 14:59:41 -06:00
}
2014-12-30 21:19:04 -06:00
# endif
2014-12-26 14:59:41 -06:00
2014-12-30 21:19:04 -06:00
int do_hash ( const K & key ) const
2014-12-26 14:59:41 -06:00
{
unsigned int hash = 0 ;
if ( ! hashtable . empty ( ) )
hash = ops . hash ( key ) % ( unsigned int ) ( hashtable . size ( ) ) ;
return hash ;
}
2014-12-30 21:19:04 -06:00
void do_rehash ( )
2014-12-29 13:24:28 -06:00
{
2014-12-30 21:19:04 -06:00
hashtable . clear ( ) ;
2016-01-31 15:50:34 -06:00
hashtable . resize ( hashtable_size ( entries . capacity ( ) * hashtable_size_factor ) , - 1 ) ;
2014-12-30 21:19:04 -06:00
for ( int i = 0 ; i < int ( entries . size ( ) ) ; i + + ) {
do_assert ( - 1 < = entries [ i ] . next & & entries [ i ] . next < int ( entries . size ( ) ) ) ;
int hash = do_hash ( entries [ i ] . udata ) ;
entries [ i ] . next = hashtable [ hash ] ;
hashtable [ hash ] = i ;
2014-12-29 13:24:28 -06:00
}
}
2014-12-30 21:19:04 -06:00
int do_erase ( int index , int hash )
2014-12-29 13:24:28 -06:00
{
2014-12-30 21:19:04 -06:00
do_assert ( index < int ( entries . size ( ) ) ) ;
if ( hashtable . empty ( ) | | index < 0 )
return 0 ;
2014-12-29 13:24:28 -06:00
2014-12-30 21:19:04 -06:00
int k = hashtable [ hash ] ;
if ( k = = index ) {
hashtable [ hash ] = entries [ index ] . next ;
} else {
while ( entries [ k ] . next ! = index ) {
k = entries [ k ] . next ;
do_assert ( 0 < = k & & k < int ( entries . size ( ) ) ) ;
}
entries [ k ] . next = entries [ index ] . next ;
}
2014-12-30 06:22:33 -06:00
2014-12-30 21:19:04 -06:00
int back_idx = entries . size ( ) - 1 ;
2014-12-26 14:59:41 -06:00
2014-12-30 21:19:04 -06:00
if ( index ! = back_idx )
{
int back_hash = do_hash ( entries [ back_idx ] . udata ) ;
2014-12-26 14:59:41 -06:00
2014-12-30 21:19:04 -06:00
k = hashtable [ back_hash ] ;
if ( k = = back_idx ) {
hashtable [ back_hash ] = index ;
2014-12-26 14:59:41 -06:00
} else {
2014-12-30 21:19:04 -06:00
while ( entries [ k ] . next ! = back_idx ) {
k = entries [ k ] . next ;
do_assert ( 0 < = k & & k < int ( entries . size ( ) ) ) ;
}
entries [ k ] . next = index ;
2014-12-26 14:59:41 -06:00
}
2014-12-29 13:24:28 -06:00
2014-12-30 21:19:04 -06:00
entries [ index ] = std : : move ( entries [ back_idx ] ) ;
2014-12-26 14:59:41 -06:00
}
2014-12-30 21:19:04 -06:00
entries . pop_back ( ) ;
if ( entries . empty ( ) )
hashtable . clear ( ) ;
return 1 ;
2014-12-26 14:59:41 -06:00
}
2014-12-30 21:19:04 -06:00
int do_lookup ( const K & key , int & hash ) const
2014-12-26 14:59:41 -06:00
{
2014-12-30 21:19:04 -06:00
if ( hashtable . empty ( ) )
return - 1 ;
if ( entries . size ( ) * hashtable_size_trigger > hashtable . size ( ) ) {
( ( pool * ) this ) - > do_rehash ( ) ;
hash = do_hash ( key ) ;
2014-12-26 14:59:41 -06:00
}
2014-12-30 21:19:04 -06:00
int index = hashtable [ hash ] ;
while ( index > = 0 & & ! ops . cmp ( entries [ index ] . udata , key ) ) {
index = entries [ index ] . next ;
do_assert ( - 1 < = index & & index < int ( entries . size ( ) ) ) ;
}
return index ;
2014-12-26 14:59:41 -06:00
}
2014-12-30 21:19:04 -06:00
int do_insert ( const K & value , int & hash )
2014-12-26 14:59:41 -06:00
{
2014-12-30 21:19:04 -06:00
if ( hashtable . empty ( ) ) {
2020-04-19 21:16:55 -05:00
entries . emplace_back ( value , - 1 ) ;
2014-12-30 21:19:04 -06:00
do_rehash ( ) ;
hash = do_hash ( value ) ;
} else {
2020-04-19 21:16:55 -05:00
entries . emplace_back ( value , hashtable [ hash ] ) ;
hashtable [ hash ] = entries . size ( ) - 1 ;
}
return entries . size ( ) - 1 ;
}
2020-04-21 12:17:47 -05:00
int do_insert ( K & & rvalue , int & hash )
2020-04-19 21:16:55 -05:00
{
if ( hashtable . empty ( ) ) {
2020-04-21 12:17:47 -05:00
entries . emplace_back ( std : : forward < K > ( rvalue ) , - 1 ) ;
2014-12-30 21:19:04 -06:00
do_rehash ( ) ;
2020-04-21 12:17:47 -05:00
hash = do_hash ( rvalue ) ;
2014-12-30 21:19:04 -06:00
} else {
2020-04-21 12:17:47 -05:00
entries . emplace_back ( std : : forward < K > ( rvalue ) , hashtable [ hash ] ) ;
2014-12-30 21:19:04 -06:00
hashtable [ hash ] = entries . size ( ) - 1 ;
2014-12-26 14:59:41 -06:00
}
2014-12-30 21:19:04 -06:00
return entries . size ( ) - 1 ;
2014-12-26 14:59:41 -06:00
}
public :
2023-12-09 11:43:38 -06:00
class const_iterator
2014-12-26 14:59:41 -06:00
{
2014-12-30 21:24:04 -06:00
friend class pool ;
2014-12-30 21:19:04 -06:00
protected :
2014-12-31 07:52:46 -06:00
const pool * ptr ;
2014-12-26 14:59:41 -06:00
int index ;
2014-12-31 07:52:46 -06:00
const_iterator ( const pool * ptr , int index ) : ptr ( ptr ) , index ( index ) { }
2014-12-26 14:59:41 -06:00
public :
2023-12-09 11:43:38 -06:00
typedef std : : forward_iterator_tag iterator_category ;
typedef K value_type ;
typedef ptrdiff_t difference_type ;
typedef K * pointer ;
typedef K & reference ;
2014-12-31 07:52:46 -06:00
const_iterator ( ) { }
const_iterator operator + + ( ) { index - - ; return * this ; }
bool operator = = ( const const_iterator & other ) const { return index = = other . index ; }
bool operator ! = ( const const_iterator & other ) const { return index ! = other . index ; }
2014-12-30 21:19:04 -06:00
const K & operator * ( ) const { return ptr - > entries [ index ] . udata ; }
const K * operator - > ( ) const { return & ptr - > entries [ index ] . udata ; }
2014-12-26 14:59:41 -06:00
} ;
2023-12-09 11:43:38 -06:00
class iterator
2014-12-26 14:59:41 -06:00
{
2014-12-30 21:24:04 -06:00
friend class pool ;
2014-12-30 21:19:04 -06:00
protected :
2014-12-31 07:52:46 -06:00
pool * ptr ;
2014-12-26 14:59:41 -06:00
int index ;
2014-12-31 07:52:46 -06:00
iterator ( pool * ptr , int index ) : ptr ( ptr ) , index ( index ) { }
2014-12-26 14:59:41 -06:00
public :
2023-12-09 11:43:38 -06:00
typedef std : : forward_iterator_tag iterator_category ;
typedef K value_type ;
typedef ptrdiff_t difference_type ;
typedef K * pointer ;
typedef K & reference ;
2014-12-31 07:52:46 -06:00
iterator ( ) { }
iterator operator + + ( ) { index - - ; return * this ; }
bool operator = = ( const iterator & other ) const { return index = = other . index ; }
bool operator ! = ( const iterator & other ) const { return index ! = other . index ; }
K & operator * ( ) { return ptr - > entries [ index ] . udata ; }
K * operator - > ( ) { return & ptr - > entries [ index ] . udata ; }
2014-12-30 21:19:04 -06:00
const K & operator * ( ) const { return ptr - > entries [ index ] . udata ; }
const K * operator - > ( ) const { return & ptr - > entries [ index ] . udata ; }
2014-12-31 07:52:46 -06:00
operator const_iterator ( ) const { return const_iterator ( ptr , index ) ; }
2014-12-26 14:59:41 -06:00
} ;
2023-12-29 12:20:44 -06:00
constexpr pool ( )
2014-12-26 14:59:41 -06:00
{
}
2014-12-30 21:19:04 -06:00
pool ( const pool & other )
2014-12-26 14:59:41 -06:00
{
2014-12-30 21:19:04 -06:00
entries = other . entries ;
do_rehash ( ) ;
2014-12-26 14:59:41 -06:00
}
2014-12-30 21:19:04 -06:00
pool ( pool & & other )
2014-12-26 14:59:41 -06:00
{
swap ( other ) ;
}
2014-12-30 21:19:04 -06:00
pool & operator = ( const pool & other ) {
entries = other . entries ;
do_rehash ( ) ;
2014-12-26 14:59:41 -06:00
return * this ;
}
2014-12-30 21:19:04 -06:00
pool & operator = ( pool & & other ) {
2014-12-26 14:59:41 -06:00
clear ( ) ;
swap ( other ) ;
return * this ;
}
pool ( const std : : initializer_list < K > & list )
{
for ( auto & it : list )
insert ( it ) ;
}
template < class InputIterator >
pool ( InputIterator first , InputIterator last )
{
insert ( first , last ) ;
}
template < class InputIterator >
void insert ( InputIterator first , InputIterator last )
{
for ( ; first ! = last ; + + first )
insert ( * first ) ;
}
2014-12-30 21:19:04 -06:00
std : : pair < iterator , bool > insert ( const K & value )
2014-12-26 14:59:41 -06:00
{
2014-12-30 21:19:04 -06:00
int hash = do_hash ( value ) ;
int i = do_lookup ( value , hash ) ;
2014-12-26 14:59:41 -06:00
if ( i > = 0 )
2014-12-28 10:51:16 -06:00
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
2014-12-30 21:19:04 -06:00
i = do_insert ( value , hash ) ;
2014-12-28 10:51:16 -06:00
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
2014-12-26 14:59:41 -06:00
}
2020-04-21 12:17:47 -05:00
std : : pair < iterator , bool > insert ( K & & rvalue )
2020-04-19 21:16:55 -05:00
{
2020-04-21 12:17:47 -05:00
int hash = do_hash ( rvalue ) ;
int i = do_lookup ( rvalue , hash ) ;
2020-04-19 21:16:55 -05:00
if ( i > = 0 )
return std : : pair < iterator , bool > ( iterator ( this , i ) , false ) ;
2020-04-21 12:17:47 -05:00
i = do_insert ( std : : forward < K > ( rvalue ) , hash ) ;
2020-04-19 21:16:55 -05:00
return std : : pair < iterator , bool > ( iterator ( this , i ) , true ) ;
}
2020-04-22 10:14:07 -05:00
template < typename . . . Args >
std : : pair < iterator , bool > emplace ( Args & & . . . args )
{
return insert ( K ( std : : forward < Args > ( args ) . . . ) ) ;
}
2014-12-28 15:26:09 -06:00
int erase ( const K & key )
2014-12-26 14:59:41 -06:00
{
2014-12-30 21:19:04 -06:00
int hash = do_hash ( key ) ;
int index = do_lookup ( key , hash ) ;
return do_erase ( index , hash ) ;
2014-12-26 14:59:41 -06:00
}
2014-12-28 15:26:09 -06:00
iterator erase ( iterator it )
2014-12-26 14:59:41 -06:00
{
2014-12-31 06:05:33 -06:00
int hash = do_hash ( * it ) ;
2014-12-30 21:19:04 -06:00
do_erase ( it . index , hash ) ;
2014-12-28 15:26:09 -06:00
return + + it ;
2014-12-26 14:59:41 -06:00
}
int count ( const K & key ) const
{
2014-12-30 21:19:04 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 14:59:41 -06:00
return i < 0 ? 0 : 1 ;
}
2014-12-31 07:52:46 -06:00
int count ( const K & key , const_iterator it ) const
{
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
return i < 0 | | i > it . index ? 0 : 1 ;
}
2014-12-26 14:59:41 -06:00
iterator find ( const K & key )
{
2014-12-30 21:19:04 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 14:59:41 -06:00
if ( i < 0 )
return end ( ) ;
return iterator ( this , i ) ;
}
const_iterator find ( const K & key ) const
{
2014-12-30 21:19:04 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 14:59:41 -06:00
if ( i < 0 )
return end ( ) ;
return const_iterator ( this , i ) ;
}
2014-12-30 21:19:04 -06:00
bool operator [ ] ( const K & key )
2014-12-26 14:59:41 -06:00
{
2014-12-30 21:19:04 -06:00
int hash = do_hash ( key ) ;
int i = do_lookup ( key , hash ) ;
2014-12-26 14:59:41 -06:00
return i > = 0 ;
}
2015-01-23 17:13:27 -06:00
template < typename Compare = std : : less < K > >
void sort ( Compare comp = Compare ( ) )
{
std : : sort ( entries . begin ( ) , entries . end ( ) , [ comp ] ( const entry_t & a , const entry_t & b ) { return comp ( b . udata , a . udata ) ; } ) ;
do_rehash ( ) ;
}
2015-04-07 08:07:01 -05:00
K pop ( )
{
iterator it = begin ( ) ;
K ret = * it ;
erase ( it ) ;
return ret ;
}
2014-12-30 21:19:04 -06:00
void swap ( pool & other )
2014-12-26 14:59:41 -06:00
{
hashtable . swap ( other . hashtable ) ;
entries . swap ( other . entries ) ;
}
2014-12-30 21:19:04 -06:00
bool operator = = ( const pool & other ) const {
if ( size ( ) ! = other . size ( ) )
2014-12-26 14:59:41 -06:00
return false ;
2014-12-30 21:19:04 -06:00
for ( auto & it : entries )
if ( ! other . count ( it . udata ) )
return false ;
2014-12-26 14:59:41 -06:00
return true ;
}
2014-12-30 21:19:04 -06:00
bool operator ! = ( const pool & other ) const {
2015-02-09 13:11:51 -06:00
return ! operator = = ( other ) ;
2014-12-26 14:59:41 -06:00
}
2023-09-26 11:56:54 -05:00
unsigned int hash ( ) const {
2017-08-22 06:04:33 -05:00
unsigned int hashval = mkhash_init ;
for ( auto & it : entries )
hashval ^ = ops . hash ( it . udata ) ;
return hashval ;
}
2016-01-31 15:50:34 -06:00
void reserve ( size_t n ) { entries . reserve ( n ) ; }
2014-12-30 21:19:04 -06:00
size_t size ( ) const { return entries . size ( ) ; }
bool empty ( ) const { return entries . empty ( ) ; }
void clear ( ) { hashtable . clear ( ) ; entries . clear ( ) ; }
2014-12-26 14:59:41 -06:00
2014-12-30 21:19:04 -06:00
iterator begin ( ) { return iterator ( this , int ( entries . size ( ) ) - 1 ) ; }
2019-03-13 11:36:06 -05:00
iterator element ( int n ) { return iterator ( this , int ( entries . size ( ) ) - 1 - n ) ; }
2014-12-30 06:30:22 -06:00
iterator end ( ) { return iterator ( nullptr , - 1 ) ; }
2014-12-26 14:59:41 -06:00
2014-12-30 21:19:04 -06:00
const_iterator begin ( ) const { return const_iterator ( this , int ( entries . size ( ) ) - 1 ) ; }
2019-03-13 11:36:06 -05:00
const_iterator element ( int n ) const { return const_iterator ( this , int ( entries . size ( ) ) - 1 - n ) ; }
2014-12-30 06:30:22 -06:00
const_iterator end ( ) const { return const_iterator ( nullptr , - 1 ) ; }
2014-12-26 14:59:41 -06:00
} ;
2015-01-18 05:12:33 -06:00
template < typename K , int offset , typename OPS >
class idict
{
pool < K , OPS > database ;
public :
2023-12-09 11:43:38 -06:00
class const_iterator
2020-04-16 14:48:03 -05:00
{
friend class idict ;
protected :
const idict & container ;
int index ;
const_iterator ( const idict & container , int index ) : container ( container ) , index ( index ) { }
public :
2023-12-09 11:43:38 -06:00
typedef std : : forward_iterator_tag iterator_category ;
typedef K value_type ;
typedef ptrdiff_t difference_type ;
typedef K * pointer ;
typedef K & reference ;
2020-04-16 14:48:03 -05:00
const_iterator ( ) { }
const_iterator operator + + ( ) { index + + ; return * this ; }
bool operator = = ( const const_iterator & other ) const { return index = = other . index ; }
bool operator ! = ( const const_iterator & other ) const { return index ! = other . index ; }
const K & operator * ( ) const { return container [ index ] ; }
const K * operator - > ( ) const { return & container [ index ] ; }
} ;
2015-01-18 05:12:33 -06:00
2023-12-29 12:20:44 -06:00
constexpr idict ( )
{
}
2015-01-18 05:12:33 -06:00
int operator ( ) ( const K & key )
{
int hash = database . do_hash ( key ) ;
int i = database . do_lookup ( key , hash ) ;
if ( i < 0 )
i = database . do_insert ( key , hash ) ;
return i + offset ;
}
int at ( const K & key ) const
{
int hash = database . do_hash ( key ) ;
int i = database . do_lookup ( key , hash ) ;
if ( i < 0 )
throw std : : out_of_range ( " idict::at() " ) ;
return i + offset ;
}
2015-12-02 13:41:57 -06:00
int at ( const K & key , int defval ) const
{
int hash = database . do_hash ( key ) ;
int i = database . do_lookup ( key , hash ) ;
if ( i < 0 )
return defval ;
return i + offset ;
}
2015-01-18 05:12:33 -06:00
int count ( const K & key ) const
{
int hash = database . do_hash ( key ) ;
int i = database . do_lookup ( key , hash ) ;
return i < 0 ? 0 : 1 ;
}
void expect ( const K & key , int i )
{
int j = ( * this ) ( key ) ;
if ( i ! = j )
throw std : : out_of_range ( " idict::expect() " ) ;
}
const K & operator [ ] ( int index ) const
{
return database . entries . at ( index - offset ) . udata ;
}
2015-10-27 09:04:47 -05:00
void swap ( idict & other )
{
database . swap ( other . database ) ;
}
2016-01-31 15:50:34 -06:00
void reserve ( size_t n ) { database . reserve ( n ) ; }
2015-10-27 09:04:47 -05:00
size_t size ( ) const { return database . size ( ) ; }
bool empty ( ) const { return database . empty ( ) ; }
void clear ( ) { database . clear ( ) ; }
2020-04-16 14:48:03 -05:00
const_iterator begin ( ) const { return const_iterator ( * this , offset ) ; }
const_iterator element ( int n ) const { return const_iterator ( * this , n ) ; }
const_iterator end ( ) const { return const_iterator ( * this , offset + size ( ) ) ; }
2015-01-18 05:12:33 -06:00
} ;
2024-07-18 09:02:11 -05:00
/**
* Union - find data structure with a promotion method
* mfp stands for " merge, find, promote "
* i - prefixed methods operate on indices in parents
*/
2015-10-27 09:04:47 -05:00
template < typename K , typename OPS >
class mfp
{
mutable idict < K , 0 , OPS > database ;
mutable std : : vector < int > parents ;
public :
2015-11-30 12:43:52 -06:00
typedef typename idict < K , 0 , OPS > : : const_iterator const_iterator ;
2023-12-29 12:20:44 -06:00
constexpr mfp ( )
{
}
2024-07-18 09:02:11 -05:00
// Finds a given element's index. If it isn't in the data structure,
// it is added as its own set
2015-10-27 09:04:47 -05:00
int operator ( ) ( const K & key ) const
{
int i = database ( key ) ;
2024-07-18 09:02:11 -05:00
// If the lookup caused the database to grow,
// also add a corresponding entry in parents initialized to -1 (no parent)
2015-10-27 09:04:47 -05:00
parents . resize ( database . size ( ) , - 1 ) ;
return i ;
}
2024-07-18 09:02:11 -05:00
// Finds an element at given index
2015-10-27 09:04:47 -05:00
const K & operator [ ] ( int index ) const
{
return database [ index ] ;
}
int ifind ( int i ) const
{
int p = i , k = i ;
while ( parents [ p ] ! = - 1 )
p = parents [ p ] ;
2024-07-18 09:02:11 -05:00
// p is now the representative of i
// Now we traverse from i up to the representative again
// and make p the parent of all the nodes along the way.
// This is a side effect and doesn't affect the return value.
// It speeds up future find operations
2015-10-27 09:04:47 -05:00
while ( k ! = p ) {
int next_k = parents [ k ] ;
parents [ k ] = p ;
k = next_k ;
}
return p ;
}
2024-07-18 09:02:11 -05:00
// Merge sets if the given indices belong to different sets
2015-10-27 09:04:47 -05:00
void imerge ( int i , int j )
{
i = ifind ( i ) ;
j = ifind ( j ) ;
if ( i ! = j )
parents [ i ] = j ;
}
void ipromote ( int i )
{
int k = i ;
while ( k ! = - 1 ) {
int next_k = parents [ k ] ;
parents [ k ] = i ;
k = next_k ;
}
parents [ i ] = - 1 ;
}
2015-10-28 05:21:55 -05:00
int lookup ( const K & a ) const
{
return ifind ( ( * this ) ( a ) ) ;
}
2015-10-27 09:04:47 -05:00
const K & find ( const K & a ) const
{
2016-02-01 03:03:03 -06:00
int i = database . at ( a , - 1 ) ;
if ( i < 0 )
return a ;
return ( * this ) [ ifind ( i ) ] ;
2015-10-27 09:04:47 -05:00
}
void merge ( const K & a , const K & b )
{
imerge ( ( * this ) ( a ) , ( * this ) ( b ) ) ;
}
void promote ( const K & a )
{
2016-02-01 03:03:03 -06:00
int i = database . at ( a , - 1 ) ;
if ( i > = 0 )
ipromote ( i ) ;
2015-10-27 09:04:47 -05:00
}
void swap ( mfp & other )
{
database . swap ( other . database ) ;
parents . swap ( other . parents ) ;
}
2016-01-31 15:50:34 -06:00
void reserve ( size_t n ) { database . reserve ( n ) ; }
2015-10-27 09:04:47 -05:00
size_t size ( ) const { return database . size ( ) ; }
bool empty ( ) const { return database . empty ( ) ; }
void clear ( ) { database . clear ( ) ; parents . clear ( ) ; }
2015-11-30 12:43:52 -06:00
const_iterator begin ( ) const { return database . begin ( ) ; }
2019-03-13 11:36:06 -05:00
const_iterator element ( int n ) const { return database . element ( n ) ; }
2015-11-30 12:43:52 -06:00
const_iterator end ( ) const { return database . end ( ) ; }
2015-10-27 09:04:47 -05:00
} ;
2014-12-28 10:51:16 -06:00
} /* namespace hashlib */
2014-12-26 12:28:52 -06:00
# endif