///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Matei David 2014 // // 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/intrusive for documentation. // ///////////////////////////////////////////////////////////////////////////// #ifndef BOUNDED_POINTER_HPP #define BOUNDED_POINTER_HPP #include #include #include #include #include #include #include #include template < typename T > class bounded_pointer; template < typename T > class bounded_reference; template < typename T > class bounded_allocator; template < typename T > class bounded_pointer { private: void unspecified_bool_type_func() const {} typedef void (bounded_pointer::*unspecified_bool_type)() const; public: typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t; typedef const mut_val_t const_val_t; typedef bounded_reference reference; static const unsigned char max_offset = (unsigned char)-1; bounded_pointer() : m_offset(max_offset) {} bounded_pointer(const bounded_pointer& other) : m_offset(other.m_offset) {} template bounded_pointer( const bounded_pointer &other , typename boost::intrusive::detail::enable_if_convertible::type* = 0) : m_offset(other.m_offset) {} bounded_pointer& operator = (const bounded_pointer& other) { m_offset = other.m_offset; return *this; } template typename boost::intrusive::detail::enable_if_convertible::type operator= (const bounded_pointer & other) { m_offset = other.m_offset; return *this; } const bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >& unconst() const { return *reinterpret_cast< const bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >* >(this); } bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >& unconst() { return *reinterpret_cast< bounded_pointer< typename boost::intrusive::detail::remove_const< T >::type >* >(this); } static mut_val_t* base() { assert(bounded_allocator< mut_val_t >::inited()); return &bounded_allocator< mut_val_t >::m_base[0]; } static bounded_pointer pointer_to(bounded_reference< T > r) { return &r; } template static bounded_pointer const_cast_from(const bounded_pointer &uptr) { return uptr.unconst(); } operator unspecified_bool_type() const { return m_offset != max_offset? &bounded_pointer::unspecified_bool_type_func : 0; } T* raw() const { return base() + m_offset; } bounded_reference< T > operator * () const { return bounded_reference< T >(*this); } T* operator -> () const { return raw(); } bounded_pointer& operator ++ () { ++m_offset; return *this; } bounded_pointer operator ++ (int) { bounded_pointer res(*this); ++(*this); return res; } friend bool operator == (const bounded_pointer& lhs, const bounded_pointer& rhs) { return lhs.m_offset == rhs.m_offset; } friend bool operator != (const bounded_pointer& lhs, const bounded_pointer& rhs) { return lhs.m_offset != rhs.m_offset; } friend bool operator < (const bounded_pointer& lhs, const bounded_pointer& rhs) { return lhs.m_offset < rhs.m_offset; } friend bool operator <= (const bounded_pointer& lhs, const bounded_pointer& rhs) { return lhs.m_offset <= rhs.m_offset; } friend bool operator >= (const bounded_pointer& lhs, const bounded_pointer& rhs) { return lhs.m_offset >= rhs.m_offset; } friend bool operator > (const bounded_pointer& lhs, const bounded_pointer& rhs) { return lhs.m_offset > rhs.m_offset; } friend std::ostream& operator << (std::ostream& os, const bounded_pointer& ptr) { os << static_cast< int >(ptr.m_offset); return os; } private: template friend class bounded_pointer; friend class bounded_reference< T >; friend class bounded_allocator< T >; unsigned char m_offset; }; // class bounded_pointer template < typename T > class bounded_reference { public: typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t; typedef const mut_val_t const_val_t; typedef bounded_pointer< T > pointer; static const unsigned char max_offset = pointer::max_offset; bounded_reference() : m_offset(max_offset) {} bounded_reference(const bounded_reference& other) : m_offset(other.m_offset) {} T& raw() const { assert(m_offset != max_offset); return *(bounded_pointer< T >::base() + m_offset); } operator T& () const { assert(m_offset != max_offset); return raw(); } bounded_pointer< T > operator & () const { assert(m_offset != max_offset); bounded_pointer< T > res; res.m_offset = m_offset; return res; } bounded_reference& operator = (const T& rhs) { assert(m_offset != max_offset); raw() = rhs; return *this; } bounded_reference& operator = (const bounded_reference& rhs) { assert(m_offset != max_offset); raw() = rhs.raw(); return *this; } template bounded_reference( const bounded_reference &other , typename boost::intrusive::detail::enable_if_convertible::type* = 0) : m_offset(other.m_offset) {} template typename boost::intrusive::detail::enable_if_convertible::type operator= (const bounded_reference & other) { m_offset = other.m_offset; return *this; } friend std::ostream& operator << (std::ostream& os, const bounded_reference< T >& ref) { os << "[bptr=" << static_cast< int >(ref.m_offset) << ",deref=" << ref.raw() << "]"; return os; } // the copy asop is shallow; we need swap overload to shuffle a vector of references friend void swap(bounded_reference& lhs, bounded_reference& rhs) { ::boost::adl_move_swap(lhs.m_offset, rhs.m_offset); } private: template friend class bounded_reference; friend class bounded_pointer< T >; bounded_reference(bounded_pointer< T > bptr) : m_offset(bptr.m_offset) { assert(m_offset != max_offset); } unsigned char m_offset; }; // class bounded_reference template < typename T > class bounded_allocator { public: typedef T value_type; typedef bounded_pointer< T > pointer; static const unsigned char max_offset = pointer::max_offset; pointer allocate(size_t n) { assert(inited()); assert(n == 1);(void)n; pointer p; unsigned char i; for (i = 0; i < max_offset && m_in_use[i]; ++i); assert(i < max_offset); p.m_offset = i; m_in_use[p.m_offset] = true; ++m_in_use_count; return p; } void deallocate(pointer p, size_t n) { assert(inited()); assert(n == 1);(void)n; assert(m_in_use[p.m_offset]); m_in_use[p.m_offset] = false; --m_in_use_count; } // static methods static void init() { assert(m_in_use.empty()); m_in_use = boost::container::vector< bool >(max_offset, false); // allocate non-constructed storage m_base = static_cast< T* >(::operator new [] (max_offset * sizeof(T))); } static bool inited() { return m_in_use.size() == max_offset; } static bool is_clear() { assert(inited()); for (unsigned char i = 0; i < max_offset; ++i) { if (m_in_use[i]) { return false; } } return true; } static void destroy() { // deallocate storage without destructors ::operator delete [] (m_base); m_in_use.clear(); } private: friend class bounded_pointer< T >; friend class bounded_pointer< const T >; static T* m_base; static boost::container::vector< bool > m_in_use; static std::size_t m_in_use_count; }; // class bounded_allocator template class bounded_allocator_scope { public: bounded_allocator_scope() { BoundedAllocator::init(); } ~bounded_allocator_scope() { assert(BoundedAllocator::is_clear()); BoundedAllocator::destroy(); } }; template < typename T > T* bounded_allocator< T >::m_base = 0; template < typename T > boost::container::vector< bool > bounded_allocator< T >::m_in_use; template < typename T > std::size_t bounded_allocator< T >::m_in_use_count; template < typename T > class bounded_reference_cont : private boost::container::vector< bounded_reference< T > > { private: typedef T val_type; typedef boost::container::vector< bounded_reference< T > > Base; typedef bounded_allocator< T > allocator_type; typedef bounded_pointer< T > pointer; public: typedef typename Base::value_type value_type; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; typedef typename Base::reverse_iterator reverse_iterator; typedef typename Base::const_reverse_iterator const_reverse_iterator; using Base::begin; using Base::rbegin; using Base::end; using Base::rend; using Base::front; using Base::back; using Base::size; using Base::operator[]; using Base::push_back; explicit bounded_reference_cont(size_t n = 0) : Base(), m_allocator() { for (size_t i = 0; i < n; ++i){ pointer p = m_allocator.allocate(1); BOOST_TRY{ new (p.raw()) val_type(); } BOOST_CATCH(...){ m_allocator.deallocate(p, 1); BOOST_RETHROW } BOOST_CATCH_END Base::push_back(*p); } } bounded_reference_cont(const bounded_reference_cont& other) : Base(), m_allocator(other.m_allocator) { *this = other; } template < typename InputIterator > bounded_reference_cont(InputIterator it_start, InputIterator it_end) : Base(), m_allocator() { for (InputIterator it = it_start; it != it_end; ++it){ pointer p = m_allocator.allocate(1); new (p.raw()) val_type(*it); Base::push_back(*p); } } template void assign(InputIterator it_start, InputIterator it_end) { this->clear(); for (InputIterator it = it_start; it != it_end;){ pointer p = m_allocator.allocate(1); new (p.raw()) val_type(*it++); Base::push_back(*p); } } ~bounded_reference_cont() { clear(); } void clear() { while (!Base::empty()){ pointer p = &Base::back(); p->~val_type(); m_allocator.deallocate(p, 1); Base::pop_back(); } } bounded_reference_cont& operator = (const bounded_reference_cont& other) { if (&other != this){ clear(); for (typename Base::const_iterator it = other.begin(); it != other.end(); ++it){ pointer p = m_allocator.allocate(1); new (p.raw()) val_type(*it); Base::push_back(*p); } } return *this; } private: allocator_type m_allocator; }; // class bounded_reference_cont template < typename T > class bounded_pointer_holder { public: typedef T value_type; typedef bounded_pointer< value_type > pointer; typedef bounded_pointer< const value_type > const_pointer; typedef bounded_allocator< value_type > allocator_type; bounded_pointer_holder() : _ptr(allocator_type().allocate(1)) { new (_ptr.raw()) value_type(); } ~bounded_pointer_holder() { _ptr->~value_type(); allocator_type().deallocate(_ptr, 1); } const_pointer get_node () const { return _ptr; } pointer get_node () { return _ptr; } private: const pointer _ptr; }; // class bounded_pointer_holder #endif