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/////////////////////////////////////////////////////////////////////////////// 25namespace boost { namespace spirit { 26 27BOOST_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 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 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 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 ~object_with_id() { base_t::release_object_id(id); } 90 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 object_with_id_base_supply<IdT>::acquire() 101 { 102#ifdef BOOST_SPIRIT_THREADSAFE 103 boost::unique_lock<boost::mutex> lock(mutex); 104#endif 105 if (!free_ids.empty()) 106 { 107 object_id id = *free_ids.rbegin(); 108 free_ids.pop_back(); 109 return id; 110 } 111 else 112 { 113 if (free_ids.capacity()<=max_id) 114 free_ids.reserve(max_id*3/2+1); 115 return ++max_id; 116 } 117 } 118 119 ////////////////////////////////// 120 template <typename IdT> 121 inline void 122 object_with_id_base_supply<IdT>::release(IdT id) 123 { 124#ifdef BOOST_SPIRIT_THREADSAFE 125 boost::unique_lock<boost::mutex> lock(mutex); 126#endif 127 if (max_id == id) 128 max_id--; 129 else 130 free_ids.push_back(id); // doesn't throw 131 } 132 133 ////////////////////////////////// 134 template <typename TagT, typename IdT> 135 inline IdT 136 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 boost::call_once(been_here, mutex_init); 146 boost::mutex &mutex = mutex_instance(); 147 boost::unique_lock<boost::mutex> lock(mutex); 148#endif 149 static boost::shared_ptr<object_with_id_base_supply<IdT> > 150 static_supply; 151 152 if (!static_supply.get()) 153 static_supply.reset(new object_with_id_base_supply<IdT>()); 154 id_supply = static_supply; 155 } 156 157 return id_supply->acquire(); 158 } 159 160 ////////////////////////////////// 161 template <typename TagT, typename IdT> 162 inline void 163 object_with_id_base<TagT, IdT>::release_object_id(IdT id) 164 { 165 id_supply->release(id); 166 } 167 168 ////////////////////////////////// 169#ifdef BOOST_SPIRIT_THREADSAFE 170 template <typename TagT, typename IdT> 171 inline boost::mutex & 172 object_with_id_base<TagT, IdT>::mutex_instance() 173 { 174 static boost::mutex mutex; 175 return mutex; 176 } 177#endif 178 179 ////////////////////////////////// 180#ifdef BOOST_SPIRIT_THREADSAFE 181 template <typename TagT, typename IdT> 182 inline void 183 object_with_id_base<TagT, IdT>::mutex_init() 184 { 185 mutex_instance(); 186 } 187#endif 188 189 } // namespace impl 190 191/////////////////////////////////////////////////////////////////////////////// 192BOOST_SPIRIT_CLASSIC_NAMESPACE_END 193 194}} // namespace boost::spirit 195 196#endif 197