| /* |
| * Copyright Andrey Semashev 2007 - 2015. |
| * Distributed under the Boost Software License, Version 1.0. |
| * (See accompanying file LICENSE_1_0.txt or copy at |
| * http://www.boost.org/LICENSE_1_0.txt) |
| */ |
| /*! |
| * \file dynamic_type_dispatcher.hpp |
| * \author Andrey Semashev |
| * \date 15.04.2007 |
| * |
| * The header contains implementation of the run-time type dispatcher. |
| */ |
| |
| #ifndef BOOST_LOG_DYNAMIC_TYPE_DISPATCHER_HPP_INCLUDED_ |
| #define BOOST_LOG_DYNAMIC_TYPE_DISPATCHER_HPP_INCLUDED_ |
| |
| #include <new> |
| #include <memory> |
| #include <map> |
| #include <boost/ref.hpp> |
| #include <boost/smart_ptr/shared_ptr.hpp> |
| #include <boost/smart_ptr/make_shared_object.hpp> |
| #include <boost/log/detail/config.hpp> |
| #include <boost/log/detail/visible_type.hpp> |
| #include <boost/log/utility/type_info_wrapper.hpp> |
| #include <boost/log/utility/type_dispatch/type_dispatcher.hpp> |
| #include <boost/log/detail/header.hpp> |
| |
| #ifdef BOOST_HAS_PRAGMA_ONCE |
| #pragma once |
| #endif |
| |
| namespace boost { |
| |
| BOOST_LOG_OPEN_NAMESPACE |
| |
| /*! |
| * \brief A dynamic type dispatcher |
| * |
| * The type dispatcher can be used to pass objects of arbitrary types from one |
| * component to another. With regard to the library, the type dispatcher |
| * can be used to extract attribute values. |
| * |
| * The dynamic type dispatcher can be initialized in run time and, therefore, |
| * can support different types, depending on runtime conditions. Each |
| * supported type is associated with a functional object that will be called |
| * when an object of the type is dispatched. |
| */ |
| class dynamic_type_dispatcher : |
| public type_dispatcher |
| { |
| private: |
| #ifndef BOOST_LOG_DOXYGEN_PASS |
| template< typename T, typename VisitorT > |
| class callback_impl : |
| public callback_base |
| { |
| private: |
| VisitorT m_Visitor; |
| |
| public: |
| explicit callback_impl(VisitorT const& visitor) : m_Visitor(visitor) |
| { |
| this->m_pVisitor = (void*)boost::addressof(m_Visitor); |
| typedef void (*trampoline_t)(void*, T const&); |
| 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"); |
| union |
| { |
| void* as_pvoid; |
| trampoline_t as_trampoline; |
| } |
| caster; |
| caster.as_trampoline = &callback_base::trampoline< VisitorT, T >; |
| this->m_pTrampoline = caster.as_pvoid; |
| } |
| }; |
| #endif // BOOST_LOG_DOXYGEN_PASS |
| |
| //! The dispatching map |
| typedef std::map< type_info_wrapper, shared_ptr< callback_base > > dispatching_map; |
| dispatching_map m_DispatchingMap; |
| |
| public: |
| /*! |
| * Default constructor |
| */ |
| dynamic_type_dispatcher() : type_dispatcher(&dynamic_type_dispatcher::get_callback) |
| { |
| } |
| |
| /*! |
| * Copy constructor |
| */ |
| dynamic_type_dispatcher(dynamic_type_dispatcher const& that) : |
| type_dispatcher(static_cast< type_dispatcher const& >(that)), |
| m_DispatchingMap(that.m_DispatchingMap) |
| { |
| } |
| |
| /*! |
| * Copy assignment |
| */ |
| dynamic_type_dispatcher& operator= (dynamic_type_dispatcher const& that) |
| { |
| m_DispatchingMap = that.m_DispatchingMap; |
| return *this; |
| } |
| |
| /*! |
| * The method registers a new type |
| * |
| * \param visitor Function object that will be associated with the type \c T |
| */ |
| template< typename T, typename VisitorT > |
| void register_type(VisitorT const& visitor) |
| { |
| boost::shared_ptr< callback_base > p( |
| boost::make_shared< callback_impl< T, VisitorT > >(boost::cref(visitor))); |
| |
| type_info_wrapper wrapper(typeid(aux::visible_type< T >)); |
| m_DispatchingMap[wrapper].swap(p); |
| } |
| |
| /*! |
| * The method returns the number of registered types |
| */ |
| dispatching_map::size_type registered_types_count() const |
| { |
| return m_DispatchingMap.size(); |
| } |
| |
| private: |
| #ifndef BOOST_LOG_DOXYGEN_PASS |
| static callback_base get_callback(type_dispatcher* p, std::type_info const& type) |
| { |
| dynamic_type_dispatcher* const self = static_cast< dynamic_type_dispatcher* >(p); |
| type_info_wrapper wrapper(type); |
| dispatching_map::iterator it = self->m_DispatchingMap.find(wrapper); |
| if (it != self->m_DispatchingMap.end()) |
| return *it->second; |
| else |
| return callback_base(); |
| } |
| #endif // BOOST_LOG_DOXYGEN_PASS |
| }; |
| |
| BOOST_LOG_CLOSE_NAMESPACE // namespace log |
| |
| } // namespace boost |
| |
| #include <boost/log/detail/footer.hpp> |
| |
| #endif // BOOST_LOG_DYNAMIC_TYPE_DISPATCHER_HPP_INCLUDED_ |