参考VC7.1和 SGI STL 中hash_map的实现
- #ifndef PAGE_HASH_MAP_HPP
- #define PAGE_HASH_MAP_HPP
- #ifdef _MSC_VER
- # include <xutility>//iterator
- #else
- # include <iterator>
- #endif
- #include "hash.hpp"
- #include "allocators.hpp"
- namespace sm
- {
- template
- <
- class Key,
- class Value,
- class PageAlloc,
- class Hash = hash::hash_compare<Key>,
- class Alloc = sm::allocator<std::pair<const Key, Value> >
- >
- class page_hash_map
- {
- page_hash_map(const page_hash_map &);
- page_hash_map & operator = (const page_hash_map &);
- public:
- typedef page_hash_map<Key,Value,PageAlloc,Hash,Alloc> self_type;
- typedef Key key_type;
- typedef Hash key_compare;
- typedef std::pair<Key,Value> value_type;
- typedef value_type & reference;
- typedef value_type const & const_reference;
- typedef ptrdiff_t difference_type;
- typedef Value mapped_type;
- typedef typename Alloc::size_type size_type;
- typedef typename Alloc::offset_type offset_type;
- typedef typename Alloc::byte byte;
- typedef typename PageAlloc::pageid_t pageid_t;
- typedef typename PageAlloc::address_t address_t;
- typedef typename PageAlloc::page_traits_t page_traits_t;
- struct hash_node
- {
- address_t next;
- value_type val;
- hash_node():next(MAXPOSITION),val(value_type())
- {}
- hash_node(value_type const & v):next(MAXPOSITION),val(v)
- {}
- };
- typedef typename Alloc::template rebind<hash_node>::other allocator_type;
- typedef typename allocator_type::pointer pointer;
- struct const_iterator
- {
- typedef std::forward_iterator_tag iterator_category;
- typedef difference_type distance_type;
- const_iterator():ht(0),ptr(0)
- {}
- const_iterator(self_type * h,pointer p)
- :ht(h),ptr(p)
- {}
- const_iterator(const_iterator const & other)
- :ht(other.ht),ptr(other.ptr)
- {}
- const_iterator & operator = (const_iterator const & other)
- {
- if(this != &other)
- {
- this->ht = other.ht;
- this->ptr = other.ptr;
- }
- return *this;
- }
- const_iterator & operator ++()
- {
- ptr = ht->_advance(ptr);
- return *this;
- }
- const_iterator operator ++(int)
- {
- const_iterator tmp(*this);
- ++*this;
- return tmp;
- }
- const_reference operator *()const
- {
- return (*ptr).val;
- }
- bool operator == ( const_iterator const & other)
- {
- return ( this->ht == other.ht && this->ptr == other.ptr );
- }
- bool operator != ( const_iterator const & other)
- {
- return !(operator ==(other) );
- }
- pointer get_node()const{ return ptr;}
- protected:
- self_type * ht;
- pointer ptr;
- };
- struct iterator : public const_iterator
- {
- typedef std::forward_iterator_tag iterator_category;
- typedef difference_type distance_type;
- iterator():const_iterator()
- {}
- iterator(self_type * h,pointer p)
- :const_iterator(h,p)
- {}
- iterator(iterator const & other):const_iterator(other)
- {}
- iterator & operator = (iterator const & other)
- {
- if(this != &other)
- {
- this->ht = other.ht;
- this->ptr = other.ptr;
- }
- return *this;
- }
- iterator & operator ++()
- {
- this->ptr = this->ht->_advance(this->ptr);
- return *this;
- }
- iterator operator ++(int)
- {
- iterator tmp(*this);
- ++*this;
- return tmp;
- }
- reference operator *()const
- {
- return (*this->ptr).val;
- }
- bool operator == ( iterator const & other)
- {
- return ( this->ht == other.ht && this->ptr == other.ptr );
- }
- bool operator != ( iterator const & other)
- {
- return !(operator ==(other) );
- }
- };
- typedef std::pair<iterator,bool> iterator_bool;
- typedef std::pair<iterator,iterator> iterator_pair;
- typedef std::pair<const_iterator,const_iterator> const_iterator_pair;
- //Don't init the remembers!!!
- page_hash_map()
- {}
- void init(pageid_t pageid,size_type n)
- {
- page_ = pageid;
- size_ = 0;
- bucket_size_ = (size_type)hash::get_next_prime(n);
- for(size_type i = 0;i < bucket_size_;++i)
- buckets_[i] = MAXPOSITION;
- }
- static size_type get_buckets_offset(size_type n)
- {
- return ((hash::get_next_prime(n) -1 )* sizeof(address_t));
- }
- ~page_hash_map()
- {
- }
- size_type max_size() const
- {
- return bucket_size_;
- }
- size_type size() const
- {
- return size_;
- }
- size_type capacity()const
- {
- PageAlloc & pa = PageAlloc::instance();
- size_type n = 0;
- for(typename PageAlloc::iterator it = pa.begin(page_); it != pa.end();++it)
- {
- allocator_type * alloc = GETALLOCTOR(allocator_type,(*it).buf);
- n += alloc->max_count();
- }
- return ( n - size() );
- }
- size_type memory_page_count()const
- {
- PageAlloc & pa = PageAlloc::instance();
- size_type n = 0;
- for(typename PageAlloc::iterator it = pa.begin(page_); it != pa.end();++it)
- {
- ++n;
- }
- return n;
- }
- double overflow()const
- {
- PageAlloc & pa = PageAlloc::instance();
- size_type n = 0;
- for(typename PageAlloc::iterator it = pa.begin(page_); it != pa.end();++it)
- {
- allocator_type * alloc = GETALLOCTOR(allocator_type,(*it).buf);
- n += alloc->max_count();
- }
- return ((double)size() / (double)n);
- }
- bool empty() const
- {
- return (size() == 0);
- }
- iterator begin()
- {
- return iterator(this,_first_node());
- }
- iterator end()
- {
- return iterator(this,0);
- }
- const_iterator begin()const
- {
- return const_iterator(this,_first_node());
- }
- const_iterator end()const
- {
- return const_iterator(this,0);
- }
- iterator find(const key_type& key)
- {
- return (lower_bound(key));
- }
- const_iterator find(const key_type& key)const
- {
- return (lower_bound(key));
- }
- mapped_type & operator[](const key_type & key)
- {
- iterator _Where = this->lower_bound(key);
- if (_Where == this->end())
- _Where = this->insert(value_type(key, mapped_type())).first;
- return ((*_Where).second);
- }
- iterator get_iterator(size_type pos)
- {
- return iterator(this,get_node(pos) );
- }
- const_iterator get_iterator(size_type pos)const
- {
- return const_iterator(this,get_node(pos) );
- }
- address_t get_address(iterator it)const
- {
- return address(it.get_node());
- }
- address_t get_address(const_iterator it)const
- {
- return address(it.get_node());
- }
- iterator lower_bound(const key_type & key)
- {
- offset_type bucket =hash_value(key);
- address_t pos = buckets_[bucket];
- while(pos != MAXPOSITION )
- {
- pointer node = get_node(pos);
- if (!comp_( get_key(*node), key))
- return ( comp_(key, get_key(*node)) ? end() : iterator(this,node));
- pos = node->next;
- }
- return end();
- }
- const_iterator lower_bound(const key_type & key)const
- {
- offset_type bucket =hash_value(key);
- address_t pos = buckets_[bucket];
- while(pos != MAXPOSITION )
- {
- pointer node = get_node(pos);
- if (!comp_( get_key(*node), key))
- return ( comp_(key, get_key(*node)) ? end() : const_iterator(this,node));
- pos = node->next;
- }
- return end();
- }
- void erase(const key_type & key)
- {
- iterator it = lower_bound(key);
- erase(it);
- }
- void erase(iterator first, iterator last)
- {
- if (first == begin() && last == end())
- {
- clear();
- }
- else
- {
- while (first != last)
- erase(first++);
- }
- }
- void fix()
- {
- offset_type n = 0;
- for(iterator first = begin(); first != end();++first)++n;
- size_ = n;
- }
- void reset(pageid_t pageid)
- {
- PageAlloc & pa = PageAlloc::instance();
- for(typename PageAlloc::iterator it = pa.begin(pageid); it != pa.end();++it)
- {
- allocator_type * alloc = GETALLOCTOR(allocator_type,(*it).buf);
- if( alloc->capacity() )
- {
- page_ = it.get();
- return;
- }
- }
- page_ = pageid;
- }
- void clear()
- {
- PageAlloc & pa = PageAlloc::instance();
- for(typename PageAlloc::iterator it = pa.begin(page_); it != pa.end();++it)
- {
- allocator_type * alloc = GETALLOCTOR(allocator_type,(*it).buf);
- alloc->reset();
- }
- for(size_type i = 0;i < bucket_size_;++i)
- {
- buckets_[i] = MAXPOSITION;
- }
- size_ = 0;
- }
- void erase(iterator it)
- {
- offset_type bucket =hash_value( get_key(*it) );
- address_t pos = buckets_[bucket];
- address_t prev = pos;
- while(pos != MAXPOSITION )
- {
- pointer node = get_node(pos);
- if (!comp_( get_key(*node), get_key(*it) ))
- {
- if(!comp_(get_key(*it), get_key(*node )))
- {
- if(prev != pos )
- {
- get_node(prev)->next = node->next;
- }
- else
- {
- buckets_[bucket]=node->next;
- }
- --size_;
- pageid_t pn = HIWORD(pos);
- allocator_type & alloc = get_allocator(pn);
- alloc.deallocate(node,1);
- }
- break;
- }
- prev = pos;
- pos = node->next;
- }
- }
- template<typename Handler>
- bool dump_bucket(const key_type & key,Handler handler)
- {
- offset_type bucket =hash_value(key);
- address_t pos = buckets_[bucket];
- if(pos == MAXPOSITION ) return false;
- while(pos != MAXPOSITION )
- {
- pointer cur = get_node(pos);
- handler(bucket,pos,get_key(*cur),get_value(*cur));
- pos = cur->next;
- }
- return true;
- }
- iterator_bool insert(const value_type & val)
- {
- offset_type bucket =hash_value( get_key(val) );
- address_t & head = buckets_[bucket];
- address_t pos,prev = head;
- for(pos = head; pos != MAXPOSITION ;)
- {
- pointer node = get_node(pos);
- if ( comp_( get_key(val), get_key( *node ) ) )
- {
- break;
- }
- else if ( comp_( get_key( *node ), get_key(val)))
- {
- prev = pos;
- pos = node->next;
- }
- else
- return (iterator_bool(iterator(this,node), false)); // already present
- }
- pointer newnode = new_node(val);
- if(!newnode)
- throw outof_memory();
- ++size_;
- address_t newpos = address(newnode);
- newnode->next = pos;
- if( prev == pos )
- {
- head = newpos;
- }
- else
- {
- get_node(prev)->next = newpos;
- }
- return (iterator_bool(iterator(this,newnode), true));
- }
- private:
- static const key_type & get_key(const value_type& val)
- {
- return (val.first);
- }
- static const key_type & get_key(const hash_node & node)
- {
- return get_key(node.val);
- }
- static const mapped_type & get_value(const hash_node & node)
- {
- return (node.val).second;
- }
- static const mapped_type & get_value(const value_type& val)
- {
- return (val.second);
- }
- allocator_type & get_allocator(pageid_t pg)const
- {
- PageAlloc & pa = PageAlloc::instance();
- typename PageAlloc::page * pp = pa.get_page(pg);
- if(!pp)
- throw page_outof_range();
- allocator_type * alloc = GETALLOCTOR(allocator_type,pp->buf);
- assert(alloc);
- return *alloc;
- }
- pointer get_node(address_t pos)const
- {
- pageid_t pn = HIWORD(pos);
- offset_type offset = LOWORD(pos);
- allocator_type & alloc = get_allocator(pn);
- return alloc.ptr(offset);
- }
- inline address_t address(pointer p)const
- {
- PageAlloc & pa = PageAlloc::instance();
- #ifdef _MSC_VER
- return pa.address<allocator_type>(p);
- #else
- return pa.address((allocator_type*)0,p);
- #endif
- }
- offset_type hash_value(key_type const & key)const
- {
- return (this->comp_( key ) % bucket_size_);
- }
- pointer new_node(const value_type& val)
- {
- PageAlloc & pa = PageAlloc::instance();
- pointer node = 0;
- allocator_type * alloc = 0;
- typename PageAlloc::iterator it = pa.get_iterator(page_);
- typename PageAlloc::iterator end = pa.end();
- for(; it != end;++it)
- {
- alloc = GETALLOCTOR(allocator_type,(*it).buf);
- if((node=alloc->allocate() ))
- {
- page_ = it.get();
- construct(node,val);
- return node;
- }
- }
- it = pa.get_iterator(page_);
- --it;
- for(; it != end; --it)
- {
- alloc = GETALLOCTOR(allocator_type,(*it).buf);
- if((node=alloc->allocate() ))
- {
- page_ = it.get();
- construct(node,val);
- return node;
- }
- }
- alloc = new_page();
- if(alloc)
- {
- node = alloc->allocate();
- construct(node,val);
- }
- return node;
- }
- allocator_type * new_page()
- {
- assert( page_ != MAXPAGE );
- PageAlloc & pa = PageAlloc::instance();
- pageid_t newpage = pa.allocate();
- if( MAXPAGE == newpage )
- return (allocator_type*)0;
- void * pb = pa.buffer(newpage);
- SETALLOCOFFSET(pb,sizeof(offset_type));
- ALLOCATE(allocator_type,alloc,pb);
- alloc->open(ALLOC_SIZE(allocator_type,pb),true);
- typename PageAlloc::page * np = pa.get_page(newpage);
- typename PageAlloc::page * cp = pa.get_page(page_);
- np->prev = cp->prev;
- np->next = page_;
- if( MAXPAGE != cp->prev )
- pa.get_page( cp->prev )->next = newpage;
- cp->prev = newpage;
- page_ = newpage;
- return alloc;
- }
- pointer _advance(pointer p)const
- {
- if(p->next != MAXPOSITION)
- return get_node(p->next);
- offset_type bucket =hash_value( get_key(*p) );
- for(size_type i = bucket + 1; i < bucket_size_;++i)
- {
- address_t bucket = buckets_[i];
- if(bucket != MAXPOSITION )
- return get_node(bucket);
- }
- return 0;
- }
- pointer _first_node()const
- {
- for(size_type i = 0; i < bucket_size_; ++i)
- {
- address_t bucket = buckets_[i];
- if(bucket != MAXPOSITION)
- return get_node(bucket);
- }
- return 0;
- }
- pointer _next_bucket_first_node(offset_type cur)const
- {
- for(size_type i = cur+1; i < bucket_size_; ++i)
- {
- address_t bucket = buckets_[i];
- if(bucket != MAXPOSITION)
- return get_node(bucket);
- }
- return 0;
- }
- private:
- pageid_t page_;
- size_type size_;
- size_type bucket_size_;
- key_compare comp_;
- address_t buckets_[1];
- };
- }; //namesapce sm
- #endif