Line data Source code
1 : /*============================================================================= 2 : Copyright (c) 2002-2003 Joel de Guzman 3 : Copyright (c) 2002-2003 Martin Wille 4 : http://spirit.sourceforge.net/ 5 : 6 : Use, modification and distribution is subject to the Boost Software 7 : License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 8 : http://www.boost.org/LICENSE_1_0.txt) 9 : =============================================================================*/ 10 : #if !defined BOOST_SPIRIT_OBJECT_WITH_ID_IPP 11 : #define BOOST_SPIRIT_OBJECT_WITH_ID_IPP 12 : 13 : #include <vector> 14 : #include <boost/shared_ptr.hpp> 15 : 16 : #ifdef BOOST_SPIRIT_THREADSAFE 17 : #include <boost/thread/mutex.hpp> 18 : #include <boost/thread/lock_types.hpp> 19 : #include <boost/thread/once.hpp> 20 : #endif 21 : 22 : #include <boost/spirit/home/classic/namespace.hpp> 23 : 24 : /////////////////////////////////////////////////////////////////////////////// 25 : namespace boost { namespace spirit { 26 : 27 : BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN 28 : 29 : namespace impl { 30 : 31 : ////////////////////////////////// 32 : template <typename IdT = std::size_t> 33 : struct object_with_id_base_supply 34 : { 35 : typedef IdT object_id; 36 : typedef std::vector<object_id> id_vector; 37 : 38 0 : object_with_id_base_supply() : max_id(object_id()) {} 39 : 40 : #ifdef BOOST_SPIRIT_THREADSAFE 41 : boost::mutex mutex; 42 : #endif 43 : object_id max_id; 44 : id_vector free_ids; 45 : 46 : object_id acquire(); 47 : void release(object_id); 48 : }; 49 : 50 : ////////////////////////////////// 51 : template <typename TagT, typename IdT = std::size_t> 52 0 : struct object_with_id_base 53 : { 54 : typedef TagT tag_t; 55 : typedef IdT object_id; 56 : 57 : protected: 58 : 59 : object_id acquire_object_id(); 60 : void release_object_id(object_id); 61 : 62 : private: 63 : #ifdef BOOST_SPIRIT_THREADSAFE 64 : static boost::mutex &mutex_instance(); 65 : static void mutex_init(); 66 : #endif 67 : 68 : boost::shared_ptr<object_with_id_base_supply<IdT> > id_supply; 69 : }; 70 : 71 : ////////////////////////////////// 72 : template<class TagT, typename IdT = std::size_t> 73 : struct object_with_id : private object_with_id_base<TagT, IdT> 74 : { 75 : typedef object_with_id<TagT, IdT> self_t; 76 : typedef object_with_id_base<TagT, IdT> base_t; 77 : typedef IdT object_id; 78 : 79 0 : object_with_id() : id(base_t::acquire_object_id()) {} 80 : object_with_id(self_t const &other) 81 : : base_t(other) 82 : , id(base_t::acquire_object_id()) 83 : {} // don't copy id 84 : self_t &operator = (self_t const &other) 85 : { // don't assign id 86 : base_t::operator=(other); 87 : return *this; 88 : } 89 0 : ~object_with_id() { base_t::release_object_id(id); } 90 0 : object_id get_object_id() const { return id; } 91 : 92 : private: 93 : 94 : object_id const id; 95 : }; 96 : 97 : ////////////////////////////////// 98 : template <typename IdT> 99 : inline IdT 100 0 : object_with_id_base_supply<IdT>::acquire() 101 : { 102 : #ifdef BOOST_SPIRIT_THREADSAFE 103 0 : boost::unique_lock<boost::mutex> lock(mutex); 104 : #endif 105 0 : if (free_ids.size()) 106 : { 107 0 : object_id id = *free_ids.rbegin(); 108 0 : free_ids.pop_back(); 109 0 : return id; 110 : } 111 : else 112 : { 113 0 : if (free_ids.capacity()<=max_id) 114 0 : free_ids.reserve(max_id*3/2+1); 115 0 : return ++max_id; 116 : } 117 : } 118 : 119 : ////////////////////////////////// 120 : template <typename IdT> 121 : inline void 122 0 : object_with_id_base_supply<IdT>::release(IdT id) 123 : { 124 : #ifdef BOOST_SPIRIT_THREADSAFE 125 0 : boost::unique_lock<boost::mutex> lock(mutex); 126 : #endif 127 0 : if (max_id == id) 128 0 : max_id--; 129 : else 130 0 : free_ids.push_back(id); // doesn't throw 131 0 : } 132 : 133 : ////////////////////////////////// 134 : template <typename TagT, typename IdT> 135 : inline IdT 136 0 : object_with_id_base<TagT, IdT>::acquire_object_id() 137 : { 138 : { 139 : #ifdef BOOST_SPIRIT_THREADSAFE 140 : #ifndef BOOST_THREAD_PROVIDES_ONCE_CXX11 141 : static boost::once_flag been_here = BOOST_ONCE_INIT; 142 : #else 143 : static boost::once_flag been_here; 144 : #endif 145 0 : boost::call_once(been_here, mutex_init); 146 0 : boost::mutex &mutex = mutex_instance(); 147 0 : boost::unique_lock<boost::mutex> lock(mutex); 148 : #endif 149 : static boost::shared_ptr<object_with_id_base_supply<IdT> > 150 0 : static_supply; 151 : 152 0 : if (!static_supply.get()) 153 0 : static_supply.reset(new object_with_id_base_supply<IdT>()); 154 0 : id_supply = static_supply; 155 : } 156 : 157 0 : return id_supply->acquire(); 158 : } 159 : 160 : ////////////////////////////////// 161 : template <typename TagT, typename IdT> 162 : inline void 163 0 : object_with_id_base<TagT, IdT>::release_object_id(IdT id) 164 : { 165 0 : id_supply->release(id); 166 0 : } 167 : 168 : ////////////////////////////////// 169 : #ifdef BOOST_SPIRIT_THREADSAFE 170 : template <typename TagT, typename IdT> 171 : inline boost::mutex & 172 0 : object_with_id_base<TagT, IdT>::mutex_instance() 173 : { 174 0 : static boost::mutex mutex; 175 0 : return mutex; 176 : } 177 : #endif 178 : 179 : ////////////////////////////////// 180 : #ifdef BOOST_SPIRIT_THREADSAFE 181 : template <typename TagT, typename IdT> 182 : inline void 183 0 : object_with_id_base<TagT, IdT>::mutex_init() 184 : { 185 0 : mutex_instance(); 186 0 : } 187 : #endif 188 : 189 : } // namespace impl 190 : 191 : /////////////////////////////////////////////////////////////////////////////// 192 : BOOST_SPIRIT_CLASSIC_NAMESPACE_END 193 : 194 : }} // namespace boost::spirit 195 : 196 : #endif