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   counter.hpp
9  * \author Andrey Semashev
10  * \date   01.05.2007
11  *
12  * The header contains implementation of the counter attribute.
13  */
14 
15 #ifndef BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_
16 #define BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_
17 
18 #include <boost/static_assert.hpp>
19 #include <boost/type_traits/is_integral.hpp>
20 #include <boost/log/detail/config.hpp>
21 #include <boost/log/attributes/attribute.hpp>
22 #include <boost/log/attributes/attribute_cast.hpp>
23 #include <boost/log/attributes/attribute_value_impl.hpp>
24 #ifndef BOOST_LOG_NO_THREADS
25 #include <boost/detail/atomic_count.hpp>
26 #endif // BOOST_LOG_NO_THREADS
27 #include <boost/log/detail/header.hpp>
28 
29 #ifdef BOOST_HAS_PRAGMA_ONCE
30 #pragma once
31 #endif
32 
33 namespace boost {
34 
35 BOOST_LOG_OPEN_NAMESPACE
36 
37 namespace attributes {
38 
39 /*!
40  * \brief A class of an attribute that counts an integral value
41  *
42  * This type of attribute acts as a counter, that is, it returns a monotonously
43  * changing value each time requested. The attribute value type can be specified
44  * as a template parameter. However, the type must be an integral type of size no
45  * more than <tt>sizeof(long)</tt>.
46  */
47 template< typename T >
48 class counter :
49     public attribute
50 {
51     //  For now only integral types up to long are supported
52     BOOST_STATIC_ASSERT_MSG(is_integral< T >::value && sizeof(T) <= sizeof(long), "Boost.Log: Only integral types up to long are supported by counter attribute");
53 
54 public:
55     //! A counter value type
56     typedef T value_type;
57 
58 protected:
59     //! Base class for factory implementation
60     class BOOST_LOG_NO_VTABLE BOOST_SYMBOL_VISIBLE impl :
61         public attribute::impl
62     {
63     };
64 
65     //! Generic factory implementation
66     class impl_generic;
67 #ifndef BOOST_LOG_NO_THREADS
68     //! Increment-by-one factory implementation
69     class impl_inc;
70     //! Decrement-by-one factory implementation
71     class impl_dec;
72 #endif
73 
74 public:
75     /*!
76      * Constructor
77      *
78      * \param initial Initial value of the counter
79      * \param step Changing step of the counter. Each value acquired from the attribute
80      *        will be greater than the previous one to this amount.
81      */
counter(value_type initial=(value_type)0,long step=1)82     explicit counter(value_type initial = (value_type)0, long step = 1) :
83 #ifndef BOOST_LOG_NO_THREADS
84         attribute()
85     {
86         if (step == 1)
87             this->set_impl(new impl_inc(initial));
88         else if (step == -1)
89             this->set_impl(new impl_dec(initial));
90         else
91             this->set_impl(new impl_generic(initial, step));
92     }
93 #else
94         attribute(new impl_generic(initial, step))
95     {
96     }
97 #endif
98     /*!
99      * Constructor for casting support
100      */
counter(cast_source const & source)101     explicit counter(cast_source const& source) :
102         attribute(source.as< impl >())
103     {
104     }
105 };
106 
107 #ifndef BOOST_LOG_NO_THREADS
108 
109 template< typename T >
110 class counter< T >::impl_generic :
111     public impl
112 {
113 private:
114     //! Initial value
115     const value_type m_Initial;
116     //! Step value
117     const long m_Step;
118     //! The counter
119     boost::detail::atomic_count m_Counter;
120 
121 public:
122     /*!
123      * Initializing constructor
124      */
impl_generic(value_type initial,long step)125     impl_generic(value_type initial, long step) : m_Initial(initial), m_Step(step), m_Counter(-1)
126     {
127     }
128 
get_value()129     attribute_value get_value()
130     {
131         const unsigned long next_counter = static_cast< unsigned long >(++m_Counter);
132         value_type next = static_cast< value_type >(m_Initial + (next_counter * m_Step));
133         return make_attribute_value(next);
134     }
135 };
136 
137 template< typename T >
138 class counter< T >::impl_inc :
139     public impl
140 {
141 private:
142     //! The counter
143     boost::detail::atomic_count m_Counter;
144 
145 public:
146     /*!
147      * Initializing constructor
148      */
impl_inc(value_type initial)149     explicit impl_inc(value_type initial) : m_Counter(initial - 1)
150     {
151     }
152 
get_value()153     attribute_value get_value()
154     {
155         return make_attribute_value(static_cast< value_type >(++m_Counter));
156     }
157 };
158 
159 template< typename T >
160 class counter< T >::impl_dec :
161     public impl
162 {
163 private:
164     //! The counter
165     boost::detail::atomic_count m_Counter;
166 
167 public:
168     /*!
169      * Initializing constructor
170      */
impl_dec(value_type initial)171     explicit impl_dec(value_type initial) : m_Counter(initial + 1)
172     {
173     }
174 
get_value()175     attribute_value get_value()
176     {
177         return make_attribute_value(static_cast< value_type >(--m_Counter));
178     }
179 };
180 
181 #else // BOOST_LOG_NO_THREADS
182 
183 template< typename T >
184 class counter< T >::impl_generic :
185     public impl
186 {
187 private:
188     //! Step value
189     const long m_Step;
190     //! The counter
191     value_type m_Counter;
192 
193 public:
194     /*!
195      * Initializing constructor
196      */
impl_generic(value_type initial,long step)197     impl_generic(value_type initial, long step) : m_Step(step), m_Counter(initial - step)
198     {
199     }
200 
get_value()201     attribute_value get_value()
202     {
203         m_Counter += m_Step;
204         return make_attribute_value(m_Counter);
205     }
206 };
207 
208 #endif // BOOST_LOG_NO_THREADS
209 
210 } // namespace attributes
211 
212 BOOST_LOG_CLOSE_NAMESPACE // namespace log
213 
214 } // namespace boost
215 
216 #include <boost/log/detail/footer.hpp>
217 
218 #endif // BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_
219