iunordered_set_index.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 368 行

HPP
368
字号
////////////////////////////////////////////////////////////////////////////////// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost// Software License, Version 1.0. (See accompanying file// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//// See http://www.boost.org/libs/interprocess for documentation.////////////////////////////////////////////////////////////////////////////////#ifndef BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP#define BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP#include <boost/interprocess/detail/config_begin.hpp>#include <boost/interprocess/detail/workaround.hpp>#include <functional>#include <utility>#include <boost/get_pointer.hpp>#include <boost/interprocess/detail/utilities.hpp>#include <boost/interprocess/containers/vector.hpp>#include <boost/intrusive/unordered_set.hpp>#include <boost/interprocess/allocators/allocator.hpp>//!\file//!Describes index adaptor of boost::intrusive::unordered_set container, to use it//!as name/shared memory indexnamespace boost { namespace interprocess {/// @cond//!Helper class to define typedefs//!from IndexTraitstemplate <class MapConfig>struct iunordered_set_index_aux{   typedef typename       MapConfig::segment_manager_base                 segment_manager_base;   typedef typename       segment_manager_base::void_pointer              void_pointer;   typedef typename bi::make_unordered_set_base_hook      < bi::void_pointer<void_pointer>      >::type        derivation_hook;   typedef typename MapConfig::template       intrusive_value_type<derivation_hook>::type     value_type;   typedef typename MapConfig::      intrusive_compare_key_type                      intrusive_compare_key_type;   typedef std::equal_to<value_type>                  value_equal;   typedef typename MapConfig::char_type              char_type;   struct equal_function   {      bool operator()(const intrusive_compare_key_type &i, const value_type &b) const      {           return (i.m_len == b.name_length()) &&                  (std::char_traits<char_type>::compare                      (i.mp_str, b.name(), i.m_len) == 0);      }      bool operator()(const value_type &b, const intrusive_compare_key_type &i) const      {           return (i.m_len == b.name_length()) &&                  (std::char_traits<char_type>::compare                      (i.mp_str, b.name(), i.m_len) == 0);      }      bool operator()(const value_type &b1, const value_type &b2) const      {           return (b1.name_length() == b2.name_length()) &&                  (std::char_traits<char_type>::compare                      (b1.name(), b2.name(), b1.name_length()) == 0);      }   };    struct hash_function      : std::unary_function<value_type, std::size_t>    {        std::size_t operator()(const value_type &val) const        {            const char_type *beg = detail::get_pointer(val.name()),                            *end = beg + val.name_length();            return boost::hash_range(beg, end);        }        std::size_t operator()(const intrusive_compare_key_type &i) const        {            const char_type *beg = i.mp_str,                            *end = beg + i.m_len;            return boost::hash_range(beg, end);        }    };   typedef typename bi::make_unordered_set      < value_type      , bi::hash<hash_function>      , bi::equal<equal_function>      >::type                                         index_t;   typedef typename index_t::bucket_type              bucket_type;   typedef allocator      <bucket_type, segment_manager_base>             allocator_type;   struct allocator_holder   {      allocator_holder(segment_manager_base *mngr)         :  alloc(mngr)      {}      allocator_type alloc;      bucket_type init_bucket;   };};/// @endcond//!Index type based in boost::intrusive::set.//!Just derives from boost::intrusive::set //!and defines the interface needed by managed memory segmentstemplate <class MapConfig>class iunordered_set_index      //Derive class from map specialization   :  private iunordered_set_index_aux<MapConfig>::allocator_holder   ,  public iunordered_set_index_aux<MapConfig>::index_t{   /// @cond   typedef iunordered_set_index_aux<MapConfig>           index_aux;   typedef typename index_aux::index_t                   index_type;   typedef typename MapConfig::      intrusive_compare_key_type                         intrusive_compare_key_type;   typedef typename index_aux::equal_function            equal_function;   typedef typename index_aux::hash_function             hash_function;   typedef typename MapConfig::char_type                 char_type;   typedef typename       iunordered_set_index_aux<MapConfig>::allocator_type      allocator_type;   typedef typename       iunordered_set_index_aux<MapConfig>::allocator_holder    allocator_holder;   /// @endcond   public:   typedef typename index_type::iterator                 iterator;   typedef typename index_type::const_iterator           const_iterator;   typedef typename index_type::insert_commit_data       insert_commit_data;   typedef typename index_type::value_type               value_type;   typedef typename index_type::bucket_ptr               bucket_ptr;   typedef typename index_type::bucket_type              bucket_type;   typedef typename index_type::bucket_traits            bucket_traits;   typedef typename index_type::size_type                size_type;   /// @cond   private:   typedef typename index_aux::      segment_manager_base             segment_manager_base;   enum {   InitBufferSize = 64};   static bucket_ptr create_buckets(allocator_type &alloc, std::size_t num)   {      num = index_type::suggested_upper_bucket_count(num);      bucket_ptr buckets = alloc.allocate(num);      bucket_ptr buckets_init = buckets;      for(std::size_t i = 0; i < num; ++i){         new(get_pointer(buckets_init++))bucket_type();      }      return buckets;   }   static std::size_t shrink_buckets      ( bucket_ptr buckets, std::size_t old_size      , allocator_type &alloc, std::size_t new_size)   {      if(old_size <= new_size )         return old_size;      std::size_t received_size;      if(!alloc.allocation_command         (try_shrink_in_place | nothrow_allocation, old_size, new_size, received_size, buckets).first){         return old_size;      }      for( bucket_type *p = detail::get_pointer(buckets) + received_size         , *pend = detail::get_pointer(buckets) + old_size         ; p != pend         ; ++p){         p->~bucket_type();      }      bucket_ptr shunk_p = alloc.allocation_command         (shrink_in_place | nothrow_allocation, received_size, received_size, received_size, buckets).first;      BOOST_ASSERT(buckets == shunk_p);      bucket_ptr buckets_init = buckets + received_size;      for(std::size_t i = 0; i < (old_size - received_size); ++i){         get_pointer(buckets_init++)->~bucket_type();      }      return received_size;   }   static bucket_ptr expand_or_create_buckets      ( bucket_ptr old_buckets, const std::size_t old_num      , allocator_type &alloc,  const std::size_t new_num)   {      std::size_t received_size;      std::pair<bucket_ptr, bool> ret =         alloc.allocation_command            (expand_fwd | allocate_new, new_num, new_num, received_size, old_buckets);      if(ret.first == old_buckets){         bucket_ptr buckets_init = old_buckets + old_num;         for(std::size_t i = 0; i < (new_num - old_num); ++i){            new(get_pointer(buckets_init++))bucket_type();         }      }      else{         bucket_ptr buckets_init = ret.first;         for(std::size_t i = 0; i < new_num; ++i){            new(get_pointer(buckets_init++))bucket_type();         }      }      return ret.first;   }   static void destroy_buckets      (allocator_type &alloc, bucket_ptr buckets, std::size_t num)   {      bucket_ptr buckets_destroy = buckets;      for(std::size_t i = 0; i < num; ++i){         get_pointer(buckets_destroy++)->~bucket_type();      }      alloc.deallocate(buckets, num);   }   iunordered_set_index<MapConfig>* get_this_pointer()   {  return this;   }   /// @endcond   public:   //!Constructor. Takes a pointer to the   //!segment manager. Can throw   iunordered_set_index(segment_manager_base *mngr)      :  allocator_holder(mngr)      ,  index_type(bucket_traits(&get_this_pointer()->init_bucket, 1))   {}   ~iunordered_set_index()   {      index_type::clear();      if(index_type::bucket_pointer() != bucket_ptr(&this->init_bucket)){         destroy_buckets(this->alloc, index_type::bucket_pointer(), index_type::bucket_count());      }   }   //!This reserves memory to optimize the insertion of n   //!elements in the index   void reserve(std::size_t new_n)   {      //Let's maintain a 1.0f load factor      size_type old_n  = this->bucket_count();      if(new_n <= old_n)         return;      bucket_ptr old_p = this->bucket_pointer();      new_n = index_type::suggested_upper_bucket_count(new_n);      bucket_ptr new_p;      //This can throw      try{         if(old_p != bucket_ptr(&this->init_bucket))            new_p = expand_or_create_buckets(old_p, old_n, this->alloc, new_n);         else            new_p = create_buckets(this->alloc, new_n);      }      catch(...){         return;      }      //Rehashing does not throw, since neither the hash nor the      //comparison function can throw      this->rehash(bucket_traits(new_p, new_n));      if(new_p != old_p && old_p != bucket_ptr(&this->init_bucket)){         destroy_buckets(this->alloc, old_p, old_n);      }   }   //!This tries to free unused memory   //!previously allocated.   void shrink_to_fit()   {      size_type cur_size   = this->size();      size_type cur_count  = this->bucket_count();      bucket_ptr old_p = this->bucket_pointer();            if(!this->size() && old_p != bucket_ptr(&this->init_bucket)){         this->rehash(bucket_traits(bucket_ptr(&this->init_bucket), 1));         destroy_buckets(this->alloc, old_p, cur_count);      }      else{         size_type sug_count = 0; //gcc warning         sug_count = index_type::suggested_upper_bucket_count(cur_size);         if(sug_count >= cur_count)            return;         try{            shrink_buckets(old_p, cur_count, this->alloc, sug_count);         }         catch(...){            return;         }         //Rehashing does not throw, since neither the hash nor the         //comparison function can throw         this->rehash(bucket_traits(old_p, sug_count));      }   }   iterator find(const intrusive_compare_key_type &key)   {  return index_type::find(key, hash_function(), equal_function());  }   const_iterator find(const intrusive_compare_key_type &key) const   {  return index_type::find(key, hash_function(), equal_function());  }   std::pair<iterator, bool>insert_check      (const intrusive_compare_key_type &key, insert_commit_data &commit_data)   {  return index_type::insert_check(key, hash_function(), equal_function(), commit_data); }   iterator insert_commit(value_type &val, insert_commit_data &commit_data)   {      iterator it = index_type::insert_commit(val, commit_data);      size_type cur_size      = this->size();      if(cur_size > this->bucket_count()){         try{            this->reserve(cur_size);         }         catch(...){            //Strong guarantee: if something goes wrong            //we should remove the insertion.            //            //We can use the iterator because the hash function               //can't throw and this means that "reserve" will            //throw only because of the memory allocation:            //the iterator has not been invalidated.            index_type::erase(it);            throw;         }      }      return it;   }};/// @cond//!Trait class to detect if an index is an intrusive//!indextemplate<class MapConfig>struct is_intrusive_index   <boost::interprocess::iunordered_set_index<MapConfig> >{   enum{ value = true };};/// @endcond}}   //namespace boost { namespace interprocess {#include <boost/interprocess/detail/config_end.hpp>#endif   //#ifndef BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?