|
| 1 | +#pragma once |
| 2 | + |
| 3 | +#include <cstdint> |
| 4 | +#include <string_view> |
| 5 | + |
| 6 | +namespace cpp_core::status_codes |
| 7 | +{ |
| 8 | + |
| 9 | +namespace detail |
| 10 | +{ |
| 11 | + |
| 12 | +using ValueType = std::int64_t; |
| 13 | + |
| 14 | +inline constexpr ValueType kCategoryMultiplier{100}; |
| 15 | + |
| 16 | +template <typename Category, ValueType NumericValue> struct Code |
| 17 | +{ |
| 18 | + static constexpr ValueType kValue = NumericValue; |
| 19 | + std::string_view kName; // NOLINT(readability-identifier-naming) |
| 20 | + |
| 21 | + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) |
| 22 | + constexpr operator ValueType() const noexcept |
| 23 | + { |
| 24 | + return kValue; |
| 25 | + } |
| 26 | + [[nodiscard]] constexpr auto value() const noexcept -> ValueType |
| 27 | + { |
| 28 | + return kValue; |
| 29 | + } |
| 30 | + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view |
| 31 | + { |
| 32 | + return kName; |
| 33 | + } |
| 34 | + [[nodiscard]] constexpr auto category() const noexcept -> std::string_view |
| 35 | + { |
| 36 | + return Category::kCategoryName; |
| 37 | + } |
| 38 | +}; |
| 39 | + |
| 40 | +template <typename Derived> struct CategoryBase |
| 41 | +{ |
| 42 | + private: |
| 43 | + constexpr CategoryBase() = default; |
| 44 | + |
| 45 | + protected: |
| 46 | + template <ValueType LocalCode> static consteval auto computeValue() -> ValueType |
| 47 | + { |
| 48 | + static_assert(Derived::kCategoryCode >= 0, "Category code must not be negative"); |
| 49 | + static_assert(LocalCode >= 0, "Code index must not be negative"); |
| 50 | + static_assert(LocalCode < kCategoryMultiplier, "Category overflow (max 99 codes)"); |
| 51 | + static_assert(Derived::kCategoryCode <= |
| 52 | + (std::numeric_limits<ValueType>::max() - kCategoryMultiplier + 1) / kCategoryMultiplier, |
| 53 | + "Category code too large, multiplication would overflow"); |
| 54 | + return -((Derived::kCategoryCode * kCategoryMultiplier) + LocalCode); |
| 55 | + } |
| 56 | + |
| 57 | + template <ValueType LocalCode> using Code = detail::Code<Derived, computeValue<LocalCode>()>; |
| 58 | + |
| 59 | + friend Derived; |
| 60 | +}; |
| 61 | + |
| 62 | +} // namespace detail |
| 63 | + |
| 64 | +struct StatusCode |
| 65 | +{ |
| 66 | + using ValueType = detail::ValueType; |
| 67 | + static constexpr ValueType kSuccess = 0; |
| 68 | + |
| 69 | + struct Configuration : detail::CategoryBase<Configuration> |
| 70 | + { |
| 71 | + static constexpr ValueType kCategoryCode = 1; |
| 72 | + static constexpr std::string_view kCategoryName{"Configuration"}; |
| 73 | + |
| 74 | + static constexpr Code<0> kSetBaudrateError{"SetBaudrateError"}; |
| 75 | + static constexpr Code<1> kSetDataBitsError{"SetDataBitsError"}; |
| 76 | + static constexpr Code<2> kSetParityError{"SetParityError"}; |
| 77 | + static constexpr Code<3> kSetStopBitsError{"SetStopBitsError"}; |
| 78 | + static constexpr Code<4> kSetFlowControlError{"SetFlowControlError"}; |
| 79 | + static constexpr Code<5> kSetTimeoutError{"SetTimeoutError"}; |
| 80 | + }; |
| 81 | + |
| 82 | + struct Connection : detail::CategoryBase<Connection> |
| 83 | + { |
| 84 | + static constexpr ValueType kCategoryCode = 2; |
| 85 | + static constexpr std::string_view kCategoryName{"Connection"}; |
| 86 | + |
| 87 | + static constexpr Code<0> kNotFoundError{"NotFoundError"}; |
| 88 | + static constexpr Code<1> kInvalidHandleError{"InvalidHandleError"}; |
| 89 | + static constexpr Code<2> kCloseHandleError{"CloseHandleError"}; |
| 90 | + }; |
| 91 | + |
| 92 | + struct Io : detail::CategoryBase<Io> |
| 93 | + { |
| 94 | + static constexpr ValueType kCategoryCode = 3; |
| 95 | + static constexpr std::string_view kCategoryName{"Io"}; |
| 96 | + |
| 97 | + static constexpr Code<0> kReadError{"ReadError"}; |
| 98 | + static constexpr Code<1> kWriteError{"WriteError"}; |
| 99 | + static constexpr Code<2> kAbortReadError{"AbortReadError"}; |
| 100 | + static constexpr Code<3> kAbortWriteError{"AbortWriteError"}; |
| 101 | + static constexpr Code<4> kBufferError{"BufferError"}; |
| 102 | + static constexpr Code<5> kClearBufferInError{"ClearBufferInError"}; |
| 103 | + static constexpr Code<6> kClearBufferOutError{"ClearBufferOutError"}; |
| 104 | + }; |
| 105 | + |
| 106 | + struct Control : detail::CategoryBase<Control> |
| 107 | + { |
| 108 | + static constexpr ValueType kCategoryCode = 4; |
| 109 | + static constexpr std::string_view kCategoryName{"Control"}; |
| 110 | + |
| 111 | + static constexpr Code<0> kSetDtrError{"SetDtrError"}; |
| 112 | + static constexpr Code<1> kSetRtsError{"SetRtsError"}; |
| 113 | + static constexpr Code<2> kGetModemStatusError{"GetModemStatusError"}; |
| 114 | + static constexpr Code<3> kSendBreakError{"SendBreakError"}; |
| 115 | + static constexpr Code<4> kGetStateError{"GetStateError"}; |
| 116 | + static constexpr Code<5> kSetStateError{"SetStateError"}; |
| 117 | + }; |
| 118 | + |
| 119 | + [[nodiscard]] static constexpr auto isError(ValueType code) noexcept -> bool |
| 120 | + { |
| 121 | + return code < 0; |
| 122 | + } |
| 123 | + [[nodiscard]] static constexpr auto isSuccess(ValueType code) noexcept -> bool |
| 124 | + { |
| 125 | + return code >= 0; |
| 126 | + } |
| 127 | + template <typename Category> [[nodiscard]] static constexpr auto belongsTo(ValueType code) noexcept -> bool |
| 128 | + { |
| 129 | + return code < 0 && (-code) / detail::kCategoryMultiplier == Category::kCategoryCode; |
| 130 | + } |
| 131 | +}; |
| 132 | + |
| 133 | +} // namespace cpp_core::status_codes |
| 134 | + |
| 135 | +namespace cpp_core |
| 136 | +{ |
| 137 | +using StatusCodes = ::cpp_core::status_codes::detail::ValueType; |
| 138 | +using ::cpp_core::status_codes::StatusCode; |
| 139 | +} // namespace cpp_core |
0 commit comments