1 /* Proposed SG14 status_code
2 (C) 2018 - 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
3 File Created: May 2020
4
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License in the accompanying file
9 Licence.txt or at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19
20 Distributed under the Boost Software License, Version 1.0.
21 (See accompanying file Licence.txt or copy at
22 http://www.boost.org/LICENSE_1_0.txt)
23 */
24
25 #ifndef BOOST_OUTCOME_SYSTEM_ERROR2_QUICK_STATUS_CODE_FROM_ENUM_HPP
26 #define BOOST_OUTCOME_SYSTEM_ERROR2_QUICK_STATUS_CODE_FROM_ENUM_HPP
27
28 #include "generic_code.hpp"
29
30 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
31
32 template <class Enum> class _quick_status_code_from_enum_domain;
33 //! A status code wrapping `Enum` generated from `quick_status_code_from_enum`.
34 template <class Enum> using quick_status_code_from_enum_code = status_code<_quick_status_code_from_enum_domain<Enum>>;
35
36 //! Defaults for an implementation of `quick_status_code_from_enum<Enum>`
37 template <class Enum> struct quick_status_code_from_enum_defaults
38 {
39 //! The type of the resulting code
40 using code_type = quick_status_code_from_enum_code<Enum>;
41 //! Used within `quick_status_code_from_enum` to define a mapping of enumeration value with its status code
42 struct mapping
43 {
44 //! The enumeration type
45 using enumeration_type = Enum;
46
47 //! The value being mapped
48 const Enum value;
49 //! A string representation for this enumeration value
50 const char *message;
51 //! A list of `errc` equivalents for this enumeration value
52 const std::initializer_list<errc> code_mappings;
53 };
54 //! Used within `quick_status_code_from_enum` to define mixins for the status code wrapping `Enum`
55 template <class Base> struct mixin : Base
56 {
57 using Base::Base;
58 };
59 };
60
61 /*! The implementation of the domain for status codes wrapping `Enum` generated from `quick_status_code_from_enum`.
62 */
63 template <class Enum> class _quick_status_code_from_enum_domain : public status_code_domain
64 {
65 template <class DomainType> friend class status_code;
66 template <class StatusCode> friend class detail::indirecting_domain;
67 using _base = status_code_domain;
68 using _src = quick_status_code_from_enum<Enum>;
69
70 public:
71 //! The value type of the quick status code from enum
72 using value_type = Enum;
73 using _base::string_ref;
74
_quick_status_code_from_enum_domain()75 constexpr _quick_status_code_from_enum_domain()
76 : status_code_domain(_src::domain_uuid, _uuid_size<detail::cstrlen(_src::domain_uuid)>())
77 {
78 }
79 _quick_status_code_from_enum_domain(const _quick_status_code_from_enum_domain &) = default;
80 _quick_status_code_from_enum_domain(_quick_status_code_from_enum_domain &&) = default;
81 _quick_status_code_from_enum_domain &operator=(const _quick_status_code_from_enum_domain &) = default;
82 _quick_status_code_from_enum_domain &operator=(_quick_status_code_from_enum_domain &&) = default;
83 ~_quick_status_code_from_enum_domain() = default;
84
85 #if __cplusplus < 201402L && !defined(_MSC_VER)
get()86 static inline const _quick_status_code_from_enum_domain &get()
87 {
88 static _quick_status_code_from_enum_domain v;
89 return v;
90 }
91 #else
92 static inline constexpr const _quick_status_code_from_enum_domain &get();
93 #endif
94
name() const95 virtual string_ref name() const noexcept override { return string_ref(_src::domain_name); }
96
97 protected:
98 // Not sure if a hash table is worth it here, most enumerations won't be long enough to be worth it
99 // Also, until C++ 20's consteval, the hash table would get emitted into the binary, bloating it
_find_mapping(value_type v)100 static BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 const typename _src::mapping *_find_mapping(value_type v) noexcept
101 {
102 for(const auto &i : _src::value_mappings())
103 {
104 if(i.value == v)
105 {
106 return &i;
107 }
108 }
109 return nullptr;
110 }
111
_do_failure(const status_code<void> & code) const112 virtual bool _do_failure(const status_code<void> &code) const noexcept override
113 {
114 assert(code.domain() == *this); // NOLINT
115 // If `errc::success` is in the generic code mapping, it is not a failure
116 const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value());
117 assert(mapping != nullptr);
118 if(mapping != nullptr)
119 {
120 for(errc ec : mapping->code_mappings)
121 {
122 if(ec == errc::success)
123 {
124 return false;
125 }
126 }
127 }
128 return true;
129 }
_do_equivalent(const status_code<void> & code1,const status_code<void> & code2) const130 virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override
131 {
132 assert(code1.domain() == *this); // NOLINT
133 const auto &c1 = static_cast<const quick_status_code_from_enum_code<value_type> &>(code1); // NOLINT
134 if(code2.domain() == *this)
135 {
136 const auto &c2 = static_cast<const quick_status_code_from_enum_code<value_type> &>(code2); // NOLINT
137 return c1.value() == c2.value();
138 }
139 if(code2.domain() == generic_code_domain)
140 {
141 const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
142 const auto *mapping = _find_mapping(c1.value());
143 assert(mapping != nullptr);
144 if(mapping != nullptr)
145 {
146 for(errc ec : mapping->code_mappings)
147 {
148 if(ec == c2.value())
149 {
150 return true;
151 }
152 }
153 }
154 }
155 return false;
156 }
_generic_code(const status_code<void> & code) const157 virtual generic_code _generic_code(const status_code<void> &code) const noexcept override
158 {
159 assert(code.domain() == *this); // NOLINT
160 const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value());
161 assert(mapping != nullptr);
162 if(mapping != nullptr)
163 {
164 if(mapping->code_mappings.size() > 0)
165 {
166 return *mapping->code_mappings.begin();
167 }
168 }
169 return errc::unknown;
170 }
_do_message(const status_code<void> & code) const171 virtual string_ref _do_message(const status_code<void> &code) const noexcept override
172 {
173 assert(code.domain() == *this); // NOLINT
174 const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value());
175 assert(mapping != nullptr);
176 if(mapping != nullptr)
177 {
178 return string_ref(mapping->message);
179 }
180 return string_ref("unknown");
181 }
182 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
_do_throw_exception(const status_code<void> & code) const183 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override
184 {
185 assert(code.domain() == *this); // NOLINT
186 const auto &c = static_cast<const quick_status_code_from_enum_code<value_type> &>(code); // NOLINT
187 throw status_error<_quick_status_code_from_enum_domain>(c);
188 }
189 #endif
190 };
191
192 #if __cplusplus >= 201402L || defined(_MSC_VER)
193 template <class Enum> constexpr _quick_status_code_from_enum_domain<Enum> quick_status_code_from_enum_domain = {};
get()194 template <class Enum> inline constexpr const _quick_status_code_from_enum_domain<Enum> &_quick_status_code_from_enum_domain<Enum>::get()
195 {
196 return quick_status_code_from_enum_domain<Enum>;
197 }
198 #endif
199
200 namespace mixins
201 {
202 template <class Base, class Enum> struct mixin<Base, _quick_status_code_from_enum_domain<Enum>> : public quick_status_code_from_enum<Enum>::template mixin<Base>
203 {
204 using quick_status_code_from_enum<Enum>::template mixin<Base>::mixin;
205 };
206 } // namespace mixins
207
208 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
209
210 #endif
211