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   record_view.hpp
9  * \author Andrey Semashev
10  * \date   09.03.2009
11  *
12  * This header contains a logging record view class definition.
13  */
14 
15 #ifndef BOOST_LOG_CORE_RECORD_VIEW_HPP_INCLUDED_
16 #define BOOST_LOG_CORE_RECORD_VIEW_HPP_INCLUDED_
17 
18 #include <boost/smart_ptr/intrusive_ptr.hpp>
19 #include <boost/move/core.hpp>
20 #include <boost/move/utility_core.hpp>
21 #include <boost/log/detail/config.hpp>
22 #include <boost/utility/explicit_operator_bool.hpp>
23 #include <boost/log/attributes/attribute_value_set.hpp>
24 #include <boost/log/expressions/keyword_fwd.hpp>
25 #ifndef BOOST_LOG_NO_THREADS
26 #include <boost/detail/atomic_count.hpp>
27 #endif // BOOST_LOG_NO_THREADS
28 #include <boost/log/detail/header.hpp>
29 
30 #ifdef BOOST_HAS_PRAGMA_ONCE
31 #pragma once
32 #endif
33 
34 namespace boost {
35 
36 BOOST_LOG_OPEN_NAMESPACE
37 
38 #ifndef BOOST_LOG_DOXYGEN_PASS
39 class core;
40 class record;
41 #endif // BOOST_LOG_DOXYGEN_PASS
42 
43 /*!
44  * \brief Logging record view class
45  *
46  * The logging record encapsulates all information related to a single logging statement,
47  * in particular, attribute values view and the log message string. The view is immutable,
48  * it is implemented as a wrapper around a reference-counted implementation.
49  */
50 class record_view
51 {
52     BOOST_COPYABLE_AND_MOVABLE(record_view)
53 
54     friend class core;
55     friend class record;
56 
57 #ifndef BOOST_LOG_DOXYGEN_PASS
58 private:
59     //! Private data
60     struct private_data;
61     friend struct private_data;
62 
63     //! Publicly available record data
64     struct public_data
65     {
66         //! Reference counter
67 #ifndef BOOST_LOG_NO_THREADS
68         mutable boost::detail::atomic_count m_ref_counter;
69 #else
70         mutable unsigned int m_ref_counter;
71 #endif // BOOST_LOG_NO_THREADS
72 
73         //! Attribute values view
74         attribute_value_set m_attribute_values;
75 
76         //! Constructor from the attribute value set
public_databoost::record_view::public_data77         explicit public_data(BOOST_RV_REF(attribute_value_set) values) BOOST_NOEXCEPT :
78             m_ref_counter(1),
79             m_attribute_values(boost::move(values))
80         {
81         }
82 
83         //! Destructor
84         BOOST_LOG_API static void destroy(const public_data* p) BOOST_NOEXCEPT;
85 
86     protected:
~public_databoost::record_view::public_data87         ~public_data() {}
88 
89         BOOST_DELETED_FUNCTION(public_data(public_data const&))
BOOST_DELETED_FUNCTION(public_data & operator=(public_data const &))90         BOOST_DELETED_FUNCTION(public_data& operator= (public_data const&))
91 
92         friend void intrusive_ptr_add_ref(const public_data* p) BOOST_NOEXCEPT { ++p->m_ref_counter; }
intrusive_ptr_release(const public_data * p)93         friend void intrusive_ptr_release(const public_data* p) BOOST_NOEXCEPT { if (--p->m_ref_counter == 0) public_data::destroy(p); }
94     };
95 
96 private:
97     //! A pointer to the log record implementation
98     intrusive_ptr< public_data > m_impl;
99 
100 private:
101     //  A private constructor, accessible from record
record_view(public_data * impl)102     explicit record_view(public_data* impl) BOOST_NOEXCEPT : m_impl(impl, false) {}
103 
104 #endif // BOOST_LOG_DOXYGEN_PASS
105 
106 public:
107     /*!
108      * Default constructor. Creates an empty record view that is equivalent to the invalid record handle.
109      *
110      * \post <tt>!*this == true</tt>
111      */
112     BOOST_CONSTEXPR record_view() BOOST_NOEXCEPT
113 #if !defined(BOOST_LOG_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS)
114         = default;
115 #else
116     {}
117 #endif
118 
119     /*!
120      * Copy constructor
121      */
record_view(record_view const & that)122     record_view(record_view const& that) BOOST_NOEXCEPT : m_impl(that.m_impl) {}
123 
124     /*!
125      * Move constructor. Source record contents unspecified after the operation.
126      */
record_view(BOOST_RV_REF (record_view)that)127     record_view(BOOST_RV_REF(record_view) that) BOOST_NOEXCEPT
128     {
129         m_impl.swap(that.m_impl);
130     }
131 
132     /*!
133      * Destructor. Destroys the record, releases any sinks and attribute values that were involved in processing this record.
134      */
~record_view()135     ~record_view() BOOST_NOEXCEPT {}
136 
137     /*!
138      * Copy assignment
139      */
operator =(BOOST_COPY_ASSIGN_REF (record_view)that)140     record_view& operator= (BOOST_COPY_ASSIGN_REF(record_view) that) BOOST_NOEXCEPT
141     {
142         m_impl = that.m_impl;
143         return *this;
144     }
145 
146     /*!
147      * Move assignment. Source record contents unspecified after the operation.
148      */
operator =(BOOST_RV_REF (record_view)that)149     record_view& operator= (BOOST_RV_REF(record_view) that) BOOST_NOEXCEPT
150     {
151         m_impl.swap(that.m_impl);
152         return *this;
153     }
154 
155     /*!
156      * \return A reference to the set of attribute values attached to this record
157      *
158      * \pre <tt>!!*this</tt>
159      */
attribute_values() const160     attribute_value_set const& attribute_values() const BOOST_NOEXCEPT
161     {
162         return m_impl->m_attribute_values;
163     }
164 
165     /*!
166      * Equality comparison
167      *
168      * \param that Comparand
169      * \return \c true if both <tt>*this</tt> and \a that identify the same log record or both do not
170      *         identify any record, \c false otherwise.
171      */
operator ==(record_view const & that) const172     bool operator== (record_view const& that) const BOOST_NOEXCEPT
173     {
174         return m_impl == that.m_impl;
175     }
176 
177     /*!
178      * Inequality comparison
179      *
180      * \param that Comparand
181      * \return <tt>!(*this == that)</tt>
182      */
operator !=(record_view const & that) const183     bool operator!= (record_view const& that) const BOOST_NOEXCEPT
184     {
185         return !operator== (that);
186     }
187 
188     /*!
189      * Conversion to an unspecified boolean type
190      *
191      * \return \c true, if the <tt>*this</tt> identifies a log record, \c false, if the <tt>*this</tt> is not valid
192      */
193     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
194 
195     /*!
196      * Inverted conversion to an unspecified boolean type
197      *
198      * \return \c false, if the <tt>*this</tt> identifies a log record, \c true, if the <tt>*this</tt> is not valid
199      */
200     bool operator! () const BOOST_NOEXCEPT
201     {
202         return !m_impl;
203     }
204 
205     /*!
206      * Swaps two handles
207      *
208      * \param that Another record to swap with
209      * <b>Throws:</b> Nothing
210      */
swap(record_view & that)211     void swap(record_view& that) BOOST_NOEXCEPT
212     {
213         m_impl.swap(that.m_impl);
214     }
215 
216     /*!
217      * Resets the log record handle. If there are no other handles left, the log record is closed
218      * and all resources referenced by the record are released.
219      *
220      * \post <tt>!*this == true</tt>
221      */
reset()222     void reset() BOOST_NOEXCEPT
223     {
224         m_impl.reset();
225     }
226 
227     /*!
228      * Attribute value lookup.
229      *
230      * \param name Attribute name.
231      * \return An \c attribute_value, non-empty if it is found, empty otherwise.
232      */
operator [](attribute_value_set::key_type name) const233     attribute_value_set::mapped_type operator[] (attribute_value_set::key_type name) const
234     {
235         return m_impl->m_attribute_values[name];
236     }
237 
238     /*!
239      * Attribute value lookup.
240      *
241      * \param keyword Attribute keyword.
242      * \return A \c value_ref with extracted attribute value if it is found, empty \c value_ref otherwise.
243      */
244     template< typename DescriptorT, template< typename > class ActorT >
245     typename result_of::extract< typename expressions::attribute_keyword< DescriptorT, ActorT >::value_type, DescriptorT >::type
operator [](expressions::attribute_keyword<DescriptorT,ActorT> const & keyword) const246     operator[] (expressions::attribute_keyword< DescriptorT, ActorT > const& keyword) const
247     {
248         return m_impl->m_attribute_values[keyword];
249     }
250 };
251 
252 /*!
253  * A free-standing swap function overload for \c record_view
254  */
swap(record_view & left,record_view & right)255 inline void swap(record_view& left, record_view& right) BOOST_NOEXCEPT
256 {
257     left.swap(right);
258 }
259 
260 BOOST_LOG_CLOSE_NAMESPACE // namespace log
261 
262 } // namespace boost
263 
264 #include <boost/log/detail/footer.hpp>
265 
266 #endif // BOOST_LOG_CORE_RECORD_VIEW_HPP_INCLUDED_
267