annotate DEPENDENCIES/generic/include/boost/interprocess/indexes/iunordered_set_index.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 //////////////////////////////////////////////////////////////////////////////
Chris@16 2 //
Chris@16 3 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
Chris@16 4 // Software License, Version 1.0. (See accompanying file
Chris@16 5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6 //
Chris@16 7 // See http://www.boost.org/libs/interprocess for documentation.
Chris@16 8 //
Chris@16 9 //////////////////////////////////////////////////////////////////////////////
Chris@16 10
Chris@16 11 #ifndef BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP
Chris@16 12 #define BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP
Chris@16 13
Chris@101 14 #ifndef BOOST_CONFIG_HPP
Chris@101 15 # include <boost/config.hpp>
Chris@101 16 #endif
Chris@101 17 #
Chris@101 18 #if defined(BOOST_HAS_PRAGMA_ONCE)
Chris@101 19 # pragma once
Chris@101 20 #endif
Chris@101 21
Chris@16 22 #include <boost/interprocess/detail/config_begin.hpp>
Chris@16 23 #include <boost/interprocess/detail/workaround.hpp>
Chris@16 24
Chris@16 25 #include <boost/interprocess/detail/utilities.hpp>
Chris@101 26 #include <boost/interprocess/allocators/allocator.hpp>
Chris@16 27 #include <boost/interprocess/containers/vector.hpp>
Chris@16 28 #include <boost/intrusive/unordered_set.hpp>
Chris@101 29 #include <boost/intrusive/detail/minimal_pair_header.hpp>
Chris@101 30 #include <boost/intrusive/detail/minimal_less_equal_header.hpp> //std::less
Chris@101 31 #include <boost/container/detail/minimal_char_traits_header.hpp> //std::char_traits
Chris@101 32 #include <boost/container/detail/placement_new.hpp>
Chris@16 33
Chris@16 34 //!\file
Chris@16 35 //!Describes index adaptor of boost::intrusive::unordered_set container, to use it
Chris@16 36 //!as name/shared memory index
Chris@16 37
Chris@16 38 namespace boost { namespace interprocess {
Chris@16 39
Chris@101 40 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
Chris@16 41
Chris@16 42 //!Helper class to define typedefs
Chris@16 43 //!from IndexTraits
Chris@16 44 template <class MapConfig>
Chris@16 45 struct iunordered_set_index_aux
Chris@16 46 {
Chris@16 47 typedef typename
Chris@16 48 MapConfig::segment_manager_base segment_manager_base;
Chris@16 49
Chris@16 50 typedef typename
Chris@16 51 segment_manager_base::void_pointer void_pointer;
Chris@16 52
Chris@16 53 typedef typename bi::make_unordered_set_base_hook
Chris@16 54 < bi::void_pointer<void_pointer>
Chris@16 55 >::type derivation_hook;
Chris@16 56
Chris@16 57 typedef typename MapConfig::template
Chris@16 58 intrusive_value_type<derivation_hook>::type value_type;
Chris@16 59
Chris@16 60 typedef typename MapConfig::
Chris@16 61 intrusive_compare_key_type intrusive_compare_key_type;
Chris@16 62
Chris@16 63 typedef std::equal_to<value_type> value_equal;
Chris@16 64
Chris@16 65 typedef typename MapConfig::char_type char_type;
Chris@16 66
Chris@16 67 struct equal_function
Chris@16 68 {
Chris@16 69 bool operator()(const intrusive_compare_key_type &i, const value_type &b) const
Chris@16 70 {
Chris@16 71 return (i.m_len == b.name_length()) &&
Chris@16 72 (std::char_traits<char_type>::compare
Chris@16 73 (i.mp_str, b.name(), i.m_len) == 0);
Chris@16 74 }
Chris@16 75
Chris@16 76 bool operator()(const value_type &b, const intrusive_compare_key_type &i) const
Chris@16 77 {
Chris@16 78 return (i.m_len == b.name_length()) &&
Chris@16 79 (std::char_traits<char_type>::compare
Chris@16 80 (i.mp_str, b.name(), i.m_len) == 0);
Chris@16 81 }
Chris@16 82
Chris@16 83 bool operator()(const value_type &b1, const value_type &b2) const
Chris@16 84 {
Chris@16 85 return (b1.name_length() == b2.name_length()) &&
Chris@16 86 (std::char_traits<char_type>::compare
Chris@16 87 (b1.name(), b2.name(), b1.name_length()) == 0);
Chris@16 88 }
Chris@16 89 };
Chris@16 90
Chris@16 91 struct hash_function
Chris@16 92 : std::unary_function<value_type, std::size_t>
Chris@16 93 {
Chris@16 94 std::size_t operator()(const value_type &val) const
Chris@16 95 {
Chris@16 96 const char_type *beg = ipcdetail::to_raw_pointer(val.name()),
Chris@16 97 *end = beg + val.name_length();
Chris@16 98 return boost::hash_range(beg, end);
Chris@16 99 }
Chris@16 100
Chris@16 101 std::size_t operator()(const intrusive_compare_key_type &i) const
Chris@16 102 {
Chris@16 103 const char_type *beg = i.mp_str,
Chris@16 104 *end = beg + i.m_len;
Chris@16 105 return boost::hash_range(beg, end);
Chris@16 106 }
Chris@16 107 };
Chris@16 108
Chris@16 109 typedef typename bi::make_unordered_set
Chris@16 110 < value_type
Chris@16 111 , bi::hash<hash_function>
Chris@16 112 , bi::equal<equal_function>
Chris@16 113 , bi::size_type<typename segment_manager_base::size_type>
Chris@16 114 >::type index_t;
Chris@16 115 typedef typename index_t::bucket_type bucket_type;
Chris@16 116 typedef allocator
Chris@16 117 <bucket_type, segment_manager_base> allocator_type;
Chris@16 118
Chris@16 119 struct allocator_holder
Chris@16 120 {
Chris@16 121 allocator_holder(segment_manager_base *mngr)
Chris@16 122 : alloc(mngr)
Chris@16 123 {}
Chris@16 124 allocator_type alloc;
Chris@16 125 bucket_type init_bucket;
Chris@16 126 };
Chris@16 127 };
Chris@101 128 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
Chris@16 129
Chris@16 130 //!Index type based in boost::intrusive::set.
Chris@16 131 //!Just derives from boost::intrusive::set
Chris@16 132 //!and defines the interface needed by managed memory segments
Chris@16 133 template <class MapConfig>
Chris@16 134 class iunordered_set_index
Chris@16 135 //Derive class from map specialization
Chris@16 136 : private iunordered_set_index_aux<MapConfig>::allocator_holder
Chris@16 137 , public iunordered_set_index_aux<MapConfig>::index_t
Chris@16 138 {
Chris@101 139 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
Chris@16 140 typedef iunordered_set_index_aux<MapConfig> index_aux;
Chris@16 141 typedef typename index_aux::index_t index_type;
Chris@16 142 typedef typename MapConfig::
Chris@16 143 intrusive_compare_key_type intrusive_compare_key_type;
Chris@16 144 typedef typename index_aux::equal_function equal_function;
Chris@16 145 typedef typename index_aux::hash_function hash_function;
Chris@16 146 typedef typename MapConfig::char_type char_type;
Chris@16 147 typedef typename
Chris@16 148 iunordered_set_index_aux<MapConfig>::allocator_type allocator_type;
Chris@16 149 typedef typename
Chris@16 150 iunordered_set_index_aux<MapConfig>::allocator_holder allocator_holder;
Chris@101 151 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
Chris@16 152
Chris@16 153 public:
Chris@16 154 typedef typename index_type::iterator iterator;
Chris@16 155 typedef typename index_type::const_iterator const_iterator;
Chris@16 156 typedef typename index_type::insert_commit_data insert_commit_data;
Chris@16 157 typedef typename index_type::value_type value_type;
Chris@16 158 typedef typename index_type::bucket_ptr bucket_ptr;
Chris@16 159 typedef typename index_type::bucket_type bucket_type;
Chris@16 160 typedef typename index_type::bucket_traits bucket_traits;
Chris@16 161 typedef typename index_type::size_type size_type;
Chris@16 162
Chris@101 163 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
Chris@16 164 private:
Chris@16 165 typedef typename index_aux::
Chris@16 166 segment_manager_base segment_manager_base;
Chris@16 167
Chris@16 168 static const std::size_t InitBufferSize = 64;
Chris@16 169
Chris@16 170 static bucket_ptr create_buckets(allocator_type &alloc, size_type num)
Chris@16 171 {
Chris@16 172 num = index_type::suggested_upper_bucket_count(num);
Chris@16 173 bucket_ptr buckets = alloc.allocate(num);
Chris@16 174 bucket_ptr buckets_init = buckets;
Chris@16 175 for(size_type i = 0; i < num; ++i){
Chris@101 176 ::new(to_raw_pointer(buckets_init++), boost_container_new_t())bucket_type();
Chris@16 177 }
Chris@16 178 return buckets;
Chris@16 179 }
Chris@16 180
Chris@16 181 static size_type shrink_buckets
Chris@16 182 ( bucket_ptr buckets, size_type old_size
Chris@16 183 , allocator_type &alloc, size_type new_size)
Chris@16 184 {
Chris@16 185 if(old_size <= new_size )
Chris@16 186 return old_size;
Chris@101 187 size_type received_size = new_size;
Chris@16 188 if(!alloc.allocation_command
Chris@101 189 (boost::interprocess::try_shrink_in_place | boost::interprocess::nothrow_allocation, old_size, received_size, buckets)){
Chris@16 190 return old_size;
Chris@16 191 }
Chris@16 192
Chris@16 193 for( bucket_type *p = ipcdetail::to_raw_pointer(buckets) + received_size
Chris@16 194 , *pend = ipcdetail::to_raw_pointer(buckets) + old_size
Chris@16 195 ; p != pend
Chris@16 196 ; ++p){
Chris@16 197 p->~bucket_type();
Chris@16 198 }
Chris@16 199
Chris@16 200 bucket_ptr shunk_p = alloc.allocation_command
Chris@101 201 (boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_size, received_size, buckets);
Chris@16 202 BOOST_ASSERT(buckets == shunk_p); (void)shunk_p;
Chris@16 203
Chris@16 204 bucket_ptr buckets_init = buckets + received_size;
Chris@16 205 for(size_type i = 0; i < (old_size - received_size); ++i){
Chris@16 206 to_raw_pointer(buckets_init++)->~bucket_type();
Chris@16 207 }
Chris@16 208 return received_size;
Chris@16 209 }
Chris@16 210
Chris@16 211 static bucket_ptr expand_or_create_buckets
Chris@16 212 ( bucket_ptr old_buckets, const size_type old_num
Chris@16 213 , allocator_type &alloc, const size_type new_num)
Chris@16 214 {
Chris@101 215 size_type received_size = new_num;
Chris@101 216 bucket_ptr reuse(old_buckets);
Chris@101 217 bucket_ptr ret = alloc.allocation_command
Chris@101 218 (boost::interprocess::expand_fwd | boost::interprocess::allocate_new, new_num, received_size, reuse);
Chris@101 219 if(ret == old_buckets){
Chris@16 220 bucket_ptr buckets_init = old_buckets + old_num;
Chris@16 221 for(size_type i = 0; i < (new_num - old_num); ++i){
Chris@101 222 ::new(to_raw_pointer(buckets_init++), boost_container_new_t())bucket_type();
Chris@16 223 }
Chris@16 224 }
Chris@16 225 else{
Chris@101 226 bucket_ptr buckets_init = ret;
Chris@16 227 for(size_type i = 0; i < new_num; ++i){
Chris@101 228 ::new(to_raw_pointer(buckets_init++), boost_container_new_t())bucket_type();
Chris@16 229 }
Chris@16 230 }
Chris@101 231 return ret;
Chris@16 232 }
Chris@16 233
Chris@16 234 static void destroy_buckets
Chris@16 235 (allocator_type &alloc, bucket_ptr buckets, size_type num)
Chris@16 236 {
Chris@16 237 bucket_ptr buckets_destroy = buckets;
Chris@16 238 for(size_type i = 0; i < num; ++i){
Chris@16 239 to_raw_pointer(buckets_destroy++)->~bucket_type();
Chris@16 240 }
Chris@16 241 alloc.deallocate(buckets, num);
Chris@16 242 }
Chris@16 243
Chris@16 244 iunordered_set_index<MapConfig>* get_this_pointer()
Chris@16 245 { return this; }
Chris@16 246
Chris@101 247 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
Chris@16 248
Chris@16 249 public:
Chris@16 250 //!Constructor. Takes a pointer to the
Chris@16 251 //!segment manager. Can throw
Chris@16 252 iunordered_set_index(segment_manager_base *mngr)
Chris@16 253 : allocator_holder(mngr)
Chris@16 254 , index_type(bucket_traits(&get_this_pointer()->init_bucket, 1))
Chris@16 255 {}
Chris@16 256
Chris@16 257 ~iunordered_set_index()
Chris@16 258 {
Chris@16 259 index_type::clear();
Chris@16 260 if(index_type::bucket_pointer() != bucket_ptr(&this->init_bucket)){
Chris@16 261 destroy_buckets(this->alloc, index_type::bucket_pointer(), index_type::bucket_count());
Chris@16 262 }
Chris@16 263 }
Chris@16 264
Chris@16 265 //!This reserves memory to optimize the insertion of n
Chris@16 266 //!elements in the index
Chris@16 267 void reserve(size_type new_n)
Chris@16 268 {
Chris@16 269 //Let's maintain a 1.0f load factor
Chris@16 270 size_type old_n = this->bucket_count();
Chris@16 271 if(new_n <= old_n)
Chris@16 272 return;
Chris@16 273 bucket_ptr old_p = this->bucket_pointer();
Chris@16 274 new_n = index_type::suggested_upper_bucket_count(new_n);
Chris@16 275 bucket_ptr new_p;
Chris@16 276 //This can throw
Chris@16 277 try{
Chris@16 278 if(old_p != bucket_ptr(&this->init_bucket))
Chris@16 279 new_p = expand_or_create_buckets(old_p, old_n, this->alloc, new_n);
Chris@16 280 else
Chris@16 281 new_p = create_buckets(this->alloc, new_n);
Chris@16 282 }
Chris@16 283 catch(...){
Chris@16 284 return;
Chris@16 285 }
Chris@16 286 //Rehashing does not throw, since neither the hash nor the
Chris@16 287 //comparison function can throw
Chris@16 288 this->rehash(bucket_traits(new_p, new_n));
Chris@16 289 if(new_p != old_p && old_p != bucket_ptr(&this->init_bucket)){
Chris@16 290 destroy_buckets(this->alloc, old_p, old_n);
Chris@16 291 }
Chris@16 292 }
Chris@16 293
Chris@16 294 //!This tries to free unused memory
Chris@16 295 //!previously allocated.
Chris@16 296 void shrink_to_fit()
Chris@16 297 {
Chris@16 298 size_type cur_size = this->size();
Chris@16 299 size_type cur_count = this->bucket_count();
Chris@16 300 bucket_ptr old_p = this->bucket_pointer();
Chris@16 301
Chris@16 302 if(!this->size() && old_p != bucket_ptr(&this->init_bucket)){
Chris@16 303 this->rehash(bucket_traits(bucket_ptr(&this->init_bucket), 1));
Chris@16 304 destroy_buckets(this->alloc, old_p, cur_count);
Chris@16 305 }
Chris@16 306 else{
Chris@16 307 size_type sug_count = 0; //gcc warning
Chris@16 308 sug_count = index_type::suggested_upper_bucket_count(cur_size);
Chris@16 309
Chris@16 310 if(sug_count >= cur_count)
Chris@16 311 return;
Chris@16 312
Chris@16 313 try{
Chris@16 314 shrink_buckets(old_p, cur_count, this->alloc, sug_count);
Chris@16 315 }
Chris@16 316 catch(...){
Chris@16 317 return;
Chris@16 318 }
Chris@16 319
Chris@16 320 //Rehashing does not throw, since neither the hash nor the
Chris@16 321 //comparison function can throw
Chris@16 322 this->rehash(bucket_traits(old_p, sug_count));
Chris@16 323 }
Chris@16 324 }
Chris@16 325
Chris@16 326 iterator find(const intrusive_compare_key_type &key)
Chris@16 327 { return index_type::find(key, hash_function(), equal_function()); }
Chris@16 328
Chris@16 329 const_iterator find(const intrusive_compare_key_type &key) const
Chris@16 330 { return index_type::find(key, hash_function(), equal_function()); }
Chris@16 331
Chris@16 332 std::pair<iterator, bool>insert_check
Chris@16 333 (const intrusive_compare_key_type &key, insert_commit_data &commit_data)
Chris@16 334 { return index_type::insert_check(key, hash_function(), equal_function(), commit_data); }
Chris@16 335
Chris@16 336 iterator insert_commit(value_type &val, insert_commit_data &commit_data)
Chris@16 337 {
Chris@16 338 iterator it = index_type::insert_commit(val, commit_data);
Chris@16 339 size_type cur_size = this->size();
Chris@16 340 if(cur_size > this->bucket_count()){
Chris@16 341 try{
Chris@16 342 this->reserve(cur_size);
Chris@16 343 }
Chris@16 344 catch(...){
Chris@16 345 //Strong guarantee: if something goes wrong
Chris@16 346 //we should remove the insertion.
Chris@16 347 //
Chris@16 348 //We can use the iterator because the hash function
Chris@16 349 //can't throw and this means that "reserve" will
Chris@16 350 //throw only because of the memory allocation:
Chris@16 351 //the iterator has not been invalidated.
Chris@16 352 index_type::erase(it);
Chris@16 353 throw;
Chris@16 354 }
Chris@16 355 }
Chris@16 356 return it;
Chris@16 357 }
Chris@16 358 };
Chris@16 359
Chris@101 360 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
Chris@16 361
Chris@16 362 //!Trait class to detect if an index is an intrusive
Chris@16 363 //!index
Chris@16 364 template<class MapConfig>
Chris@16 365 struct is_intrusive_index
Chris@16 366 <boost::interprocess::iunordered_set_index<MapConfig> >
Chris@16 367 {
Chris@16 368 static const bool value = true;
Chris@16 369 };
Chris@101 370 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
Chris@16 371
Chris@16 372 }} //namespace boost { namespace interprocess {
Chris@16 373
Chris@16 374 #include <boost/interprocess/detail/config_end.hpp>
Chris@16 375
Chris@16 376 #endif //#ifndef BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP