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 template<
9     typename ResultT
10     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), typename ArgT)
11 >
12 class light_function< ResultT (BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), ArgT)) >
13 {
14     typedef light_function this_type;
15     BOOST_COPYABLE_AND_MOVABLE(this_type)
16 
17 public:
18     typedef ResultT result_type;
19 
20 private:
21     struct impl_base
22     {
23         typedef result_type (*invoke_type)(void* BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), ArgT));
24         const invoke_type invoke;
25 
26         typedef impl_base* (*clone_type)(const void*);
27         const clone_type clone;
28 
29         typedef void (*destroy_type)(void*);
30         const destroy_type destroy;
31 
impl_baselight_function::impl_base32         impl_base(invoke_type inv, clone_type cl, destroy_type dstr) : invoke(inv), clone(cl), destroy(dstr)
33         {
34         }
35 
36         BOOST_DELETED_FUNCTION(impl_base(impl_base const&))
37         BOOST_DELETED_FUNCTION(impl_base& operator= (impl_base const&))
38     };
39 
40 #if !defined(BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS)
41     template< typename FunT >
42     class impl;
43     template< typename FunT >
44     friend class impl;
45 #endif
46 
47     template< typename FunT >
48     class impl :
49         public impl_base
50     {
51         typedef impl< FunT > this_type;
52 
53         FunT m_Function;
54 
55     public:
impl(FunT const & fun)56         explicit impl(FunT const& fun) :
57             impl_base(&this_type::invoke_impl, &this_type::clone_impl, &this_type::destroy_impl),
58             m_Function(fun)
59         {
60         }
61 
62 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
impl(FunT && fun)63         explicit impl(FunT&& fun) :
64             impl_base(&this_type::invoke_impl, &this_type::clone_impl, &this_type::destroy_impl),
65             m_Function(boost::move(fun))
66         {
67         }
68 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
69 
destroy_impl(void * self)70         static void destroy_impl(void* self)
71         {
72             delete static_cast< impl* >(static_cast< impl_base* >(self));
73         }
clone_impl(const void * self)74         static impl_base* clone_impl(const void* self)
75         {
76             return new impl(static_cast< const impl* >(static_cast< const impl_base* >(self))->m_Function);
77         }
invoke_impl(void * self BOOST_PP_ENUM_TRAILING_BINARY_PARAMS (BOOST_PP_ITERATION (),ArgT,arg))78         static result_type invoke_impl(void* self BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PP_ITERATION(), ArgT, arg))
79         {
80             return static_cast< impl* >(static_cast< impl_base* >(self))->m_Function(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), arg));
81         }
82 
83         BOOST_DELETED_FUNCTION(impl(impl const&))
84         BOOST_DELETED_FUNCTION(impl& operator= (impl const&))
85     };
86 
87 private:
88     impl_base* m_pImpl;
89 
90 public:
light_function()91     BOOST_CONSTEXPR light_function() BOOST_NOEXCEPT : m_pImpl(NULL)
92     {
93     }
light_function(this_type const & that)94     light_function(this_type const& that)
95     {
96         if (that.m_pImpl)
97             m_pImpl = that.m_pImpl->clone(that.m_pImpl);
98         else
99             m_pImpl = NULL;
100     }
101 
light_function(BOOST_RV_REF (this_type)that)102     light_function(BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
103     {
104         m_pImpl = that.m_pImpl;
105         that.m_pImpl = NULL;
106     }
107 
light_function(BOOST_RV_REF (const this_type)that)108     light_function(BOOST_RV_REF(const this_type) that) BOOST_NOEXCEPT
109     {
110         m_pImpl = that.m_pImpl;
111         ((this_type&)that).m_pImpl = NULL;
112     }
113 
114 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
115     template< typename FunT >
light_function(FunT && fun)116     light_function(FunT&& fun) :
117         m_pImpl(new impl< typename remove_cv< typename remove_reference< FunT >::type >::type >(boost::forward< FunT >(fun)))
118     {
119     }
120 #else
121     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 ())122     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()) :
123         m_pImpl(new impl< FunT >(fun))
124     {
125     }
126     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 ())127     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()) :
128         m_pImpl(new impl< typename remove_cv< FunT >::type >(fun))
129     {
130     }
131 #endif
132 
133     //! Constructor from NULL
134 #if !defined(BOOST_NO_CXX11_NULLPTR)
light_function(std::nullptr_t)135     BOOST_CONSTEXPR light_function(std::nullptr_t) BOOST_NOEXCEPT
136 #else
137     BOOST_CONSTEXPR light_function(int p) BOOST_NOEXCEPT
138 #endif
139         : m_pImpl(NULL)
140     {
141 #if defined(BOOST_NO_CXX11_NULLPTR)
142         BOOST_ASSERT(p == 0);
143 #endif
144     }
~light_function()145     ~light_function()
146     {
147         clear();
148     }
149 
operator =(BOOST_RV_REF (this_type)that)150     light_function& operator= (BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
151     {
152         this->swap(that);
153         return *this;
154     }
operator =(BOOST_COPY_ASSIGN_REF (this_type)that)155     light_function& operator= (BOOST_COPY_ASSIGN_REF(this_type) that)
156     {
157         light_function tmp = static_cast< this_type const& >(that);
158         this->swap(tmp);
159         return *this;
160     }
161     //! Assignment of NULL
162 #if !defined(BOOST_NO_CXX11_NULLPTR)
operator =(std::nullptr_t)163     light_function& operator= (std::nullptr_t)
164 #else
165     light_function& operator= (int p)
166 #endif
167     {
168 #if defined(BOOST_NO_CXX11_NULLPTR)
169         BOOST_ASSERT(p == 0);
170 #endif
171         clear();
172         return *this;
173     }
174 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
175     template< typename FunT >
operator =(FunT && fun)176     light_function& operator= (FunT&& fun)
177     {
178         light_function tmp(boost::forward< FunT >(fun));
179         this->swap(tmp);
180         return *this;
181     }
182 #else
183     template< typename FunT >
184     typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type
operator =(FunT const & fun)185     operator= (FunT const& fun)
186     {
187         light_function tmp(fun);
188         this->swap(tmp);
189         return *this;
190     }
191 #endif
192 
operator ()(BOOST_PP_ENUM_BINARY_PARAMS (BOOST_PP_ITERATION (),ArgT,arg)) const193     result_type operator() (BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), ArgT, arg)) const
194     {
195         return m_pImpl->invoke(m_pImpl BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), arg));
196     }
197 
198     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
199     bool operator! () const BOOST_NOEXCEPT { return (m_pImpl == NULL); }
empty() const200     bool empty() const BOOST_NOEXCEPT { return (m_pImpl == NULL); }
clear()201     void clear() BOOST_NOEXCEPT
202     {
203         if (m_pImpl)
204         {
205             m_pImpl->destroy(m_pImpl);
206             m_pImpl = NULL;
207         }
208     }
209 
swap(this_type & that)210     void swap(this_type& that) BOOST_NOEXCEPT
211     {
212         impl_base* p = m_pImpl;
213         m_pImpl = that.m_pImpl;
214         that.m_pImpl = p;
215     }
216 };
217 
218 template<
219     BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), typename ArgT)
220 >
221 class light_function< void (BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), ArgT)) >
222 {
223     typedef light_function this_type;
224     BOOST_COPYABLE_AND_MOVABLE(this_type)
225 
226 public:
227     typedef void result_type;
228 
229 private:
230     struct impl_base
231     {
232         typedef void (*invoke_type)(void* BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), ArgT));
233         const invoke_type invoke;
234 
235         typedef impl_base* (*clone_type)(const void*);
236         const clone_type clone;
237 
238         typedef void (*destroy_type)(void*);
239         const destroy_type destroy;
240 
impl_baselight_function::impl_base241         impl_base(invoke_type inv, clone_type cl, destroy_type dstr) : invoke(inv), clone(cl), destroy(dstr)
242         {
243         }
244 
245         BOOST_DELETED_FUNCTION(impl_base(impl_base const&))
246         BOOST_DELETED_FUNCTION(impl_base& operator= (impl_base const&))
247     };
248 
249 #if !defined(BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS)
250     template< typename FunT >
251     class impl;
252     template< typename FunT >
253     friend class impl;
254 #endif
255 
256     template< typename FunT >
257     class impl :
258         public impl_base
259     {
260         typedef impl< FunT > this_type;
261 
262         FunT m_Function;
263 
264     public:
impl(FunT const & fun)265         explicit impl(FunT const& fun) :
266             impl_base(&this_type::invoke_impl, &this_type::clone_impl, &this_type::destroy_impl),
267             m_Function(fun)
268         {
269         }
270 
271 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
impl(FunT && fun)272         explicit impl(FunT&& fun) :
273             impl_base(&this_type::invoke_impl, &this_type::clone_impl, &this_type::destroy_impl),
274             m_Function(boost::move(fun))
275         {
276         }
277 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
278 
destroy_impl(void * self)279         static void destroy_impl(void* self)
280         {
281             delete static_cast< impl* >(static_cast< impl_base* >(self));
282         }
clone_impl(const void * self)283         static impl_base* clone_impl(const void* self)
284         {
285             return new impl(static_cast< const impl* >(static_cast< const impl_base* >(self))->m_Function);
286         }
invoke_impl(void * self BOOST_PP_ENUM_TRAILING_BINARY_PARAMS (BOOST_PP_ITERATION (),ArgT,arg))287         static result_type invoke_impl(void* self BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PP_ITERATION(), ArgT, arg))
288         {
289             static_cast< impl* >(static_cast< impl_base* >(self))->m_Function(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), arg));
290         }
291 
292         BOOST_DELETED_FUNCTION(impl(impl const&))
293         BOOST_DELETED_FUNCTION(impl& operator= (impl const&))
294     };
295 
296 private:
297     impl_base* m_pImpl;
298 
299 public:
light_function()300     BOOST_CONSTEXPR light_function() BOOST_NOEXCEPT : m_pImpl(NULL)
301     {
302     }
light_function(this_type const & that)303     light_function(this_type const& that)
304     {
305         if (that.m_pImpl)
306             m_pImpl = that.m_pImpl->clone(that.m_pImpl);
307         else
308             m_pImpl = NULL;
309     }
light_function(BOOST_RV_REF (this_type)that)310     light_function(BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
311     {
312         m_pImpl = that.m_pImpl;
313         that.m_pImpl = NULL;
314     }
315 
light_function(BOOST_RV_REF (const this_type)that)316     light_function(BOOST_RV_REF(const this_type) that) BOOST_NOEXCEPT
317     {
318         m_pImpl = that.m_pImpl;
319         ((this_type&)that).m_pImpl = NULL;
320     }
321 
322 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
323     template< typename FunT >
light_function(FunT && fun)324     light_function(FunT&& fun) :
325         m_pImpl(new impl< typename remove_cv< typename remove_reference< FunT >::type >::type >(boost::forward< FunT >(fun)))
326     {
327     }
328 #else
329     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 ())330     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()) :
331         m_pImpl(new impl< FunT >(fun))
332     {
333     }
334     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 ())335     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()) :
336         m_pImpl(new impl< typename remove_cv< FunT >::type >(fun))
337     {
338     }
339 #endif
340 
341     //! Constructor from NULL
342 #if !defined(BOOST_NO_CXX11_NULLPTR)
light_function(std::nullptr_t)343     BOOST_CONSTEXPR light_function(std::nullptr_t) BOOST_NOEXCEPT
344 #else
345     BOOST_CONSTEXPR light_function(int p) BOOST_NOEXCEPT
346 #endif
347         : m_pImpl(NULL)
348     {
349 #if defined(BOOST_NO_CXX11_NULLPTR)
350         BOOST_ASSERT(p == 0);
351 #endif
352     }
~light_function()353     ~light_function()
354     {
355         clear();
356     }
357 
operator =(BOOST_RV_REF (this_type)that)358     light_function& operator= (BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
359     {
360         this->swap(that);
361         return *this;
362     }
operator =(BOOST_COPY_ASSIGN_REF (this_type)that)363     light_function& operator= (BOOST_COPY_ASSIGN_REF(this_type) that)
364     {
365         light_function tmp = static_cast< this_type const& >(that);
366         this->swap(tmp);
367         return *this;
368     }
369     //! Assignment of NULL
370 #if !defined(BOOST_NO_CXX11_NULLPTR)
operator =(std::nullptr_t)371     light_function& operator= (std::nullptr_t)
372 #else
373     light_function& operator= (int p)
374 #endif
375     {
376 #if defined(BOOST_NO_CXX11_NULLPTR)
377         BOOST_ASSERT(p == 0);
378 #endif
379         clear();
380         return *this;
381     }
382 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
383     template< typename FunT >
operator =(FunT && fun)384     light_function& operator= (FunT&& fun)
385     {
386         light_function tmp(boost::forward< FunT >(fun));
387         this->swap(tmp);
388         return *this;
389     }
390 #else
391     template< typename FunT >
392     typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type
operator =(FunT const & fun)393     operator= (FunT const& fun)
394     {
395         light_function tmp(fun);
396         this->swap(tmp);
397         return *this;
398     }
399 #endif
400 
operator ()(BOOST_PP_ENUM_BINARY_PARAMS (BOOST_PP_ITERATION (),ArgT,arg)) const401     result_type operator() (BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), ArgT, arg)) const
402     {
403         m_pImpl->invoke(m_pImpl BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), arg));
404     }
405 
406     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
407     bool operator! () const BOOST_NOEXCEPT { return (m_pImpl == NULL); }
empty() const408     bool empty() const BOOST_NOEXCEPT { return (m_pImpl == NULL); }
clear()409     void clear() BOOST_NOEXCEPT
410     {
411         if (m_pImpl)
412         {
413             m_pImpl->destroy(m_pImpl);
414             m_pImpl = NULL;
415         }
416     }
417 
swap(this_type & that)418     void swap(this_type& that) BOOST_NOEXCEPT
419     {
420         impl_base* p = m_pImpl;
421         m_pImpl = that.m_pImpl;
422         that.m_pImpl = p;
423     }
424 };
425