• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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