]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/leaf/error.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / leaf / error.hpp
1 #ifndef BOOST_LEAF_ERROR_HPP_INCLUDED
2 #define BOOST_LEAF_ERROR_HPP_INCLUDED
3
4 // Copyright 2018-2022 Emil Dotchevski and Reverge Studios, Inc.
5
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8
9 #include <boost/leaf/config.hpp>
10 #include <boost/leaf/detail/optional.hpp>
11 #include <boost/leaf/detail/demangle.hpp>
12 #include <boost/leaf/detail/function_traits.hpp>
13 #include <boost/leaf/detail/print.hpp>
14
15 #include <type_traits>
16 #include <iosfwd>
17
18 #if BOOST_LEAF_CFG_DIAGNOSTICS
19 # include <sstream>
20 # include <string>
21 # include <set>
22 #endif
23
24 #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
25 # include <system_error>
26 #endif
27
28 #if BOOST_LEAF_CFG_CAPTURE
29 # include <memory>
30 #endif
31
32 #define BOOST_LEAF_TOKEN_PASTE(x, y) x ## y
33 #define BOOST_LEAF_TOKEN_PASTE2(x, y) BOOST_LEAF_TOKEN_PASTE(x, y)
34 #define BOOST_LEAF_TMP BOOST_LEAF_TOKEN_PASTE2(boost_leaf_tmp_, __LINE__)
35
36 #define BOOST_LEAF_ASSIGN(v,r)\
37 auto && BOOST_LEAF_TMP = r;\
38 static_assert(::boost::leaf::is_result_type<typename std::decay<decltype(BOOST_LEAF_TMP)>::type>::value,\
39 "BOOST_LEAF_ASSIGN/BOOST_LEAF_AUTO requires a result object as the second argument (see is_result_type)");\
40 if( !BOOST_LEAF_TMP )\
41 return BOOST_LEAF_TMP.error();\
42 v = std::forward<decltype(BOOST_LEAF_TMP)>(BOOST_LEAF_TMP).value()
43
44 #define BOOST_LEAF_AUTO(v, r)\
45 BOOST_LEAF_ASSIGN(auto v, r)
46
47 #if BOOST_LEAF_CFG_GNUC_STMTEXPR
48
49 #define BOOST_LEAF_CHECK(r)\
50 ({\
51 auto && BOOST_LEAF_TMP = (r);\
52 static_assert(::boost::leaf::is_result_type<typename std::decay<decltype(BOOST_LEAF_TMP)>::type>::value,\
53 "BOOST_LEAF_CHECK requires a result object (see is_result_type)");\
54 if( !BOOST_LEAF_TMP )\
55 return BOOST_LEAF_TMP.error();\
56 std::move(BOOST_LEAF_TMP);\
57 }).value()
58
59 #else
60
61 #define BOOST_LEAF_CHECK(r)\
62 {\
63 auto && BOOST_LEAF_TMP = (r);\
64 static_assert(::boost::leaf::is_result_type<typename std::decay<decltype(BOOST_LEAF_TMP)>::type>::value,\
65 "BOOST_LEAF_CHECK requires a result object (see is_result_type)");\
66 if( !BOOST_LEAF_TMP )\
67 return BOOST_LEAF_TMP.error();\
68 }
69
70 #endif
71
72 #define BOOST_LEAF_NEW_ERROR ::boost::leaf::leaf_detail::inject_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::new_error
73
74 namespace boost { namespace leaf {
75
76 class error_id;
77
78 namespace leaf_detail
79 {
80 struct BOOST_LEAF_SYMBOL_VISIBLE tls_tag_unexpected_enabled_counter;
81 struct BOOST_LEAF_SYMBOL_VISIBLE tls_tag_id_factory_current_id;
82
83 struct inject_loc
84 {
85 char const * const file;
86 int const line;
87 char const * const fn;
88
89 template <class T>
90 friend T operator+( inject_loc loc, T && x ) noexcept
91 {
92 x.load_source_location_(loc.file, loc.line, loc.fn);
93 return std::move(x);
94 }
95 };
96 }
97
98 } }
99
100 ////////////////////////////////////////
101
102 #ifdef BOOST_LEAF_NO_EXCEPTIONS
103
104 namespace boost
105 {
106 BOOST_LEAF_NORETURN void throw_exception( std::exception const & ); // user defined
107 }
108
109 namespace boost { namespace leaf {
110
111 template <class T>
112 BOOST_LEAF_NORETURN void throw_exception( T const & e )
113 {
114 ::boost::throw_exception(e);
115 }
116
117 } }
118
119 #else
120
121 namespace boost { namespace leaf {
122
123 template <class T>
124 BOOST_LEAF_NORETURN void throw_exception( T const & e )
125 {
126 throw e;
127 }
128
129 } }
130
131 #endif
132
133 ////////////////////////////////////////
134
135 namespace boost { namespace leaf {
136
137 #if BOOST_LEAF_CFG_DIAGNOSTICS
138
139 namespace leaf_detail
140 {
141 class BOOST_LEAF_SYMBOL_VISIBLE e_unexpected_count
142 {
143 public:
144
145 char const * (*first_type)();
146 int count;
147
148 BOOST_LEAF_CONSTEXPR explicit e_unexpected_count(char const * (*first_type)()) noexcept:
149 first_type(first_type),
150 count(1)
151 {
152 }
153
154 template <class CharT, class Traits>
155 void print( std::basic_ostream<CharT, Traits> & os ) const
156 {
157 BOOST_LEAF_ASSERT(first_type != 0);
158 BOOST_LEAF_ASSERT(count>0);
159 os << "Detected ";
160 if( count==1 )
161 os << "1 attempt to communicate an unexpected error object";
162 else
163 os << count << " attempts to communicate unexpected error objects, the first one";
164 (os << " of type " << first_type() << '\n').flush();
165 }
166 };
167
168 template <>
169 struct diagnostic<e_unexpected_count, false, false>
170 {
171 static constexpr bool is_invisible = true;
172
173 template <class CharT, class Traits>
174 BOOST_LEAF_CONSTEXPR static void print( std::basic_ostream<CharT, Traits> &, e_unexpected_count const &) noexcept { }
175 };
176
177 class BOOST_LEAF_SYMBOL_VISIBLE e_unexpected_info
178 {
179 std::string s_;
180 std::set<char const *(*)()> already_;
181
182 public:
183
184 e_unexpected_info() noexcept
185 {
186 }
187
188 template <class E>
189 void add(E && e)
190 {
191 if( !diagnostic<E>::is_invisible && already_.insert(&type<E>).second )
192 {
193 std::stringstream s;
194 diagnostic<E>::print(s,e);
195 (s << '\n').flush();
196 s_ += s.str();
197 }
198 }
199
200 template <class CharT, class Traits>
201 void print( std::basic_ostream<CharT, Traits> & os ) const
202 {
203 os << "Unhandled error objects:\n" << s_;
204 }
205 };
206
207 template <>
208 struct diagnostic<e_unexpected_info, false, false>
209 {
210 static constexpr bool is_invisible = true;
211
212 template <class CharT, class Traits>
213 BOOST_LEAF_CONSTEXPR static void print( std::basic_ostream<CharT, Traits> &, e_unexpected_info const &) noexcept { }
214 };
215
216 }
217
218 #endif
219
220 } }
221
222 ////////////////////////////////////////
223
224 namespace boost { namespace leaf {
225
226 struct BOOST_LEAF_SYMBOL_VISIBLE e_source_location
227 {
228 char const * file;
229 int line;
230 char const * function;
231
232 template <class CharT, class Traits>
233 friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, e_source_location const & x )
234 {
235 return os << leaf::type<e_source_location>() << ": " << x.file << '(' << x.line << ") in function " << x.function;
236 }
237 };
238
239 ////////////////////////////////////////
240
241 namespace leaf_detail
242 {
243 template <class E>
244 class BOOST_LEAF_SYMBOL_VISIBLE slot:
245 optional<E>
246 {
247 slot( slot const & ) = delete;
248 slot & operator=( slot const & ) = delete;
249
250 using impl = optional<E>;
251 slot<E> * prev_;
252
253 public:
254
255 BOOST_LEAF_CONSTEXPR slot() noexcept:
256 prev_(0)
257 {
258 }
259
260 BOOST_LEAF_CONSTEXPR slot( slot && x ) noexcept:
261 optional<E>(std::move(x)),
262 prev_(0)
263 {
264 BOOST_LEAF_ASSERT(x.prev_==0);
265 }
266
267 BOOST_LEAF_CONSTEXPR void activate() noexcept
268 {
269 prev_ = tls::read_ptr<slot<E>>();
270 tls::write_ptr<slot<E>>(this);
271 }
272
273 BOOST_LEAF_CONSTEXPR void deactivate() noexcept
274 {
275 tls::write_ptr<slot<E>>(prev_);
276 }
277
278 BOOST_LEAF_CONSTEXPR void propagate( int err_id ) noexcept;
279
280 template <class CharT, class Traits>
281 void print( std::basic_ostream<CharT, Traits> & os, int key_to_print ) const
282 {
283 #if BOOST_LEAF_CFG_DIAGNOSTICS
284 if( !diagnostic<E>::is_invisible )
285 if( int k = this->key() )
286 {
287 if( key_to_print )
288 {
289 if( key_to_print!=k )
290 return;
291 }
292 else
293 os << '[' << k << ']';
294 diagnostic<E>::print(os, value(k));
295 (os << '\n').flush();
296 }
297 #endif
298 }
299
300 using impl::put;
301 using impl::has_value;
302 using impl::value;
303 };
304
305 #if BOOST_LEAF_CFG_DIAGNOSTICS
306
307 template <class E>
308 BOOST_LEAF_CONSTEXPR inline void load_unexpected_count( int err_id ) noexcept
309 {
310 if( slot<e_unexpected_count> * sl = tls::read_ptr<slot<e_unexpected_count>>() )
311 if( e_unexpected_count * unx = sl->has_value(err_id) )
312 ++unx->count;
313 else
314 sl->put(err_id, e_unexpected_count(&type<E>));
315 }
316
317 template <class E>
318 BOOST_LEAF_CONSTEXPR inline void load_unexpected_info( int err_id, E && e ) noexcept
319 {
320 if( slot<e_unexpected_info> * sl = tls::read_ptr<slot<e_unexpected_info>>() )
321 if( e_unexpected_info * unx = sl->has_value(err_id) )
322 unx->add(std::forward<E>(e));
323 else
324 sl->put(err_id, e_unexpected_info()).add(std::forward<E>(e));
325 }
326
327 template <class E>
328 BOOST_LEAF_CONSTEXPR inline void load_unexpected( int err_id, E && e ) noexcept
329 {
330 load_unexpected_count<E>(err_id);
331 load_unexpected_info(err_id, std::forward<E>(e));
332 }
333
334 #endif
335
336 template <class E>
337 BOOST_LEAF_CONSTEXPR inline void slot<E>::propagate( int err_id ) noexcept
338 {
339 if( this->key()!=err_id && err_id!=0 )
340 return;
341 if( impl * p = tls::read_ptr<slot<E>>() )
342 *p = std::move(*this);
343 #if BOOST_LEAF_CFG_DIAGNOSTICS
344 else
345 {
346 int c = tls::read_uint32<tls_tag_unexpected_enabled_counter>();
347 BOOST_LEAF_ASSERT(c>=0);
348 if( c )
349 load_unexpected(err_id, std::move(*this).value(err_id));
350 }
351 #endif
352 }
353
354 template <class E>
355 BOOST_LEAF_CONSTEXPR inline int load_slot( int err_id, E && e ) noexcept
356 {
357 static_assert(!std::is_pointer<E>::value, "Error objects of pointer types are not allowed");
358 static_assert(!std::is_same<typename std::decay<E>::type, error_id>::value, "Error objects of type error_id are not allowed");
359 using T = typename std::decay<E>::type;
360 BOOST_LEAF_ASSERT((err_id&3)==1);
361 if( slot<T> * p = tls::read_ptr<slot<T>>() )
362 (void) p->put(err_id, std::forward<E>(e));
363 #if BOOST_LEAF_CFG_DIAGNOSTICS
364 else
365 {
366 int c = tls::read_uint32<tls_tag_unexpected_enabled_counter>();
367 BOOST_LEAF_ASSERT(c>=0);
368 if( c )
369 load_unexpected(err_id, std::forward<E>(e));
370 }
371 #endif
372 return 0;
373 }
374
375 template <class F>
376 BOOST_LEAF_CONSTEXPR inline int accumulate_slot( int err_id, F && f ) noexcept
377 {
378 static_assert(function_traits<F>::arity==1, "Lambdas passed to accumulate must take a single e-type argument by reference");
379 using E = typename std::decay<fn_arg_type<F,0>>::type;
380 static_assert(!std::is_pointer<E>::value, "Error objects of pointer types are not allowed");
381 BOOST_LEAF_ASSERT((err_id&3)==1);
382 if( auto sl = tls::read_ptr<slot<E>>() )
383 if( auto v = sl->has_value(err_id) )
384 (void) std::forward<F>(f)(*v);
385 else
386 (void) std::forward<F>(f)(sl->put(err_id,E()));
387 return 0;
388 }
389 }
390
391 ////////////////////////////////////////
392
393 namespace leaf_detail
394 {
395 template <class=void>
396 struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
397 {
398 static atomic_unsigned_int counter;
399
400 BOOST_LEAF_CONSTEXPR static unsigned generate_next_id() noexcept
401 {
402 auto id = (counter+=4);
403 BOOST_LEAF_ASSERT((id&3)==1);
404 return id;
405 }
406 };
407
408 template <class T>
409 atomic_unsigned_int id_factory<T>::counter(-3);
410
411 inline int current_id() noexcept
412 {
413 auto id = tls::read_uint32<tls_tag_id_factory_current_id>();
414 BOOST_LEAF_ASSERT(id==0 || (id&3)==1);
415 return id;
416 }
417
418 inline int new_id() noexcept
419 {
420 auto id = id_factory<>::generate_next_id();
421 tls::write_uint32<tls_tag_id_factory_current_id>(id);
422 return id;
423 }
424 }
425
426 ////////////////////////////////////////
427
428 namespace leaf_detail
429 {
430 template <class T, int Arity = function_traits<T>::arity>
431 struct load_item
432 {
433 static_assert(Arity==0 || Arity==1, "If a functions is passed to new_error or load, it must take zero or one argument");
434 };
435
436 template <class E>
437 struct load_item<E, -1>
438 {
439 BOOST_LEAF_CONSTEXPR static int load( int err_id, E && e ) noexcept
440 {
441 return load_slot(err_id, std::forward<E>(e));
442 }
443 };
444
445 template <class F>
446 struct load_item<F, 0>
447 {
448 BOOST_LEAF_CONSTEXPR static int load( int err_id, F && f ) noexcept
449 {
450 return load_slot(err_id, std::forward<F>(f)());
451 }
452 };
453
454 template <class F>
455 struct load_item<F, 1>
456 {
457 BOOST_LEAF_CONSTEXPR static int load( int err_id, F && f ) noexcept
458 {
459 return accumulate_slot(err_id, std::forward<F>(f));
460 }
461 };
462 }
463
464 ////////////////////////////////////////
465
466 #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
467 namespace leaf_detail
468 {
469 class leaf_category final: public std::error_category
470 {
471 bool equivalent( int, std::error_condition const & ) const noexcept final override { return false; }
472 bool equivalent( std::error_code const &, int ) const noexcept final override { return false; }
473 char const * name() const noexcept final override { return "LEAF error"; }
474 std::string message( int condition ) const final override { return name(); }
475 public:
476 ~leaf_category() noexcept final override { }
477 };
478
479 template <class=void>
480 struct get_error_category
481 {
482 static leaf_category cat;
483 };
484
485 template <class T>
486 leaf_category get_error_category<T>::cat;
487
488 inline int import_error_code( std::error_code const & ec ) noexcept
489 {
490 if( int err_id = ec.value() )
491 {
492 std::error_category const & cat = get_error_category<>::cat;
493 if( &ec.category()==&cat )
494 {
495 BOOST_LEAF_ASSERT((err_id&3)==1);
496 return (err_id&~3)|1;
497 }
498 else
499 {
500 err_id = new_id();
501 (void) load_slot(err_id, ec);
502 return (err_id&~3)|1;
503 }
504 }
505 else
506 return 0;
507 }
508 }
509
510 inline bool is_error_id( std::error_code const & ec ) noexcept
511 {
512 bool res = (&ec.category() == &leaf_detail::get_error_category<>::cat);
513 BOOST_LEAF_ASSERT(!res || !ec.value() || ((ec.value()&3)==1));
514 return res;
515 }
516 #endif
517
518 ////////////////////////////////////////
519
520 namespace leaf_detail
521 {
522 BOOST_LEAF_CONSTEXPR error_id make_error_id(int) noexcept;
523 }
524
525 class BOOST_LEAF_SYMBOL_VISIBLE error_id
526 {
527 friend error_id BOOST_LEAF_CONSTEXPR leaf_detail::make_error_id(int) noexcept;
528
529 int value_;
530
531 BOOST_LEAF_CONSTEXPR explicit error_id( int value ) noexcept:
532 value_(value)
533 {
534 BOOST_LEAF_ASSERT(value_==0 || ((value_&3)==1));
535 }
536
537 public:
538
539 BOOST_LEAF_CONSTEXPR error_id() noexcept:
540 value_(0)
541 {
542 }
543
544 #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
545 error_id( std::error_code const & ec ) noexcept:
546 value_(leaf_detail::import_error_code(ec))
547 {
548 BOOST_LEAF_ASSERT(!value_ || ((value_&3)==1));
549 }
550
551 template <class Enum>
552 error_id( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, Enum>::type * = 0 ) noexcept:
553 value_(leaf_detail::import_error_code(e))
554 {
555 }
556
557 std::error_code to_error_code() const noexcept
558 {
559 return std::error_code(value_, leaf_detail::get_error_category<>::cat);
560 }
561 #endif
562
563 BOOST_LEAF_CONSTEXPR error_id load() const noexcept
564 {
565 return *this;
566 }
567
568 template <class... Item>
569 BOOST_LEAF_CONSTEXPR error_id load( Item && ... item ) const noexcept
570 {
571 if( int err_id = value() )
572 {
573 int const unused[ ] = { 42, leaf_detail::load_item<Item>::load(err_id, std::forward<Item>(item))... };
574 (void) unused;
575 }
576 return *this;
577 }
578
579 BOOST_LEAF_CONSTEXPR int value() const noexcept
580 {
581 if( int v = value_ )
582 {
583 BOOST_LEAF_ASSERT((v&3)==1);
584 return (v&~3)|1;
585 }
586 else
587 return 0;
588 }
589
590 BOOST_LEAF_CONSTEXPR explicit operator bool() const noexcept
591 {
592 return value_ != 0;
593 }
594
595 BOOST_LEAF_CONSTEXPR friend bool operator==( error_id a, error_id b ) noexcept
596 {
597 return a.value_ == b.value_;
598 }
599
600 BOOST_LEAF_CONSTEXPR friend bool operator!=( error_id a, error_id b ) noexcept
601 {
602 return !(a == b);
603 }
604
605 BOOST_LEAF_CONSTEXPR friend bool operator<( error_id a, error_id b ) noexcept
606 {
607 return a.value_ < b.value_;
608 }
609
610 template <class CharT, class Traits>
611 friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, error_id x )
612 {
613 return os << x.value_;
614 }
615
616 BOOST_LEAF_CONSTEXPR void load_source_location_( char const * file, int line, char const * function ) const noexcept
617 {
618 BOOST_LEAF_ASSERT(file&&*file);
619 BOOST_LEAF_ASSERT(line>0);
620 BOOST_LEAF_ASSERT(function&&*function);
621 BOOST_LEAF_ASSERT(value_);
622 (void) load(e_source_location {file,line,function});
623 }
624 };
625
626 namespace leaf_detail
627 {
628 BOOST_LEAF_CONSTEXPR inline error_id make_error_id( int err_id ) noexcept
629 {
630 BOOST_LEAF_ASSERT(err_id==0 || (err_id&3)==1);
631 return error_id((err_id&~3)|1);
632 }
633 }
634
635 inline error_id new_error() noexcept
636 {
637 return leaf_detail::make_error_id(leaf_detail::new_id());
638 }
639
640 template <class... Item>
641 inline error_id new_error( Item && ... item ) noexcept
642 {
643 return leaf_detail::make_error_id(leaf_detail::new_id()).load(std::forward<Item>(item)...);
644 }
645
646 inline error_id current_error() noexcept
647 {
648 return leaf_detail::make_error_id(leaf_detail::current_id());
649 }
650
651 ////////////////////////////////////////////
652
653 class polymorphic_context
654 {
655 protected:
656
657 polymorphic_context() noexcept = default;
658 ~polymorphic_context() noexcept = default;
659
660 public:
661
662 virtual error_id propagate_captured_errors() noexcept = 0;
663 virtual void activate() noexcept = 0;
664 virtual void deactivate() noexcept = 0;
665 virtual void propagate( error_id ) noexcept = 0;
666 virtual bool is_active() const noexcept = 0;
667 inline virtual void print( std::ostream & ) const { };
668 error_id captured_id_;
669 };
670
671 #if BOOST_LEAF_CFG_CAPTURE
672 using context_ptr = std::shared_ptr<polymorphic_context>;
673 #endif
674
675 ////////////////////////////////////////////
676
677 template <class Ctx>
678 class context_activator
679 {
680 context_activator( context_activator const & ) = delete;
681 context_activator & operator=( context_activator const & ) = delete;
682
683 #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
684 int const uncaught_exceptions_;
685 #endif
686 Ctx * ctx_;
687
688 public:
689
690 explicit BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator(Ctx & ctx) noexcept:
691 #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
692 uncaught_exceptions_(std::uncaught_exceptions()),
693 #endif
694 ctx_(ctx.is_active() ? 0 : &ctx)
695 {
696 if( ctx_ )
697 ctx_->activate();
698 }
699
700 BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator( context_activator && x ) noexcept:
701 #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
702 uncaught_exceptions_(x.uncaught_exceptions_),
703 #endif
704 ctx_(x.ctx_)
705 {
706 x.ctx_ = 0;
707 }
708
709 BOOST_LEAF_ALWAYS_INLINE ~context_activator() noexcept
710 {
711 if( ctx_ && ctx_->is_active() )
712 ctx_->deactivate();
713 }
714 };
715
716 template <class Ctx>
717 BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator<Ctx> activate_context(Ctx & ctx) noexcept
718 {
719 return context_activator<Ctx>(ctx);
720 }
721
722 ////////////////////////////////////////////
723
724 template <class R>
725 struct is_result_type: std::false_type
726 {
727 };
728
729 template <class R>
730 struct is_result_type<R const>: is_result_type<R>
731 {
732 };
733
734 } }
735
736 #endif