1 /////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Matei David 2014
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)
9 // See http://www.boost.org/libs/intrusive for documentation.
11 /////////////////////////////////////////////////////////////////////////////
13 #ifndef BOUNDED_POINTER_HPP
14 #define BOUNDED_POINTER_HPP
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>
25 template < typename T >
26 class bounded_pointer;
28 template < typename T >
29 class bounded_reference;
31 template < typename T >
32 class bounded_allocator;
35 template < typename T >
39 void unspecified_bool_type_func() const {}
40 typedef void (bounded_pointer::*unspecified_bool_type)() const;
43 typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t;
44 typedef const mut_val_t const_val_t;
46 typedef bounded_reference<T> reference;
48 static const unsigned char max_offset = (unsigned char)-1;
50 bounded_pointer() : m_offset(max_offset) {}
52 bounded_pointer(const bounded_pointer& other)
53 : m_offset(other.m_offset)
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)
62 bounded_pointer& operator = (const bounded_pointer& other)
63 { m_offset = other.m_offset; return *this; }
66 typename boost::intrusive::detail::enable_if_convertible<T2*, T*, bounded_pointer&>::type
67 operator= (const bounded_pointer<T2> & other)
68 { m_offset = other.m_offset; return *this; }
70 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); }
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); }
76 static mut_val_t* base()
78 assert(bounded_allocator< mut_val_t >::inited());
79 return &bounded_allocator< mut_val_t >::m_base[0];
82 static bounded_pointer pointer_to(bounded_reference< T > r) { return &r; }
85 static bounded_pointer const_cast_from(const bounded_pointer<U> &uptr)
86 { return uptr.unconst(); }
88 operator unspecified_bool_type() const
90 return m_offset != max_offset? &bounded_pointer::unspecified_bool_type_func : 0;
94 { return base() + m_offset; }
96 bounded_reference< T > operator * () const
97 { return bounded_reference< T >(*this); }
99 T* operator -> () const
102 bounded_pointer& operator ++ ()
103 { ++m_offset; return *this; }
105 bounded_pointer operator ++ (int)
106 { bounded_pointer res(*this); ++(*this); return res; }
108 friend bool operator == (const bounded_pointer& lhs, const bounded_pointer& rhs)
109 { return lhs.m_offset == rhs.m_offset; }
111 friend bool operator != (const bounded_pointer& lhs, const bounded_pointer& rhs)
112 { return lhs.m_offset != rhs.m_offset; }
114 friend bool operator < (const bounded_pointer& lhs, const bounded_pointer& rhs)
115 { return lhs.m_offset < rhs.m_offset; }
117 friend bool operator <= (const bounded_pointer& lhs, const bounded_pointer& rhs)
118 { return lhs.m_offset <= rhs.m_offset; }
120 friend bool operator >= (const bounded_pointer& lhs, const bounded_pointer& rhs)
121 { return lhs.m_offset >= rhs.m_offset; }
123 friend bool operator > (const bounded_pointer& lhs, const bounded_pointer& rhs)
124 { return lhs.m_offset > rhs.m_offset; }
126 friend std::ostream& operator << (std::ostream& os, const bounded_pointer& ptr)
128 os << static_cast< int >(ptr.m_offset);
133 template <typename> friend class bounded_pointer;
134 friend class bounded_reference< T >;
135 friend class bounded_allocator< T >;
137 unsigned char m_offset;
138 }; // class bounded_pointer
140 template < typename T >
141 class bounded_reference
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;
151 : m_offset(max_offset)
154 bounded_reference(const bounded_reference& other)
155 : m_offset(other.m_offset)
159 { assert(m_offset != max_offset); return *(bounded_pointer< T >::base() + m_offset); }
162 { assert(m_offset != max_offset); return raw(); }
164 bounded_pointer< T > operator & () const
165 { assert(m_offset != max_offset); bounded_pointer< T > res; res.m_offset = m_offset; return res; }
167 bounded_reference& operator = (const T& rhs)
168 { assert(m_offset != max_offset); raw() = rhs; return *this; }
170 bounded_reference& operator = (const bounded_reference& rhs)
171 { assert(m_offset != max_offset); raw() = rhs.raw(); return *this; }
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)
180 typename boost::intrusive::detail::enable_if_convertible<T2*, T*, bounded_reference&>::type
181 operator= (const bounded_reference<T2> & other)
182 { m_offset = other.m_offset; return *this; }
184 friend std::ostream& operator << (std::ostream& os, const bounded_reference< T >& ref)
186 os << "[bptr=" << static_cast< int >(ref.m_offset) << ",deref=" << ref.raw() << "]";
190 // the copy asop is shallow; we need swap overload to shuffle a vector of references
191 friend void swap(bounded_reference& lhs, bounded_reference& rhs)
192 { ::boost::adl_move_swap(lhs.m_offset, rhs.m_offset); }
195 template <typename> friend class bounded_reference;
196 friend class bounded_pointer< T >;
197 bounded_reference(bounded_pointer< T > bptr) : m_offset(bptr.m_offset) { assert(m_offset != max_offset); }
199 unsigned char m_offset;
200 }; // class bounded_reference
202 template < typename T >
203 class bounded_allocator
206 typedef T value_type;
207 typedef bounded_pointer< T > pointer;
209 static const unsigned char max_offset = pointer::max_offset;
211 pointer allocate(size_t n)
214 assert(n == 1);(void)n;
217 for (i = 0; i < max_offset && m_in_use[i]; ++i);
218 assert(i < max_offset);
220 m_in_use[p.m_offset] = true;
225 void deallocate(pointer p, size_t n)
228 assert(n == 1);(void)n;
229 assert(m_in_use[p.m_offset]);
230 m_in_use[p.m_offset] = false;
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)));
245 return m_in_use.size() == max_offset;
248 static bool is_clear()
251 for (unsigned char i = 0; i < max_offset; ++i)
261 static void destroy()
263 // deallocate storage without destructors
264 ::operator delete [] (m_base);
269 friend class bounded_pointer< T >;
270 friend class bounded_pointer< const T >;
272 static boost::container::vector< bool > m_in_use;
273 static std::size_t m_in_use_count;
274 }; // class bounded_allocator
276 template <class BoundedAllocator>
277 class bounded_allocator_scope
280 bounded_allocator_scope()
281 { BoundedAllocator::init(); }
283 ~bounded_allocator_scope()
285 assert(BoundedAllocator::is_clear());
286 BoundedAllocator::destroy();
290 template < typename T >
291 T* bounded_allocator< T >::m_base = 0;
293 template < typename T >
294 boost::container::vector< bool > bounded_allocator< T >::m_in_use;
296 template < typename T >
297 std::size_t bounded_allocator< T >::m_in_use_count;
299 template < typename T >
300 class bounded_reference_cont
301 : private boost::container::vector< bounded_reference< T > >
305 typedef boost::container::vector< bounded_reference< T > > Base;
306 typedef bounded_allocator< T > allocator_type;
307 typedef bounded_pointer< T > pointer;
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;
325 using Base::operator[];
326 using Base::push_back;
328 explicit bounded_reference_cont(size_t n = 0)
329 : Base(), m_allocator()
331 for (size_t i = 0; i < n; ++i){
332 pointer p = m_allocator.allocate(1);
334 new (p.raw()) val_type();
337 m_allocator.deallocate(p, 1);
345 bounded_reference_cont(const bounded_reference_cont& other)
346 : Base(), m_allocator(other.m_allocator)
349 template < typename InputIterator >
350 bounded_reference_cont(InputIterator it_start, InputIterator it_end)
351 : Base(), m_allocator()
353 for (InputIterator it = it_start; it != it_end; ++it){
354 pointer p = m_allocator.allocate(1);
355 new (p.raw()) val_type(*it);
360 template <typename InputIterator>
361 void assign(InputIterator it_start, InputIterator it_end)
364 for (InputIterator it = it_start; it != it_end;){
365 pointer p = m_allocator.allocate(1);
366 new (p.raw()) val_type(*it++);
371 ~bounded_reference_cont()
376 while (!Base::empty()){
377 pointer p = &Base::back();
379 m_allocator.deallocate(p, 1);
384 bounded_reference_cont& operator = (const bounded_reference_cont& other)
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);
398 allocator_type m_allocator;
399 }; // class bounded_reference_cont
401 template < typename T >
402 class bounded_pointer_holder
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;
410 bounded_pointer_holder() : _ptr(allocator_type().allocate(1))
411 { new (_ptr.raw()) value_type(); }
413 ~bounded_pointer_holder()
416 allocator_type().deallocate(_ptr, 1);
419 const_pointer get_node () const
427 }; // class bounded_pointer_holder