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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
|
/*
* 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 format.hpp
* \author Andrey Semashev
* \date 15.11.2012
*
* \brief This header is the Boost.Log library implementation, see the library documentation
* at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
*/
#ifndef BOOST_LOG_DETAIL_FORMAT_HPP_INCLUDED_
#define BOOST_LOG_DETAIL_FORMAT_HPP_INCLUDED_
#include <string>
#include <vector>
#include <iosfwd>
#include <boost/assert.hpp>
#include <boost/move/core.hpp>
#include <boost/move/utility.hpp>
#include <boost/log/detail/config.hpp>
#include <boost/log/detail/unhandled_exception_count.hpp>
#include <boost/log/detail/cleanup_scope_guard.hpp>
#include <boost/log/utility/formatting_ostream.hpp>
#include <boost/log/detail/header.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif
namespace boost {
BOOST_LOG_OPEN_NAMESPACE
namespace aux {
//! An element (either literal or placeholder) of the format string
struct format_element
{
//! Argument placeholder number or -1 if it's not a placeholder (i.e. a literal)
int arg_number;
//! If the element describes a constant literal, the starting character and length of the literal
unsigned int literal_start_pos, literal_len;
format_element() : arg_number(0), literal_start_pos(0), literal_len(0)
{
}
static format_element literal(unsigned int start_pos, unsigned int len)
{
format_element el;
el.arg_number = -1;
el.literal_start_pos = start_pos;
el.literal_len = len;
return el;
}
static format_element positional_argument(unsigned int arg_n)
{
format_element el;
el.arg_number = arg_n;
return el;
}
};
//! Parsed format string description
template< typename CharT >
struct format_description
{
BOOST_COPYABLE_AND_MOVABLE_ALT(format_description)
public:
//! Character type
typedef CharT char_type;
//! String type
typedef std::basic_string< char_type > string_type;
//! Array of format element descriptors
typedef std::vector< format_element > format_element_list;
//! Characters of all literal parts of the format string
string_type literal_chars;
//! Format element descriptors
format_element_list format_elements;
BOOST_DEFAULTED_FUNCTION(format_description(), {})
format_description(format_description const& that) : literal_chars(that.literal_chars), format_elements(that.format_elements)
{
}
format_description(BOOST_RV_REF(format_description) that)
{
literal_chars.swap(that.literal_chars);
format_elements.swap(that.format_elements);
}
format_description& operator= (format_description that)
{
literal_chars.swap(that.literal_chars);
format_elements.swap(that.format_elements);
return *this;
}
};
//! Parses format string
template< typename CharT >
BOOST_LOG_API format_description< CharT > parse_format(const CharT* begin, const CharT* end);
//! Parses format string
template< typename CharT >
BOOST_FORCEINLINE format_description< CharT > parse_format(const CharT* begin)
{
return parse_format(begin, begin + std::char_traits< CharT >::length(begin));
}
//! Parses format string
template< typename CharT, typename TraitsT, typename AllocatorT >
BOOST_FORCEINLINE format_description< CharT > parse_format(std::basic_string< CharT, TraitsT, AllocatorT > const& fmt)
{
const CharT* begin = fmt.c_str();
return parse_format(begin, begin + fmt.size());
}
//! Formatter object
template< typename CharT >
class basic_format
{
public:
//! Character type
typedef CharT char_type;
//! String type
typedef std::basic_string< char_type > string_type;
//! Stream type
typedef basic_formatting_ostream< char_type > stream_type;
//! Format description type
typedef format_description< char_type > format_description_type;
//! The pump receives arguments and formats them into strings. At destruction the pump composes the final string in the attached stream.
class pump;
friend class pump;
private:
//! Formatting params for a single placeholder in the format string
struct formatting_params
{
//! Formatting element index in the format description
unsigned int element_idx;
//! Formatting result
string_type target;
formatting_params() : element_idx(~0u) {}
};
typedef std::vector< formatting_params > formatting_params_list;
private:
//! Format string description
format_description_type m_format;
//! Formatting parameters for all placeholders
formatting_params_list m_formatting_params;
//! Current formatting position
unsigned int m_current_idx;
public:
//! Initializing constructor
explicit basic_format(string_type const& fmt) : m_format(aux::parse_format(fmt)), m_current_idx(0)
{
init_params();
}
//! Initializing constructor
explicit basic_format(const char_type* fmt) : m_format(aux::parse_format(fmt)), m_current_idx(0)
{
init_params();
}
//! Clears all formatted strings and resets the current formatting position
void clear() BOOST_NOEXCEPT
{
for (typename formatting_params_list::iterator it = m_formatting_params.begin(), end = m_formatting_params.end(); it != end; ++it)
{
it->target.clear();
}
m_current_idx = 0;
}
//! Creates a pump that will receive all format arguments and put the formatted string into the stream
pump make_pump(stream_type& strm) BOOST_NOEXCEPT
{
return pump(*this, strm);
}
//! Composes the final string from the formatted pieces
void compose(string_type& str) const
{
typename format_description_type::format_element_list::const_iterator it = m_format.format_elements.begin(), end = m_format.format_elements.end();
for (; it != end; ++it)
{
if (it->arg_number >= 0)
{
// This is a placeholder
str.append(m_formatting_params[it->arg_number].target);
}
else
{
// This is a literal
const char_type* p = m_format.literal_chars.c_str() + it->literal_start_pos;
str.append(p, it->literal_len);
}
}
}
//! Composes the final string from the formatted pieces
string_type str() const
{
string_type result;
compose(result);
return boost::move(result);
}
private:
//! Initializes the formatting params
void init_params()
{
typename format_description_type::format_element_list::const_iterator it = m_format.format_elements.begin(), end = m_format.format_elements.end();
for (; it != end; ++it)
{
if (it->arg_number >= 0)
{
if (static_cast< unsigned int >(it->arg_number) >= m_formatting_params.size())
m_formatting_params.resize(it->arg_number + 1);
m_formatting_params[it->arg_number].element_idx = static_cast< unsigned int >(it - m_format.format_elements.begin());
}
}
}
};
//! The pump receives arguments and formats them into strings. At destruction the pump composes the final string in the attached stream.
template< typename CharT >
class basic_format< CharT >::pump
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(pump)
private:
//! The guard temporarily replaces storage string in the specified stream
struct scoped_storage
{
scoped_storage(stream_type& strm, string_type& storage) : m_stream(strm), m_storage_backup(*strm.rdbuf()->storage())
{
strm.attach(storage);
}
~scoped_storage()
{
m_stream.attach(m_storage_backup);
}
private:
stream_type& m_stream;
string_type& m_storage_backup;
};
private:
//! Reference to the owner
basic_format* m_owner;
//! Reference to the stream
stream_type* m_stream;
//! Unhandled exception count
const unsigned int m_exception_count;
public:
//! Initializing constructor
pump(basic_format& owner, stream_type& strm) BOOST_NOEXCEPT : m_owner(&owner), m_stream(&strm), m_exception_count(unhandled_exception_count())
{
}
//! Move constructor
pump(BOOST_RV_REF(pump) that) BOOST_NOEXCEPT : m_owner(that.m_owner), m_stream(that.m_stream), m_exception_count(that.m_exception_count)
{
that.m_owner = NULL;
that.m_stream = NULL;
}
//! Destructor
~pump() BOOST_NOEXCEPT_IF(false)
{
if (m_owner)
{
// Whether or not the destructor is called because of an exception, the format object has to be cleared
boost::log::aux::cleanup_guard< basic_format< char_type > > cleanup1(*m_owner);
BOOST_ASSERT(m_stream != NULL);
if (m_exception_count >= unhandled_exception_count())
{
// Compose the final string in the stream buffer
m_stream->flush();
m_owner->compose(*m_stream->rdbuf()->storage());
}
}
}
/*!
* Puts an argument to the formatter. Note the pump has to be returned by value and not by reference in order this to
* work with Boost.Phoenix expressions. Otherwise the pump that is returned from \c basic_format::make_pump is
* destroyed after the first call to \c operator%, and the returned reference becomes dangling.
*/
template< typename T >
pump operator% (T const& val)
{
BOOST_ASSERT_MSG(m_owner != NULL && m_stream != NULL, "Boost.Log: This basic_format::pump has already been moved from");
if (m_owner->m_current_idx < m_owner->m_formatting_params.size())
{
scoped_storage storage_guard(*m_stream, m_owner->m_formatting_params[m_owner->m_current_idx].target);
*m_stream << val;
m_stream->flush();
++m_owner->m_current_idx;
}
return boost::move(*this);
}
};
} // namespace aux
BOOST_LOG_CLOSE_NAMESPACE // namespace log
} // namespace boost
#include <boost/log/detail/footer.hpp>
#endif // BOOST_LOG_DETAIL_FORMAT_HPP_INCLUDED_
|