1 ///////////////////////////////////////////////////////////////////////////// 2 // 3 // (C) Copyright Matei David 2014 4 // 5 // Distributed under the Boost Software License, Version 1.0. 6 // (See accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 // 9 // See http://www.boost.org/libs/intrusive for documentation. 10 // 11 ///////////////////////////////////////////////////////////////////////////// 12 13 #ifndef BOUNDED_POINTER_HPP 14 #define BOUNDED_POINTER_HPP 15 16 #include <iostream> 17 #include <cstdlib> 18 #include <cassert> 19 #include <boost/container/vector.hpp> 20 #include <boost/intrusive/detail/mpl.hpp> 21 #include <boost/intrusive/pointer_traits.hpp> 22 #include <boost/core/no_exceptions_support.hpp> 23 #include <boost/move/adl_move_swap.hpp> 24 25 template < typename T > 26 class bounded_pointer; 27 28 template < typename T > 29 class bounded_reference; 30 31 template < typename T > 32 class bounded_allocator; 33 34 35 template < typename T > 36 class bounded_pointer 37 { 38 private: unspecified_bool_type_func() const39 void unspecified_bool_type_func() const {} 40 typedef void (bounded_pointer::*unspecified_bool_type)() const; 41 42 public: 43 typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t; 44 typedef const mut_val_t const_val_t; 45 46 typedef bounded_reference<T> reference; 47 48 static const unsigned char max_offset = (unsigned char)-1; 49 bounded_pointer()50 bounded_pointer() : m_offset(max_offset) {} 51 bounded_pointer(const bounded_pointer & other)52 bounded_pointer(const bounded_pointer& other) 53 : m_offset(other.m_offset) 54 {} 55 56 template<class T2> bounded_pointer(const bounded_pointer<T2> & other,typename boost::intrusive::detail::enable_if_convertible<T2 *,T * >::type * =0)57 bounded_pointer( const bounded_pointer<T2> &other 58 , typename boost::intrusive::detail::enable_if_convertible<T2*, T*>::type* = 0) 59 : m_offset(other.m_offset) 60 {} 61 operator =(const bounded_pointer & other)62 bounded_pointer& operator = (const bounded_pointer& other) 63 { m_offset = other.m_offset; return *this; } 64 65 template <class T2> 66 typename boost::intrusive::detail::enable_if_convertible<T2*, T*, bounded_pointer&>::type operator =(const bounded_pointer<T2> & other)67 operator= (const bounded_pointer<T2> & other) 68 { m_offset = other.m_offset; return *this; } 69 unconst() const70 const bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >& unconst() const 71 { return *reinterpret_cast< const bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >* >(this); } 72 unconst()73 bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >& unconst() 74 { return *reinterpret_cast< bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >* >(this); } 75 base()76 static mut_val_t* base() 77 { 78 assert(bounded_allocator< mut_val_t >::inited()); 79 return &bounded_allocator< mut_val_t >::m_base[0]; 80 } 81 pointer_to(bounded_reference<T> r)82 static bounded_pointer pointer_to(bounded_reference< T > r) { return &r; } 83 84 template<class U> const_cast_from(const bounded_pointer<U> & uptr)85 static bounded_pointer const_cast_from(const bounded_pointer<U> &uptr) 86 { return uptr.unconst(); } 87 operator unspecified_bool_type() const88 operator unspecified_bool_type() const 89 { 90 return m_offset != max_offset? &bounded_pointer::unspecified_bool_type_func : 0; 91 } 92 raw() const93 T* raw() const 94 { return base() + m_offset; } 95 operator *() const96 bounded_reference< T > operator * () const 97 { return bounded_reference< T >(*this); } 98 operator ->() const99 T* operator -> () const 100 { return raw(); } 101 operator ++()102 bounded_pointer& operator ++ () 103 { ++m_offset; return *this; } 104 operator ++(int)105 bounded_pointer operator ++ (int) 106 { bounded_pointer res(*this); ++(*this); return res; } 107 operator ==(const bounded_pointer & lhs,const bounded_pointer & rhs)108 friend bool operator == (const bounded_pointer& lhs, const bounded_pointer& rhs) 109 { return lhs.m_offset == rhs.m_offset; } 110 operator !=(const bounded_pointer & lhs,const bounded_pointer & rhs)111 friend bool operator != (const bounded_pointer& lhs, const bounded_pointer& rhs) 112 { return lhs.m_offset != rhs.m_offset; } 113 operator <(const bounded_pointer & lhs,const bounded_pointer & rhs)114 friend bool operator < (const bounded_pointer& lhs, const bounded_pointer& rhs) 115 { return lhs.m_offset < rhs.m_offset; } 116 operator <=(const bounded_pointer & lhs,const bounded_pointer & rhs)117 friend bool operator <= (const bounded_pointer& lhs, const bounded_pointer& rhs) 118 { return lhs.m_offset <= rhs.m_offset; } 119 operator >=(const bounded_pointer & lhs,const bounded_pointer & rhs)120 friend bool operator >= (const bounded_pointer& lhs, const bounded_pointer& rhs) 121 { return lhs.m_offset >= rhs.m_offset; } 122 operator >(const bounded_pointer & lhs,const bounded_pointer & rhs)123 friend bool operator > (const bounded_pointer& lhs, const bounded_pointer& rhs) 124 { return lhs.m_offset > rhs.m_offset; } 125 operator <<(std::ostream & os,const bounded_pointer & ptr)126 friend std::ostream& operator << (std::ostream& os, const bounded_pointer& ptr) 127 { 128 os << static_cast< int >(ptr.m_offset); 129 return os; 130 } 131 private: 132 133 template <typename> friend class bounded_pointer; 134 friend class bounded_reference< T >; 135 friend class bounded_allocator< T >; 136 137 unsigned char m_offset; 138 }; // class bounded_pointer 139 140 template < typename T > 141 class bounded_reference 142 { 143 public: 144 typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t; 145 typedef const mut_val_t const_val_t; 146 typedef bounded_pointer< T > pointer; 147 static const unsigned char max_offset = pointer::max_offset; 148 149 bounded_reference()150 bounded_reference() 151 : m_offset(max_offset) 152 {} 153 bounded_reference(const bounded_reference & other)154 bounded_reference(const bounded_reference& other) 155 : m_offset(other.m_offset) 156 {} 157 raw() const158 T& raw() const 159 { assert(m_offset != max_offset); return *(bounded_pointer< T >::base() + m_offset); } 160 operator T&() const161 operator T& () const 162 { assert(m_offset != max_offset); return raw(); } 163 operator &() const164 bounded_pointer< T > operator & () const 165 { assert(m_offset != max_offset); bounded_pointer< T > res; res.m_offset = m_offset; return res; } 166 operator =(const T & rhs)167 bounded_reference& operator = (const T& rhs) 168 { assert(m_offset != max_offset); raw() = rhs; return *this; } 169 operator =(const bounded_reference & rhs)170 bounded_reference& operator = (const bounded_reference& rhs) 171 { assert(m_offset != max_offset); raw() = rhs.raw(); return *this; } 172 173 template<class T2> bounded_reference(const bounded_reference<T2> & other,typename boost::intrusive::detail::enable_if_convertible<T2 *,T * >::type * =0)174 bounded_reference( const bounded_reference<T2> &other 175 , typename boost::intrusive::detail::enable_if_convertible<T2*, T*>::type* = 0) 176 : m_offset(other.m_offset) 177 {} 178 179 template <class T2> 180 typename boost::intrusive::detail::enable_if_convertible<T2*, T*, bounded_reference&>::type operator =(const bounded_reference<T2> & other)181 operator= (const bounded_reference<T2> & other) 182 { m_offset = other.m_offset; return *this; } 183 operator <<(std::ostream & os,const bounded_reference<T> & ref)184 friend std::ostream& operator << (std::ostream& os, const bounded_reference< T >& ref) 185 { 186 os << "[bptr=" << static_cast< int >(ref.m_offset) << ",deref=" << ref.raw() << "]"; 187 return os; 188 } 189 190 // the copy asop is shallow; we need swap overload to shuffle a vector of references swap(bounded_reference & lhs,bounded_reference & rhs)191 friend void swap(bounded_reference& lhs, bounded_reference& rhs) 192 { ::boost::adl_move_swap(lhs.m_offset, rhs.m_offset); } 193 194 private: 195 template <typename> friend class bounded_reference; 196 friend class bounded_pointer< T >; bounded_reference(bounded_pointer<T> bptr)197 bounded_reference(bounded_pointer< T > bptr) : m_offset(bptr.m_offset) { assert(m_offset != max_offset); } 198 199 unsigned char m_offset; 200 }; // class bounded_reference 201 202 template < typename T > 203 class bounded_allocator 204 { 205 public: 206 typedef T value_type; 207 typedef bounded_pointer< T > pointer; 208 209 static const unsigned char max_offset = pointer::max_offset; 210 allocate(size_t n)211 pointer allocate(size_t n) 212 { 213 assert(inited()); 214 assert(n == 1);(void)n; 215 pointer p; 216 unsigned char i; 217 for (i = 0; i < max_offset && m_in_use[i]; ++i); 218 assert(i < max_offset); 219 p.m_offset = i; 220 m_in_use[p.m_offset] = true; 221 ++m_in_use_count; 222 return p; 223 } 224 deallocate(pointer p,size_t n)225 void deallocate(pointer p, size_t n) 226 { 227 assert(inited()); 228 assert(n == 1);(void)n; 229 assert(m_in_use[p.m_offset]); 230 m_in_use[p.m_offset] = false; 231 --m_in_use_count; 232 } 233 234 // static methods init()235 static void init() 236 { 237 assert(m_in_use.empty()); 238 m_in_use = boost::container::vector< bool >(max_offset, false); 239 // allocate non-constructed storage 240 m_base = static_cast< T* >(::operator new [] (max_offset * sizeof(T))); 241 } 242 inited()243 static bool inited() 244 { 245 return m_in_use.size() == max_offset; 246 } 247 is_clear()248 static bool is_clear() 249 { 250 assert(inited()); 251 for (unsigned char i = 0; i < max_offset; ++i) 252 { 253 if (m_in_use[i]) 254 { 255 return false; 256 } 257 } 258 return true; 259 } 260 destroy()261 static void destroy() 262 { 263 // deallocate storage without destructors 264 ::operator delete [] (m_base); 265 m_in_use.clear(); 266 } 267 268 private: 269 friend class bounded_pointer< T >; 270 friend class bounded_pointer< const T >; 271 static T* m_base; 272 static boost::container::vector< bool > m_in_use; 273 static std::size_t m_in_use_count; 274 }; // class bounded_allocator 275 276 template <class BoundedAllocator> 277 class bounded_allocator_scope 278 { 279 public: bounded_allocator_scope()280 bounded_allocator_scope() 281 { BoundedAllocator::init(); } 282 ~bounded_allocator_scope()283 ~bounded_allocator_scope() 284 { 285 assert(BoundedAllocator::is_clear()); 286 BoundedAllocator::destroy(); 287 } 288 }; 289 290 template < typename T > 291 T* bounded_allocator< T >::m_base = 0; 292 293 template < typename T > 294 boost::container::vector< bool > bounded_allocator< T >::m_in_use; 295 296 template < typename T > 297 std::size_t bounded_allocator< T >::m_in_use_count; 298 299 template < typename T > 300 class bounded_reference_cont 301 : private boost::container::vector< bounded_reference< T > > 302 { 303 private: 304 typedef T val_type; 305 typedef boost::container::vector< bounded_reference< T > > Base; 306 typedef bounded_allocator< T > allocator_type; 307 typedef bounded_pointer< T > pointer; 308 309 public: 310 typedef typename Base::value_type value_type; 311 typedef typename Base::iterator iterator; 312 typedef typename Base::const_iterator const_iterator; 313 typedef typename Base::reference reference; 314 typedef typename Base::const_reference const_reference; 315 typedef typename Base::reverse_iterator reverse_iterator; 316 typedef typename Base::const_reverse_iterator const_reverse_iterator; 317 318 using Base::begin; 319 using Base::rbegin; 320 using Base::end; 321 using Base::rend; 322 using Base::front; 323 using Base::back; 324 using Base::size; 325 using Base::operator[]; 326 using Base::push_back; 327 bounded_reference_cont(size_t n=0)328 explicit bounded_reference_cont(size_t n = 0) 329 : Base(), m_allocator() 330 { 331 for (size_t i = 0; i < n; ++i){ 332 pointer p = m_allocator.allocate(1); 333 BOOST_TRY{ 334 new (p.raw()) val_type(); 335 } 336 BOOST_CATCH(...){ 337 m_allocator.deallocate(p, 1); 338 BOOST_RETHROW 339 } 340 BOOST_CATCH_END 341 Base::push_back(*p); 342 } 343 } 344 bounded_reference_cont(const bounded_reference_cont & other)345 bounded_reference_cont(const bounded_reference_cont& other) 346 : Base(), m_allocator(other.m_allocator) 347 { *this = other; } 348 349 template < typename InputIterator > bounded_reference_cont(InputIterator it_start,InputIterator it_end)350 bounded_reference_cont(InputIterator it_start, InputIterator it_end) 351 : Base(), m_allocator() 352 { 353 for (InputIterator it = it_start; it != it_end; ++it){ 354 pointer p = m_allocator.allocate(1); 355 new (p.raw()) val_type(*it); 356 Base::push_back(*p); 357 } 358 } 359 360 template <typename InputIterator> assign(InputIterator it_start,InputIterator it_end)361 void assign(InputIterator it_start, InputIterator it_end) 362 { 363 this->clear(); 364 for (InputIterator it = it_start; it != it_end;){ 365 pointer p = m_allocator.allocate(1); 366 new (p.raw()) val_type(*it++); 367 Base::push_back(*p); 368 } 369 } 370 ~bounded_reference_cont()371 ~bounded_reference_cont() 372 { clear(); } 373 clear()374 void clear() 375 { 376 while (!Base::empty()){ 377 pointer p = &Base::back(); 378 p->~val_type(); 379 m_allocator.deallocate(p, 1); 380 Base::pop_back(); 381 } 382 } 383 operator =(const bounded_reference_cont & other)384 bounded_reference_cont& operator = (const bounded_reference_cont& other) 385 { 386 if (&other != this){ 387 clear(); 388 for (typename Base::const_iterator it = other.begin(); it != other.end(); ++it){ 389 pointer p = m_allocator.allocate(1); 390 new (p.raw()) val_type(*it); 391 Base::push_back(*p); 392 } 393 } 394 return *this; 395 } 396 397 private: 398 allocator_type m_allocator; 399 }; // class bounded_reference_cont 400 401 template < typename T > 402 class bounded_pointer_holder 403 { 404 public: 405 typedef T value_type; 406 typedef bounded_pointer< value_type > pointer; 407 typedef bounded_pointer< const value_type > const_pointer; 408 typedef bounded_allocator< value_type > allocator_type; 409 bounded_pointer_holder()410 bounded_pointer_holder() : _ptr(allocator_type().allocate(1)) 411 { new (_ptr.raw()) value_type(); } 412 ~bounded_pointer_holder()413 ~bounded_pointer_holder() 414 { 415 _ptr->~value_type(); 416 allocator_type().deallocate(_ptr, 1); 417 } 418 get_node() const419 const_pointer get_node () const 420 { return _ptr; } 421 get_node()422 pointer get_node () 423 { return _ptr; } 424 425 private: 426 const pointer _ptr; 427 }; // class bounded_pointer_holder 428 429 #endif 430