• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
operator ()boost::attribute_name::repository::node::order_by_name86             bool operator() (node const& left, node const& right) const
87             {
88                 return std::strcmp(left.m_name.c_str(), right.m_name.c_str()) < 0;
89             }
operator ()boost::attribute_name::repository::node::order_by_name90             bool operator() (node const& left, const char* right) const
91             {
92                 return std::strcmp(left.m_name.c_str(), right) < 0;
93             }
operator ()boost::attribute_name::repository::node::order_by_name94             bool operator() (const char* left, node const& right) const
95             {
96                 return std::strcmp(left, right.m_name.c_str()) < 0;
97             }
98         };
99 
100     public:
101         id_type m_id;
102         string_type m_name;
103 
104     public:
nodeboost::attribute_name::repository::node105         node() : m_id(0), m_name() {}
nodeboost::attribute_name::repository::node106         node(id_type i, string_type const& n) :
107             base_type(),
108             m_id(i),
109             m_name(n)
110         {
111         }
nodeboost::attribute_name::repository::node112         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
get_id_from_string(const char * name)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(name, 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(name, 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(node(static_cast< id_type >(new_id), name));
165             it = m_NodeSet.insert(it, m_NodeList.back());
166         }
167         return it->m_id;
168     }
169 
170     //! Converts id to the attribute name string
get_string_from_id(id_type id)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
init_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
get_id_from_string(const char * name)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&
get_string_from_id(id_type id)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 >
operator <<(std::basic_ostream<CharT,TraitsT> & strm,attribute_name const & name)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