| /*============================================================================= |
| Copyright (c) 2002-2003 Joel de Guzman |
| Copyright (c) 2002-2003 Martin Wille |
| http://spirit.sourceforge.net/ |
| |
| Use, modification and distribution is subject to 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) |
| =============================================================================*/ |
| #if !defined BOOST_SPIRIT_OBJECT_WITH_ID_IPP |
| #define BOOST_SPIRIT_OBJECT_WITH_ID_IPP |
| |
| #include <vector> |
| #include <boost/shared_ptr.hpp> |
| |
| #ifdef BOOST_SPIRIT_THREADSAFE |
| #include <boost/thread/mutex.hpp> |
| #include <boost/thread/once.hpp> |
| #endif |
| |
| #include <boost/spirit/home/classic/namespace.hpp> |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { namespace spirit { |
| |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN |
| |
| namespace impl { |
| |
| ////////////////////////////////// |
| template <typename IdT = std::size_t> |
| struct object_with_id_base_supply |
| { |
| typedef IdT object_id; |
| typedef std::vector<object_id> id_vector; |
| |
| object_with_id_base_supply() : max_id(object_id()) {} |
| |
| #ifdef BOOST_SPIRIT_THREADSAFE |
| boost::mutex mutex; |
| #endif |
| object_id max_id; |
| id_vector free_ids; |
| |
| object_id acquire(); |
| void release(object_id); |
| }; |
| |
| ////////////////////////////////// |
| template <typename TagT, typename IdT = std::size_t> |
| struct object_with_id_base |
| { |
| typedef TagT tag_t; |
| typedef IdT object_id; |
| |
| protected: |
| |
| object_id acquire_object_id(); |
| void release_object_id(object_id); |
| |
| private: |
| #ifdef BOOST_SPIRIT_THREADSAFE |
| static boost::mutex &mutex_instance(); |
| static void mutex_init(); |
| #endif |
| |
| boost::shared_ptr<object_with_id_base_supply<IdT> > id_supply; |
| }; |
| |
| ////////////////////////////////// |
| template<class TagT, typename IdT = std::size_t> |
| struct object_with_id : private object_with_id_base<TagT, IdT> |
| { |
| typedef object_with_id<TagT, IdT> self_t; |
| typedef object_with_id_base<TagT, IdT> base_t; |
| typedef IdT object_id; |
| |
| object_with_id() : id(base_t::acquire_object_id()) {} |
| object_with_id(self_t const &other) |
| : base_t(other) |
| , id(base_t::acquire_object_id()) |
| {} // don't copy id |
| self_t &operator = (self_t const &other) |
| { // don't assign id |
| base_t::operator=(other); |
| return *this; |
| } |
| ~object_with_id() { base_t::release_object_id(id); } |
| object_id get_object_id() const { return id; } |
| |
| private: |
| |
| object_id const id; |
| }; |
| |
| ////////////////////////////////// |
| template <typename IdT> |
| inline IdT |
| object_with_id_base_supply<IdT>::acquire() |
| { |
| #ifdef BOOST_SPIRIT_THREADSAFE |
| boost::mutex::scoped_lock lock(mutex); |
| #endif |
| if (free_ids.size()) |
| { |
| object_id id = *free_ids.rbegin(); |
| free_ids.pop_back(); |
| return id; |
| } |
| else |
| { |
| if (free_ids.capacity()<=max_id) |
| free_ids.reserve(max_id*3/2+1); |
| return ++max_id; |
| } |
| } |
| |
| ////////////////////////////////// |
| template <typename IdT> |
| inline void |
| object_with_id_base_supply<IdT>::release(IdT id) |
| { |
| #ifdef BOOST_SPIRIT_THREADSAFE |
| boost::mutex::scoped_lock lock(mutex); |
| #endif |
| if (max_id == id) |
| max_id--; |
| else |
| free_ids.push_back(id); // doesn't throw |
| } |
| |
| ////////////////////////////////// |
| template <typename TagT, typename IdT> |
| inline IdT |
| object_with_id_base<TagT, IdT>::acquire_object_id() |
| { |
| { |
| #ifdef BOOST_SPIRIT_THREADSAFE |
| static boost::once_flag been_here = BOOST_ONCE_INIT; |
| boost::call_once(been_here, mutex_init); |
| boost::mutex &mutex = mutex_instance(); |
| boost::mutex::scoped_lock lock(mutex); |
| #endif |
| static boost::shared_ptr<object_with_id_base_supply<IdT> > |
| static_supply; |
| |
| if (!static_supply.get()) |
| static_supply.reset(new object_with_id_base_supply<IdT>()); |
| id_supply = static_supply; |
| } |
| |
| return id_supply->acquire(); |
| } |
| |
| ////////////////////////////////// |
| template <typename TagT, typename IdT> |
| inline void |
| object_with_id_base<TagT, IdT>::release_object_id(IdT id) |
| { |
| id_supply->release(id); |
| } |
| |
| ////////////////////////////////// |
| #ifdef BOOST_SPIRIT_THREADSAFE |
| template <typename TagT, typename IdT> |
| inline boost::mutex & |
| object_with_id_base<TagT, IdT>::mutex_instance() |
| { |
| static boost::mutex mutex; |
| return mutex; |
| } |
| #endif |
| |
| ////////////////////////////////// |
| #ifdef BOOST_SPIRIT_THREADSAFE |
| template <typename TagT, typename IdT> |
| inline void |
| object_with_id_base<TagT, IdT>::mutex_init() |
| { |
| mutex_instance(); |
| } |
| #endif |
| |
| } // namespace impl |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_END |
| |
| }} // namespace boost::spirit |
| |
| #endif |