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   light_function.hpp
9  * \author Andrey Semashev
10  * \date   20.06.2010
11  *
12  * \brief  This header is the Boost.Log library impl, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  *
15  * The file contains a lightweight alternative of Boost.Function. It does not provide all
16  * features of Boost.Function but doesn't introduce dependency on Boost.Bind.
17  */
18 
19 #ifndef BOOST_LOG_DETAIL_LIGHT_FUNCTION_HPP_INCLUDED_
20 #define BOOST_LOG_DETAIL_LIGHT_FUNCTION_HPP_INCLUDED_
21 
22 #include <cstddef>
23 #include <boost/move/core.hpp>
24 #include <boost/move/utility_core.hpp>
25 #include <boost/log/detail/config.hpp>
26 #include <boost/utility/explicit_operator_bool.hpp>
27 #include <boost/type_traits/remove_cv.hpp>
28 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
29 #include <boost/preprocessor/iteration/iterate.hpp>
30 #include <boost/preprocessor/repetition/enum_params.hpp>
31 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
32 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
33 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
34 #endif
35 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
36 #include <boost/log/detail/sfinae_tools.hpp>
37 #else
38 #include <boost/type_traits/remove_reference.hpp>
39 #endif
40 #if defined(BOOST_NO_CXX11_NULLPTR)
41 #include <boost/assert.hpp>
42 #endif
43 #include <boost/log/detail/header.hpp>
44 
45 #ifdef BOOST_HAS_PRAGMA_ONCE
46 #pragma once
47 #endif
48 
49 #ifndef BOOST_LOG_LIGHT_FUNCTION_LIMIT
50 #define BOOST_LOG_LIGHT_FUNCTION_LIMIT 2
51 #endif
52 
53 namespace boost {
54 
55 BOOST_LOG_OPEN_NAMESPACE
56 
57 namespace aux {
58 
59 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
60 
61 template< typename T, typename ThisT >
62 struct is_cv_same { enum _ { value = false }; };
63 template< typename T >
64 struct is_cv_same< T, T > { enum _ { value = true }; };
65 template< typename T >
66 struct is_cv_same< T, const T > { enum _ { value = true }; };
67 template< typename T >
68 struct is_cv_same< T, volatile T > { enum _ { value = true }; };
69 template< typename T >
70 struct is_cv_same< T, const volatile T > { enum _ { value = true }; };
71 
72 template< typename T, typename ThisT >
73 struct is_rv_or_same { enum _ { value = false }; };
74 template< typename T >
75 struct is_rv_or_same< T, T > { enum _ { value = true }; };
76 template< typename T, typename ThisT >
77 struct is_rv_or_same< boost::rv< T >, ThisT > { enum _ { value = true }; };
78 
79 #endif
80 
81 template< typename SignatureT >
82 class light_function;
83 
84 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
85 
86 template< typename ResultT, typename... ArgsT >
87 class light_function< ResultT (ArgsT...) >
88 {
89     typedef light_function this_type;
90     BOOST_COPYABLE_AND_MOVABLE(this_type)
91 
92 public:
93     typedef ResultT result_type;
94 
95 private:
96     struct impl_base
97     {
98         typedef result_type (*invoke_type)(void*, ArgsT...);
99         const invoke_type invoke;
100 
101         typedef impl_base* (*clone_type)(const void*);
102         const clone_type clone;
103 
104         typedef void (*destroy_type)(void*);
105         const destroy_type destroy;
106 
impl_baseboost::aux::light_function::impl_base107         impl_base(invoke_type inv, clone_type cl, destroy_type dstr) : invoke(inv), clone(cl), destroy(dstr)
108         {
109         }
110 
111         BOOST_DELETED_FUNCTION(impl_base(impl_base const&))
112         BOOST_DELETED_FUNCTION(impl_base& operator= (impl_base const&))
113     };
114 
115 #if !defined(BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS)
116     template< typename FunT >
117     class impl;
118     template< typename FunT >
119     friend class impl;
120 #endif
121 
122     template< typename FunT >
123     class impl :
124         public impl_base
125     {
126         typedef impl< FunT > this_type;
127 
128         FunT m_Function;
129 
130     public:
impl(FunT const & fun)131         explicit impl(FunT const& fun) :
132             impl_base(&this_type::invoke_impl, &this_type::clone_impl, &this_type::destroy_impl),
133             m_Function(fun)
134         {
135         }
136 
137 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
impl(FunT && fun)138         explicit impl(FunT&& fun) :
139             impl_base(&this_type::invoke_impl, &this_type::clone_impl, &this_type::destroy_impl),
140             m_Function(boost::move(fun))
141         {
142         }
143 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
144 
destroy_impl(void * self)145         static void destroy_impl(void* self)
146         {
147             delete static_cast< impl* >(static_cast< impl_base* >(self));
148         }
clone_impl(const void * self)149         static impl_base* clone_impl(const void* self)
150         {
151             return new impl(static_cast< const impl* >(static_cast< const impl_base* >(self))->m_Function);
152         }
invoke_impl(void * self,ArgsT...args)153         static result_type invoke_impl(void* self, ArgsT... args)
154         {
155             return static_cast< impl* >(static_cast< impl_base* >(self))->m_Function(args...);
156         }
157 
158         BOOST_DELETED_FUNCTION(impl(impl const&))
159         BOOST_DELETED_FUNCTION(impl& operator= (impl const&))
160     };
161 
162 private:
163     impl_base* m_pImpl;
164 
165 public:
light_function()166     BOOST_CONSTEXPR light_function() BOOST_NOEXCEPT : m_pImpl(NULL)
167     {
168     }
light_function(this_type const & that)169     light_function(this_type const& that)
170     {
171         if (that.m_pImpl)
172             m_pImpl = that.m_pImpl->clone(that.m_pImpl);
173         else
174             m_pImpl = NULL;
175     }
176 
light_function(BOOST_RV_REF (this_type)that)177     light_function(BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
178     {
179         m_pImpl = that.m_pImpl;
180         that.m_pImpl = NULL;
181     }
182 
light_function(BOOST_RV_REF (const this_type)that)183     light_function(BOOST_RV_REF(const this_type) that) BOOST_NOEXCEPT
184     {
185         m_pImpl = that.m_pImpl;
186         ((this_type&)that).m_pImpl = NULL;
187     }
188 
189 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
190     template< typename FunT >
light_function(FunT && fun)191     light_function(FunT&& fun) :
192         m_pImpl(new impl< typename remove_cv< typename remove_reference< FunT >::type >::type >(boost::forward< FunT >(fun)))
193     {
194     }
195 #else
196     template< typename FunT >
light_function(FunT const & fun,typename boost::disable_if_c<is_rv_or_same<FunT,this_type>::value,boost::log::aux::sfinae_dummy>::type=boost::log::aux::sfinae_dummy ())197     light_function(FunT const& fun, typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :
198         m_pImpl(new impl< FunT >(fun))
199     {
200     }
201     template< typename FunT >
light_function(BOOST_RV_REF (FunT)fun,typename boost::disable_if_c<is_cv_same<FunT,this_type>::value,boost::log::aux::sfinae_dummy>::type=boost::log::aux::sfinae_dummy ())202     light_function(BOOST_RV_REF(FunT) fun, typename boost::disable_if_c< is_cv_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :
203         m_pImpl(new impl< typename remove_cv< FunT >::type >(fun))
204     {
205     }
206 #endif
207 
208     //! Constructor from NULL
209 #if !defined(BOOST_NO_CXX11_NULLPTR)
light_function(std::nullptr_t)210     BOOST_CONSTEXPR light_function(std::nullptr_t) BOOST_NOEXCEPT
211 #else
212     BOOST_CONSTEXPR light_function(int p) BOOST_NOEXCEPT
213 #endif
214         : m_pImpl(NULL)
215     {
216 #if defined(BOOST_NO_CXX11_NULLPTR)
217         BOOST_ASSERT(p == 0);
218 #endif
219     }
~light_function()220     ~light_function()
221     {
222         clear();
223     }
224 
operator =(BOOST_RV_REF (this_type)that)225     light_function& operator= (BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
226     {
227         this->swap(that);
228         return *this;
229     }
operator =(BOOST_COPY_ASSIGN_REF (this_type)that)230     light_function& operator= (BOOST_COPY_ASSIGN_REF(this_type) that)
231     {
232         light_function tmp = static_cast< this_type const& >(that);
233         this->swap(tmp);
234         return *this;
235     }
236     //! Assignment of NULL
237 #if !defined(BOOST_NO_CXX11_NULLPTR)
operator =(std::nullptr_t)238     light_function& operator= (std::nullptr_t)
239 #else
240     light_function& operator= (int p)
241 #endif
242     {
243 #if defined(BOOST_NO_CXX11_NULLPTR)
244         BOOST_ASSERT(p == 0);
245 #endif
246         clear();
247         return *this;
248     }
249 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
250     template< typename FunT >
operator =(FunT && fun)251     light_function& operator= (FunT&& fun)
252     {
253         light_function tmp(boost::forward< FunT >(fun));
254         this->swap(tmp);
255         return *this;
256     }
257 #else
258     template< typename FunT >
259     typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type
operator =(FunT const & fun)260     operator= (FunT const& fun)
261     {
262         light_function tmp(fun);
263         this->swap(tmp);
264         return *this;
265     }
266 #endif
267 
operator ()(ArgsT...args) const268     result_type operator() (ArgsT... args) const
269     {
270         return m_pImpl->invoke(m_pImpl, args...);
271     }
272 
273     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
274     bool operator! () const BOOST_NOEXCEPT { return (m_pImpl == NULL); }
empty() const275     bool empty() const BOOST_NOEXCEPT { return (m_pImpl == NULL); }
clear()276     void clear() BOOST_NOEXCEPT
277     {
278         if (m_pImpl)
279         {
280             m_pImpl->destroy(m_pImpl);
281             m_pImpl = NULL;
282         }
283     }
284 
swap(this_type & that)285     void swap(this_type& that) BOOST_NOEXCEPT
286     {
287         impl_base* p = m_pImpl;
288         m_pImpl = that.m_pImpl;
289         that.m_pImpl = p;
290     }
291 };
292 
293 template< typename... ArgsT >
294 class light_function< void (ArgsT...) >
295 {
296     typedef light_function this_type;
297     BOOST_COPYABLE_AND_MOVABLE(this_type)
298 
299 public:
300     typedef void result_type;
301 
302 private:
303     struct impl_base
304     {
305         typedef void (*invoke_type)(void*, ArgsT...);
306         const invoke_type invoke;
307 
308         typedef impl_base* (*clone_type)(const void*);
309         const clone_type clone;
310 
311         typedef void (*destroy_type)(void*);
312         const destroy_type destroy;
313 
impl_baseboost::aux::light_function::impl_base314         impl_base(invoke_type inv, clone_type cl, destroy_type dstr) : invoke(inv), clone(cl), destroy(dstr)
315         {
316         }
317 
318         BOOST_DELETED_FUNCTION(impl_base(impl_base const&))
319         BOOST_DELETED_FUNCTION(impl_base& operator= (impl_base const&))
320     };
321 
322 #if !defined(BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS)
323     template< typename FunT >
324     class impl;
325     template< typename FunT >
326     friend class impl;
327 #endif
328 
329     template< typename FunT >
330     class impl :
331         public impl_base
332     {
333         typedef impl< FunT > this_type;
334 
335         FunT m_Function;
336 
337     public:
impl(FunT const & fun)338         explicit impl(FunT const& fun) :
339             impl_base(&this_type::invoke_impl, &this_type::clone_impl, &this_type::destroy_impl),
340             m_Function(fun)
341         {
342         }
343 
344 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
impl(FunT && fun)345         explicit impl(FunT&& fun) :
346             impl_base(&this_type::invoke_impl, &this_type::clone_impl, &this_type::destroy_impl),
347             m_Function(boost::move(fun))
348         {
349         }
350 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
351 
destroy_impl(void * self)352         static void destroy_impl(void* self)
353         {
354             delete static_cast< impl* >(static_cast< impl_base* >(self));
355         }
clone_impl(const void * self)356         static impl_base* clone_impl(const void* self)
357         {
358             return new impl(static_cast< const impl* >(static_cast< const impl_base* >(self))->m_Function);
359         }
invoke_impl(void * self,ArgsT...args)360         static result_type invoke_impl(void* self, ArgsT... args)
361         {
362             static_cast< impl* >(static_cast< impl_base* >(self))->m_Function(args...);
363         }
364 
365         BOOST_DELETED_FUNCTION(impl(impl const&))
366         BOOST_DELETED_FUNCTION(impl& operator= (impl const&))
367     };
368 
369 private:
370     impl_base* m_pImpl;
371 
372 public:
light_function()373     BOOST_CONSTEXPR light_function() BOOST_NOEXCEPT : m_pImpl(NULL)
374     {
375     }
light_function(this_type const & that)376     light_function(this_type const& that)
377     {
378         if (that.m_pImpl)
379             m_pImpl = that.m_pImpl->clone(that.m_pImpl);
380         else
381             m_pImpl = NULL;
382     }
light_function(BOOST_RV_REF (this_type)that)383     light_function(BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
384     {
385         m_pImpl = that.m_pImpl;
386         that.m_pImpl = NULL;
387     }
388 
light_function(BOOST_RV_REF (const this_type)that)389     light_function(BOOST_RV_REF(const this_type) that) BOOST_NOEXCEPT
390     {
391         m_pImpl = that.m_pImpl;
392         ((this_type&)that).m_pImpl = NULL;
393     }
394 
395 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
396     template< typename FunT >
light_function(FunT && fun)397     light_function(FunT&& fun) :
398         m_pImpl(new impl< typename remove_cv< typename remove_reference< FunT >::type >::type >(boost::forward< FunT >(fun)))
399     {
400     }
401 #else
402     template< typename FunT >
light_function(FunT const & fun,typename boost::disable_if_c<is_rv_or_same<FunT,this_type>::value,boost::log::aux::sfinae_dummy>::type=boost::log::aux::sfinae_dummy ())403     light_function(FunT const& fun, typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :
404         m_pImpl(new impl< FunT >(fun))
405     {
406     }
407     template< typename FunT >
light_function(BOOST_RV_REF (FunT)fun,typename boost::disable_if_c<is_cv_same<FunT,this_type>::value,boost::log::aux::sfinae_dummy>::type=boost::log::aux::sfinae_dummy ())408     light_function(BOOST_RV_REF(FunT) fun, typename boost::disable_if_c< is_cv_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :
409         m_pImpl(new impl< typename remove_cv< FunT >::type >(fun))
410     {
411     }
412 #endif
413 
414     //! Constructor from NULL
415 #if !defined(BOOST_NO_CXX11_NULLPTR)
light_function(std::nullptr_t)416     BOOST_CONSTEXPR light_function(std::nullptr_t) BOOST_NOEXCEPT
417 #else
418     BOOST_CONSTEXPR light_function(int p) BOOST_NOEXCEPT
419 #endif
420         : m_pImpl(NULL)
421     {
422 #if defined(BOOST_NO_CXX11_NULLPTR)
423         BOOST_ASSERT(p == 0);
424 #endif
425     }
~light_function()426     ~light_function()
427     {
428         clear();
429     }
430 
operator =(BOOST_RV_REF (this_type)that)431     light_function& operator= (BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
432     {
433         this->swap(that);
434         return *this;
435     }
operator =(BOOST_COPY_ASSIGN_REF (this_type)that)436     light_function& operator= (BOOST_COPY_ASSIGN_REF(this_type) that)
437     {
438         light_function tmp = static_cast< this_type const& >(that);
439         this->swap(tmp);
440         return *this;
441     }
442     //! Assignment of NULL
443 #if !defined(BOOST_NO_CXX11_NULLPTR)
operator =(std::nullptr_t)444     light_function& operator= (std::nullptr_t)
445 #else
446     light_function& operator= (int p)
447 #endif
448     {
449 #if defined(BOOST_NO_CXX11_NULLPTR)
450         BOOST_ASSERT(p == 0);
451 #endif
452         clear();
453         return *this;
454     }
455 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
456     template< typename FunT >
operator =(FunT && fun)457     light_function& operator= (FunT&& fun)
458     {
459         light_function tmp(boost::forward< FunT >(fun));
460         this->swap(tmp);
461         return *this;
462     }
463 #else
464     template< typename FunT >
465     typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type
operator =(FunT const & fun)466     operator= (FunT const& fun)
467     {
468         light_function tmp(fun);
469         this->swap(tmp);
470         return *this;
471     }
472 #endif
473 
operator ()(ArgsT...args) const474     result_type operator() (ArgsT... args) const
475     {
476         m_pImpl->invoke(m_pImpl, args...);
477     }
478 
479     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
480     bool operator! () const BOOST_NOEXCEPT { return (m_pImpl == NULL); }
empty() const481     bool empty() const BOOST_NOEXCEPT { return (m_pImpl == NULL); }
clear()482     void clear() BOOST_NOEXCEPT
483     {
484         if (m_pImpl)
485         {
486             m_pImpl->destroy(m_pImpl);
487             m_pImpl = NULL;
488         }
489     }
490 
swap(this_type & that)491     void swap(this_type& that) BOOST_NOEXCEPT
492     {
493         impl_base* p = m_pImpl;
494         m_pImpl = that.m_pImpl;
495         that.m_pImpl = p;
496     }
497 };
498 
499 #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
500 
501 #define BOOST_PP_FILENAME_1 <boost/log/detail/light_function_pp.hpp>
502 #define BOOST_PP_ITERATION_LIMITS (0, BOOST_LOG_LIGHT_FUNCTION_LIMIT)
503 #include BOOST_PP_ITERATE()
504 
505 #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
506 
507 template< typename SignatureT >
swap(light_function<SignatureT> & left,light_function<SignatureT> & right)508 inline void swap(light_function< SignatureT >& left, light_function< SignatureT >& right)
509 {
510     left.swap(right);
511 }
512 
513 } // namespace aux
514 
515 BOOST_LOG_CLOSE_NAMESPACE // namespace log
516 
517 } // namespace boost
518 
519 #include <boost/log/detail/footer.hpp>
520 
521 #endif // BOOST_LOG_DETAIL_LIGHT_FUNCTION_HPP_INCLUDED_
522