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