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 attribute_set.hpp
9 * \author Andrey Semashev
10 * \date 08.03.2007
11 *
12 * This header contains definition of the attribute set container.
13 */
14
15 #ifndef BOOST_LOG_ATTRIBUTE_SET_HPP_INCLUDED_
16 #define BOOST_LOG_ATTRIBUTE_SET_HPP_INCLUDED_
17
18 #include <cstddef>
19 #include <utility>
20 #include <iterator>
21 #include <boost/move/core.hpp>
22 #include <boost/core/enable_if.hpp>
23 #include <boost/type_traits/conditional.hpp>
24 #include <boost/log/detail/config.hpp>
25 #include <boost/log/detail/sfinae_tools.hpp>
26 #include <boost/log/attributes/attribute_name.hpp>
27 #include <boost/log/attributes/attribute.hpp>
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 class attribute_set;
39 class attribute_value_set;
40
41 namespace aux {
42
43 //! Reference proxy object to implement \c operator[]
44 class attribute_set_reference_proxy
45 {
46 private:
47 //! Key type
48 typedef attribute_name key_type;
49 //! Mapped attribute type
50 typedef attribute mapped_type;
51
52 private:
53 attribute_set* const m_pContainer;
54 const key_type m_key;
55
56 public:
57 //! Constructor
attribute_set_reference_proxy(attribute_set * pContainer,key_type const & key)58 explicit attribute_set_reference_proxy(attribute_set* pContainer, key_type const& key) BOOST_NOEXCEPT :
59 m_pContainer(pContainer),
60 m_key(key)
61 {
62 }
63
64 //! Conversion operator (would be invoked in case of reading from the container)
operator mapped_type() const65 BOOST_FORCEINLINE operator mapped_type() const BOOST_NOEXCEPT
66 {
67 return read_mapped_value();
68 }
69 //! Assignment operator (would be invoked in case of writing to the container)
70 mapped_type& operator= (mapped_type const& val) const;
71
72 private:
73 //! Reads the referenced mapped value from the container
74 mapped_type read_mapped_value() const BOOST_NOEXCEPT;
75 };
76
77 } // namespace aux
78
79 /*!
80 * \brief An attribute set class.
81 *
82 * An attribute set is an associative container with attribute name as a key and
83 * pointer to the attribute as a mapped value. The container allows storing only one element for each distinct
84 * key value. In most regards attribute set container provides interface similar to \c std::unordered_map.
85 * However, there are differences in \c operator[] semantics and a number of optimizations with regard to iteration.
86 * Besides, attribute names are stored as a read-only <tt>attribute_name</tt>'s instead of \c std::string,
87 * which saves memory and CPU time.
88 */
89 class attribute_set
90 {
91 BOOST_COPYABLE_AND_MOVABLE_ALT(attribute_set)
92
93 friend class attribute_value_set;
94 friend class aux::attribute_set_reference_proxy;
95
96 public:
97 //! Key type
98 typedef attribute_name key_type;
99 //! Mapped attribute type
100 typedef attribute mapped_type;
101
102 //! Value type
103 typedef std::pair< const key_type, mapped_type > value_type;
104 //! Reference type
105 typedef value_type& reference;
106 //! Const reference type
107 typedef value_type const& const_reference;
108 //! Pointer type
109 typedef value_type* pointer;
110 //! Const pointer type
111 typedef value_type const* const_pointer;
112 //! Size type
113 typedef std::size_t size_type;
114 //! Difference type
115 typedef std::ptrdiff_t difference_type;
116
117 private:
118 //! \cond
119
120 //! Implementation
121 struct implementation;
122 friend struct implementation;
123
124 //! A base class for the container nodes
125 struct node_base
126 {
127 node_base* m_pPrev;
128 node_base* m_pNext;
129
130 node_base();
131
132 BOOST_DELETED_FUNCTION(node_base(node_base const&))
133 BOOST_DELETED_FUNCTION(node_base& operator= (node_base const&))
134 };
135
136 //! Container elements
137 struct node;
138 friend struct node;
139 struct node :
140 public node_base
141 {
142 value_type m_Value;
143
144 node(key_type const& key, mapped_type const& data);
145 };
146
147 //! Iterator class
148 #ifndef BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS
149 template< bool fConstV > class iter;
150 template< bool fConstV > friend class iter;
151 #endif
152 template< bool fConstV >
153 class iter
154 {
155 friend class iter< !fConstV >;
156 friend class attribute_set;
157
158 public:
159 // Standard typedefs
160 typedef attribute_set::difference_type difference_type;
161 typedef attribute_set::value_type value_type;
162 typedef typename boost::conditional<
163 fConstV,
164 attribute_set::const_reference,
165 attribute_set::reference
166 >::type reference;
167 typedef typename boost::conditional<
168 fConstV,
169 attribute_set::const_pointer,
170 attribute_set::pointer
171 >::type pointer;
172 typedef std::bidirectional_iterator_tag iterator_category;
173
174 public:
175 // Constructors
iter()176 BOOST_CONSTEXPR iter() BOOST_NOEXCEPT : m_pNode(NULL) {}
iter(node_base * pNode)177 explicit iter(node_base* pNode) BOOST_NOEXCEPT : m_pNode(pNode) {}
178 #if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS)
179 template< bool fOtherConstV, typename = typename boost::enable_if_c< !fOtherConstV && fOtherConstV != fConstV >::type >
iter(iter<fOtherConstV> const & that)180 iter(iter< fOtherConstV > const& that) BOOST_NOEXCEPT : m_pNode(that.m_pNode) {}
181 #else
182 template< bool fOtherConstV >
iter(iter<fOtherConstV> const & that,typename boost::enable_if_c<!fOtherConstV && fOtherConstV!=fConstV,boost::log::aux::sfinae_dummy>::type=boost::log::aux::sfinae_dummy ())183 iter(iter< fOtherConstV > const& that, typename boost::enable_if_c< !fOtherConstV && fOtherConstV != fConstV, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) BOOST_NOEXCEPT :
184 m_pNode(that.m_pNode)
185 {
186 }
187 #endif
188
189 //! Assignment
190 template< bool fOtherConstV >
operator =(iter<fOtherConstV> const & that)191 typename boost::enable_if_c< !fOtherConstV && fOtherConstV != fConstV, iter& >::type operator= (iter< fOtherConstV > const& that) BOOST_NOEXCEPT
192 {
193 m_pNode = that.m_pNode;
194 return *this;
195 }
196
197 // Comparison
198 template< bool fOtherConstV >
operator ==(iter<fOtherConstV> const & that) const199 typename boost::enable_if_c< !fOtherConstV || fOtherConstV == fConstV, bool >::type operator== (iter< fOtherConstV > const& that) const BOOST_NOEXCEPT { return (m_pNode == that.m_pNode); }
200 template< bool fOtherConstV >
operator !=(iter<fOtherConstV> const & that) const201 typename boost::enable_if_c< !fOtherConstV || fOtherConstV == fConstV, bool >::type operator!= (iter< fOtherConstV > const& that) const BOOST_NOEXCEPT { return (m_pNode != that.m_pNode); }
202
203 // Modification
operator ++()204 iter& operator++ () BOOST_NOEXCEPT
205 {
206 m_pNode = m_pNode->m_pNext;
207 return *this;
208 }
operator --()209 iter& operator-- () BOOST_NOEXCEPT
210 {
211 m_pNode = m_pNode->m_pPrev;
212 return *this;
213 }
operator ++(int)214 iter operator++ (int) BOOST_NOEXCEPT
215 {
216 iter tmp(*this);
217 m_pNode = m_pNode->m_pNext;
218 return tmp;
219 }
operator --(int)220 iter operator-- (int) BOOST_NOEXCEPT
221 {
222 iter tmp(*this);
223 m_pNode = m_pNode->m_pPrev;
224 return tmp;
225 }
226
227 // Dereferencing
operator ->() const228 pointer operator-> () const BOOST_NOEXCEPT { return &(static_cast< node* >(m_pNode)->m_Value); }
operator *() const229 reference operator* () const BOOST_NOEXCEPT { return static_cast< node* >(m_pNode)->m_Value; }
230
base() const231 node_base* base() const BOOST_NOEXCEPT { return m_pNode; }
232
233 private:
234 node_base* m_pNode;
235 };
236
237 //! \endcond
238
239 public:
240 #ifndef BOOST_LOG_DOXYGEN_PASS
241 //! Iterator type
242 typedef iter< false > iterator;
243 //! Const iterator type
244 typedef iter< true > const_iterator;
245 #else
246 /*!
247 * Iterator type. The iterator complies to the bidirectional iterator requirements.
248 */
249 typedef implementation_defined iterator;
250 /*!
251 * Constant iterator type. The iterator complies to the bidirectional iterator requirements with read-only capabilities.
252 */
253 typedef implementation_defined const_iterator;
254 #endif // BOOST_LOG_DOXYGEN_PASS
255
256 private:
257 //! Pointer to implementation
258 implementation* m_pImpl;
259
260 public:
261 /*!
262 * Default constructor.
263 *
264 * \post <tt>empty() == true</tt>
265 */
266 BOOST_LOG_API attribute_set();
267
268 /*!
269 * Copy constructor.
270 *
271 * \post <tt>size() == that.size() && std::equal(begin(), end(), that.begin()) == true</tt>
272 */
273 BOOST_LOG_API attribute_set(attribute_set const& that);
274
275 /*!
276 * Move constructor
277 */
attribute_set(BOOST_RV_REF (attribute_set)that)278 attribute_set(BOOST_RV_REF(attribute_set) that) BOOST_NOEXCEPT : m_pImpl(that.m_pImpl)
279 {
280 that.m_pImpl = NULL;
281 }
282
283 /*!
284 * Destructor. All stored references to attributes are released.
285 */
286 BOOST_LOG_API ~attribute_set() BOOST_NOEXCEPT;
287
288 /*!
289 * Copy assignment operator.
290 *
291 * \post <tt>size() == that.size() && std::equal(begin(), end(), that.begin()) == true</tt>
292 */
operator =(attribute_set that)293 attribute_set& operator= (attribute_set that) BOOST_NOEXCEPT
294 {
295 this->swap(that);
296 return *this;
297 }
298
299 /*!
300 * Swaps two instances of the container.
301 *
302 * \b Throws: Nothing.
303 */
swap(attribute_set & that)304 void swap(attribute_set& that) BOOST_NOEXCEPT
305 {
306 implementation* const p = m_pImpl;
307 m_pImpl = that.m_pImpl;
308 that.m_pImpl = p;
309 }
310
311 /*!
312 * \return Iterator to the first element of the container.
313 */
314 BOOST_LOG_API iterator begin() BOOST_NOEXCEPT;
315 /*!
316 * \return Iterator to the after-the-last element of the container.
317 */
318 BOOST_LOG_API iterator end() BOOST_NOEXCEPT;
319 /*!
320 * \return Constant iterator to the first element of the container.
321 */
322 BOOST_LOG_API const_iterator begin() const BOOST_NOEXCEPT;
323 /*!
324 * \return Constant iterator to the after-the-last element of the container.
325 */
326 BOOST_LOG_API const_iterator end() const BOOST_NOEXCEPT;
327
328 /*!
329 * \return Number of elements in the container.
330 */
331 BOOST_LOG_API size_type size() const BOOST_NOEXCEPT;
332 /*!
333 * \return true if there are no elements in the container, false otherwise.
334 */
empty() const335 bool empty() const BOOST_NOEXCEPT { return (this->size() == 0); }
336
337 /*!
338 * The method finds the attribute by name.
339 *
340 * \param key Attribute name.
341 * \return Iterator to the found element or end() if the attribute with such name is not found.
342 */
343 BOOST_LOG_API iterator find(key_type key) BOOST_NOEXCEPT;
344 /*!
345 * The method finds the attribute by name.
346 *
347 * \param key Attribute name.
348 * \return Iterator to the found element or \c end() if the attribute with such name is not found.
349 */
find(key_type key) const350 const_iterator find(key_type key) const BOOST_NOEXCEPT
351 {
352 return const_iterator(const_cast< attribute_set* >(this)->find(key));
353 }
354 /*!
355 * The method counts the number of the attribute occurrences in the container. Since there can be only one
356 * attribute with a particular key, the method always return 0 or 1.
357 *
358 * \param key Attribute name.
359 * \return The number of times the attribute is found in the container.
360 */
count(key_type key) const361 size_type count(key_type key) const BOOST_NOEXCEPT { return size_type(this->find(key) != this->end()); }
362
363 /*!
364 * Combined lookup/insertion operator. The operator semantics depends on the further usage of the returned reference.
365 * \li If the reference is used as an assignment target, the assignment expression is equivalent to element insertion,
366 * where the element is composed of the second argument of the \c operator[] as a key and the second argument of assignment
367 * as a mapped value.
368 * \li If the returned reference is used in context where a conversion to the mapped type is required,
369 * the result of the conversion is equivalent to the mapped value found with the second argument of the \c operator[] as a key,
370 * if such an element exists in the container, or a default-constructed mapped value, if an element does not exist in the
371 * container.
372 *
373 * \param key Attribute name.
374 * \return A smart reference object of unspecified type.
375 */
operator [](key_type key)376 aux::attribute_set_reference_proxy operator[] (key_type key) BOOST_NOEXCEPT
377 {
378 return aux::attribute_set_reference_proxy(this, key);
379 }
380 /*!
381 * Lookup operator
382 *
383 * \param key Attribute name.
384 * \return If an element with the corresponding attribute name is found in the container, its mapped value
385 * is returned. Otherwise a default-constructed mapped value is returned.
386 */
operator [](key_type key) const387 mapped_type operator[] (key_type key) const BOOST_NOEXCEPT
388 {
389 const_iterator it = this->find(key);
390 if (it != end())
391 return it->second;
392 else
393 return mapped_type();
394 }
395
396 /*!
397 * Insertion method
398 *
399 * \param key Attribute name.
400 * \param data Pointer to the attribute. Must not be NULL.
401 * \returns A pair of values. If second is true, the insertion succeeded and the first component points to the
402 * inserted element. Otherwise the first component points to the element that prevents insertion.
403 */
404 BOOST_LOG_API std::pair< iterator, bool > insert(key_type key, mapped_type const& data);
405
406 /*!
407 * Insertion method
408 *
409 * \param value An element to be inserted.
410 * \returns A pair of values. If second is true, the insertion succeeded and the first component points to the
411 * inserted element. Otherwise the first component points to the element that prevents insertion.
412 */
insert(const_reference value)413 std::pair< iterator, bool > insert(const_reference value)
414 {
415 return this->insert(value.first, value.second);
416 }
417
418 /*!
419 * Mass insertion method.
420 *
421 * \param begin A forward iterator that points to the first element to be inserted.
422 * \param end A forward iterator that points to the after-the-last element to be inserted.
423 */
424 template< typename FwdIteratorT >
insert(FwdIteratorT begin,FwdIteratorT end)425 void insert(FwdIteratorT begin, FwdIteratorT end)
426 {
427 for (; begin != end; ++begin)
428 this->insert(*begin);
429 }
430
431 /*!
432 * Mass insertion method with ability to acquire iterators to the inserted elements.
433 *
434 * \param begin A forward iterator that points to the first element to be inserted.
435 * \param end A forward iterator that points to the after-the-last element to be inserted.
436 * \param out An output iterator that receives results of insertion of the elements
437 */
438 template< typename FwdIteratorT, typename OutputIteratorT >
insert(FwdIteratorT begin,FwdIteratorT end,OutputIteratorT out)439 void insert(FwdIteratorT begin, FwdIteratorT end, OutputIteratorT out)
440 {
441 for (; begin != end; ++begin, ++out)
442 *out = this->insert(*begin);
443 }
444
445 /*!
446 * The method erases all attributes with the specified name
447 *
448 * \post All iterators to the erased elements become invalid.
449 * \param key Attribute name.
450 * \return Tne number of erased elements
451 */
452 BOOST_LOG_API size_type erase(key_type key) BOOST_NOEXCEPT;
453 /*!
454 * The method erases the specified attribute
455 *
456 * \post All iterators to the erased element become invalid.
457 * \param it A valid iterator to the element to be erased.
458 * \return Tne number of erased elements
459 */
460 BOOST_LOG_API void erase(iterator it) BOOST_NOEXCEPT;
461 /*!
462 * The method erases all attributes within the specified range
463 *
464 * \pre \a end is reachable from \a begin with a finite number of increments.
465 * \post All iterators to the erased elements become invalid.
466 * \param begin An iterator that points to the first element to be erased.
467 * \param end An iterator that points to the after-the-last element to be erased.
468 */
469 BOOST_LOG_API void erase(iterator begin, iterator end) BOOST_NOEXCEPT;
470
471 /*!
472 * The method removes all elements from the container
473 *
474 * \post <tt>empty() == true</tt>
475 */
476 BOOST_LOG_API void clear() BOOST_NOEXCEPT;
477 };
478
479 /*!
480 * Free swap overload
481 */
swap(attribute_set & left,attribute_set & right)482 inline void swap(attribute_set& left, attribute_set& right) BOOST_NOEXCEPT
483 {
484 left.swap(right);
485 }
486
487 namespace aux {
488
489 //! Reads the referenced mapped value from the container
read_mapped_value() const490 inline attribute_set_reference_proxy::mapped_type attribute_set_reference_proxy::read_mapped_value() const BOOST_NOEXCEPT
491 {
492 attribute_set::iterator it = m_pContainer->find(m_key);
493 if (it != m_pContainer->end())
494 return it->second;
495 else
496 return mapped_type();
497 }
498
499 //! Assignment operator (would be invoked in case of writing to the container)
operator =(mapped_type const & val) const500 inline attribute_set_reference_proxy::mapped_type& attribute_set_reference_proxy::operator= (mapped_type const& val) const
501 {
502 std::pair< attribute_set::iterator, bool > res = m_pContainer->insert(m_key, val);
503 if (!res.second)
504 res.first->second = val;
505 return res.first->second;
506 }
507
508 } // namespace aux
509
510 #ifndef BOOST_LOG_DOXYGEN_PASS
operator =(aux::attribute_set_reference_proxy const & that)511 inline attribute& attribute::operator= (aux::attribute_set_reference_proxy const& that) BOOST_NOEXCEPT
512 {
513 attribute attr = that;
514 this->swap(attr);
515 return *this;
516 }
517 #endif
518
519 BOOST_LOG_CLOSE_NAMESPACE // namespace log
520
521 } // namespace boost
522
523 #include <boost/log/detail/footer.hpp>
524
525 #endif // BOOST_LOG_ATTRIBUTE_SET_HPP_INCLUDED_
526