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_name.cpp |
9 | * \author Andrey Semashev |
10 | * \date 28.06.2010 |
11 | * |
12 | * \brief This header is the Boost.Log library implementation, see the library documentation |
13 | * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. |
14 | */ |
15 | |
16 | #include <boost/log/detail/config.hpp> |
17 | #include <cstring> |
18 | #include <deque> |
19 | #include <ostream> |
20 | #include <stdexcept> |
21 | #include <boost/assert.hpp> |
22 | #include <boost/throw_exception.hpp> |
23 | #include <boost/smart_ptr/shared_ptr.hpp> |
24 | #include <boost/smart_ptr/make_shared_object.hpp> |
25 | #include <boost/intrusive/set.hpp> |
26 | #include <boost/intrusive/set_hook.hpp> |
27 | #include <boost/intrusive/options.hpp> |
28 | #include <boost/log/exceptions.hpp> |
29 | #include <boost/log/detail/singleton.hpp> |
30 | #include <boost/log/attributes/attribute_name.hpp> |
31 | #if !defined(BOOST_LOG_NO_THREADS) |
32 | #include <boost/log/detail/locks.hpp> |
33 | #include <boost/log/detail/light_rw_mutex.hpp> |
34 | #endif |
35 | #include <boost/log/detail/header.hpp> |
36 | |
37 | namespace boost { |
38 | |
39 | BOOST_LOG_OPEN_NAMESPACE |
40 | |
41 | //! A global container of all known attribute names |
42 | class attribute_name::repository : |
43 | public log::aux::lazy_singleton< |
44 | repository, |
45 | shared_ptr< repository > |
46 | > |
47 | { |
48 | typedef log::aux::lazy_singleton< |
49 | repository, |
50 | shared_ptr< repository > |
51 | > base_type; |
52 | |
53 | #if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS) |
54 | friend class log::aux::lazy_singleton< |
55 | repository, |
56 | shared_ptr< repository > |
57 | >; |
58 | #else |
59 | friend class base_type; |
60 | #endif |
61 | |
62 | public: |
63 | // Import types from the basic_attribute_name template |
64 | typedef attribute_name::id_type id_type; |
65 | typedef attribute_name::string_type string_type; |
66 | |
67 | //! A base hook for arranging the attribute names into a set |
68 | typedef intrusive::set_base_hook< |
69 | intrusive::link_mode< intrusive::safe_link >, |
70 | intrusive::optimize_size< true > |
71 | > node_by_name_hook; |
72 | |
73 | private: |
74 | //! An element of the attribute names repository |
75 | struct node : |
76 | public node_by_name_hook |
77 | { |
78 | typedef node_by_name_hook base_type; |
79 | |
80 | public: |
81 | //! A predicate for name-based ordering |
82 | struct order_by_name |
83 | { |
84 | typedef bool result_type; |
85 | |
86 | bool operator() (node const& left, node const& right) const |
87 | { |
88 | return std::strcmp(s1: left.m_name.c_str(), s2: right.m_name.c_str()) < 0; |
89 | } |
90 | bool operator() (node const& left, const char* right) const |
91 | { |
92 | return std::strcmp(s1: left.m_name.c_str(), s2: right) < 0; |
93 | } |
94 | bool operator() (const char* left, node const& right) const |
95 | { |
96 | return std::strcmp(s1: left, s2: right.m_name.c_str()) < 0; |
97 | } |
98 | }; |
99 | |
100 | public: |
101 | id_type m_id; |
102 | string_type m_name; |
103 | |
104 | public: |
105 | node() : m_id(0), m_name() {} |
106 | node(id_type i, string_type const& n) : |
107 | base_type(), |
108 | m_id(i), |
109 | m_name(n) |
110 | { |
111 | } |
112 | node(node const& that) : |
113 | base_type(), |
114 | m_id(that.m_id), |
115 | m_name(that.m_name) |
116 | { |
117 | } |
118 | }; |
119 | |
120 | //! The container that provides storage for nodes |
121 | typedef std::deque< node > node_list; |
122 | //! The container that provides name-based lookup |
123 | typedef intrusive::set< |
124 | node, |
125 | intrusive::base_hook< node_by_name_hook >, |
126 | intrusive::constant_time_size< false >, |
127 | intrusive::compare< node::order_by_name > |
128 | > node_set; |
129 | |
130 | private: |
131 | #if !defined(BOOST_LOG_NO_THREADS) |
132 | typedef log::aux::light_rw_mutex mutex_type; |
133 | log::aux::light_rw_mutex m_Mutex; |
134 | #endif |
135 | node_list m_NodeList; |
136 | node_set m_NodeSet; |
137 | |
138 | public: |
139 | //! Converts attribute name string to id |
140 | id_type get_id_from_string(const char* name) |
141 | { |
142 | BOOST_ASSERT(name != NULL); |
143 | |
144 | #if !defined(BOOST_LOG_NO_THREADS) |
145 | { |
146 | // Do a non-blocking lookup first |
147 | log::aux::shared_lock_guard< mutex_type > _(m_Mutex); |
148 | node_set::const_iterator it = |
149 | m_NodeSet.find(key: name, comp: node::order_by_name()); |
150 | if (it != m_NodeSet.end()) |
151 | return it->m_id; |
152 | } |
153 | #endif // !defined(BOOST_LOG_NO_THREADS) |
154 | |
155 | BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< mutex_type > _(m_Mutex);) |
156 | node_set::iterator it = |
157 | m_NodeSet.lower_bound(key: name, comp: node::order_by_name()); |
158 | if (it == m_NodeSet.end() || it->m_name != name) |
159 | { |
160 | const std::size_t new_id = m_NodeList.size(); |
161 | if (new_id >= static_cast< id_type >(attribute_name::uninitialized)) |
162 | BOOST_THROW_EXCEPTION(limitation_error("Too many log attribute names" )); |
163 | |
164 | m_NodeList.push_back(x: node(static_cast< id_type >(new_id), name)); |
165 | it = m_NodeSet.insert(hint: it, value&: m_NodeList.back()); |
166 | } |
167 | return it->m_id; |
168 | } |
169 | |
170 | //! Converts id to the attribute name string |
171 | string_type const& get_string_from_id(id_type id) |
172 | { |
173 | BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< mutex_type > _(m_Mutex);) |
174 | BOOST_ASSERT(id < m_NodeList.size()); |
175 | return m_NodeList[id].m_name; |
176 | } |
177 | |
178 | private: |
179 | //! Initializes the singleton instance |
180 | static void init_instance() |
181 | { |
182 | base_type::get_instance() = boost::make_shared< repository >(); |
183 | } |
184 | }; |
185 | |
186 | BOOST_LOG_API attribute_name::id_type |
187 | attribute_name::get_id_from_string(const char* name) |
188 | { |
189 | return repository::get()->get_id_from_string(name); |
190 | } |
191 | |
192 | BOOST_LOG_API attribute_name::string_type const& |
193 | attribute_name::get_string_from_id(id_type id) |
194 | { |
195 | return repository::get()->get_string_from_id(id); |
196 | } |
197 | |
198 | template< typename CharT, typename TraitsT > |
199 | BOOST_LOG_API std::basic_ostream< CharT, TraitsT >& operator<< ( |
200 | std::basic_ostream< CharT, TraitsT >& strm, |
201 | attribute_name const& name) |
202 | { |
203 | if (!!name) |
204 | strm << name.string().c_str(); |
205 | else |
206 | strm << "[uninitialized]" ; |
207 | return strm; |
208 | } |
209 | |
210 | // Explicitly instantiate attribute name implementation |
211 | #ifdef BOOST_LOG_USE_CHAR |
212 | template BOOST_LOG_API std::basic_ostream< char, std::char_traits< char > >& |
213 | operator<< < char, std::char_traits< char > >( |
214 | std::basic_ostream< char, std::char_traits< char > >& strm, |
215 | attribute_name const& name); |
216 | #endif |
217 | #ifdef BOOST_LOG_USE_WCHAR_T |
218 | template BOOST_LOG_API std::basic_ostream< wchar_t, std::char_traits< wchar_t > >& |
219 | operator<< < wchar_t, std::char_traits< wchar_t > >( |
220 | std::basic_ostream< wchar_t, std::char_traits< wchar_t > >& strm, |
221 | attribute_name const& name); |
222 | #endif |
223 | |
224 | BOOST_LOG_CLOSE_NAMESPACE // namespace log |
225 | |
226 | } // namespace boost |
227 | |
228 | #include <boost/log/detail/footer.hpp> |
229 | |