1 | //Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. |
2 | |
3 | //Distributed under the Boost Software License, Version 1.0. (See accompanying |
4 | //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
5 | |
6 | #ifndef BOOST_EXCEPTION_8D22C4CA9CC811DCAA9133D256D89593 |
7 | #define BOOST_EXCEPTION_8D22C4CA9CC811DCAA9133D256D89593 |
8 | |
9 | #include <boost/config.hpp> |
10 | #include <boost/exception/exception.hpp> |
11 | #include <boost/exception/to_string_stub.hpp> |
12 | #include <boost/exception/detail/error_info_impl.hpp> |
13 | #include <boost/exception/detail/shared_ptr.hpp> |
14 | #include <map> |
15 | |
16 | #ifndef BOOST_EXCEPTION_ENABLE_WARNINGS |
17 | #if __GNUC__*100+__GNUC_MINOR__>301 |
18 | #pragma GCC system_header |
19 | #endif |
20 | #ifdef __clang__ |
21 | #pragma clang system_header |
22 | #endif |
23 | #ifdef _MSC_VER |
24 | #pragma warning(push,1) |
25 | #endif |
26 | #endif |
27 | |
28 | namespace |
29 | boost |
30 | { |
31 | template <class Tag,class T> |
32 | inline |
33 | std::string |
34 | error_info_name( error_info<Tag,T> const & x ) |
35 | { |
36 | return tag_type_name<Tag>(); |
37 | } |
38 | |
39 | template <class Tag,class T> |
40 | inline |
41 | std::string |
42 | to_string( error_info<Tag,T> const & x ) |
43 | { |
44 | return '[' + error_info_name(x) + "] = " + to_string_stub(x.value()) + '\n'; |
45 | } |
46 | |
47 | template <class Tag,class T> |
48 | inline |
49 | std::string |
50 | error_info<Tag,T>:: |
51 | name_value_string() const |
52 | { |
53 | return to_string_stub(*this); |
54 | } |
55 | |
56 | namespace |
57 | exception_detail |
58 | { |
59 | class |
60 | error_info_container_impl BOOST_FINAL: |
61 | public error_info_container |
62 | { |
63 | public: |
64 | |
65 | error_info_container_impl(): |
66 | count_(0) |
67 | { |
68 | } |
69 | |
70 | ~error_info_container_impl() BOOST_NOEXCEPT_OR_NOTHROW |
71 | { |
72 | } |
73 | |
74 | void |
75 | set( shared_ptr<error_info_base> const & x, type_info_ const & typeid_ ) |
76 | { |
77 | BOOST_ASSERT(x); |
78 | info_[typeid_] = x; |
79 | diagnostic_info_str_.clear(); |
80 | } |
81 | |
82 | shared_ptr<error_info_base> |
83 | get( type_info_ const & ti ) const |
84 | { |
85 | error_info_map::const_iterator i=info_.find(x: ti); |
86 | if( info_.end()!=i ) |
87 | { |
88 | shared_ptr<error_info_base> const & p = i->second; |
89 | #ifndef BOOST_NO_RTTI |
90 | BOOST_ASSERT( *BOOST_EXCEPTION_DYNAMIC_TYPEID(*p).type_==*ti.type_ ); |
91 | #endif |
92 | return p; |
93 | } |
94 | return shared_ptr<error_info_base>(); |
95 | } |
96 | |
97 | char const * |
98 | diagnostic_information( char const * ) const |
99 | { |
100 | if( header ) |
101 | { |
102 | std::ostringstream tmp; |
103 | tmp << header; |
104 | for( error_info_map::const_iterator i=info_.begin(),end=info_.end(); i!=end; ++i ) |
105 | { |
106 | error_info_base const & x = *i->second; |
107 | tmp << x.name_value_string(); |
108 | } |
109 | tmp.str().swap(s&: diagnostic_info_str_); |
110 | } |
111 | return diagnostic_info_str_.c_str(); |
112 | } |
113 | |
114 | private: |
115 | |
116 | friend class boost::exception; |
117 | |
118 | typedef std::map< type_info_, shared_ptr<error_info_base> > error_info_map; |
119 | error_info_map info_; |
120 | mutable std::string diagnostic_info_str_; |
121 | mutable int count_; |
122 | |
123 | error_info_container_impl( error_info_container_impl const & ); |
124 | error_info_container_impl & operator=( error_info_container const & ); |
125 | |
126 | void |
127 | add_ref() const |
128 | { |
129 | ++count_; |
130 | } |
131 | |
132 | bool |
133 | release() const |
134 | { |
135 | if( --count_ ) |
136 | return false; |
137 | else |
138 | { |
139 | delete this; |
140 | return true; |
141 | } |
142 | } |
143 | |
144 | refcount_ptr<error_info_container> |
145 | clone() const |
146 | { |
147 | refcount_ptr<error_info_container> p; |
148 | error_info_container_impl * c=new error_info_container_impl; |
149 | p.adopt(px: c); |
150 | for( error_info_map::const_iterator i=info_.begin(),e=info_.end(); i!=e; ++i ) |
151 | { |
152 | shared_ptr<error_info_base> cp(i->second->clone()); |
153 | c->info_.insert(x: std::make_pair(x: i->first,y&: cp)); |
154 | } |
155 | return p; |
156 | } |
157 | }; |
158 | |
159 | template <class E,class Tag,class T> |
160 | inline |
161 | E const & |
162 | set_info( E const & x, error_info<Tag,T> const & v ) |
163 | { |
164 | typedef error_info<Tag,T> error_info_tag_t; |
165 | shared_ptr<error_info_tag_t> p( new error_info_tag_t(v) ); |
166 | exception_detail::error_info_container * c=x.data_.get(); |
167 | if( !c ) |
168 | x.data_.adopt(c=new exception_detail::error_info_container_impl); |
169 | c->set(p,BOOST_EXCEPTION_STATIC_TYPEID(error_info_tag_t)); |
170 | return x; |
171 | } |
172 | |
173 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
174 | template <class E,class Tag,class T> |
175 | E const & set_info( E const &, error_info<Tag,T> && ); |
176 | template <class T> |
177 | struct set_info_rv; |
178 | template <class Tag,class T> |
179 | struct |
180 | set_info_rv<error_info<Tag,T> > |
181 | { |
182 | template <class E,class Tag1,class T1> |
183 | friend E const & set_info( E const &, error_info<Tag1,T1> && ); |
184 | template <class E> |
185 | static |
186 | E const & |
187 | set( E const & x, error_info<Tag,T> && v ) |
188 | { |
189 | typedef error_info<Tag,T> error_info_tag_t; |
190 | shared_ptr<error_info_tag_t> p( new error_info_tag_t(std::move(v)) ); |
191 | exception_detail::error_info_container * c=x.data_.get(); |
192 | if( !c ) |
193 | x.data_.adopt(c=new exception_detail::error_info_container_impl); |
194 | c->set(p,BOOST_EXCEPTION_STATIC_TYPEID(error_info_tag_t)); |
195 | return x; |
196 | } |
197 | }; |
198 | template <> |
199 | struct |
200 | set_info_rv<throw_function> |
201 | { |
202 | template <class E,class Tag1,class T1> |
203 | friend E const & set_info( E const &, error_info<Tag1,T1> && ); |
204 | template <class E> |
205 | static |
206 | E const & |
207 | set( E const & x, throw_function && y ) |
208 | { |
209 | x.throw_function_=y.v_; |
210 | return x; |
211 | } |
212 | }; |
213 | template <> |
214 | struct |
215 | set_info_rv<throw_file> |
216 | { |
217 | template <class E,class Tag1,class T1> |
218 | friend E const & set_info( E const &, error_info<Tag1,T1> && ); |
219 | template <class E> |
220 | static |
221 | E const & |
222 | set( E const & x, throw_file && y ) |
223 | { |
224 | x.throw_file_=y.v_; |
225 | return x; |
226 | } |
227 | }; |
228 | template <> |
229 | struct |
230 | set_info_rv<throw_line> |
231 | { |
232 | template <class E,class Tag1,class T1> |
233 | friend E const & set_info( E const &, error_info<Tag1,T1> && ); |
234 | template <class E> |
235 | static |
236 | E const & |
237 | set( E const & x, throw_line && y ) |
238 | { |
239 | x.throw_line_=y.v_; |
240 | return x; |
241 | } |
242 | }; |
243 | template <class E,class Tag,class T> |
244 | inline |
245 | E const & |
246 | set_info( E const & x, error_info<Tag,T> && v ) |
247 | { |
248 | return set_info_rv<error_info<Tag,T> >::template set<E>(x,std::move(v)); |
249 | } |
250 | #endif |
251 | |
252 | template <class T> |
253 | struct |
254 | derives_boost_exception |
255 | { |
256 | enum e { value = (sizeof(dispatch_boost_exception((T*)0))==sizeof(large_size)) }; |
257 | }; |
258 | } |
259 | |
260 | template <class E,class Tag,class T> |
261 | inline |
262 | typename enable_if<exception_detail::derives_boost_exception<E>,E const &>::type |
263 | operator<<( E const & x, error_info<Tag,T> const & v ) |
264 | { |
265 | return exception_detail::set_info(x,v); |
266 | } |
267 | |
268 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
269 | template <class E,class Tag,class T> |
270 | inline |
271 | typename enable_if<exception_detail::derives_boost_exception<E>,E const &>::type |
272 | operator<<( E const & x, error_info<Tag,T> && v ) |
273 | { |
274 | return exception_detail::set_info(x,std::move(v)); |
275 | } |
276 | #endif |
277 | } |
278 | |
279 | #if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) |
280 | #pragma warning(pop) |
281 | #endif |
282 | #endif |
283 | |