]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
7c673cae | 21 | #include <boost/move/core.hpp> |
f67539c2 TL |
22 | #include <boost/core/enable_if.hpp> |
23 | #include <boost/type_traits/conditional.hpp> | |
7c673cae | 24 | #include <boost/log/detail/config.hpp> |
f67539c2 | 25 | #include <boost/log/detail/sfinae_tools.hpp> |
7c673cae FG |
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 | |
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) | |
65 | 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; | |
f67539c2 | 162 | typedef typename boost::conditional< |
7c673cae FG |
163 | fConstV, |
164 | attribute_set::const_reference, | |
165 | attribute_set::reference | |
166 | >::type reference; | |
f67539c2 | 167 | typedef typename boost::conditional< |
7c673cae FG |
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 | |
f67539c2 | 176 | BOOST_CONSTEXPR iter() BOOST_NOEXCEPT : m_pNode(NULL) {} |
7c673cae | 177 | explicit iter(node_base* pNode) BOOST_NOEXCEPT : m_pNode(pNode) {} |
f67539c2 TL |
178 | #if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) |
179 | template< bool fOtherConstV, typename = typename boost::enable_if_c< !fOtherConstV && fOtherConstV != fConstV >::type > | |
180 | iter(iter< fOtherConstV > const& that) BOOST_NOEXCEPT : m_pNode(that.m_pNode) {} | |
181 | #else | |
182 | template< bool fOtherConstV > | |
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 | |
7c673cae FG |
188 | |
189 | //! Assignment | |
f67539c2 TL |
190 | template< bool fOtherConstV > |
191 | typename boost::enable_if_c< !fOtherConstV && fOtherConstV != fConstV, iter& >::type operator= (iter< fOtherConstV > const& that) BOOST_NOEXCEPT | |
7c673cae FG |
192 | { |
193 | m_pNode = that.m_pNode; | |
194 | return *this; | |
195 | } | |
196 | ||
197 | // Comparison | |
f67539c2 TL |
198 | template< bool fOtherConstV > |
199 | 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 > | |
201 | typename boost::enable_if_c< !fOtherConstV || fOtherConstV == fConstV, bool >::type operator!= (iter< fOtherConstV > const& that) const BOOST_NOEXCEPT { return (m_pNode != that.m_pNode); } | |
7c673cae FG |
202 | |
203 | // Modification | |
204 | iter& operator++ () BOOST_NOEXCEPT | |
205 | { | |
206 | m_pNode = m_pNode->m_pNext; | |
207 | return *this; | |
208 | } | |
209 | iter& operator-- () BOOST_NOEXCEPT | |
210 | { | |
211 | m_pNode = m_pNode->m_pPrev; | |
212 | return *this; | |
213 | } | |
214 | iter operator++ (int) BOOST_NOEXCEPT | |
215 | { | |
216 | iter tmp(*this); | |
217 | m_pNode = m_pNode->m_pNext; | |
218 | return tmp; | |
219 | } | |
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 | |
228 | pointer operator-> () const BOOST_NOEXCEPT { return &(static_cast< node* >(m_pNode)->m_Value); } | |
229 | reference operator* () const BOOST_NOEXCEPT { return static_cast< node* >(m_pNode)->m_Value; } | |
230 | ||
231 | 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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
335 | 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 | */ | |
350 | 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 | */ | |
361 | 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 | */ | |
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 | */ | |
387 | 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 | */ | |
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 > | |
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 > | |
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 | */ | |
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 | |
490 | 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) | |
500 | 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 | |
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_ |