#include "UtilityCommon.h" #include "./SolarHashTable.h" #include //================================================================================================== //================================================================================================== //================================================================================================== #if SOLAR_HASH_TABLE_VERSION >= 0x0200 //================================================================================================== //================================================================================================== //================================================================================================== namespace util { namespace internal { ; const util::internal::WxHashTableBase::hash_type kHashMask = mpl::if_c, mpl::if_c, void>::type >::type::value; extern const PrimeNode hash_primes[7 + 1]; static const PrimeNode* GetPrimeNode(size_t hint_bucket_size); static WxHashTableBase::hash_type GetBaseHashValue( const PrimeNode* prime_node, WxHashTableBase::complex_type key); }}; //end of namespace const util::internal::PrimeNode util::internal::hash_primes[7 + 1] = { { 7, 7 * 4 }, { 19, 19 * 4 }, { 103, 103 * 4 }, { 601, 601 * 4 }, { 2411, 2411 * 4 }, { 9973, 9973 * 4 }, { 81839, ULONG_MAX }, { 0, 0 } // divide by 0 exception }; static const util::internal::PrimeNode* util::internal::GetPrimeNode(size_t hint_bucket_size) { const PrimeNode* it = hash_primes, * const end = &hash_primes[_countof(hash_primes)]; for (; it != end; ++it) { if (it->need_change_next > hint_bucket_size) { return it; }; }; return NULL; }; __forceinline static util::internal::WxHashTableBase::hash_type util::internal::GetBaseHashValue(const PrimeNode* prime_node, WxHashTableBase::complex_type key) { return ((WxHashTableBase::hash_type(key) ^ kHashMask) % prime_node->prime); } //================================================================================================== util::internal::WxHashTableBase::WxHashTableBase() { ZeroMemory(this, sizeof(*this)); util::LList::Init(&list_root_); prime_node_ = GetPrimeNode(1); list_root_.key = complex_type(-1); list_root_.data = complex_type(-1); } util::internal::WxHashTableBase::WxHashTableBase(ulong init_bucket_size) { ZeroMemory(this, sizeof(*this)); this->Initialize(init_bucket_size); } util::internal::WxHashTableBase::~WxHashTableBase() { if (buckets_) { TAllocFree(buckets_); }; WxHashNode* it = list_root_.next; while (it != &list_root_) { WxHashNode* delete_it = it; it = it->next; util::LList::Delete(delete_it); TAllocDelete(WxHashNode, delete_it); }; ZeroMemory(this, sizeof(*this)); } // bool util::internal::WxHashTableBase::Initialize(ulong init_bucket_size) { if (FlowControl::FCAssert(initialized_mark_ != kInitializedTag && buckets_ == NULL) == false) { return false; }; ZeroMemory(this, sizeof(*this)); prime_node_ = GetPrimeNode(init_bucket_size); buckets_ = reinterpret_cast(\ TAllocMalloc(sizeof(WxHashNode*) * (prime_node_->prime << 1))); ZeroMemory(buckets_, sizeof(WxHashNode*) * (prime_node_->prime << 1)); util::LList::Init(&list_root_); list_root_.key = complex_type(-1); list_root_.data = complex_type(-1); initialized_mark_ = kInitializedTag; // return true; } util::internal::WxHashTableBase::node_type* util::internal::WxHashTableBase::find(complex_type key) const { hash_type hash_value = GetBaseHashValue(prime_node_, key) << 1; node_type* node_it = buckets_[hash_value]; if (node_it == NULL) { return const_cast(&this->list_root_); }; node_type* const family_end = buckets_[hash_value + 1]; for (; node_it != family_end; node_it = node_it->next) { if (node_it->key == key) { return node_it; }; }; return const_cast(&this->list_root_); } bool util::internal::WxHashTableBase::insert(complex_type key, complex_type data) { #if SOLAR_HASH_TABLE_VERSION >= 0x0210 if (prime_node_->need_change_next < this->number_of_nodes_) { make_balanced_buckets(this); }; #endif hash_type hash_value = GetBaseHashValue(prime_node_, key) << 1; node_type* node_it = buckets_[hash_value]; struct NodeInstance { typedef util::internal::WxHashTableBase::node_type node_type; typedef util::internal::WxHashTableBase::complex_type complex_type; node_type* instance(complex_type key, complex_type data) { node_type* new_node = TAllocNew(node_type); util::LList::Init(new_node); new_node->key = key; new_node->data = data; return new_node; }; } node_instance; // if (node_it == NULL) { node_type* new_node = node_instance.instance(key, data); // util::LList::AddPrev(new_node, &list_root_); buckets_[hash_value] = new_node; buckets_[hash_value + 1] = &list_root_; end_bucket_ = &buckets_[hash_value + 1]; // node_type* prev_node = static_cast(new_node->prev); if (prev_node != &list_root_) { hash_type prev_hash_value = GetBaseHashValue(prime_node_, prev_node->key) << 1; assert(prev_hash_value != hash_value); buckets_[prev_hash_value + 1] = new_node; }; // ++this->number_of_nodes_; return true; } else if (this->find(key) == &list_root_) { node_type* new_node = node_instance.instance(key, data); // util::LList::AddPrev(new_node, node_it); node_type* prev_node = static_cast(new_node->prev); if (prev_node != &list_root_) { hash_type prev_hash_value = GetBaseHashValue(prime_node_, prev_node->key) << 1; assert(prev_hash_value != hash_value); buckets_[prev_hash_value + 1] = new_node; } assert(end_bucket_); buckets_[hash_value] = new_node; // ++this->number_of_nodes_; return true; } else { //ASSERT(!"this table can't allow multi-keys"); } // return false; } // if the operation is success, the result is the next node also changed to empty table. util::internal::WxHashTableBase::node_type* util::internal::WxHashTableBase::erase(node_type* const entry_it) { if (entry_it == &list_root_) { return &list_root_; }; const complex_type entry_key = entry_it->key; hash_type hash_value = GetBaseHashValue(prime_node_, entry_key) << 1; node_type* node_it = buckets_[hash_value]; if (node_it == NULL) { return &list_root_; }; node_type* const family_end = buckets_[hash_value + 1]; for (; node_it != family_end; node_it = node_it->next) { if (node_it != entry_it) { continue; }; // (prev_end) node (node_end) node_type* prev_node = node_it->prev; node_type* next_node = node_it->next; if (prev_node != &list_root_) { hash_type prev_hash_value = GetBaseHashValue(prime_node_, prev_node->key) << 1; if (hash_value != prev_hash_value) { buckets_[prev_hash_value + 1] = next_node; if (next_node == &list_root_) { end_bucket_ = &buckets_[prev_hash_value + 1]; }; }; }; // util::LList::Delete(node_it); if (buckets_[hash_value] == node_it) { if (next_node == &list_root_) // changed to empty bucket (in prev node, entry_it's cleared) { buckets_[hash_value] = NULL; buckets_[hash_value + 1] = NULL; } else //if (next_node != &list_root_) { hash_type next_hash_value = GetBaseHashValue(prime_node_, next_node->key) << 1; if (hash_value == next_hash_value) { buckets_[hash_value] = next_node; } else { buckets_[hash_value] = NULL; buckets_[hash_value + 1] = NULL; }; } }; // CHANGES: f110609.6L, fixed memory leaks TAllocDelete(node_type, node_it); // --this->number_of_nodes_; // return next_node; }; return &list_root_; } bool util::internal::WxHashTableBase::erase(complex_type key) { node_type* found_it = find(key); if (found_it == &list_root_) { return false; }; this->erase(found_it); return true; } void util::internal::WxHashTableBase::clear() { WxHashNode* it = static_cast(list_root_.next); while (it != &list_root_) { WxHashNode* delete_it = it; it = it->next; util::LList::Delete(delete_it); TAllocDelete(WxHashNode, delete_it); }; this->number_of_nodes_ = 0; this->end_bucket_ = NULL; ZeroMemory(buckets_, sizeof(WxHashNode*) * (prime_node_->prime << 1)); } void util::internal::WxHashTableBase::make_balanced_buckets(WxHashTableBase* cur_hash) { __TOUCHED(cur_hash); #if SOLAR_HASH_TABLE_VERSION >= 0x0210 // NOTE: f110529.3L, implemented const PrimeNode* next_prime = cur_hash->prime_node_ + 1; WxHashTableBase t_hash; ;{ t_hash.prime_node_ = next_prime; t_hash.buckets_ = reinterpret_cast( TAllocMalloc(sizeof(WxHashNode*) * (next_prime->prime << 1))); ZeroMemory(t_hash.buckets_, sizeof(WxHashNode*) * (next_prime->prime << 1)); t_hash.initialized_mark_ = kInitializedTag; }; // node_type* it = static_cast(cur_hash->list_root_.next); while (it != &cur_hash->list_root_) { node_type* new_node = it; it = it->next; util::LList::Delete(new_node); // hash_type hash_value = GetBaseHashValue(t_hash.prime_node_, new_node->key) << 1; node_type* node_it = t_hash.buckets_[hash_value]; // if (node_it == NULL) { util::LList::AddPrev(new_node, &t_hash.list_root_); t_hash.buckets_[hash_value] = new_node; t_hash.buckets_[hash_value + 1] = &t_hash.list_root_; t_hash.end_bucket_ = &t_hash.buckets_[hash_value + 1]; // node_type* prev_node = static_cast(new_node->prev); if (prev_node != &t_hash.list_root_) { hash_type prev_hash_value = GetBaseHashValue(t_hash.prime_node_, prev_node->key) << 1; assert(prev_hash_value != hash_value); t_hash.buckets_[prev_hash_value + 1] = new_node; }; // ++t_hash.number_of_nodes_; continue; } else if (t_hash.find(new_node->key) == &t_hash.list_root_) { util::LList::AddPrev(new_node, node_it); node_type* prev_node = static_cast(new_node->prev); if (prev_node != &t_hash.list_root_) { hash_type prev_hash_value = GetBaseHashValue(t_hash.prime_node_, prev_node->key) << 1; assert(prev_hash_value != hash_value); t_hash.buckets_[prev_hash_value + 1] = new_node; } assert(t_hash.end_bucket_); t_hash.buckets_[hash_value] = new_node; // ++t_hash.number_of_nodes_; continue; } else { ASSERT(!"unexpected node"); }; }; // swap ;{ cur_hash->number_of_nodes_ = t_hash.number_of_nodes_; cur_hash->prime_node_ = t_hash.prime_node_; TAllocFree(cur_hash->buckets_); cur_hash->buckets_ = t_hash.buckets_; t_hash.buckets_ = NULL; assert(util::LList::IsEmpty(&cur_hash->list_root_)); // node_type* first_node = util::LList::Delete(&t_hash.list_root_); util::LList::AddPrev(&cur_hash->list_root_, first_node); // *t_hash.end_bucket_ = &cur_hash->list_root_; cur_hash->end_bucket_ = t_hash.end_bucket_; // }; #endif //SOLAR_HASH_TABLE_VERSION >= 0x0210 } //================================================================================================== //================================================================================================== //================================================================================================== #else //SOLAR_HASH_TABLE_VERSION < 0x0200 //================================================================================================== //================================================================================================== //================================================================================================== __EMPTY_FILE_TAG(); //================================================================================================== //================================================================================================== //================================================================================================== #endif //SOLAR_HASH_TABLE_VERSION < 0x0200 //================================================================================================== //================================================================================================== //==================================================================================================