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 value_ref.hpp
9 * \author Andrey Semashev
10 * \date 27.07.2012
11 *
12 * The header contains implementation of a value reference wrapper.
13 */
14
15#ifndef BOOST_LOG_UTILITY_VALUE_REF_HPP_INCLUDED_
16#define BOOST_LOG_UTILITY_VALUE_REF_HPP_INCLUDED_
17
18#include <cstddef>
19#include <iosfwd>
20#include <boost/assert.hpp>
21#include <boost/mpl/if.hpp>
22#include <boost/mpl/eval_if.hpp>
23#include <boost/mpl/is_sequence.hpp>
24#include <boost/mpl/front.hpp>
25#include <boost/mpl/size.hpp>
26#include <boost/mpl/int.hpp>
27#include <boost/mpl/and.hpp>
28#include <boost/mpl/identity.hpp>
29#include <boost/mpl/equal_to.hpp>
30#include <boost/mpl/contains.hpp>
31#include <boost/mpl/index_of.hpp>
32#include <boost/core/explicit_operator_bool.hpp>
33#include <boost/core/addressof.hpp>
34#include <boost/optional/optional_fwd.hpp>
35#include <boost/type_traits/is_void.hpp>
36#include <boost/log/detail/config.hpp>
37#include <boost/log/detail/parameter_tools.hpp>
38#include <boost/log/detail/value_ref_visitation.hpp>
39#include <boost/log/detail/sfinae_tools.hpp>
40#include <boost/log/utility/formatting_ostream_fwd.hpp>
41#include <boost/log/utility/functional/logical.hpp>
42#include <boost/log/utility/functional/bind.hpp>
43#include <boost/log/utility/functional/bind_output.hpp>
44#include <boost/log/utility/functional/bind_to_log.hpp>
45#include <boost/log/utility/manipulators/to_log.hpp>
46#include <boost/log/utility/value_ref_fwd.hpp>
47#include <boost/log/detail/header.hpp>
48
49#ifdef BOOST_HAS_PRAGMA_ONCE
50#pragma once
51#endif
52
53namespace boost {
54
55BOOST_LOG_OPEN_NAMESPACE
56
57namespace aux {
58
59//! The function object applies the function object to the bound visitable object and argument
60template< typename VisitableT, typename FunT >
61struct vistation_invoker
62{
63 typedef typename FunT::result_type result_type;
64
65 vistation_invoker(VisitableT& visitable, result_type const& def_val) : m_visitable(visitable), m_def_val(def_val)
66 {
67 }
68
69 template< typename ArgT >
70 result_type operator() (ArgT const& arg) const
71 {
72 return m_visitable.apply_visitor_or_default(binder1st< FunT, ArgT const& >(FunT(), arg), m_def_val);
73 }
74
75private:
76 VisitableT& m_visitable;
77 result_type m_def_val;
78};
79
80//! Traits for testing type compatibility with the reference wrapper
81struct singular_ref_compatibility_traits
82{
83 template< typename T, typename U >
84 struct is_compatible
85 {
86 BOOST_STATIC_CONSTANT(bool, value = false);
87 };
88 template< typename T >
89 struct is_compatible< T, T >
90 {
91 BOOST_STATIC_CONSTANT(bool, value = true);
92 };
93};
94
95//! Attribute value reference implementation for a single type case
96template< typename T, typename TagT >
97class singular_ref
98{
99public:
100 //! Referenced value type
101 typedef T value_type;
102 //! Tag type
103 typedef TagT tag_type;
104
105protected:
106 //! Traits for testing type compatibility with the reference wrapper
107 typedef singular_ref_compatibility_traits compatibility_traits;
108
109protected:
110 //! Pointer to the value
111 const value_type* m_ptr;
112
113protected:
114 //! Default constructor
115 BOOST_CONSTEXPR singular_ref() BOOST_NOEXCEPT : m_ptr(NULL)
116 {
117 }
118
119 //! Initializing constructor
120 explicit singular_ref(const value_type* p) BOOST_NOEXCEPT : m_ptr(p)
121 {
122 }
123
124public:
125 //! Returns a pointer to the referred value
126 const value_type* operator-> () const BOOST_NOEXCEPT
127 {
128 BOOST_ASSERT(m_ptr != NULL);
129 return m_ptr;
130 }
131
132 //! Returns a pointer to the referred value
133 const value_type* get_ptr() const BOOST_NOEXCEPT
134 {
135 return m_ptr;
136 }
137
138 //! Returns a pointer to the referred value
139 template< typename U >
140 typename boost::enable_if_c< compatibility_traits::is_compatible< value_type, U >::value, const U* >::type get_ptr() const BOOST_NOEXCEPT
141 {
142 return m_ptr;
143 }
144
145 //! Returns a reference to the value
146 value_type const& operator* () const BOOST_NOEXCEPT
147 {
148 BOOST_ASSERT(m_ptr != NULL);
149 return *m_ptr;
150 }
151
152 //! Returns a reference to the value
153 value_type const& get() const BOOST_NOEXCEPT
154 {
155 BOOST_ASSERT(m_ptr != NULL);
156 return *m_ptr;
157 }
158
159 //! Returns a reference to the value
160 template< typename U >
161 typename boost::enable_if_c< compatibility_traits::is_compatible< value_type, U >::value, U const& >::type get() const BOOST_NOEXCEPT
162 {
163 BOOST_ASSERT(m_ptr != NULL);
164 return *m_ptr;
165 }
166
167
168 //! Resets the reference
169 void reset() BOOST_NOEXCEPT
170 {
171 m_ptr = NULL;
172 }
173
174 //! Returns the stored type index
175 static BOOST_CONSTEXPR unsigned int which()
176 {
177 return 0u;
178 }
179
180 //! Swaps two reference wrappers
181 void swap(singular_ref& that) BOOST_NOEXCEPT
182 {
183 const void* p = m_ptr;
184 m_ptr = that.m_ptr;
185 that.m_ptr = p;
186 }
187
188 //! Applies a visitor function object to the referred value
189 template< typename VisitorT >
190 typename VisitorT::result_type apply_visitor(VisitorT visitor) const
191 {
192 BOOST_ASSERT(m_ptr != NULL);
193 return visitor(*m_ptr);
194 }
195
196 //! Applies a visitor function object to the referred value
197 template< typename VisitorT >
198 typename boost::enable_if_c< is_void< typename VisitorT::result_type >::value, bool >::type apply_visitor_optional(VisitorT visitor) const
199 {
200 if (m_ptr)
201 {
202 visitor(*m_ptr);
203 return true;
204 }
205 else
206 return false;
207 }
208
209 //! Applies a visitor function object to the referred value
210 template< typename VisitorT >
211 typename boost::disable_if_c< is_void< typename VisitorT::result_type >::value, optional< typename VisitorT::result_type > >::type apply_visitor_optional(VisitorT visitor) const
212 {
213 typedef optional< typename VisitorT::result_type > result_type;
214 if (m_ptr)
215 return result_type(visitor(*m_ptr));
216 else
217 return result_type();
218 }
219
220 //! Applies a visitor function object to the referred value or returns a default value
221 template< typename VisitorT, typename DefaultT >
222 typename VisitorT::result_type apply_visitor_or_default(VisitorT visitor, DefaultT& def_val) const
223 {
224 if (m_ptr)
225 return visitor(*m_ptr);
226 else
227 return def_val;
228 }
229
230 //! Applies a visitor function object to the referred value or returns a default value
231 template< typename VisitorT, typename DefaultT >
232 typename VisitorT::result_type apply_visitor_or_default(VisitorT visitor, DefaultT const& def_val) const
233 {
234 if (m_ptr)
235 return visitor(*m_ptr);
236 else
237 return def_val;
238 }
239};
240
241//! Traits for testing type compatibility with the reference wrapper
242struct variant_ref_compatibility_traits
243{
244 template< typename T, typename U >
245 struct is_compatible
246 {
247 BOOST_STATIC_CONSTANT(bool, value = (mpl::contains< T, U >::type::value));
248 };
249};
250
251//! Attribute value reference implementation for multiple types case
252template< typename T, typename TagT >
253class variant_ref
254{
255public:
256 //! Referenced value type
257 typedef T value_type;
258 //! Tag type
259 typedef TagT tag_type;
260
261protected:
262 //! Traits for testing type compatibility with the reference wrapper
263 typedef variant_ref_compatibility_traits compatibility_traits;
264
265protected:
266 //! Pointer to the value
267 const void* m_ptr;
268 //! Type index
269 unsigned int m_type_idx;
270
271protected:
272 //! Default constructor
273 BOOST_CONSTEXPR variant_ref() BOOST_NOEXCEPT : m_ptr(NULL), m_type_idx(0u)
274 {
275 }
276
277 //! Initializing constructor
278 template< typename U >
279 explicit variant_ref(const U* p) BOOST_NOEXCEPT : m_ptr(p), m_type_idx(mpl::index_of< value_type, U >::type::value)
280 {
281 }
282
283public:
284 //! Resets the reference
285 void reset() BOOST_NOEXCEPT
286 {
287 m_ptr = NULL;
288 m_type_idx = 0;
289 }
290
291 //! Returns a pointer to the referred value
292 template< typename U >
293 typename boost::enable_if_c< compatibility_traits::is_compatible< value_type, U >::value, const U* >::type get_ptr() const BOOST_NOEXCEPT
294 {
295 if (m_type_idx == static_cast< unsigned int >(mpl::index_of< value_type, U >::type::value))
296 return static_cast< const U* >(m_ptr);
297 else
298 return NULL;
299 }
300
301 //! Returns a reference to the value
302 template< typename U >
303 typename boost::enable_if_c< compatibility_traits::is_compatible< value_type, U >::value, U const& >::type get() const BOOST_NOEXCEPT
304 {
305 const U* const p = get_ptr< U >();
306 BOOST_ASSERT(p != NULL);
307 return *p;
308 }
309
310 //! Returns the stored type index
311 unsigned int which() const BOOST_NOEXCEPT
312 {
313 return m_type_idx;
314 }
315
316 //! Swaps two reference wrappers
317 void swap(variant_ref& that) BOOST_NOEXCEPT
318 {
319 const void* p = m_ptr;
320 m_ptr = that.m_ptr;
321 that.m_ptr = p;
322 unsigned int type_idx = m_type_idx;
323 m_type_idx = that.m_type_idx;
324 that.m_type_idx = type_idx;
325 }
326
327 //! Applies a visitor function object to the referred value
328 template< typename VisitorT >
329 typename VisitorT::result_type apply_visitor(VisitorT visitor) const
330 {
331 BOOST_ASSERT(m_ptr != NULL);
332 return do_apply_visitor(visitor);
333 }
334
335 //! Applies a visitor function object to the referred value
336 template< typename VisitorT >
337 typename boost::enable_if_c< is_void< typename VisitorT::result_type >::value, bool >::type apply_visitor_optional(VisitorT visitor) const
338 {
339 if (m_ptr)
340 {
341 do_apply_visitor(visitor);
342 return true;
343 }
344 else
345 return false;
346 }
347
348 //! Applies a visitor function object to the referred value
349 template< typename VisitorT >
350 typename boost::disable_if_c< is_void< typename VisitorT::result_type >::value, optional< typename VisitorT::result_type > >::type apply_visitor_optional(VisitorT visitor) const
351 {
352 typedef optional< typename VisitorT::result_type > result_type;
353 if (m_ptr)
354 return result_type(do_apply_visitor(visitor));
355 else
356 return result_type();
357 }
358
359 //! Applies a visitor function object to the referred value or returns a default value
360 template< typename VisitorT, typename DefaultT >
361 typename VisitorT::result_type apply_visitor_or_default(VisitorT visitor, DefaultT& def_val) const
362 {
363 if (m_ptr)
364 return do_apply_visitor(visitor);
365 else
366 return def_val;
367 }
368
369 //! Applies a visitor function object to the referred value or returns a default value
370 template< typename VisitorT, typename DefaultT >
371 typename VisitorT::result_type apply_visitor_or_default(VisitorT visitor, DefaultT const& def_val) const
372 {
373 if (m_ptr)
374 return do_apply_visitor(visitor);
375 else
376 return def_val;
377 }
378
379private:
380 template< typename VisitorT >
381 typename VisitorT::result_type do_apply_visitor(VisitorT& visitor) const
382 {
383 BOOST_ASSERT(m_type_idx < static_cast< unsigned int >(mpl::size< value_type >::value));
384 return apply_visitor_dispatch< value_type, VisitorT >::call(m_ptr, m_type_idx, visitor);
385 }
386};
387
388template< typename T, typename TagT >
389struct value_ref_base
390{
391 typedef typename mpl::eval_if<
392 mpl::and_< mpl::is_sequence< T >, mpl::equal_to< mpl::size< T >, mpl::int_< 1 > > >,
393 mpl::front< T >,
394 mpl::identity< T >
395 >::type value_type;
396
397 typedef typename mpl::if_<
398 mpl::is_sequence< value_type >,
399 variant_ref< value_type, TagT >,
400 singular_ref< value_type, TagT >
401 >::type type;
402};
403
404} // namespace aux
405
406/*!
407 * \brief Reference wrapper for a stored attribute value.
408 *
409 * The \c value_ref class template provides access to the stored attribute value. It is not a traditional reference wrapper
410 * since it may be empty (i.e. refer to no value at all) and it can also refer to values of different types. Therefore its
411 * interface and behavior combines features of Boost.Ref, Boost.Optional and Boost.Variant, depending on the use case.
412 *
413 * The template parameter \c T can be a single type or an MPL sequence of possible types being referred. The reference wrapper
414 * will act as either an optional reference or an optional variant of references to the specified types. In any case, the
415 * referred values will not be modifiable (i.e. \c value_ref always models a const reference).
416 *
417 * Template parameter \c TagT is optional. It can be used for customizing the operations on this reference wrapper, such as
418 * putting the referred value to log.
419 */
420template< typename T, typename TagT >
421class value_ref :
422 public aux::value_ref_base< T, TagT >::type
423{
424#ifndef BOOST_LOG_DOXYGEN_PASS
425public:
426 typedef void _has_basic_formatting_ostream_insert_operator;
427#endif
428
429private:
430 //! Base implementation type
431 typedef typename aux::value_ref_base< T, TagT >::type base_type;
432 //! Traits for testing type compatibility with the reference wrapper
433 typedef typename base_type::compatibility_traits compatibility_traits;
434
435public:
436#ifndef BOOST_LOG_DOXYGEN_PASS
437 //! Referenced value type
438 typedef typename base_type::value_type value_type;
439#else
440 //! Referenced value type
441 typedef T value_type;
442 //! Tag type
443 typedef TagT tag_type;
444#endif
445
446public:
447 /*!
448 * Default constructor. Creates a reference wrapper that does not refer to a value.
449 */
450 BOOST_DEFAULTED_FUNCTION(BOOST_CONSTEXPR value_ref(), BOOST_NOEXCEPT {})
451
452 /*!
453 * Initializing constructor. Creates a reference wrapper that refers to the specified value.
454 */
455 template< typename U >
456 explicit value_ref(U const& val
457#ifndef BOOST_LOG_DOXYGEN_PASS
458// MSVC-8 can't handle SFINAE in this case properly and often wrongly disables this constructor
459#if !defined(BOOST_MSVC) || BOOST_MSVC >= 1500
460 , typename boost::enable_if_c< compatibility_traits::BOOST_NESTED_TEMPLATE is_compatible< value_type, U >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()
461#endif
462#endif
463 ) BOOST_NOEXCEPT :
464 base_type(boost::addressof(val))
465 {
466 }
467
468 /*!
469 * The operator verifies if the wrapper refers to a value.
470 */
471 BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
472
473 /*!
474 * The operator verifies if the wrapper does not refer to a value.
475 */
476 bool operator! () const BOOST_NOEXCEPT
477 {
478 return !this->m_ptr;
479 }
480
481 /*!
482 * \return \c true if the wrapper does not refer to a value.
483 */
484 bool empty() const BOOST_NOEXCEPT
485 {
486 return !this->m_ptr;
487 }
488
489 /*!
490 * Swaps two reference wrappers
491 */
492 void swap(value_ref& that) BOOST_NOEXCEPT
493 {
494 base_type::swap(that);
495 }
496};
497
498//! Free swap function
499template< typename T, typename TagT >
500inline void swap(value_ref< T, TagT >& left, value_ref< T, TagT >& right)
501{
502 left.swap(right);
503}
504
505//! Stream output operator
506template< typename CharT, typename TraitsT, typename T, typename TagT >
507inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, value_ref< T, TagT > const& val)
508{
509 if (!!val)
510 val.apply_visitor(boost::log::bind_output(strm));
511 return strm;
512}
513
514//! Log formatting operator
515template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename TagT >
516inline basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, value_ref< T, TagT > const& val)
517{
518 if (!!val)
519 val.apply_visitor(boost::log::bind_to_log< TagT >(strm));
520 return strm;
521}
522
523// Equality comparison
524template< typename T, typename TagT, typename U >
525inline bool operator== (value_ref< T, TagT > const& left, U const& right)
526{
527 return left.apply_visitor_or_default(binder2nd< equal_to, U const& >(equal_to(), right), false);
528}
529
530template< typename U, typename T, typename TagT >
531inline bool operator== (U const& left, value_ref< T, TagT > const& right)
532{
533 return right.apply_visitor_or_default(binder1st< equal_to, U const& >(equal_to(), left), false);
534}
535
536template< typename T1, typename TagT1, typename T2, typename TagT2 >
537inline bool operator== (value_ref< T1, TagT1 > const& left, value_ref< T2, TagT2 > const& right)
538{
539 if (!left && !right)
540 return true;
541 return left.apply_visitor_or_default(aux::vistation_invoker< value_ref< T2, TagT2 >, equal_to >(right, false), false);
542}
543
544// Inequality comparison
545template< typename T, typename TagT, typename U >
546inline bool operator!= (value_ref< T, TagT > const& left, U const& right)
547{
548 return left.apply_visitor_or_default(binder2nd< not_equal_to, U const& >(not_equal_to(), right), false);
549}
550
551template< typename U, typename T, typename TagT >
552inline bool operator!= (U const& left, value_ref< T, TagT > const& right)
553{
554 return right.apply_visitor_or_default(binder1st< not_equal_to, U const& >(not_equal_to(), left), false);
555}
556
557template< typename T1, typename TagT1, typename T2, typename TagT2 >
558inline bool operator!= (value_ref< T1, TagT1 > const& left, value_ref< T2, TagT2 > const& right)
559{
560 if (!left && !right)
561 return false;
562 return left.apply_visitor_or_default(aux::vistation_invoker< value_ref< T2, TagT2 >, not_equal_to >(right, false), false);
563}
564
565// Less than ordering
566template< typename T, typename TagT, typename U >
567inline bool operator< (value_ref< T, TagT > const& left, U const& right)
568{
569 return left.apply_visitor_or_default(binder2nd< less, U const& >(less(), right), false);
570}
571
572template< typename U, typename T, typename TagT >
573inline bool operator< (U const& left, value_ref< T, TagT > const& right)
574{
575 return right.apply_visitor_or_default(binder1st< less, U const& >(less(), left), false);
576}
577
578template< typename T1, typename TagT1, typename T2, typename TagT2 >
579inline bool operator< (value_ref< T1, TagT1 > const& left, value_ref< T2, TagT2 > const& right)
580{
581 return left.apply_visitor_or_default(aux::vistation_invoker< value_ref< T2, TagT2 >, less >(right, false), false);
582}
583
584// Greater than ordering
585template< typename T, typename TagT, typename U >
586inline bool operator> (value_ref< T, TagT > const& left, U const& right)
587{
588 return left.apply_visitor_or_default(binder2nd< greater, U const& >(greater(), right), false);
589}
590
591template< typename U, typename T, typename TagT >
592inline bool operator> (U const& left, value_ref< T, TagT > const& right)
593{
594 return right.apply_visitor_or_default(binder1st< greater, U const& >(greater(), left), false);
595}
596
597template< typename T1, typename TagT1, typename T2, typename TagT2 >
598inline bool operator> (value_ref< T1, TagT1 > const& left, value_ref< T2, TagT2 > const& right)
599{
600 return left.apply_visitor_or_default(aux::vistation_invoker< value_ref< T2, TagT2 >, greater >(right, false), false);
601}
602
603// Less or equal ordering
604template< typename T, typename TagT, typename U >
605inline bool operator<= (value_ref< T, TagT > const& left, U const& right)
606{
607 return left.apply_visitor_or_default(binder2nd< less_equal, U const& >(less_equal(), right), false);
608}
609
610template< typename U, typename T, typename TagT >
611inline bool operator<= (U const& left, value_ref< T, TagT > const& right)
612{
613 return right.apply_visitor_or_default(binder1st< less_equal, U const& >(less_equal(), left), false);
614}
615
616template< typename T1, typename TagT1, typename T2, typename TagT2 >
617inline bool operator<= (value_ref< T1, TagT1 > const& left, value_ref< T2, TagT2 > const& right)
618{
619 if (!left && !right)
620 return true;
621 return left.apply_visitor_or_default(aux::vistation_invoker< value_ref< T2, TagT2 >, less_equal >(right, false), false);
622}
623
624// Greater or equal ordering
625template< typename T, typename TagT, typename U >
626inline bool operator>= (value_ref< T, TagT > const& left, U const& right)
627{
628 return left.apply_visitor_or_default(binder2nd< greater_equal, U const& >(greater_equal(), right), false);
629}
630
631template< typename U, typename T, typename TagT >
632inline bool operator>= (U const& left, value_ref< T, TagT > const& right)
633{
634 return right.apply_visitor_or_default(binder1st< greater_equal, U const& >(greater_equal(), left), false);
635}
636
637template< typename T1, typename TagT1, typename T2, typename TagT2 >
638inline bool operator>= (value_ref< T1, TagT1 > const& left, value_ref< T2, TagT2 > const& right)
639{
640 if (!left && !right)
641 return true;
642 return left.apply_visitor_or_default(aux::vistation_invoker< value_ref< T2, TagT2 >, greater_equal >(right, false), false);
643}
644
645BOOST_LOG_CLOSE_NAMESPACE // namespace log
646
647} // namespace boost
648
649#include <boost/log/detail/footer.hpp>
650
651#endif // BOOST_LOG_UTILITY_VALUE_REF_HPP_INCLUDED_
652

source code of boost/libs/log/include/boost/log/utility/value_ref.hpp