Chris@16: /* Chris@101: * Copyright Andrey Semashev 2007 - 2015. Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: */ Chris@16: /*! Chris@16: * \file attribute_set.hpp Chris@16: * \author Andrey Semashev Chris@16: * \date 08.03.2007 Chris@16: * Chris@16: * This header contains definition of the attribute set container. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_LOG_ATTRIBUTE_SET_HPP_INCLUDED_ Chris@16: #define BOOST_LOG_ATTRIBUTE_SET_HPP_INCLUDED_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_HAS_PRAGMA_ONCE Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: BOOST_LOG_OPEN_NAMESPACE Chris@16: Chris@16: class attribute_set; Chris@16: class attribute_value_set; Chris@16: Chris@16: namespace aux { Chris@16: Chris@16: //! Reference proxy object to implement \c operator[] Chris@16: class attribute_set_reference_proxy Chris@16: { Chris@16: private: Chris@16: //! Key type Chris@16: typedef attribute_name key_type; Chris@16: //! Mapped attribute type Chris@16: typedef attribute mapped_type; Chris@16: Chris@16: private: Chris@16: attribute_set* const m_pContainer; Chris@16: const key_type m_key; Chris@16: Chris@16: public: Chris@16: //! Constructor Chris@16: explicit attribute_set_reference_proxy(attribute_set* pContainer, key_type const& key) BOOST_NOEXCEPT : Chris@16: m_pContainer(pContainer), Chris@16: m_key(key) Chris@16: { Chris@16: } Chris@16: Chris@16: //! Conversion operator (would be invoked in case of reading from the container) Chris@16: operator mapped_type() const BOOST_NOEXCEPT; Chris@16: //! Assignment operator (would be invoked in case of writing to the container) Chris@16: mapped_type& operator= (mapped_type const& val) const; Chris@16: }; Chris@16: Chris@16: } // namespace aux Chris@16: Chris@16: /*! Chris@16: * \brief An attribute set class. Chris@16: * Chris@16: * An attribute set is an associative container with attribute name as a key and Chris@16: * pointer to the attribute as a mapped value. The container allows storing only one element for each distinct Chris@16: * key value. In most regards attribute set container provides interface similar to \c std::unordered_map. Chris@16: * However, there are differences in \c operator[] semantics and a number of optimizations with regard to iteration. Chris@16: * Besides, attribute names are stored as a read-only attribute_name's instead of \c std::string, Chris@16: * which saves memory and CPU time. Chris@16: */ Chris@16: class attribute_set Chris@16: { Chris@16: BOOST_COPYABLE_AND_MOVABLE_ALT(attribute_set) Chris@16: Chris@16: friend class attribute_value_set; Chris@16: friend class aux::attribute_set_reference_proxy; Chris@16: Chris@16: public: Chris@16: //! Key type Chris@16: typedef attribute_name key_type; Chris@16: //! Mapped attribute type Chris@16: typedef attribute mapped_type; Chris@16: Chris@16: //! Value type Chris@16: typedef std::pair< const key_type, mapped_type > value_type; Chris@16: //! Reference type Chris@16: typedef value_type& reference; Chris@16: //! Const reference type Chris@16: typedef value_type const& const_reference; Chris@16: //! Pointer type Chris@16: typedef value_type* pointer; Chris@16: //! Const pointer type Chris@16: typedef value_type const* const_pointer; Chris@16: //! Size type Chris@16: typedef std::size_t size_type; Chris@16: //! Difference type Chris@16: typedef std::ptrdiff_t difference_type; Chris@16: Chris@16: private: Chris@16: //! \cond Chris@16: Chris@16: //! Implementation Chris@16: struct implementation; Chris@16: friend struct implementation; Chris@16: Chris@16: //! A base class for the container nodes Chris@16: struct node_base Chris@16: { Chris@16: node_base* m_pPrev; Chris@16: node_base* m_pNext; Chris@16: Chris@16: node_base(); Chris@16: Chris@16: BOOST_DELETED_FUNCTION(node_base(node_base const&)) Chris@16: BOOST_DELETED_FUNCTION(node_base& operator= (node_base const&)) Chris@16: }; Chris@16: Chris@16: //! Container elements Chris@16: struct node; Chris@16: friend struct node; Chris@16: struct node : Chris@16: public node_base Chris@16: { Chris@16: value_type m_Value; Chris@16: Chris@16: node(key_type const& key, mapped_type const& data); Chris@16: }; Chris@16: Chris@16: //! Iterator class Chris@16: #ifndef BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS Chris@16: template< bool fConstV > class iter; Chris@16: template< bool fConstV > friend class iter; Chris@16: #endif Chris@16: template< bool fConstV > Chris@16: class iter Chris@16: { Chris@16: friend class iter< !fConstV >; Chris@16: friend class attribute_set; Chris@16: Chris@16: public: Chris@16: // Standard typedefs Chris@16: typedef attribute_set::difference_type difference_type; Chris@16: typedef attribute_set::value_type value_type; Chris@16: typedef typename mpl::if_c< Chris@16: fConstV, Chris@16: attribute_set::const_reference, Chris@16: attribute_set::reference Chris@16: >::type reference; Chris@16: typedef typename mpl::if_c< Chris@16: fConstV, Chris@16: attribute_set::const_pointer, Chris@16: attribute_set::pointer Chris@16: >::type pointer; Chris@16: typedef std::bidirectional_iterator_tag iterator_category; Chris@16: Chris@16: public: Chris@16: // Constructors Chris@16: BOOST_CONSTEXPR iter() : m_pNode(NULL) {} Chris@16: explicit iter(node_base* pNode) BOOST_NOEXCEPT : m_pNode(pNode) {} Chris@16: iter(iter< false > const& that) BOOST_NOEXCEPT : m_pNode(that.m_pNode) {} Chris@16: Chris@16: //! Assignment Chris@16: template< bool f > Chris@16: iter& operator= (iter< f > const& that) BOOST_NOEXCEPT Chris@16: { Chris@16: m_pNode = that.m_pNode; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Comparison Chris@16: template< bool f > Chris@16: bool operator== (iter< f > const& that) const BOOST_NOEXCEPT { return (m_pNode == that.m_pNode); } Chris@16: template< bool f > Chris@16: bool operator!= (iter< f > const& that) const BOOST_NOEXCEPT { return (m_pNode != that.m_pNode); } Chris@16: Chris@16: // Modification Chris@16: iter& operator++ () BOOST_NOEXCEPT Chris@16: { Chris@16: m_pNode = m_pNode->m_pNext; Chris@16: return *this; Chris@16: } Chris@16: iter& operator-- () BOOST_NOEXCEPT Chris@16: { Chris@16: m_pNode = m_pNode->m_pPrev; Chris@16: return *this; Chris@16: } Chris@16: iter operator++ (int) BOOST_NOEXCEPT Chris@16: { Chris@16: iter tmp(*this); Chris@16: m_pNode = m_pNode->m_pNext; Chris@16: return tmp; Chris@16: } Chris@16: iter operator-- (int) BOOST_NOEXCEPT Chris@16: { Chris@16: iter tmp(*this); Chris@16: m_pNode = m_pNode->m_pPrev; Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: // Dereferencing Chris@16: pointer operator-> () const BOOST_NOEXCEPT { return &(static_cast< node* >(m_pNode)->m_Value); } Chris@16: reference operator* () const BOOST_NOEXCEPT { return static_cast< node* >(m_pNode)->m_Value; } Chris@16: Chris@16: node_base* base() const BOOST_NOEXCEPT { return m_pNode; } Chris@16: Chris@16: private: Chris@16: node_base* m_pNode; Chris@16: }; Chris@16: Chris@16: //! \endcond Chris@16: Chris@16: public: Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: //! Iterator type Chris@16: typedef iter< false > iterator; Chris@16: //! Const iterator type Chris@16: typedef iter< true > const_iterator; Chris@16: #else Chris@16: /*! Chris@16: * Iterator type. The iterator complies to the bidirectional iterator requirements. Chris@16: */ Chris@16: typedef implementation_defined iterator; Chris@16: /*! Chris@16: * Constant iterator type. The iterator complies to the bidirectional iterator requirements with read-only capabilities. Chris@16: */ Chris@16: typedef implementation_defined const_iterator; Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: private: Chris@16: //! Pointer to implementation Chris@16: implementation* m_pImpl; Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Default constructor. Chris@16: * Chris@16: * \post empty() == true Chris@16: */ Chris@16: BOOST_LOG_API attribute_set(); Chris@16: Chris@16: /*! Chris@16: * Copy constructor. Chris@16: * Chris@16: * \post size() == that.size() && std::equal(begin(), end(), that.begin()) == true Chris@16: */ Chris@16: BOOST_LOG_API attribute_set(attribute_set const& that); Chris@16: Chris@16: /*! Chris@16: * Move constructor Chris@16: */ Chris@16: attribute_set(BOOST_RV_REF(attribute_set) that) BOOST_NOEXCEPT : m_pImpl(that.m_pImpl) Chris@16: { Chris@16: that.m_pImpl = NULL; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Destructor. All stored references to attributes are released. Chris@16: */ Chris@16: BOOST_LOG_API ~attribute_set() BOOST_NOEXCEPT; Chris@16: Chris@16: /*! Chris@16: * Copy assignment operator. Chris@16: * Chris@16: * \post size() == that.size() && std::equal(begin(), end(), that.begin()) == true Chris@16: */ Chris@16: attribute_set& operator= (attribute_set that) BOOST_NOEXCEPT Chris@16: { Chris@16: this->swap(that); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Swaps two instances of the container. Chris@16: * Chris@16: * \b Throws: Nothing. Chris@16: */ Chris@16: void swap(attribute_set& that) BOOST_NOEXCEPT Chris@16: { Chris@101: implementation* const p = m_pImpl; Chris@16: m_pImpl = that.m_pImpl; Chris@16: that.m_pImpl = p; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * \return Iterator to the first element of the container. Chris@16: */ Chris@16: BOOST_LOG_API iterator begin() BOOST_NOEXCEPT; Chris@16: /*! Chris@16: * \return Iterator to the after-the-last element of the container. Chris@16: */ Chris@16: BOOST_LOG_API iterator end() BOOST_NOEXCEPT; Chris@16: /*! Chris@16: * \return Constant iterator to the first element of the container. Chris@16: */ Chris@16: BOOST_LOG_API const_iterator begin() const BOOST_NOEXCEPT; Chris@16: /*! Chris@16: * \return Constant iterator to the after-the-last element of the container. Chris@16: */ Chris@16: BOOST_LOG_API const_iterator end() const BOOST_NOEXCEPT; Chris@16: Chris@16: /*! Chris@16: * \return Number of elements in the container. Chris@16: */ Chris@16: BOOST_LOG_API size_type size() const BOOST_NOEXCEPT; Chris@16: /*! Chris@16: * \return true if there are no elements in the container, false otherwise. Chris@16: */ Chris@16: bool empty() const BOOST_NOEXCEPT { return (this->size() == 0); } Chris@16: Chris@16: /*! Chris@16: * The method finds the attribute by name. Chris@16: * Chris@16: * \param key Attribute name. Chris@16: * \return Iterator to the found element or end() if the attribute with such name is not found. Chris@16: */ Chris@16: BOOST_LOG_API iterator find(key_type key) BOOST_NOEXCEPT; Chris@16: /*! Chris@16: * The method finds the attribute by name. Chris@16: * Chris@16: * \param key Attribute name. Chris@16: * \return Iterator to the found element or \c end() if the attribute with such name is not found. Chris@16: */ Chris@16: const_iterator find(key_type key) const BOOST_NOEXCEPT Chris@16: { Chris@16: return const_iterator(const_cast< attribute_set* >(this)->find(key)); Chris@16: } Chris@16: /*! Chris@16: * The method counts the number of the attribute occurrences in the container. Since there can be only one Chris@16: * attribute with a particular key, the method always return 0 or 1. Chris@16: * Chris@16: * \param key Attribute name. Chris@16: * \return The number of times the attribute is found in the container. Chris@16: */ Chris@16: size_type count(key_type key) const BOOST_NOEXCEPT { return size_type(this->find(key) != this->end()); } Chris@16: Chris@16: /*! Chris@16: * Combined lookup/insertion operator. The operator semantics depends on the further usage of the returned reference. Chris@16: * \li If the reference is used as an assignment target, the assignment expression is equivalent to element insertion, Chris@16: * where the element is composed of the second argument of the \c operator[] as a key and the second argument of assignment Chris@16: * as a mapped value. Chris@16: * \li If the returned reference is used in context where a conversion to the mapped type is required, Chris@16: * the result of the conversion is equivalent to the mapped value found with the second argument of the \c operator[] as a key, Chris@16: * if such an element exists in the container, or a default-constructed mapped value, if an element does not exist in the Chris@16: * container. Chris@16: * Chris@16: * \param key Attribute name. Chris@16: * \return A smart reference object of unspecified type. Chris@16: */ Chris@16: aux::attribute_set_reference_proxy operator[] (key_type key) BOOST_NOEXCEPT Chris@16: { Chris@16: return aux::attribute_set_reference_proxy(this, key); Chris@16: } Chris@16: /*! Chris@16: * Lookup operator Chris@16: * Chris@16: * \param key Attribute name. Chris@16: * \return If an element with the corresponding attribute name is found in the container, its mapped value Chris@16: * is returned. Otherwise a default-constructed mapped value is returned. Chris@16: */ Chris@16: mapped_type operator[] (key_type key) const BOOST_NOEXCEPT Chris@16: { Chris@16: const_iterator it = this->find(key); Chris@16: if (it != end()) Chris@16: return it->second; Chris@16: else Chris@16: return mapped_type(); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Insertion method Chris@16: * Chris@16: * \param key Attribute name. Chris@16: * \param data Pointer to the attribute. Must not be NULL. Chris@16: * \returns A pair of values. If second is true, the insertion succeeded and the first component points to the Chris@16: * inserted element. Otherwise the first component points to the element that prevents insertion. Chris@16: */ Chris@16: BOOST_LOG_API std::pair< iterator, bool > insert(key_type key, mapped_type const& data); Chris@16: Chris@16: /*! Chris@16: * Insertion method Chris@16: * Chris@16: * \param value An element to be inserted. Chris@16: * \returns A pair of values. If second is true, the insertion succeeded and the first component points to the Chris@16: * inserted element. Otherwise the first component points to the element that prevents insertion. Chris@16: */ Chris@16: std::pair< iterator, bool > insert(const_reference value) Chris@16: { Chris@16: return this->insert(value.first, value.second); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Mass insertion method. Chris@16: * Chris@16: * \param begin A forward iterator that points to the first element to be inserted. Chris@16: * \param end A forward iterator that points to the after-the-last element to be inserted. Chris@16: */ Chris@16: template< typename FwdIteratorT > Chris@16: void insert(FwdIteratorT begin, FwdIteratorT end) Chris@16: { Chris@16: for (; begin != end; ++begin) Chris@16: this->insert(*begin); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Mass insertion method with ability to acquire iterators to the inserted elements. Chris@16: * Chris@16: * \param begin A forward iterator that points to the first element to be inserted. Chris@16: * \param end A forward iterator that points to the after-the-last element to be inserted. Chris@16: * \param out An output iterator that receives results of insertion of the elements Chris@16: */ Chris@16: template< typename FwdIteratorT, typename OutputIteratorT > Chris@16: void insert(FwdIteratorT begin, FwdIteratorT end, OutputIteratorT out) Chris@16: { Chris@16: for (; begin != end; ++begin, ++out) Chris@16: *out = this->insert(*begin); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * The method erases all attributes with the specified name Chris@16: * Chris@16: * \post All iterators to the erased elements become invalid. Chris@16: * \param key Attribute name. Chris@16: * \return Tne number of erased elements Chris@16: */ Chris@16: BOOST_LOG_API size_type erase(key_type key) BOOST_NOEXCEPT; Chris@16: /*! Chris@16: * The method erases the specified attribute Chris@16: * Chris@16: * \post All iterators to the erased element become invalid. Chris@16: * \param it A valid iterator to the element to be erased. Chris@16: * \return Tne number of erased elements Chris@16: */ Chris@16: BOOST_LOG_API void erase(iterator it) BOOST_NOEXCEPT; Chris@16: /*! Chris@16: * The method erases all attributes within the specified range Chris@16: * Chris@16: * \pre \a end is reachable from \a begin with a finite number of increments. Chris@16: * \post All iterators to the erased elements become invalid. Chris@16: * \param begin An iterator that points to the first element to be erased. Chris@16: * \param end An iterator that points to the after-the-last element to be erased. Chris@16: */ Chris@16: BOOST_LOG_API void erase(iterator begin, iterator end) BOOST_NOEXCEPT; Chris@16: Chris@16: /*! Chris@16: * The method removes all elements from the container Chris@16: * Chris@16: * \post empty() == true Chris@16: */ Chris@16: BOOST_LOG_API void clear() BOOST_NOEXCEPT; Chris@16: }; Chris@16: Chris@16: /*! Chris@16: * Free swap overload Chris@16: */ Chris@16: inline void swap(attribute_set& left, attribute_set& right) BOOST_NOEXCEPT Chris@16: { Chris@16: left.swap(right); Chris@16: } Chris@16: Chris@16: namespace aux { Chris@16: Chris@16: //! Conversion operator (would be invoked in case of reading from the container) Chris@16: inline attribute_set_reference_proxy::operator mapped_type() const BOOST_NOEXCEPT Chris@16: { Chris@16: attribute_set::iterator it = m_pContainer->find(m_key); Chris@16: if (it != m_pContainer->end()) Chris@16: return it->second; Chris@16: else Chris@16: return mapped_type(); Chris@16: } Chris@16: Chris@16: //! Assignment operator (would be invoked in case of writing to the container) Chris@16: inline attribute_set_reference_proxy::mapped_type& attribute_set_reference_proxy::operator= (mapped_type const& val) const Chris@16: { Chris@16: std::pair< attribute_set::iterator, bool > res = m_pContainer->insert(m_key, val); Chris@16: if (!res.second) Chris@16: res.first->second = val; Chris@16: return res.first->second; Chris@16: } Chris@16: Chris@16: } // namespace aux Chris@16: Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: inline attribute& attribute::operator= (aux::attribute_set_reference_proxy const& that) BOOST_NOEXCEPT Chris@16: { Chris@16: attribute attr = that; Chris@16: this->swap(attr); Chris@16: return *this; Chris@16: } Chris@16: #endif Chris@16: Chris@16: BOOST_LOG_CLOSE_NAMESPACE // namespace log Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_LOG_ATTRIBUTE_SET_HPP_INCLUDED_