File Coverage

src/panda/error.h
Criterion Covered Total %
statement 3 9 33.3
branch 1 2 50.0
condition n/a
subroutine n/a
pod n/a
total 4 11 36.3


line stmt bran cond sub pod time code
1             #pragma once
2              
3             #include
4             #include
5             #include
6              
7             #include
8             #include
9             #include
10              
11             namespace panda {
12              
13             namespace error {
14 8 50         class NestedCategory : public std::error_category {
15             public:
16             const std::error_category& self;
17             const NestedCategory* next;
18              
19 8           constexpr NestedCategory(const std::error_category& self, const NestedCategory* next = nullptr) noexcept : self(self), next(next) {}
20              
21             // delegate all implementation to self
22 0           virtual const char* name() const noexcept { return self.name(); }
23 0           virtual std::error_condition default_error_condition(int code) const noexcept { return self.default_error_condition(code); }
24 0           virtual bool equivalent(int code, const std::error_condition& condition) const noexcept {
25 0           return self.equivalent(code, condition);
26             }
27 0           virtual bool equivalent(const std::error_code& code, int condition) const noexcept {
28 0           return self.equivalent(code, condition);
29             }
30 30           virtual std::string message(int condition) const { return self.message(condition); }
31             bool operator==( const std::error_category& rhs ) const noexcept { return self.operator ==(rhs); }
32             bool operator!=( const std::error_category& rhs ) const noexcept { return self.operator !=(rhs); }
33             bool operator<( const std::error_category& rhs ) const noexcept { return self.operator <(rhs); }
34             };
35              
36             const NestedCategory& get_nested_categoty(const std::error_category& self, const NestedCategory* next);
37             }
38              
39             struct ErrorCode : AllocatedObject {
40             ErrorCode() noexcept : ErrorCode(0, std::system_category()) {}
41             ErrorCode(const ErrorCode& o) = default;
42             ErrorCode(ErrorCode&&) = default;
43              
44             ErrorCode(int ec, const std::error_category& ecat) noexcept
45             : cat(&error::get_nested_categoty(ecat, nullptr))
46             {
47             codes.push(ec);
48             }
49              
50             explicit ErrorCode(const std::error_code& c) noexcept : ErrorCode(c.value(), c.category()) {}
51              
52             template< class ErrorCodeEnum >
53             explicit ErrorCode(ErrorCodeEnum e) noexcept : ErrorCode(std::error_code(e)) {}
54              
55             ErrorCode(const std::error_code& c, const ErrorCode& next) noexcept
56             : codes(next.codes)
57             , cat(&error::get_nested_categoty(c.category(), next.cat))
58             {
59             codes.push(c.value());
60             }
61              
62             ErrorCode& operator=(const ErrorCode& o) noexcept {
63             codes = o.codes;
64             cat = o.cat;
65             return *this;
66             }
67              
68             ErrorCode& operator=(ErrorCode&& o) noexcept {
69             codes = std::move(o.codes);
70             cat = o.cat;
71             return *this;
72             }
73              
74             template
75             ErrorCode& operator=(ErrorCodeEnum e) noexcept {
76             std::error_code ec(e);
77             codes = CodeStack{};
78             codes.push(ec.value());
79             cat = &error::get_nested_categoty(ec.category(), nullptr);
80             return *this;
81             }
82              
83             void assign( int ec, const std::error_category& ecat ) noexcept {
84             codes = CodeStack{};
85             codes.push(ec);
86             cat = &error::get_nested_categoty(ecat, nullptr);
87             }
88              
89             void clear() noexcept {
90             *this = {};
91             }
92              
93             int value() const noexcept {
94             return codes.top();
95             }
96              
97             const std::error_category& category() const noexcept {
98             return cat->self;
99             }
100              
101             std::error_condition default_error_condition() const noexcept {
102             return code().default_error_condition();
103             }
104              
105             std::string message() const {
106             return cat->message(codes.top());
107             }
108              
109             string what() const {
110             //TODO: optimize with foreach code and next category
111             std::string std_msg = message();
112             string res(std_msg.data(), std_msg.length());
113             if (codes.size() > 1) {
114             res += ", preceded by:\n" + next().what();
115             }
116             return res;
117             }
118              
119             explicit operator bool() const noexcept {
120             return bool(code());
121             }
122              
123             std::error_code code() const noexcept {
124             return std::error_code(codes.top(), cat->self);
125             }
126              
127             ErrorCode next() const noexcept {
128             if (codes.size() <= 1) return {};
129             CodeStack new_stack = codes;
130             new_stack.pop();
131             const error::NestedCategory* new_cat = cat->next;
132             return ErrorCode(std::move(new_stack), new_cat);
133             }
134              
135             ~ErrorCode() = default;
136              
137             // any user can add specialization for his own result and get any data
138             template
139             T private_access(Args...);
140              
141             template
142             T private_access(Args...) const;
143              
144             private:
145             using CodeStack = VarIntStack;
146              
147             ErrorCode(CodeStack&& codes, const error::NestedCategory* cat) : codes(std::move(codes)), cat(cat) {}
148              
149             CodeStack codes;
150             const error::NestedCategory* cat;
151             };
152              
153             inline bool operator==(const ErrorCode& lhs, const ErrorCode& rhs) noexcept { return lhs.code() == rhs.code(); }
154             inline bool operator==(const ErrorCode& lhs, const std::error_code& rhs) noexcept { return lhs.code() == rhs; }
155             inline bool operator==(const std::error_code& lhs, const ErrorCode& rhs) noexcept { return lhs == rhs.code(); }
156              
157             inline bool operator!=(const ErrorCode& lhs, const ErrorCode& rhs) noexcept { return !(lhs.code() == rhs.code()); }
158             inline bool operator!=(const ErrorCode& lhs, const std::error_code& rhs) noexcept { return lhs.code() != rhs; }
159             inline bool operator!=(const std::error_code& lhs, const ErrorCode& rhs) noexcept { return lhs != rhs.code(); }
160              
161             inline bool operator<(const ErrorCode& lhs, const ErrorCode& rhs) noexcept { return lhs.code() < rhs.code(); }
162             inline bool operator<(const ErrorCode& lhs, const std::error_code& rhs) noexcept { return lhs.code() < rhs; }
163             inline bool operator<(const std::error_code& lhs, const ErrorCode& rhs) noexcept { return lhs < rhs.code(); }
164              
165             template< class CharT, class Traits >
166             std::basic_ostream& operator<<( std::basic_ostream& os, const ErrorCode& ec ) {
167             return os << ec.message();
168             }
169              
170             }
171              
172             namespace std {
173             template<> struct hash {
174             typedef panda::ErrorCode argument_type;
175             typedef std::size_t result_type;
176              
177             result_type operator()(argument_type const& c) const noexcept {
178             result_type const h1 ( std::hash{}(c.code()) );
179             result_type const h2 ( std::hash{}((size_t)&c.category()));
180             return h1 ^ (h2 << 1); // simplest hash combine
181             }
182             };
183             }