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_value_set.hpp Chris@16: * \author Andrey Semashev Chris@16: * \date 21.04.2007 Chris@16: * Chris@16: * This header file contains definition of attribute value set. The set is constructed from Chris@16: * three attribute sets (global, thread-specific and source-specific) and contains attribute Chris@16: * values. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_LOG_ATTRIBUTE_VALUE_SET_HPP_INCLUDED_ Chris@16: #define BOOST_LOG_ATTRIBUTE_VALUE_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: #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: /*! Chris@16: * \brief A set of attribute values Chris@16: * Chris@16: * The set of attribute values is an associative container with attribute name as a key and Chris@16: * a pointer to attribute value object as a mapped type. This is a collection of elements with unique Chris@16: * keys, that is, there can be only one attribute value with a given name in the set. With respect to Chris@16: * read-only capabilities, the set interface is close to \c std::unordered_map. Chris@16: * Chris@16: * The set is designed to be only capable of adding elements to it. Once added, the attribute value Chris@16: * cannot be removed from the set. Chris@16: * Chris@16: * An instance of attribute value set can be constructed from three attribute sets. The constructor attempts to Chris@16: * accommodate values of all attributes from the sets. The situation when a same-named attribute is found Chris@16: * in more than one attribute set is possible. This problem is solved on construction of the value set: the three Chris@16: * attribute sets have different priorities when it comes to solving conflicts. Chris@16: * Chris@16: * From the library perspective the three source attribute sets are global, thread-specific and source-specific Chris@16: * attributes, with the latter having the highest priority. This feature allows to override attributes of wider scopes Chris@16: * with the more specific ones. Chris@16: * Chris@16: * For sake of performance, the attribute values are not immediately acquired from attribute sets at construction. Chris@16: * Instead, on-demand acquisition is performed either on iterator dereferencing or on call to the \c freeze method. Chris@16: * Once acquired, the attribute value stays within the set until its destruction. This nuance does not affect Chris@16: * other set properties, such as size or lookup ability. The logging core automatically freezes the set Chris@16: * at the right point, so users should not be bothered unless they manually create attribute value sets. Chris@16: * Chris@16: * \note The attribute sets that were used for the value set construction must not be modified or destroyed Chris@16: * until the value set is frozen. Otherwise the behavior is undefined. Chris@16: */ Chris@16: class attribute_value_set Chris@16: { Chris@16: BOOST_COPYABLE_AND_MOVABLE_ALT(attribute_value_set) 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_value 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: //! Pointer difference type Chris@16: typedef std::ptrdiff_t difference_type; Chris@16: Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: private: 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: bool m_DynamicallyAllocated; Chris@16: Chris@16: node(key_type const& key, mapped_type& data, bool dynamic); Chris@16: }; Chris@16: Chris@16: public: Chris@16: class const_iterator; Chris@16: friend class const_iterator; Chris@16: class const_iterator Chris@16: { Chris@16: public: Chris@16: // Standard typedefs Chris@16: typedef attribute_value_set::difference_type difference_type; Chris@16: typedef attribute_value_set::value_type value_type; Chris@16: typedef attribute_value_set::const_reference reference; Chris@16: typedef attribute_value_set::const_pointer pointer; Chris@16: typedef std::bidirectional_iterator_tag iterator_category; Chris@16: Chris@16: public: Chris@16: // Constructors Chris@16: BOOST_CONSTEXPR const_iterator() : m_pNode(NULL), m_pContainer(NULL) {} Chris@16: explicit const_iterator(node_base* n, attribute_value_set* cont) BOOST_NOEXCEPT : Chris@16: m_pNode(n), Chris@16: m_pContainer(cont) Chris@16: { Chris@16: } Chris@16: Chris@16: // Comparison Chris@16: bool operator== (const_iterator const& that) const BOOST_NOEXCEPT Chris@16: { Chris@16: return (m_pNode == that.m_pNode); Chris@16: } Chris@16: bool operator!= (const_iterator const& that) const BOOST_NOEXCEPT Chris@16: { Chris@16: return (m_pNode != that.m_pNode); Chris@16: } Chris@16: Chris@16: // Modification Chris@16: const_iterator& operator++ () Chris@16: { Chris@16: m_pContainer->freeze(); Chris@16: m_pNode = m_pNode->m_pNext; Chris@16: return *this; Chris@16: } Chris@16: const_iterator& operator-- () Chris@16: { Chris@16: m_pContainer->freeze(); Chris@16: m_pNode = m_pNode->m_pPrev; Chris@16: return *this; Chris@16: } Chris@16: const_iterator operator++ (int) Chris@16: { Chris@16: const_iterator tmp(*this); Chris@16: m_pContainer->freeze(); Chris@16: m_pNode = m_pNode->m_pNext; Chris@16: return tmp; Chris@16: } Chris@16: const_iterator operator-- (int) Chris@16: { Chris@16: const_iterator tmp(*this); Chris@16: m_pContainer->freeze(); 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: private: Chris@16: node_base* m_pNode; Chris@16: attribute_value_set* m_pContainer; Chris@16: }; Chris@16: Chris@16: #else Chris@16: Chris@16: /*! Chris@16: * Constant iterator type with bidirectional capabilities. Chris@16: */ Chris@16: typedef implementation_defined const_iterator; Chris@16: Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: private: Chris@16: //! Pointer to the container implementation Chris@16: implementation* m_pImpl; Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Default constructor Chris@16: * Chris@16: * The constructor creates an empty set which can be filled later by subsequent Chris@16: * calls of \c insert method. Optionally, the amount of storage reserved for elements Chris@16: * to be inserted may be passed to the constructor. Chris@16: * The constructed set is frozen. Chris@16: * Chris@16: * \param reserve_count Number of elements to reserve space for. Chris@16: */ Chris@16: BOOST_LOG_API explicit attribute_value_set(size_type reserve_count = 8); Chris@16: Chris@16: /*! Chris@16: * Move constructor Chris@16: */ Chris@16: attribute_value_set(BOOST_RV_REF(attribute_value_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: * The constructor adopts three attribute sets into the value set. Chris@16: * The \a source_attrs attributes have the greatest preference when a same-named Chris@16: * attribute is found in several sets, \a global_attrs has the least. Chris@16: * The constructed set is not frozen. Chris@16: * Chris@16: * \param source_attrs A set of source-specific attributes. Chris@16: * \param thread_attrs A set of thread-specific attributes. Chris@16: * \param global_attrs A set of global attributes. Chris@16: * \param reserve_count Amount of elements to reserve space for, in addition to the elements in the three attribute sets provided. Chris@16: */ Chris@16: BOOST_LOG_API attribute_value_set( Chris@16: attribute_set const& source_attrs, Chris@16: attribute_set const& thread_attrs, Chris@16: attribute_set const& global_attrs, Chris@16: size_type reserve_count = 8); Chris@16: Chris@16: /*! Chris@16: * The constructor adopts three attribute sets into the value set. Chris@16: * The \a source_attrs attributes have the greatest preference when a same-named Chris@16: * attribute is found in several sets, \a global_attrs has the least. Chris@16: * The constructed set is not frozen. Chris@16: * Chris@16: * \pre The \a source_attrs set is frozen. Chris@16: * Chris@16: * \param source_attrs A set of source-specific attributes. Chris@16: * \param thread_attrs A set of thread-specific attributes. Chris@16: * \param global_attrs A set of global attributes. Chris@16: * \param reserve_count Amount of elements to reserve space for, in addition to the elements in the three attribute sets provided. Chris@16: */ Chris@16: BOOST_LOG_API attribute_value_set( Chris@16: attribute_value_set const& source_attrs, Chris@16: attribute_set const& thread_attrs, Chris@16: attribute_set const& global_attrs, Chris@16: size_type reserve_count = 8); Chris@16: Chris@16: /*! Chris@16: * The constructor adopts three attribute sets into the value set. Chris@16: * The \a source_attrs attributes have the greatest preference when a same-named Chris@16: * attribute is found in several sets, \a global_attrs has the least. Chris@16: * The constructed set is not frozen. Chris@16: * Chris@16: * \pre The \a source_attrs set is frozen. Chris@16: * Chris@16: * \param source_attrs A set of source-specific attributes. Chris@16: * \param thread_attrs A set of thread-specific attributes. Chris@16: * \param global_attrs A set of global attributes. Chris@16: * \param reserve_count Amount of elements to reserve space for, in addition to the elements in the three attribute sets provided. Chris@16: */ Chris@16: attribute_value_set( Chris@16: BOOST_RV_REF(attribute_value_set) source_attrs, Chris@16: attribute_set const& thread_attrs, Chris@16: attribute_set const& global_attrs, Chris@16: size_type reserve_count = 8) : m_pImpl(NULL) Chris@16: { Chris@16: construct(static_cast< attribute_value_set& >(source_attrs), thread_attrs, global_attrs, reserve_count); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Copy constructor. Chris@16: * Chris@16: * \pre The original set is frozen. Chris@16: * \post The constructed set is frozen, std::equal(begin(), end(), that.begin()) == true Chris@16: */ Chris@16: BOOST_LOG_API attribute_value_set(attribute_value_set const& that); Chris@16: Chris@16: /*! Chris@16: * Destructor. Releases all referenced attribute values. Chris@16: */ Chris@16: BOOST_LOG_API ~attribute_value_set() BOOST_NOEXCEPT; Chris@16: Chris@16: /*! Chris@16: * Assignment operator Chris@16: */ Chris@16: attribute_value_set& operator= (attribute_value_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 sets Chris@16: * Chris@16: * \b Throws: Nothing. Chris@16: */ Chris@16: void swap(attribute_value_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 set. Chris@16: */ Chris@16: BOOST_LOG_API const_iterator begin() const; Chris@16: /*! Chris@16: * \return Iterator to the after-the-last element of the set. Chris@16: */ Chris@16: BOOST_LOG_API const_iterator end() const; Chris@16: Chris@16: /*! Chris@16: * \return Number of elements in the set. Chris@16: */ Chris@16: BOOST_LOG_API size_type size() const; Chris@16: /*! Chris@101: * \return \c true if there are no elements in the container, \c false otherwise. Chris@16: */ Chris@16: bool empty() const { return (this->size() == 0); } Chris@16: Chris@16: /*! Chris@16: * The method finds the attribute value 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: BOOST_LOG_API const_iterator find(key_type key) const; Chris@16: Chris@16: /*! Chris@16: * Alternative lookup syntax. Chris@16: * Chris@16: * \param key Attribute name. Chris@16: * \return A pointer to the attribute value if it is found with \a key, default-constructed mapped value otherwise. Chris@16: */ Chris@16: mapped_type operator[] (key_type key) const Chris@16: { Chris@16: const_iterator it = this->find(key); Chris@16: if (it != this->end()) Chris@16: return it->second; Chris@16: else Chris@16: return mapped_type(); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Alternative lookup syntax. Chris@16: * Chris@16: * \param keyword Attribute keyword. Chris@16: * \return A \c value_ref with extracted attribute value if it is found, empty \c value_ref otherwise. Chris@16: */ Chris@16: template< typename DescriptorT, template< typename > class ActorT > Chris@16: typename result_of::extract< typename expressions::attribute_keyword< DescriptorT, ActorT >::value_type, DescriptorT >::type Chris@16: operator[] (expressions::attribute_keyword< DescriptorT, ActorT > const& keyword) const Chris@16: { Chris@16: typedef typename expressions::attribute_keyword< DescriptorT, ActorT >::value_type attr_value_type; Chris@16: typedef typename result_of::extract< attr_value_type, DescriptorT >::type result_type; Chris@16: const_iterator it = this->find(keyword.get_name()); Chris@16: if (it != this->end()) Chris@16: return it->second.extract< attr_value_type, DescriptorT >(); Chris@16: else Chris@16: return result_type(); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * The method counts the number of the attribute value occurrences in the set. Since there can be only one Chris@16: * attribute value 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 value is found in the container. Chris@16: */ Chris@16: size_type count(key_type key) const { return size_type(this->find(key) != this->end()); } Chris@16: Chris@16: /*! Chris@16: * The method acquires values of all adopted attributes. Chris@16: * Chris@16: * \post The set is frozen. Chris@16: */ Chris@16: BOOST_LOG_API void freeze(); Chris@16: Chris@16: /*! Chris@16: * Inserts an element into the set. The complexity of the operation is amortized constant. Chris@16: * Chris@16: * \pre The set is frozen. Chris@16: * Chris@16: * \param key The attribute name. Chris@16: * \param mapped The attribute value. Chris@16: * Chris@16: * \returns An iterator to the inserted element and \c true if insertion succeeded. Otherwise, Chris@16: * if the set already contains a same-named attribute value, iterator to the Chris@16: * existing element and \c false. Chris@16: */ Chris@16: BOOST_LOG_API std::pair< const_iterator, bool > insert(key_type key, mapped_type const& mapped); Chris@16: Chris@16: /*! Chris@16: * Inserts an element into the set. The complexity of the operation is amortized constant. Chris@16: * Chris@16: * \pre The set is frozen. Chris@16: * Chris@16: * \param value The attribute name and value. Chris@16: * Chris@16: * \returns An iterator to the inserted element and \c true if insertion succeeded. Otherwise, Chris@16: * if the set already contains a same-named attribute value, iterator to the Chris@16: * existing element and \c false. Chris@16: */ Chris@16: std::pair< const_iterator, bool > insert(const_reference value) { return this->insert(value.first, value.second); } Chris@16: Chris@16: /*! Chris@16: * Mass insertion method. The complexity of the operation is linear to the number of elements inserted. Chris@16: * Chris@16: * \pre The set is frozen. 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: * The complexity of the operation is linear to the number of elements inserted times the complexity Chris@16: * of filling the \a out iterator. Chris@16: * Chris@16: * \pre The set is frozen. 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: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: private: Chris@16: //! Constructs the object by moving from \a source_attrs. This function is mostly needed to maintain ABI stable between C++03 and C++11. Chris@16: BOOST_LOG_API void construct( Chris@16: attribute_value_set& source_attrs, Chris@16: attribute_set const& thread_attrs, Chris@16: attribute_set const& global_attrs, Chris@16: size_type reserve_count); Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: }; Chris@16: Chris@16: /*! Chris@16: * Free swap overload Chris@16: */ Chris@16: inline void swap(attribute_value_set& left, attribute_value_set& right) BOOST_NOEXCEPT Chris@16: { Chris@16: left.swap(right); Chris@16: } 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_VALUE_SET_HPP_INCLUDED_