]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Copyright Andrey Semashev 2007 - 2015. | |
3 | * Distributed under the Boost Software License, Version 1.0. | |
4 | * (See accompanying file LICENSE_1_0.txt or copy at | |
5 | * http://www.boost.org/LICENSE_1_0.txt) | |
6 | */ | |
7 | /*! | |
8 | * \file static_type_dispatcher.hpp | |
9 | * \author Andrey Semashev | |
10 | * \date 15.04.2007 | |
11 | * | |
12 | * The header contains implementation of a compile-time type dispatcher. | |
13 | */ | |
14 | ||
15 | #ifndef BOOST_LOG_STATIC_TYPE_DISPATCHER_HPP_INCLUDED_ | |
16 | #define BOOST_LOG_STATIC_TYPE_DISPATCHER_HPP_INCLUDED_ | |
17 | ||
18 | #include <cstddef> | |
19 | #include <utility> | |
20 | #include <iterator> | |
21 | #include <algorithm> | |
22 | #include <boost/array.hpp> | |
23 | #include <boost/static_assert.hpp> | |
24 | #include <boost/type_index.hpp> | |
25 | #include <boost/mpl/if.hpp> | |
26 | #include <boost/mpl/size.hpp> | |
27 | #include <boost/mpl/begin.hpp> | |
28 | #include <boost/mpl/end.hpp> | |
29 | #include <boost/mpl/deref.hpp> | |
30 | #include <boost/mpl/next.hpp> | |
31 | #include <boost/mpl/is_sequence.hpp> | |
32 | #include <boost/core/addressof.hpp> | |
33 | #include <boost/log/detail/config.hpp> | |
34 | #include <boost/log/utility/once_block.hpp> | |
35 | #include <boost/log/utility/type_dispatch/type_dispatcher.hpp> | |
36 | #include <boost/log/detail/header.hpp> | |
37 | ||
38 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
39 | #pragma once | |
40 | #endif | |
41 | ||
42 | namespace boost { | |
43 | ||
44 | BOOST_LOG_OPEN_NAMESPACE | |
45 | ||
46 | namespace aux { | |
47 | ||
48 | //! Ordering predicate for type dispatching map | |
49 | struct dispatching_map_order | |
50 | { | |
51 | typedef bool result_type; | |
52 | typedef std::pair< typeindex::type_index, void* > first_argument_type, second_argument_type; | |
53 | result_type operator() (first_argument_type const& left, second_argument_type const& right) const | |
54 | { | |
55 | return (left.first < right.first); | |
56 | } | |
57 | }; | |
58 | ||
59 | //! Dispatching map filler | |
60 | template< typename VisitorT > | |
61 | struct dispatching_map_initializer | |
62 | { | |
63 | template< typename IteratorT > | |
64 | static BOOST_FORCEINLINE void init(IteratorT*, IteratorT*, std::pair< typeindex::type_index, void* >*) | |
65 | { | |
66 | } | |
67 | ||
68 | template< typename BeginIteratorT, typename EndIteratorT > | |
69 | static BOOST_FORCEINLINE void init(BeginIteratorT*, EndIteratorT* end, std::pair< typeindex::type_index, void* >* p) | |
70 | { | |
71 | typedef typename mpl::deref< BeginIteratorT >::type type; | |
72 | do_init(static_cast< type* >(0), p); | |
73 | ||
74 | typedef typename mpl::next< BeginIteratorT >::type next_iterator_type; | |
75 | init(static_cast< next_iterator_type* >(0), end, p + 1); | |
76 | } | |
77 | ||
78 | private: | |
79 | template< typename T > | |
80 | static BOOST_FORCEINLINE void do_init(T*, std::pair< typeindex::type_index, void* >* p) | |
81 | { | |
82 | p->first = typeindex::type_id< T >(); | |
83 | ||
84 | typedef void (*trampoline_t)(void*, T const&); | |
85 | BOOST_STATIC_ASSERT_MSG(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); | |
86 | union | |
87 | { | |
88 | void* as_pvoid; | |
89 | trampoline_t as_trampoline; | |
90 | } | |
91 | caster; | |
92 | caster.as_trampoline = (trampoline_t)&type_dispatcher::callback_base::trampoline< VisitorT, T >; | |
93 | p->second = caster.as_pvoid; | |
94 | } | |
95 | }; | |
96 | ||
97 | //! A base class for a dispatcher that supports a sequence of types | |
98 | class type_sequence_dispatcher_base : | |
99 | public type_dispatcher | |
100 | { | |
101 | private: | |
102 | //! Dispatching map element type | |
103 | typedef std::pair< typeindex::type_index, void* > dispatching_map_element_type; | |
104 | ||
105 | private: | |
106 | //! Dispatching map | |
107 | const dispatching_map_element_type* m_dispatching_map_begin; | |
108 | //! Dispatching map size | |
109 | std::size_t m_dispatching_map_size; | |
110 | //! Pointer to the receiver function | |
111 | void* m_visitor; | |
112 | ||
113 | protected: | |
114 | //! Initializing constructor | |
115 | type_sequence_dispatcher_base(const dispatching_map_element_type* disp_map, std::size_t disp_map_size, void* visitor) BOOST_NOEXCEPT : | |
116 | type_dispatcher(&type_sequence_dispatcher_base::get_callback), | |
117 | m_dispatching_map_begin(disp_map), | |
118 | m_dispatching_map_size(disp_map_size), | |
119 | m_visitor(visitor) | |
120 | { | |
121 | } | |
122 | ||
123 | private: | |
124 | //! The get_callback method implementation | |
125 | static callback_base get_callback(type_dispatcher* p, typeindex::type_index type) | |
126 | { | |
127 | type_sequence_dispatcher_base* const self = static_cast< type_sequence_dispatcher_base* >(p); | |
128 | const dispatching_map_element_type* begin = self->m_dispatching_map_begin; | |
129 | const dispatching_map_element_type* end = begin + self->m_dispatching_map_size; | |
130 | const dispatching_map_element_type* it = std::lower_bound | |
131 | ( | |
132 | begin, | |
133 | end, | |
134 | dispatching_map_element_type(type, (void*)0), | |
135 | dispatching_map_order() | |
136 | ); | |
137 | ||
138 | if (it != end && it->first == type) | |
139 | return callback_base(self->m_visitor, it->second); | |
140 | else | |
141 | return callback_base(); | |
142 | } | |
143 | ||
144 | // Copying and assignment closed | |
145 | BOOST_DELETED_FUNCTION(type_sequence_dispatcher_base(type_sequence_dispatcher_base const&)) | |
146 | BOOST_DELETED_FUNCTION(type_sequence_dispatcher_base& operator= (type_sequence_dispatcher_base const&)) | |
147 | }; | |
148 | ||
149 | //! A dispatcher that supports a sequence of types | |
150 | template< typename TypeSequenceT > | |
151 | class type_sequence_dispatcher : | |
152 | public type_sequence_dispatcher_base | |
153 | { | |
154 | public: | |
155 | //! Type sequence of the supported types | |
156 | typedef TypeSequenceT supported_types; | |
157 | ||
158 | private: | |
159 | //! The dispatching map | |
160 | typedef array< | |
161 | std::pair< typeindex::type_index, void* >, | |
162 | mpl::size< supported_types >::value | |
163 | > dispatching_map; | |
164 | ||
165 | public: | |
166 | /*! | |
167 | * Constructor. Initializes the dispatcher internals. | |
168 | */ | |
169 | template< typename VisitorT > | |
170 | explicit type_sequence_dispatcher(VisitorT& visitor) : | |
171 | type_sequence_dispatcher_base(get_dispatching_map< VisitorT >().data(), dispatching_map::static_size, (void*)boost::addressof(visitor)) | |
172 | { | |
173 | } | |
174 | ||
175 | private: | |
176 | //! The method returns the dispatching map instance | |
177 | template< typename VisitorT > | |
178 | static dispatching_map const& get_dispatching_map() | |
179 | { | |
180 | static const dispatching_map* pinstance = NULL; | |
181 | ||
182 | BOOST_LOG_ONCE_BLOCK() | |
183 | { | |
184 | static dispatching_map instance; | |
185 | typename dispatching_map::value_type* p = &*instance.begin(); | |
186 | ||
187 | typedef typename mpl::begin< supported_types >::type begin_iterator_type; | |
188 | typedef typename mpl::end< supported_types >::type end_iterator_type; | |
189 | typedef dispatching_map_initializer< VisitorT > initializer; | |
190 | initializer::init(static_cast< begin_iterator_type* >(0), static_cast< end_iterator_type* >(0), p); | |
191 | ||
192 | std::sort(instance.begin(), instance.end(), dispatching_map_order()); | |
193 | ||
194 | pinstance = &instance; | |
195 | } | |
196 | ||
197 | return *pinstance; | |
198 | } | |
199 | ||
200 | // Copying and assignment closed | |
201 | BOOST_DELETED_FUNCTION(type_sequence_dispatcher(type_sequence_dispatcher const&)) | |
202 | BOOST_DELETED_FUNCTION(type_sequence_dispatcher& operator= (type_sequence_dispatcher const&)) | |
203 | }; | |
204 | ||
205 | //! A base class for a single-type dispatcher | |
206 | class single_type_dispatcher_base : | |
207 | public type_dispatcher | |
208 | { | |
209 | private: | |
210 | //! The type to match against | |
211 | typeindex::type_index m_type; | |
212 | //! A callback for the supported type | |
213 | callback_base m_callback; | |
214 | ||
215 | protected: | |
216 | //! Initializing constructor | |
217 | single_type_dispatcher_base(typeindex::type_index type, callback_base const& cb) BOOST_NOEXCEPT : | |
218 | type_dispatcher(&single_type_dispatcher_base::get_callback), | |
219 | m_type(type), | |
220 | m_callback(cb) | |
221 | { | |
222 | } | |
223 | ||
224 | private: | |
225 | //! The get_callback method implementation | |
226 | static callback_base get_callback(type_dispatcher* p, typeindex::type_index type) | |
227 | { | |
228 | single_type_dispatcher_base* const self = static_cast< single_type_dispatcher_base* >(p); | |
229 | if (type == self->m_type) | |
230 | return self->m_callback; | |
231 | else | |
232 | return callback_base(); | |
233 | } | |
234 | ||
235 | // Copying and assignment closed | |
236 | BOOST_DELETED_FUNCTION(single_type_dispatcher_base(single_type_dispatcher_base const&)) | |
237 | BOOST_DELETED_FUNCTION(single_type_dispatcher_base& operator= (single_type_dispatcher_base const&)) | |
238 | }; | |
239 | ||
240 | //! A simple dispatcher that only supports one type | |
241 | template< typename T > | |
242 | class single_type_dispatcher : | |
243 | public single_type_dispatcher_base | |
244 | { | |
245 | private: | |
246 | typedef void (*trampoline_t)(void*, T const&); | |
247 | ||
248 | public: | |
249 | //! Constructor | |
250 | template< typename VisitorT > | |
251 | explicit single_type_dispatcher(VisitorT& visitor) BOOST_NOEXCEPT : | |
252 | single_type_dispatcher_base(typeindex::type_id< T >(), callback_base((void*)boost::addressof(visitor), (trampoline_t)&callback_base::trampoline< VisitorT, T >)) | |
253 | { | |
254 | } | |
255 | ||
256 | // Copying and assignment closed | |
257 | BOOST_DELETED_FUNCTION(single_type_dispatcher(single_type_dispatcher const&)) | |
258 | BOOST_DELETED_FUNCTION(single_type_dispatcher& operator= (single_type_dispatcher const&)) | |
259 | }; | |
260 | ||
261 | } // namespace aux | |
262 | ||
263 | /*! | |
264 | * \brief A static type dispatcher class | |
265 | * | |
266 | * The type dispatcher can be used to pass objects of arbitrary types from one | |
267 | * component to another. With regard to the library, the type dispatcher | |
268 | * can be used to extract attribute values. | |
269 | * | |
270 | * Static type dispatchers allow to specify one or several supported types at compile | |
271 | * time. | |
272 | */ | |
273 | template< typename T > | |
274 | class static_type_dispatcher | |
275 | #ifndef BOOST_LOG_DOXYGEN_PASS | |
276 | : | |
277 | public mpl::if_< | |
278 | mpl::is_sequence< T >, | |
279 | boost::log::aux::type_sequence_dispatcher< T >, | |
280 | boost::log::aux::single_type_dispatcher< T > | |
281 | >::type | |
282 | #endif | |
283 | { | |
284 | private: | |
285 | //! Base type | |
286 | typedef typename mpl::if_< | |
287 | mpl::is_sequence< T >, | |
288 | boost::log::aux::type_sequence_dispatcher< T >, | |
289 | boost::log::aux::single_type_dispatcher< T > | |
290 | >::type base_type; | |
291 | ||
292 | public: | |
293 | /*! | |
294 | * Constructor. Initializes the dispatcher internals. | |
295 | * | |
296 | * The \a receiver object is not copied inside the dispatcher, but references to | |
297 | * it may be kept by the dispatcher after construction. The receiver object must remain | |
298 | * valid until the dispatcher is destroyed. | |
299 | * | |
300 | * \param receiver Unary function object that will be called on a dispatched value. The receiver | |
301 | * must be callable with an argument of any of the supported types of the dispatcher. | |
302 | */ | |
303 | template< typename ReceiverT > | |
304 | explicit static_type_dispatcher(ReceiverT& receiver) : | |
305 | base_type(receiver) | |
306 | { | |
307 | } | |
308 | ||
309 | // Copying and assignment prohibited | |
310 | BOOST_DELETED_FUNCTION(static_type_dispatcher(static_type_dispatcher const&)) | |
311 | BOOST_DELETED_FUNCTION(static_type_dispatcher& operator= (static_type_dispatcher const&)) | |
312 | }; | |
313 | ||
314 | BOOST_LOG_CLOSE_NAMESPACE // namespace log | |
315 | ||
316 | } // namespace boost | |
317 | ||
318 | #include <boost/log/detail/footer.hpp> | |
319 | ||
320 | #endif // BOOST_LOG_STATIC_TYPE_DISPATCHER_HPP_INCLUDED_ |