C++ Essence Library 0.1.0
A Utility Library for Modern C++ Programming
Loading...
Searching...
No Matches
exception.hpp
1/*
2 * Copyright (c) 2024 The RefValue Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include "abi/string.hpp"
26#include "abi/vector.hpp"
27#include "compat.hpp"
28
29#include <concepts>
30#include <cstddef>
31#include <cstdint>
32#include <optional>
33#include <stdexcept>
34#include <string_view>
35#include <type_traits>
36#include <utility>
37
38namespace essence {
39 inline constexpr std::int32_t default_nested_exception_indent = 4;
40
41 class aggregate_error : public std::runtime_error {
42 public:
43 using value_type = std::exception_ptr;
44 using iterator = const value_type*;
45 using reverse_iterator = std::reverse_iterator<iterator>;
46
47 [[nodiscard]] ES_API(CPPESSENCE) iterator begin() const noexcept;
48 [[nodiscard]] ES_API(CPPESSENCE) iterator end() const noexcept;
49 [[nodiscard]] ES_API(CPPESSENCE) reverse_iterator rbegin() const noexcept;
50 [[nodiscard]] ES_API(CPPESSENCE) reverse_iterator rend() const noexcept;
51 [[nodiscard]] ES_API(CPPESSENCE) bool empty() const noexcept;
52 [[nodiscard]] ES_API(CPPESSENCE) std::size_t size() const noexcept;
53 [[noreturn]] ES_API(CPPESSENCE) static void flatten_and_throw(
54 const std::exception_ptr& root, std::int32_t indent = default_nested_exception_indent);
55
56 template <typename E, bool Reverse = false>
57 std::optional<E> extract() const {
58 auto iter = [this] {
59 if constexpr (Reverse) {
60 return rbegin();
61 } else {
62 return begin();
63 }
64 }();
65 auto iter_end = [this] {
66 if constexpr (Reverse) {
67 return rend();
68 } else {
69 return end();
70 }
71 }();
72
73 for (; iter != iter_end; ++iter) {
74 try {
75 std::rethrow_exception(*iter);
76 } catch (const std::exception& ex) {
77 if (auto concrete = dynamic_cast<const E*>(&ex)) {
78 return *concrete;
79 }
80 }
81 }
82
83 return std::nullopt;
84 }
85
86 private:
87 aggregate_error(abi::vector<value_type>&& exceptions, std::string_view what);
88
89 abi::vector<value_type> exceptions_;
90 };
91
92 ES_API(CPPESSENCE)
93 abi::string serialize_nested_exceptions(
94 const std::exception_ptr& root, std::int32_t indent = default_nested_exception_indent);
95
96#if ES_HAS_CXX20
97 template <typename E, std::invocable Callable>
98#else
99 template <typename E, typename Callable, std::enable_if_t<std::is_invocable_v<Callable>>* = nullptr>
100#endif
101 decltype(auto) throw_nested_and_flatten(
102 E&& ex, Callable&& callable, std::int32_t indent = default_nested_exception_indent) try {
103 try {
104 return std::forward<Callable>(callable)();
105 } catch (...) {
106 std::throw_with_nested(std::forward<E>(ex));
107 }
108 } catch (const std::exception&) {
109 aggregate_error::flatten_and_throw(std::current_exception(), indent);
110 }
111} // namespace essence
Definition exception.hpp:41