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

source code of boost/libs/log/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp