summaryrefslogtreecommitdiff
path: root/boost/log/attributes/counter.hpp
blob: 6cd5bd8ce0ac3bd78a8cdca7304466566db4d27b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
 *          Copyright Andrey Semashev 2007 - 2015.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   counter.hpp
 * \author Andrey Semashev
 * \date   01.05.2007
 *
 * The header contains implementation of the counter attribute.
 */

#ifndef BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_
#define BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_

#include <boost/static_assert.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/log/detail/config.hpp>
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_cast.hpp>
#include <boost/log/attributes/attribute_value_impl.hpp>
#ifndef BOOST_LOG_NO_THREADS
#include <boost/detail/atomic_count.hpp>
#endif // BOOST_LOG_NO_THREADS
#include <boost/log/detail/header.hpp>

#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif

namespace boost {

BOOST_LOG_OPEN_NAMESPACE

namespace attributes {

/*!
 * \brief A class of an attribute that counts an integral value
 *
 * This type of attribute acts as a counter, that is, it returns a monotonously
 * changing value each time requested. The attribute value type can be specified
 * as a template parameter. However, the type must be an integral type of size no
 * more than <tt>sizeof(long)</tt>.
 */
template< typename T >
class counter :
    public attribute
{
    //  For now only integral types up to long are supported
    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");

public:
    //! A counter value type
    typedef T value_type;

protected:
    //! Base class for factory implementation
    class BOOST_LOG_NO_VTABLE BOOST_SYMBOL_VISIBLE impl :
        public attribute::impl
    {
    };

    //! Generic factory implementation
    class impl_generic;
#ifndef BOOST_LOG_NO_THREADS
    //! Increment-by-one factory implementation
    class impl_inc;
    //! Decrement-by-one factory implementation
    class impl_dec;
#endif

public:
    /*!
     * Constructor
     *
     * \param initial Initial value of the counter
     * \param step Changing step of the counter. Each value acquired from the attribute
     *        will be greater than the previous one to this amount.
     */
    explicit counter(value_type initial = (value_type)0, long step = 1) :
#ifndef BOOST_LOG_NO_THREADS
        attribute()
    {
        if (step == 1)
            this->set_impl(new impl_inc(initial));
        else if (step == -1)
            this->set_impl(new impl_dec(initial));
        else
            this->set_impl(new impl_generic(initial, step));
    }
#else
        attribute(new impl_generic(initial, step))
    {
    }
#endif
    /*!
     * Constructor for casting support
     */
    explicit counter(cast_source const& source) :
        attribute(source.as< impl >())
    {
    }
};

#ifndef BOOST_LOG_NO_THREADS

template< typename T >
class counter< T >::impl_generic :
    public impl
{
private:
    //! Initial value
    const value_type m_Initial;
    //! Step value
    const long m_Step;
    //! The counter
    boost::detail::atomic_count m_Counter;

public:
    /*!
     * Initializing constructor
     */
    impl_generic(value_type initial, long step) : m_Initial(initial), m_Step(step), m_Counter(-1)
    {
    }

    attribute_value get_value()
    {
        const unsigned long next_counter = static_cast< unsigned long >(++m_Counter);
        value_type next = static_cast< value_type >(m_Initial + (next_counter * m_Step));
        return make_attribute_value(next);
    }
};

template< typename T >
class counter< T >::impl_inc :
    public impl
{
private:
    //! The counter
    boost::detail::atomic_count m_Counter;

public:
    /*!
     * Initializing constructor
     */
    explicit impl_inc(value_type initial) : m_Counter(initial - 1)
    {
    }

    attribute_value get_value()
    {
        return make_attribute_value(static_cast< value_type >(++m_Counter));
    }
};

template< typename T >
class counter< T >::impl_dec :
    public impl
{
private:
    //! The counter
    boost::detail::atomic_count m_Counter;

public:
    /*!
     * Initializing constructor
     */
    explicit impl_dec(value_type initial) : m_Counter(initial + 1)
    {
    }

    attribute_value get_value()
    {
        return make_attribute_value(static_cast< value_type >(--m_Counter));
    }
};

#else // BOOST_LOG_NO_THREADS

template< typename T >
class counter< T >::impl_generic :
    public impl
{
private:
    //! Step value
    const long m_Step;
    //! The counter
    value_type m_Counter;

public:
    /*!
     * Initializing constructor
     */
    impl_generic(value_type initial, long step) : m_Step(step), m_Counter(initial - step)
    {
    }

    attribute_value get_value()
    {
        m_Counter += m_Step;
        return make_attribute_value(m_Counter);
    }
};

#endif // BOOST_LOG_NO_THREADS

} // namespace attributes

BOOST_LOG_CLOSE_NAMESPACE // namespace log

} // namespace boost

#include <boost/log/detail/footer.hpp>

#endif // BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_