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.size())
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