bounded_pointer.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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. #ifndef BOUNDED_POINTER_HPP
  13. #define BOUNDED_POINTER_HPP
  14. #include <iostream>
  15. #include <cstdlib>
  16. #include <cassert>
  17. #include <boost/container/vector.hpp>
  18. #include <boost/intrusive/detail/mpl.hpp>
  19. #include <boost/intrusive/pointer_traits.hpp>
  20. #include <boost/core/no_exceptions_support.hpp>
  21. #include <boost/move/adl_move_swap.hpp>
  22. template < typename T >
  23. class bounded_pointer;
  24. template < typename T >
  25. class bounded_reference;
  26. template < typename T >
  27. class bounded_allocator;
  28. template < typename T >
  29. class bounded_pointer
  30. {
  31. private:
  32. void unspecified_bool_type_func() const {}
  33. typedef void (bounded_pointer::*unspecified_bool_type)() const;
  34. public:
  35. typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t;
  36. typedef const mut_val_t const_val_t;
  37. typedef bounded_reference<T> reference;
  38. static const unsigned char max_offset = (unsigned char)-1;
  39. bounded_pointer() : m_offset(max_offset) {}
  40. bounded_pointer(const bounded_pointer& other)
  41. : m_offset(other.m_offset)
  42. {}
  43. template<class T2>
  44. bounded_pointer( const bounded_pointer<T2> &other
  45. , typename boost::intrusive::detail::enable_if_convertible<T2*, T*>::type* = 0)
  46. : m_offset(other.m_offset)
  47. {}
  48. bounded_pointer& operator = (const bounded_pointer& other)
  49. { m_offset = other.m_offset; return *this; }
  50. template <class T2>
  51. typename boost::intrusive::detail::enable_if_convertible<T2*, T*, bounded_pointer&>::type
  52. operator= (const bounded_pointer<T2> & other)
  53. { m_offset = other.m_offset; return *this; }
  54. const bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >& unconst() const
  55. { return *reinterpret_cast< const bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >* >(this); }
  56. bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >& unconst()
  57. { return *reinterpret_cast< bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >* >(this); }
  58. static mut_val_t* base()
  59. {
  60. assert(bounded_allocator< mut_val_t >::inited());
  61. return &bounded_allocator< mut_val_t >::m_base[0];
  62. }
  63. static bounded_pointer pointer_to(bounded_reference< T > r) { return &r; }
  64. template<class U>
  65. static bounded_pointer const_cast_from(const bounded_pointer<U> &uptr)
  66. { return uptr.unconst(); }
  67. operator unspecified_bool_type() const
  68. {
  69. return m_offset != max_offset? &bounded_pointer::unspecified_bool_type_func : 0;
  70. }
  71. T* raw() const
  72. { return base() + m_offset; }
  73. bounded_reference< T > operator * () const
  74. { return bounded_reference< T >(*this); }
  75. T* operator -> () const
  76. { return raw(); }
  77. bounded_pointer& operator ++ ()
  78. { ++m_offset; return *this; }
  79. bounded_pointer operator ++ (int)
  80. { bounded_pointer res(*this); ++(*this); return res; }
  81. friend bool operator == (const bounded_pointer& lhs, const bounded_pointer& rhs)
  82. { return lhs.m_offset == rhs.m_offset; }
  83. friend bool operator != (const bounded_pointer& lhs, const bounded_pointer& rhs)
  84. { return lhs.m_offset != rhs.m_offset; }
  85. friend bool operator < (const bounded_pointer& lhs, const bounded_pointer& rhs)
  86. { return lhs.m_offset < rhs.m_offset; }
  87. friend bool operator <= (const bounded_pointer& lhs, const bounded_pointer& rhs)
  88. { return lhs.m_offset <= rhs.m_offset; }
  89. friend bool operator >= (const bounded_pointer& lhs, const bounded_pointer& rhs)
  90. { return lhs.m_offset >= rhs.m_offset; }
  91. friend bool operator > (const bounded_pointer& lhs, const bounded_pointer& rhs)
  92. { return lhs.m_offset > rhs.m_offset; }
  93. friend std::ostream& operator << (std::ostream& os, const bounded_pointer& ptr)
  94. {
  95. os << static_cast< int >(ptr.m_offset);
  96. return os;
  97. }
  98. private:
  99. template <typename> friend class bounded_pointer;
  100. friend class bounded_reference< T >;
  101. friend class bounded_allocator< T >;
  102. unsigned char m_offset;
  103. }; // class bounded_pointer
  104. template < typename T >
  105. class bounded_reference
  106. {
  107. public:
  108. typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t;
  109. typedef const mut_val_t const_val_t;
  110. typedef bounded_pointer< T > pointer;
  111. static const unsigned char max_offset = pointer::max_offset;
  112. bounded_reference()
  113. : m_offset(max_offset)
  114. {}
  115. bounded_reference(const bounded_reference& other)
  116. : m_offset(other.m_offset)
  117. {}
  118. T& raw() const
  119. { assert(m_offset != max_offset); return *(bounded_pointer< T >::base() + m_offset); }
  120. operator T& () const
  121. { assert(m_offset != max_offset); return raw(); }
  122. bounded_pointer< T > operator & () const
  123. { assert(m_offset != max_offset); bounded_pointer< T > res; res.m_offset = m_offset; return res; }
  124. bounded_reference& operator = (const T& rhs)
  125. { assert(m_offset != max_offset); raw() = rhs; return *this; }
  126. bounded_reference& operator = (const bounded_reference& rhs)
  127. { assert(m_offset != max_offset); raw() = rhs.raw(); return *this; }
  128. template<class T2>
  129. bounded_reference( const bounded_reference<T2> &other
  130. , typename boost::intrusive::detail::enable_if_convertible<T2*, T*>::type* = 0)
  131. : m_offset(other.m_offset)
  132. {}
  133. template <class T2>
  134. typename boost::intrusive::detail::enable_if_convertible<T2*, T*, bounded_reference&>::type
  135. operator= (const bounded_reference<T2> & other)
  136. { m_offset = other.m_offset; return *this; }
  137. friend std::ostream& operator << (std::ostream& os, const bounded_reference< T >& ref)
  138. {
  139. os << "[bptr=" << static_cast< int >(ref.m_offset) << ",deref=" << ref.raw() << "]";
  140. return os;
  141. }
  142. // the copy asop is shallow; we need swap overload to shuffle a vector of references
  143. friend void swap(bounded_reference& lhs, bounded_reference& rhs)
  144. { ::boost::adl_move_swap(lhs.m_offset, rhs.m_offset); }
  145. private:
  146. template <typename> friend class bounded_reference;
  147. friend class bounded_pointer< T >;
  148. bounded_reference(bounded_pointer< T > bptr) : m_offset(bptr.m_offset) { assert(m_offset != max_offset); }
  149. unsigned char m_offset;
  150. }; // class bounded_reference
  151. template < typename T >
  152. class bounded_allocator
  153. {
  154. public:
  155. typedef T value_type;
  156. typedef bounded_pointer< T > pointer;
  157. static const unsigned char max_offset = pointer::max_offset;
  158. pointer allocate(size_t n)
  159. {
  160. assert(inited());
  161. assert(n == 1);(void)n;
  162. pointer p;
  163. unsigned char i;
  164. for (i = 0; i < max_offset && m_in_use[i]; ++i);
  165. assert(i < max_offset);
  166. p.m_offset = i;
  167. m_in_use[p.m_offset] = true;
  168. ++m_in_use_count;
  169. return p;
  170. }
  171. void deallocate(pointer p, size_t n)
  172. {
  173. assert(inited());
  174. assert(n == 1);(void)n;
  175. assert(m_in_use[p.m_offset]);
  176. m_in_use[p.m_offset] = false;
  177. --m_in_use_count;
  178. }
  179. // static methods
  180. static void init()
  181. {
  182. assert(m_in_use.empty());
  183. m_in_use = boost::container::vector< bool >(max_offset, false);
  184. // allocate non-constructed storage
  185. m_base = static_cast< T* >(::operator new [] (max_offset * sizeof(T)));
  186. }
  187. static bool inited()
  188. {
  189. return m_in_use.size() == max_offset;
  190. }
  191. static bool is_clear()
  192. {
  193. assert(inited());
  194. for (unsigned char i = 0; i < max_offset; ++i)
  195. {
  196. if (m_in_use[i])
  197. {
  198. return false;
  199. }
  200. }
  201. return true;
  202. }
  203. static void destroy()
  204. {
  205. // deallocate storage without destructors
  206. ::operator delete [] (m_base);
  207. m_in_use.clear();
  208. }
  209. private:
  210. friend class bounded_pointer< T >;
  211. friend class bounded_pointer< const T >;
  212. static T* m_base;
  213. static boost::container::vector< bool > m_in_use;
  214. static std::size_t m_in_use_count;
  215. }; // class bounded_allocator
  216. template <class BoundedAllocator>
  217. class bounded_allocator_scope
  218. {
  219. public:
  220. bounded_allocator_scope()
  221. { BoundedAllocator::init(); }
  222. ~bounded_allocator_scope()
  223. {
  224. assert(BoundedAllocator::is_clear());
  225. BoundedAllocator::destroy();
  226. }
  227. };
  228. template < typename T >
  229. T* bounded_allocator< T >::m_base = 0;
  230. template < typename T >
  231. boost::container::vector< bool > bounded_allocator< T >::m_in_use;
  232. template < typename T >
  233. std::size_t bounded_allocator< T >::m_in_use_count;
  234. template < typename T >
  235. class bounded_reference_cont
  236. : private boost::container::vector< bounded_reference< T > >
  237. {
  238. private:
  239. typedef T val_type;
  240. typedef boost::container::vector< bounded_reference< T > > Base;
  241. typedef bounded_allocator< T > allocator_type;
  242. typedef bounded_pointer< T > pointer;
  243. public:
  244. typedef typename Base::value_type value_type;
  245. typedef typename Base::iterator iterator;
  246. typedef typename Base::const_iterator const_iterator;
  247. typedef typename Base::reference reference;
  248. typedef typename Base::const_reference const_reference;
  249. typedef typename Base::reverse_iterator reverse_iterator;
  250. typedef typename Base::const_reverse_iterator const_reverse_iterator;
  251. using Base::begin;
  252. using Base::rbegin;
  253. using Base::end;
  254. using Base::rend;
  255. using Base::front;
  256. using Base::back;
  257. using Base::size;
  258. using Base::operator[];
  259. using Base::push_back;
  260. explicit bounded_reference_cont(size_t n = 0)
  261. : Base(), m_allocator()
  262. {
  263. for (size_t i = 0; i < n; ++i){
  264. pointer p = m_allocator.allocate(1);
  265. BOOST_TRY{
  266. new (p.raw()) val_type();
  267. }
  268. BOOST_CATCH(...){
  269. m_allocator.deallocate(p, 1);
  270. BOOST_RETHROW
  271. }
  272. BOOST_CATCH_END
  273. Base::push_back(*p);
  274. }
  275. }
  276. bounded_reference_cont(const bounded_reference_cont& other)
  277. : Base(), m_allocator(other.m_allocator)
  278. { *this = other; }
  279. template < typename InputIterator >
  280. bounded_reference_cont(InputIterator it_start, InputIterator it_end)
  281. : Base(), m_allocator()
  282. {
  283. for (InputIterator it = it_start; it != it_end; ++it){
  284. pointer p = m_allocator.allocate(1);
  285. new (p.raw()) val_type(*it);
  286. Base::push_back(*p);
  287. }
  288. }
  289. template <typename InputIterator>
  290. void assign(InputIterator it_start, InputIterator it_end)
  291. {
  292. this->clear();
  293. for (InputIterator it = it_start; it != it_end;){
  294. pointer p = m_allocator.allocate(1);
  295. new (p.raw()) val_type(*it++);
  296. Base::push_back(*p);
  297. }
  298. }
  299. ~bounded_reference_cont()
  300. { clear(); }
  301. void clear()
  302. {
  303. while (!Base::empty()){
  304. pointer p = &Base::back();
  305. p->~val_type();
  306. m_allocator.deallocate(p, 1);
  307. Base::pop_back();
  308. }
  309. }
  310. bounded_reference_cont& operator = (const bounded_reference_cont& other)
  311. {
  312. if (&other != this){
  313. clear();
  314. for (typename Base::const_iterator it = other.begin(); it != other.end(); ++it){
  315. pointer p = m_allocator.allocate(1);
  316. new (p.raw()) val_type(*it);
  317. Base::push_back(*p);
  318. }
  319. }
  320. return *this;
  321. }
  322. private:
  323. allocator_type m_allocator;
  324. }; // class bounded_reference_cont
  325. template < typename T >
  326. class bounded_pointer_holder
  327. {
  328. public:
  329. typedef T value_type;
  330. typedef bounded_pointer< value_type > pointer;
  331. typedef bounded_pointer< const value_type > const_pointer;
  332. typedef bounded_allocator< value_type > allocator_type;
  333. bounded_pointer_holder() : _ptr(allocator_type().allocate(1))
  334. { new (_ptr.raw()) value_type(); }
  335. ~bounded_pointer_holder()
  336. {
  337. _ptr->~value_type();
  338. allocator_type().deallocate(_ptr, 1);
  339. }
  340. const_pointer get_node () const
  341. { return _ptr; }
  342. pointer get_node ()
  343. { return _ptr; }
  344. private:
  345. const pointer _ptr;
  346. }; // class bounded_pointer_holder
  347. #endif