├── .clang-format ├── .clang-tidy ├── .cmake-format.yaml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── Conan.cmake ├── include └── rd │ └── expected.hpp └── test ├── CMakeLists.txt ├── bad_expected_access_test.cpp ├── exepcted_monadic_edge_cases_test.cpp ├── expected_assignment_test.cpp ├── expected_constructor_test.cpp ├── expected_equality_test.cpp ├── expected_modifier_test.cpp ├── expected_monadic_test.cpp ├── expected_observer_test.cpp ├── expected_swap_test.cpp ├── expected_void_assignment_test.cpp ├── expected_void_constructor_test.cpp ├── expected_void_equality_test.cpp ├── expected_void_modifier_test.cpp ├── expected_void_monadic_test.cpp ├── expected_void_observer_test.cpp ├── expected_void_swap_test.cpp ├── int_to_str.hpp ├── test_include.hpp ├── test_runner.cpp └── unexpected_test.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: None 7 | AlignConsecutiveMacros: None 8 | AlignConsecutiveAssignments: None 9 | AlignConsecutiveBitFields: None 10 | AlignConsecutiveDeclarations: None 11 | AlignEscapedNewlines: Left 12 | AlignOperands: Align 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: true 15 | AllowAllConstructorInitializersOnNextLine: true 16 | AllowAllParametersOfDeclarationOnNextLine: true 17 | AllowShortEnumsOnASingleLine: true 18 | AllowShortBlocksOnASingleLine: Never 19 | AllowShortCaseLabelsOnASingleLine: false 20 | AllowShortFunctionsOnASingleLine: All 21 | AllowShortLambdasOnASingleLine: All 22 | AllowShortIfStatementsOnASingleLine: WithoutElse 23 | AllowShortLoopsOnASingleLine: true 24 | AlwaysBreakAfterDefinitionReturnType: None 25 | AlwaysBreakAfterReturnType: None 26 | AlwaysBreakBeforeMultilineStrings: true 27 | AlwaysBreakTemplateDeclarations: Yes 28 | AttributeMacros: 29 | - __capability 30 | BinPackArguments: true 31 | BinPackParameters: true 32 | BraceWrapping: 33 | AfterCaseLabel: false 34 | AfterClass: false 35 | AfterControlStatement: Never 36 | AfterEnum: false 37 | AfterFunction: false 38 | AfterNamespace: false 39 | AfterObjCDeclaration: false 40 | AfterStruct: false 41 | AfterUnion: false 42 | AfterExternBlock: false 43 | BeforeCatch: false 44 | BeforeElse: false 45 | BeforeLambdaBody: false 46 | BeforeWhile: false 47 | IndentBraces: false 48 | SplitEmptyFunction: true 49 | SplitEmptyRecord: true 50 | SplitEmptyNamespace: true 51 | BreakBeforeBinaryOperators: None 52 | BreakBeforeConceptDeclarations: true 53 | BreakBeforeBraces: Attach 54 | BreakBeforeInheritanceComma: false 55 | BreakInheritanceList: BeforeColon 56 | BreakBeforeTernaryOperators: true 57 | BreakConstructorInitializersBeforeComma: false 58 | BreakConstructorInitializers: BeforeColon 59 | BreakAfterJavaFieldAnnotations: false 60 | BreakStringLiterals: true 61 | ColumnLimit: 80 62 | CommentPragmas: '^ IWYU pragma:' 63 | CompactNamespaces: false 64 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 65 | ConstructorInitializerIndentWidth: 4 66 | ContinuationIndentWidth: 4 67 | Cpp11BracedListStyle: true 68 | DeriveLineEnding: true 69 | DerivePointerAlignment: true 70 | DisableFormat: false 71 | EmptyLineAfterAccessModifier: Never 72 | EmptyLineBeforeAccessModifier: LogicalBlock 73 | ExperimentalAutoDetectBinPacking: false 74 | FixNamespaceComments: true 75 | ForEachMacros: 76 | - foreach 77 | - Q_FOREACH 78 | - BOOST_FOREACH 79 | IfMacros: 80 | - KJ_IF_MAYBE 81 | IncludeBlocks: Regroup 82 | IncludeCategories: 83 | - Regex: '^' 84 | Priority: 2 85 | SortPriority: 0 86 | CaseSensitive: false 87 | - Regex: '^<.*\.h>' 88 | Priority: 1 89 | SortPriority: 0 90 | CaseSensitive: false 91 | - Regex: '^<.*' 92 | Priority: 2 93 | SortPriority: 0 94 | CaseSensitive: false 95 | - Regex: '.*' 96 | Priority: 3 97 | SortPriority: 0 98 | CaseSensitive: false 99 | IncludeIsMainRegex: '([-_](test|unittest))?$' 100 | IncludeIsMainSourceRegex: '' 101 | IndentAccessModifiers: false 102 | IndentCaseLabels: true 103 | IndentCaseBlocks: false 104 | IndentGotoLabels: true 105 | IndentPPDirectives: None 106 | IndentExternBlock: AfterExternBlock 107 | IndentRequires: false 108 | IndentWidth: 2 109 | IndentWrappedFunctionNames: false 110 | InsertTrailingCommas: None 111 | JavaScriptQuotes: Leave 112 | JavaScriptWrapImports: true 113 | KeepEmptyLinesAtTheStartOfBlocks: false 114 | LambdaBodyIndentation: Signature 115 | MacroBlockBegin: '' 116 | MacroBlockEnd: '' 117 | MaxEmptyLinesToKeep: 1 118 | NamespaceIndentation: None 119 | ObjCBinPackProtocolList: Never 120 | ObjCBlockIndentWidth: 2 121 | ObjCBreakBeforeNestedBlockParam: true 122 | ObjCSpaceAfterProperty: false 123 | ObjCSpaceBeforeProtocolList: true 124 | PenaltyBreakAssignment: 2 125 | PenaltyBreakBeforeFirstCallParameter: 1 126 | PenaltyBreakComment: 300 127 | PenaltyBreakFirstLessLess: 120 128 | PenaltyBreakString: 1000 129 | PenaltyBreakTemplateDeclaration: 10 130 | PenaltyExcessCharacter: 1000000 131 | PenaltyReturnTypeOnItsOwnLine: 200 132 | PenaltyIndentedWhitespace: 0 133 | PointerAlignment: Left 134 | PPIndentWidth: -1 135 | RawStringFormats: 136 | - Language: Cpp 137 | Delimiters: 138 | - cc 139 | - CC 140 | - cpp 141 | - Cpp 142 | - CPP 143 | - 'c++' 144 | - 'C++' 145 | CanonicalDelimiter: '' 146 | BasedOnStyle: google 147 | - Language: TextProto 148 | Delimiters: 149 | - pb 150 | - PB 151 | - proto 152 | - PROTO 153 | EnclosingFunctions: 154 | - EqualsProto 155 | - EquivToProto 156 | - PARSE_PARTIAL_TEXT_PROTO 157 | - PARSE_TEST_PROTO 158 | - PARSE_TEXT_PROTO 159 | - ParseTextOrDie 160 | - ParseTextProtoOrDie 161 | - ParseTestProto 162 | - ParsePartialTestProto 163 | CanonicalDelimiter: pb 164 | BasedOnStyle: google 165 | ReferenceAlignment: Pointer 166 | ReflowComments: true 167 | ShortNamespaceLines: 1 168 | SortIncludes: CaseSensitive 169 | SortJavaStaticImport: Before 170 | SortUsingDeclarations: true 171 | SpaceAfterCStyleCast: false 172 | SpaceAfterLogicalNot: false 173 | SpaceAfterTemplateKeyword: true 174 | SpaceBeforeAssignmentOperators: true 175 | SpaceBeforeCaseColon: false 176 | SpaceBeforeCpp11BracedList: false 177 | SpaceBeforeCtorInitializerColon: true 178 | SpaceBeforeInheritanceColon: true 179 | SpaceBeforeParens: ControlStatements 180 | SpaceAroundPointerQualifiers: Default 181 | SpaceBeforeRangeBasedForLoopColon: true 182 | SpaceInEmptyBlock: false 183 | SpaceInEmptyParentheses: false 184 | SpacesBeforeTrailingComments: 2 185 | SpacesInAngles: Never 186 | SpacesInConditionalStatement: false 187 | SpacesInContainerLiterals: true 188 | SpacesInCStyleCastParentheses: false 189 | SpacesInLineCommentPrefix: 190 | Minimum: 1 191 | Maximum: -1 192 | SpacesInParentheses: false 193 | SpacesInSquareBrackets: false 194 | SpaceBeforeSquareBrackets: false 195 | BitFieldColonSpacing: Both 196 | Standard: Auto 197 | StatementAttributeLikeMacros: 198 | - Q_EMIT 199 | StatementMacros: 200 | - Q_UNUSED 201 | - QT_REQUIRE_VERSION 202 | TabWidth: 8 203 | UseCRLF: false 204 | UseTab: Never 205 | WhitespaceSensitiveMacros: 206 | - STRINGIZE 207 | - PP_STRINGIZE 208 | - BOOST_PP_STRINGIZE 209 | - NS_SWIFT_NAME 210 | - CF_SWIFT_NAME 211 | ... 212 | 213 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: '*, 3 | -readability-magic-numbers, 4 | -cppcoreguidelines-avoid-magic-numbers, 5 | -cert-err58-cpp, 6 | -clang-analyzer-optin.performance.Padding, 7 | -altera-struct-pack-align, 8 | -altera-unroll-loops, 9 | -hicpp-braces-around-statements, 10 | -readability-braces-around-statements, 11 | -fuchsia-*, 12 | -google-*, 13 | -zircon-*, 14 | -abseil-*, 15 | -llvm*' 16 | WarningsAsErrors: '*' 17 | HeaderFilterRegex: '' 18 | FormatStyle: none 19 | 20 | 21 | -------------------------------------------------------------------------------- /.cmake-format.yaml: -------------------------------------------------------------------------------- 1 | additional_commands: 2 | foo: 3 | flags: 4 | - BAR 5 | - BAZ 6 | kwargs: 7 | DEPENDS: '*' 8 | HEADERS: '*' 9 | SOURCES: '*' 10 | bullet_char: '*' 11 | dangle_parens: false 12 | enum_char: . 13 | line_ending: unix 14 | line_width: 120 15 | max_pargs_hwrap: 3 16 | separate_ctrl_name_with_space: false 17 | separate_fn_name_with_space: false 18 | tab_size: 2 19 | 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .cache 3 | .ccls-cache 4 | compile_commands.json 5 | .noformat 6 | experiments/ 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2022 Rishabh Dwivedi 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | cmake_minimum_required(VERSION 3.15) 24 | 25 | project(expected LANGUAGES CXX) 26 | 27 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 28 | 29 | add_library(project_options INTERFACE) 30 | target_compile_features(project_options INTERFACE cxx_std_20) 31 | 32 | option(ENABLE_TESTING "Enable Test Builds" ON) 33 | option(ENABLE_EXAMPLES "Enable Example Builds" OFF) 34 | 35 | include(cmake/Conan.cmake) 36 | run_conan() 37 | 38 | if(ENABLE_TESTING) 39 | enable_testing() 40 | add_subdirectory(test) 41 | endif() 42 | 43 | if(ENABLE_EXAMPLES) 44 | add_subdirectory(examples) 45 | endif() 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Rishabh Dwivedi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # expected 2 | 3 | Single header std::expected implementation using C++20. 4 | 5 | The library implements these 2 proposals: 6 | 7 | - [P0323](https://wg21.link/p0323) defines the basic interface for std::expected. 8 | - [P2505](https://wg21.link/p2505) defines the monadic inteface extensions for std::expected. 9 | 10 | This implementation provides expected in namespace rd. 11 | So, for any use of std::expected, use rd::expected. 12 | 13 | ## What std::expected does 14 | 15 | std::expected is a mechanism for error handling. This is very similar to rust's std::result. 16 | std::expected basically contains one of Result or Error. 17 | 18 | ## Why not just use exceptions 19 | 20 | There are probably 2 reasons for not "always" using exceptions: 21 | 22 | - Exceptions are forbidden in many codebases 23 | - Exceptions are too costly when any exception case arise. 24 | 25 | While writing any library, this poses a big problem for error handling. In 26 | library, if we choose to throw exception on error condition, we are making the 27 | choice for library user. Error condition in library can or can not be an 28 | exceptional situation in context of the application that uses that library. 29 | 30 | std::expected provides a standard alternative for exception that can be used 31 | for error condition that are not exceptional in context of application. 32 | 33 | While saying this, this should be noted that exceptions are great for panic 34 | conditions. And there exists many obvious panic conditions, for which only 35 | exceptions should be used. 36 | 37 | ## What about other alternatives 38 | 39 | error_code used to be simplest error handling mechanism. Historically, 40 | error_code is a simple integer, that is not good for rich error context. 41 | 42 | Nowadays, C++ header <system_error> provides richer error code. However, 43 | error_code leads to monopolization of return channel. And thus value need to be 44 | outputted with some other channel. 45 | 46 | It also forces you to write if condition after each function call. 47 | 48 | ## Never empty guarantee 49 | 50 | std::expected guarantees that it is never going to be empty. i.e., it would 51 | either contain one of value or error at any point of time. 52 | This makes it really easy to use. 53 | 54 | ## Simple code with rd::expected 55 | 56 | ```cpp 57 | auto get_file_handle(std::string_view path) -> rd::expected; 58 | 59 | auto read_file(file f) -> rd::expected; 60 | 61 | auto to_int(std::string str) -> rd::expected; 62 | 63 | auto increment(int x) -> int; 64 | 65 | auto read_int_with_increment(std::string_view path) -> rd::expected{ 66 | return get_file_handle(path) 67 | .and_then(read_file) 68 | .and_then(to_int) 69 | .transform(increment); 70 | } 71 | ``` 72 | 73 | ## Documentation 74 | 75 | ### rd::expected 76 | 77 | ```cpp 78 | template 79 | class expected 80 | ``` 81 | 82 | T, E can't be a reference type, as they are not supported in paper too. 83 | 84 | #### Member types 85 | 86 | ```cpp 87 | using value_type = T; 88 | using error_type = E; 89 | using unexpected_type = unexpected; 90 | 91 | template 92 | using rebind = expected; 93 | ``` 94 | 95 | #### Constructors 96 | 97 | Default constructor: 98 | 99 | ```cpp 100 | constexpr expected(); 101 | ``` 102 | 103 | Copy constructor: 104 | 105 | ```cpp 106 | constexpr expected(expected const&); 107 | ``` 108 | 109 | Move constructor: 110 | 111 | ```cpp 112 | constexpr expected(expected &&); 113 | ``` 114 | 115 | Expected constructor: 116 | 117 | U should be convertible to T, and G should be convertible to E. 118 | 119 | ```cpp 120 | template 121 | constexpr expected(expected const&); 122 | 123 | template 124 | constexpr expected(expected &&); 125 | ``` 126 | 127 | Value constructor: 128 | 129 | Constructor for expected \\<T , E> that accepts value to initialize T(value 130 | part of expected). 131 | 132 | ```cpp 133 | template 134 | constexpr expected(U&& v); 135 | ``` 136 | 137 | Unexpected constructor: 138 | 139 | Constructor for expected<T, E> that accepts rd::unexpected instance to 140 | initialize E(error part of expected). 141 | 142 | ```cpp 143 | template 144 | constexpr expected(unexpected const&); 145 | 146 | template 147 | constexpr expected(unexpected &&); 148 | ``` 149 | 150 | in_place_t constructor: 151 | 152 | Constructor for expected<T, E> that accepts in_place tag and arguments(to 153 | be forwarded) to initialize T. 154 | 155 | ```cpp 156 | template 157 | constexpr expected(std::in_place_t, Args&&... args); 158 | 159 | template 160 | constexpr expected(std::in_place_t, std::initializer_list, Args&&... args); 161 | ``` 162 | 163 | unexpect_t constructor: 164 | 165 | Constructor for expected<T, E> that accepts rd::unexpect tag and and arguments(to 166 | be forwarded) to initialize E. 167 | 168 | ```cpp 169 | template 170 | constexpr expected(rd::unexpect_t, Args&&... args); 171 | 172 | template 173 | constexpr expected(rd::unexpect_t, std::initializer_list, Args&&... args); 174 | ``` 175 | 176 | #### Assignment 177 | 178 | copy assignment: 179 | 180 | ```cpp 181 | constexpr expected& operator=(expected const&); 182 | ``` 183 | 184 | move assignment: 185 | 186 | ```cpp 187 | constexpr expected& operator=(expected &&); 188 | ``` 189 | 190 | Value assignment: 191 | 192 | Assigns value to expected 193 | 194 | ```cpp 195 | template 196 | constexpr expected& operator=(U&& rhs); 197 | ``` 198 | 199 | rd::unexpected assignment: 200 | 201 | Assigns error to expected 202 | 203 | ```cpp 204 | template 205 | constexpr expected& operator=(unexpected const&); 206 | 207 | template 208 | constexpr expected& operator=(unexpected &&); 209 | ``` 210 | 211 | #### Modifiers 212 | 213 | emplace: 214 | 215 | Accepts args to constructor new value for expected and assign to it. 216 | 217 | ```cpp 218 | template 219 | constexpr T& emplace(Args&&... args); 220 | 221 | template 222 | constexpr T& emplace(std::initializer_list, Args&&...); 223 | ``` 224 | 225 | #### Swap 226 | 227 | swap member function and friend function 228 | 229 | #### Observers 230 | 231 | ```cpp 232 | // For accessing T's members 233 | 234 | // precondition: has_value() == true 235 | constexpr T const* operator->() const noexcept; 236 | 237 | // precondition: has_value() == true 238 | constexpr T* operator->() noexcept; 239 | ``` 240 | 241 | ```cpp 242 | // Getting reference to T 243 | 244 | // precondition: has_value() == true 245 | constexpr T const& operator*() const& noexcept; 246 | 247 | // precondition: has_value() == true 248 | constexpr T& operator*() & noexcept; 249 | 250 | // precondition: has_value() == true 251 | constexpr T&& operator*() && noexcept; 252 | 253 | // precondition: has_value() == true 254 | constexpr T const&& operator*() const&& noexcept; 255 | ``` 256 | 257 | ```cpp 258 | // Query if value exists 259 | 260 | constexpr explicit operator bool() const noexcept; 261 | 262 | constexpr bool has_value() const noexcept; 263 | ``` 264 | 265 | ```cpp 266 | // Get value, if not exists throws exception rd::bad_expected_access(error()) 267 | 268 | constexpr T const& value() const&; 269 | constexpr T& value() &; 270 | constexpr T&& value() &&; 271 | constexpr T const&& value() const&&; 272 | ``` 273 | 274 | ```cpp 275 | // Get error, (undefined behavior if error not exists) 276 | 277 | constexpr E const& error() const&; 278 | constexpr E& error() &; 279 | constexpr E&& error() &&; 280 | constexpr E const&& error() const&&; 281 | ``` 282 | 283 | ```cpp 284 | // Get the value, if value doesn't exist return v 285 | 286 | template 287 | constexpr T value_or(U&& v) const&; 288 | 289 | template 290 | constexpr T value_or(U&& v) &&; 291 | ``` 292 | 293 | #### Monadic 294 | 295 | and_then: 296 | 297 | F should be invocable with value type of expected and should return expected 298 | whose error type should be E. 299 | It returns error of current expected, if error is there, other returns the 300 | result of invoking f with value. 301 | 302 | ```cpp 303 | template 304 | constexpr auto and_then(F&& f) &; 305 | 306 | template 307 | constexpr auto and_then(F&& f) &&; 308 | 309 | template 310 | constexpr auto and_then(F&& f) const &; 311 | 312 | template 313 | constexpr auto and_then(F&& f) const &&; 314 | ``` 315 | 316 | or_else: 317 | 318 | F should be invocable with error type of expected and should return expected 319 | whose value type should be T. 320 | 321 | If `invoke_result_t` is any specialization of expected (whose value type should be same as T), then 322 | if a value is there, value is returned wrapped in invoke_result_t of F otherwise returns the result of 323 | invoking f. 324 | 325 | If `invoke_result_t` is void, then, if error is there, then F is invoked with error. 326 | Current expected is returned as result. 327 | 328 | ```cpp 329 | template 330 | constexpr auto or_else(F&& f) &; 331 | 332 | template 333 | constexpr auto or_else(F&& f) &&; 334 | 335 | template 336 | constexpr auto or_else(F&& f) const &; 337 | 338 | template 339 | constexpr auto or_else(F&& f) const &&; 340 | ``` 341 | 342 | transform: 343 | 344 | F should be invocable with value type of current expected. If current expected 345 | contains error the resultant expected contains that error otherwise contains the 346 | result of invocation of current expected value with F. 347 | 348 | ```cpp 349 | template 350 | constexpr auto transform(F&& f) &; 351 | 352 | template 353 | constexpr auto transform(F&& f) &&; 354 | 355 | template 356 | constexpr auto transform(F&& f) const &; 357 | 358 | template 359 | constexpr auto transform(F&& f) const &&; 360 | ``` 361 | 362 | transform_error: 363 | 364 | F should be invocable with error type of current expected. If current expected 365 | contains value the resultant expected contains that value otherwise contains the 366 | result of invocation of current expected error with F. 367 | 368 | ```cpp 369 | template 370 | constexpr auto transform_error(F&& f) &; 371 | 372 | template 373 | constexpr auto transform_error(F&& f) &&; 374 | 375 | template 376 | constexpr auto transform_error(F&& f) const &; 377 | 378 | template 379 | constexpr auto transform_error(F&& f) const &&; 380 | ``` 381 | 382 | #### Equality 383 | 384 | ```cpp 385 | template 386 | constexpr friend bool operator==(expected const&, expected const&); 387 | 388 | template 389 | constexpr friend bool operator==(expected const&, U const&); 390 | 391 | template 392 | constexpr friend bool operator==(expected const&, rd::unexpected const&); 393 | ``` 394 | 395 | ### rd::unexpected 396 | 397 | ```cpp 398 | template 399 | class unexpected 400 | ``` 401 | 402 | #### Member types 403 | 404 | ```cpp 405 | using value_type = T 406 | ``` 407 | 408 | #### Constructors 409 | 410 | Copy constructor: 411 | 412 | ```cpp 413 | constexpr unexpected(unexpected const&); 414 | ``` 415 | 416 | Move constructor: 417 | 418 | ```cpp 419 | constexpr unexpected(unexpected&&); 420 | ``` 421 | 422 | in_place_t constructor: 423 | 424 | It accepts a std::in_place tag and constructs T with args. 425 | 426 | ```cpp 427 | template 428 | constexpr unexpected(std::in_place_t, Args&&... args); 429 | 430 | template 431 | constexpr unexpected(std::in_place_t, std::initializer_list, Args&&... args); 432 | ``` 433 | 434 | value constructor: 435 | 436 | Constructs T with err. 437 | 438 | ```cpp 439 | template 440 | constexpr unexpected(Err&& err); 441 | ``` 442 | 443 | #### Observer 444 | 445 | ```cpp 446 | // value(): gets the stored T value 447 | 448 | constexpr T & value() &; 449 | constexpr T const& value() const&; 450 | constexpr T && value() &&; 451 | constexpr T const&& value() const&&; 452 | ``` 453 | 454 | #### Equality operator 455 | 456 | ```cpp 457 | template 458 | friend constexpr bool operator==(unexpected const& x, unexpected const& y); 459 | ``` 460 | 461 | ### rd::bad_expected_access 462 | 463 | bad_expected_access derives from exception. Stores the error value. 464 | 465 | ```cpp 466 | template 467 | class bad_expected_access; 468 | ``` 469 | 470 | ```cpp 471 | E& error() & noexcept; 472 | E const& error() const& noexcept; 473 | E&& error() && noexcept; 474 | E const&& error() const&& noexcept; 475 | ``` 476 | 477 | ### rd::unexpect_t 478 | 479 | This is just a tag type, to signify constructing error for expected. 480 | 481 | Library also exposes a unexpect variable of type rd::unexpect_t. 482 | 483 | ```cpp 484 | inline constexpr unexpect_t unexpect{}; 485 | ``` 486 | 487 | ## TODO 488 | 489 | - Improve Documentation 490 | - Have a conan package 491 | - Add some good examples 492 | -------------------------------------------------------------------------------- /cmake/Conan.cmake: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2022 Rishabh Dwivedi 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | function(package p_name) 24 | conan_cmake_run( 25 | REQUIRES 26 | ${CONAN_EXTRA_REQUIRES} 27 | ${p_name} 28 | OPTIONS 29 | ${CONAN_EXTRA_OPTIONS} 30 | BASIC_SETUP 31 | CMAKE_TARGETS # individual targets to link to 32 | BUILD 33 | missing) 34 | endfunction() 35 | 36 | macro(run_conan) 37 | # Download automatically, you can also just copy the conan.cmake file 38 | if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake") 39 | message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan") 40 | file(DOWNLOAD "https://github.com/conan-io/cmake-conan/raw/v0.15/conan.cmake" "${CMAKE_BINARY_DIR}/conan.cmake") 41 | endif() 42 | 43 | include(${CMAKE_BINARY_DIR}/conan.cmake) 44 | 45 | conan_add_remote( 46 | NAME 47 | bincrafters 48 | URL 49 | https://api.bintray.com/conan/bincrafters/public-conan) 50 | 51 | package(doctest/2.4.8) 52 | endmacro() 53 | -------------------------------------------------------------------------------- /include/rd/expected.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | namespace rd { 37 | 38 | template 39 | class unexpected { 40 | public: 41 | using value_type = E; 42 | constexpr unexpected(unexpected const&) = default; 43 | constexpr unexpected(unexpected&&) = default; // NOLINT 44 | constexpr auto operator=(unexpected const&) -> unexpected& = default; 45 | constexpr auto operator=(unexpected&&) -> unexpected& = default; // NOLINT 46 | ~unexpected() = default; 47 | 48 | template 49 | requires std::constructible_from 50 | constexpr explicit unexpected(std::in_place_t /*unused*/, Args&&... args) 51 | : val(std::forward(args)...) {} 52 | 53 | template 54 | requires std::constructible_from < E, std::initializer_list 55 | &, Args... > constexpr explicit unexpected(std::in_place_t /*unused*/, 56 | std::initializer_list i_list, 57 | Args&&... args) 58 | : val(i_list, std::forward(args)...) {} 59 | 60 | template 61 | requires 62 | (!std::same_as, unexpected>) && 63 | (!std::same_as, std::in_place_t>)&& 64 | std::constructible_from 65 | constexpr explicit unexpected(Err&& err) // NOLINT 66 | : val(std::forward(err)) {} 67 | 68 | constexpr auto value() const& noexcept -> E const& { return val; } 69 | constexpr auto value() & noexcept -> E& { return val; } 70 | constexpr auto value() const&& noexcept -> E const&& { 71 | return std::move(val); 72 | } 73 | constexpr auto value() && noexcept -> E&& { return std::move(val); } 74 | 75 | constexpr void swap(unexpected& other) noexcept( 76 | std::is_nothrow_swappable_v) requires(std::is_swappable_v) { 77 | using std::swap; 78 | swap(val, other.val); 79 | } 80 | 81 | template 82 | requires(requires(E const& x, E2 const& y) { 83 | { x == y } -> std::convertible_to; 84 | }) 85 | friend constexpr auto operator==(unexpected const& x, unexpected const& y) -> bool { 86 | return x.value() == y.value(); 87 | } 88 | 89 | friend constexpr void swap(unexpected& x, unexpected& y) 90 | noexcept(noexcept(x.swap(y))) 91 | requires(std::is_swappable_v) { 92 | x.swap(y); 93 | } 94 | 95 | private : E val; 96 | }; 97 | 98 | template 99 | unexpected(E) -> unexpected; 100 | 101 | template 102 | class bad_expected_access; 103 | 104 | template <> 105 | class bad_expected_access : public std::exception { 106 | protected: 107 | bad_expected_access() noexcept = default; 108 | bad_expected_access(bad_expected_access const&) = default; 109 | bad_expected_access(bad_expected_access&&) = default; 110 | auto operator=(bad_expected_access const&) -> bad_expected_access& = default; 111 | auto operator=(bad_expected_access&&) -> bad_expected_access& = default; 112 | ~bad_expected_access() override = default; 113 | 114 | public: 115 | auto what() const noexcept -> char const* override { // NOLINT 116 | return "bad expected access"; 117 | } 118 | }; 119 | 120 | template 121 | class bad_expected_access : public bad_expected_access { 122 | public: 123 | explicit bad_expected_access(E e) : val(std::move(e)) {} 124 | auto what() const noexcept -> char const* override { // NOLINT 125 | return "bad expected access"; 126 | } 127 | 128 | auto error() & noexcept -> E& { return val; } 129 | auto error() const& noexcept -> E const& { return val; } 130 | auto error() && noexcept -> E&& { return std::move(val); } 131 | auto error() const&& noexcept -> const E&& { return std::move(val); } 132 | 133 | private: 134 | E val; 135 | }; 136 | 137 | struct unexpect_t {}; 138 | inline constexpr unexpect_t unexpect{}; 139 | 140 | namespace detail { 141 | template 142 | concept non_void_destructible = std::same_as || std::destructible; 143 | } 144 | 145 | template 146 | class expected; 147 | 148 | namespace detail { 149 | template 151 | concept expected_constructible_from_other = 152 | std::constructible_from && 153 | std::constructible_from && 154 | (!std::constructible_from&>)&& 155 | (!std::constructible_from>)&& 156 | (!std::constructible_from const&>)&& 157 | (!std::constructible_from const>)&& 158 | (!std::convertible_to&, T>)&& 159 | (!std::convertible_to&&, T>)&& 160 | (!std::convertible_to const&, T>)&& 161 | (!std::convertible_to const&&, T>)&& 162 | (!std::constructible_from, expected&>)&& 163 | (!std::constructible_from, expected>)&& 164 | (!std::constructible_from, expected const&>)&& 165 | (!std::constructible_from, expected const>); 166 | 167 | template 168 | concept is_unexpected = 169 | std::same_as, unexpected>; 170 | 171 | template 172 | concept is_expected = 173 | std::same_as, 174 | expected>; 175 | 176 | // This function makes sure expected doesn't get into valueless_by_exception 177 | // state due to any exception while assignment 178 | template 179 | constexpr void reinit_expected(T& newval, U& oldval, Args&&... args) { 180 | if constexpr (std::is_nothrow_constructible_v) { 181 | std::destroy_at(std::addressof(oldval)); 182 | std::construct_at(std::addressof(newval), std::forward(args)...); 183 | } else if constexpr (std::is_nothrow_move_constructible_v) { 184 | T tmp(std::forward(args)...); 185 | std::destroy_at(std::addressof(oldval)); 186 | std::construct_at(std::addressof(newval), std::move(tmp)); 187 | } else { 188 | U tmp(std::move(oldval)); 189 | std::destroy_at(std::addressof(oldval)); 190 | try { 191 | std::construct_at(std::addressof(newval), std::forward(args)...); 192 | } catch (...) { 193 | std::construct_at(std::addressof(oldval), std::move(tmp)); 194 | throw; 195 | } 196 | } 197 | } 198 | 199 | } // namespace detail 200 | 201 | template 202 | class expected { 203 | public: 204 | using value_type = T; 205 | using error_type = E; 206 | using unexpected_type = unexpected; 207 | 208 | template 209 | using rebind = expected; 210 | 211 | // constructors 212 | // postcondition: has_value() = true 213 | constexpr expected() requires std::default_initializable : val{} {}; 214 | 215 | // postcondition: has_value() = rhs.has_value() 216 | constexpr expected(expected const& rhs) 217 | requires std::copy_constructible && std::copy_constructible && 218 | std::is_trivially_copy_constructible_v && 219 | std::is_trivially_copy_constructible_v 220 | = default; 221 | 222 | // postcondition: has_value() = rhs.has_value() 223 | constexpr expected(expected const& rhs) 224 | requires std::copy_constructible && std::copy_constructible 225 | : has_val(rhs.has_val) { 226 | if (rhs.has_value()) { 227 | std::construct_at(std::addressof(this->val), *rhs); 228 | } else { 229 | std::construct_at(std::addressof(this->unex), rhs.error()); 230 | } 231 | } 232 | 233 | constexpr expected(expected&&) noexcept( 234 | std::is_nothrow_move_constructible_v&& 235 | std::is_nothrow_move_constructible_v) requires 236 | std::move_constructible && std::move_constructible && 237 | std::is_trivially_move_constructible_v && 238 | std::is_trivially_move_constructible_v 239 | = default; 240 | 241 | constexpr expected(expected&& rhs) noexcept( 242 | std::is_nothrow_move_constructible_v&& 243 | std::is_nothrow_move_constructible_v) requires 244 | std::move_constructible && std::move_constructible 245 | : has_val(rhs.has_value()) { 246 | if (rhs.has_value()) { 247 | std::construct_at(std::addressof(this->val), std::move(*rhs)); 248 | } else { 249 | std::construct_at(std::addressof(this->unex), std::move(rhs.error())); 250 | } 251 | } 252 | 253 | template 254 | requires detail::expected_constructible_from_other 256 | constexpr explicit(!std::convertible_to || 257 | !std::convertible_to) 258 | expected(expected const& rhs) // NOLINT 259 | : has_val(rhs.has_value()) { 260 | using UF = U const&; 261 | using GF = G const&; 262 | if (rhs.has_value()) { 263 | std::construct_at(std::addressof(this->val), std::forward(*rhs)); 264 | } else { 265 | std::construct_at(std::addressof(this->unex), 266 | std::forward(rhs.error())); 267 | } 268 | } 269 | 270 | template 271 | requires detail::expected_constructible_from_other 272 | constexpr explicit(!std::convertible_to || !std::convertible_to) 273 | expected(expected&& rhs) // NOLINT 274 | : has_val(rhs.has_value()) { 275 | using UF = U const&; 276 | using GF = G const&; 277 | if (rhs.has_value()) { 278 | std::construct_at(std::addressof(this->val), std::forward(*rhs)); 279 | } else { 280 | std::construct_at(std::addressof(this->unex), 281 | std::forward(rhs.error())); 282 | } 283 | } 284 | 285 | template 286 | requires(!std::same_as, std::in_place_t>) && 287 | (!std::same_as, std::remove_cvref_t>)&& 288 | (!detail::is_unexpected)&& 289 | std::constructible_from 290 | constexpr explicit(!std::convertible_to) expected(U&& v) // NOLINT 291 | : val(std::forward(v)) {} 292 | 293 | template 294 | requires std::constructible_from 295 | constexpr explicit(!std::convertible_to) 296 | expected(unexpected const& e) // NOLINT 297 | : has_val{false}, unex(std::forward(e.value())) {} 298 | 299 | template 300 | requires std::constructible_from 301 | constexpr explicit(!std::convertible_to) 302 | expected(unexpected&& e) // NOLINT 303 | : has_val{false}, unex(std::forward(e.value())) {} 304 | 305 | template 306 | requires std::constructible_from 307 | constexpr explicit expected(std::in_place_t /*unused*/, Args&&... args) 308 | : val(std::forward(args)...) {} 309 | 310 | template 311 | requires std::constructible_from < T, std::initializer_list 312 | &, Args... > constexpr explicit expected(std::in_place_t /*unused*/, 313 | std::initializer_list il, 314 | Args&&... args) 315 | : val(il, std::forward(args)...) {} 316 | 317 | template 318 | requires std::constructible_from 319 | constexpr explicit expected(unexpect_t /*unused*/, Args&&... args) 320 | : has_val{false}, unex(std::forward(args)...) {} 321 | 322 | template 323 | requires std::constructible_from < E, std::initializer_list 324 | &, 325 | Args... > constexpr explicit expected(unexpect_t /*unused*/, 326 | std::initializer_list il, 327 | Args&&... args) 328 | : has_val(false), 329 | unex(il, std::forward(args)...) {} 330 | 331 | // destructor 332 | constexpr ~expected() { 333 | if constexpr (std::is_trivially_destructible_v and 334 | std::is_trivially_destructible_v) { 335 | } else if constexpr (std::is_trivially_destructible_v) { 336 | if (!has_val) { 337 | std::destroy_at(std::addressof(this->unex)); 338 | } 339 | } else if constexpr (std::is_trivially_destructible_v) { 340 | if (has_val) { 341 | std::destroy_at(std::addressof(this->val)); 342 | } 343 | } else { 344 | if (has_val) { 345 | std::destroy_at(std::addressof(this->val)); 346 | } else { 347 | std::destroy_at(std::addressof(this->unex)); 348 | } 349 | } 350 | } 351 | 352 | // assignment 353 | constexpr auto operator=(expected const& rhs) // NOLINT 354 | -> expected& requires std::is_copy_assignable_v && 355 | std::is_copy_constructible_v && 356 | std::is_copy_assignable_v && 357 | std::is_copy_constructible_v && 358 | (std::is_nothrow_move_constructible_v || 359 | std::is_nothrow_move_constructible_v) 360 | { 361 | if (this->has_value() and rhs.has_value()) { 362 | this->val = *rhs; 363 | } else if (this->has_value()) { 364 | detail::reinit_expected(this->unex, this->val, rhs.error()); 365 | } else if (rhs.has_value()) { 366 | detail::reinit_expected(this->val, this->unex, *rhs); 367 | } else { 368 | this->unex = rhs.error(); 369 | } 370 | has_val = rhs.has_value(); 371 | return *this; 372 | } 373 | 374 | constexpr auto operator=(expected&& rhs) // 375 | noexcept(std::is_nothrow_move_assignable_v&& 376 | std::is_nothrow_move_constructible_v&& 377 | std::is_nothrow_move_assignable_v&& 378 | std::is_nothrow_move_constructible_v) 379 | -> expected& requires std::is_move_constructible_v && 380 | std::is_move_assignable_v && 381 | std::is_move_constructible_v && 382 | std::is_move_assignable_v && 383 | (std::is_nothrow_move_constructible_v || std::is_nothrow_move_constructible_v) 384 | { 385 | if (this->has_value() and rhs.has_value()) { 386 | this->val = std::move(*rhs); 387 | } else if (this->has_value()) { 388 | detail::reinit_expected(this->unex, this->val, std::move(rhs.error())); 389 | } else if (rhs.has_value()) { 390 | detail::reinit_expected(this->val, this->unex, std::move(*rhs)); 391 | } else { 392 | this->unex = std::move(rhs.error()); 393 | } 394 | has_val = rhs.has_value(); 395 | return *this; 396 | } 397 | 398 | template 399 | constexpr auto operator=(U&& rhs) -> expected& 400 | requires 401 | (!std::same_as>) && 402 | (!detail::is_unexpected>)&& 403 | std::constructible_from&& 404 | std::is_assignable_v && 405 | ( std::is_nothrow_constructible_v || 406 | std::is_nothrow_move_constructible_v || 407 | std::is_nothrow_move_constructible_v 408 | ) { 409 | if (this->has_value()) { 410 | this->val = std::forward(rhs); 411 | return *this; 412 | } 413 | detail::reinit_expected(this->val, this->unex, std::forward(rhs)); 414 | has_val = true; 415 | return *this; 416 | } 417 | 418 | template 419 | requires std::constructible_from && 420 | std::is_assignable_v && 421 | (std::is_nothrow_constructible_v || 422 | std::is_nothrow_move_constructible_v || 423 | std::is_nothrow_move_constructible_v 424 | ) 425 | constexpr auto operator=(unexpected const& e) -> expected& { 426 | using GF = G const&; 427 | if (has_value()) { 428 | detail::reinit_expected(this->unex, this->val, 429 | std::forward(e.value())); 430 | } else { 431 | this->unex = std::forward(e.value()); 432 | } 433 | has_val = false; 434 | return *this; 435 | } 436 | 437 | template 438 | requires std::constructible_from && 439 | std::is_assignable_v && 440 | (std::is_nothrow_constructible_v || 441 | std::is_nothrow_move_constructible_v || 442 | std::is_nothrow_move_constructible_v 443 | ) 444 | constexpr auto operator=(unexpected&& e) -> expected& { 445 | using GF = G; 446 | if (has_value()) { 447 | detail::reinit_expected(this->unex, this->val, 448 | std::forward(e.value())); 449 | } else { 450 | this->unex = std::forward(e.value()); 451 | } 452 | has_val = false; 453 | return *this; 454 | } 455 | 456 | // modifiers 457 | template 458 | requires std::is_nothrow_constructible_v 459 | constexpr auto emplace(Args&&... args) noexcept -> T& { 460 | if (has_value()) { 461 | std::destroy_at(std::addressof(this->val)); 462 | } else { 463 | std::destroy_at(std::addressof(this->unex)); 464 | has_val = true; 465 | } 466 | return *std::construct_at(std::addressof(this->val), 467 | std::forward(args)...); 468 | } 469 | 470 | template 471 | requires std::is_nothrow_constructible_v < T, std::initializer_list &, Args...> 472 | constexpr auto emplace(std::initializer_list il, 473 | Args&&... args) noexcept -> T& { 474 | if (has_value()) { 475 | std::destroy_at(std::addressof(this->val)); 476 | } else { 477 | std::destroy_at(std::addressof(this->unex)); 478 | has_val = true; 479 | } 480 | return *std::construct_at(std::addressof(this->val), il, 481 | std::forward(args)...); 482 | } 483 | 484 | // swap 485 | constexpr void swap(expected& rhs) noexcept( 486 | std::is_nothrow_constructible_v&& 487 | std::is_nothrow_swappable_v&& 488 | std::is_nothrow_move_constructible_v&& 489 | std::is_nothrow_swappable_v) 490 | requires std::is_swappable_v && 491 | std::is_swappable_v && 492 | std::is_move_constructible_v && 493 | std::is_move_constructible_v && 494 | (std::is_nothrow_constructible_v || 495 | std::is_nothrow_constructible_v) 496 | { 497 | if (rhs.has_value()) { 498 | if (has_value()) { 499 | using std::swap; 500 | swap(this->val, rhs.val); 501 | } else { 502 | rhs.swap(*this); 503 | } 504 | } else { 505 | if (has_value()) { 506 | if constexpr (std::is_nothrow_move_constructible_v) { 507 | E tmp(std::move(rhs.unex)); 508 | std::destroy_at(std::addressof(rhs.unex)); 509 | try { 510 | std::construct_at(std::addressof(rhs.val), std::move(this->val)); 511 | std::destroy_at(std::addressof(this->val)); 512 | std::construct_at(std::addressof(this->unex), std::move(tmp)); 513 | } catch (...) { 514 | std::construct_at(std::addressof(rhs.unex), std::move(tmp)); 515 | throw; 516 | } 517 | } else { 518 | T tmp(std::move(this->val)); 519 | std::destroy_at(std::addressof(this->val)); 520 | try { 521 | std::construct_at(std::addressof(this->unex), std::move(rhs.unex)); 522 | std::destroy_at(std::addressof(rhs.unex)); 523 | std::construct_at(std::addressof(rhs.val), std::move(tmp)); 524 | } catch (...) { 525 | std::construct_at(std::addressof(this->val), std::move(tmp)); 526 | throw; 527 | } 528 | } 529 | has_val = false; 530 | rhs.has_val = true; 531 | } else { 532 | using std::swap; 533 | swap(this->unex, rhs.unex); 534 | } 535 | } 536 | } 537 | 538 | // observers 539 | 540 | // precondition: has_value() = true 541 | constexpr auto operator->() const noexcept -> T const* { 542 | return std::addressof(this->val); 543 | } 544 | 545 | // precondition: has_value() = true 546 | constexpr auto operator->() noexcept -> T* { 547 | return std::addressof(this->val); 548 | } 549 | 550 | // precondition: has_value() = true 551 | constexpr auto operator*() const& noexcept -> T const& { return this->val; } 552 | 553 | // precondition: has_value() = true 554 | constexpr auto operator*() & noexcept -> T& { return this->val; } 555 | 556 | // precondition: has_value() = true 557 | constexpr auto operator*() const&& noexcept -> T const&& { 558 | return std::move(this->val); 559 | } 560 | 561 | // precondition: has_value() = true 562 | constexpr auto operator*() && noexcept -> T&& { return std::move(this->val); } 563 | 564 | constexpr explicit operator bool() const noexcept { return has_val; } 565 | 566 | [[nodiscard]] constexpr auto has_value() const noexcept -> bool { 567 | return has_val; 568 | } 569 | 570 | constexpr auto value() const& -> T const& { 571 | if (has_value()) { 572 | return this->val; 573 | } 574 | throw bad_expected_access(error()); 575 | } 576 | 577 | constexpr auto value() & -> T& { 578 | if (has_value()) { 579 | return this->val; 580 | } 581 | throw bad_expected_access(error()); 582 | } 583 | 584 | constexpr auto value() const&& -> T const&& { 585 | if (has_value()) { 586 | return std::move(this->val); 587 | } 588 | throw bad_expected_access(std::move(error())); 589 | } 590 | 591 | constexpr auto value() && -> T&& { 592 | if (has_value()) { 593 | return std::move(this->val); 594 | } 595 | throw bad_expected_access(std::move(error())); 596 | } 597 | 598 | // precondition: has_value() = false 599 | constexpr auto error() const& -> E const& { return this->unex; } 600 | 601 | // precondition: has_value() = false 602 | constexpr auto error() & -> E& { return this->unex; } 603 | 604 | // precondition: has_value() = false 605 | constexpr auto error() const&& -> E const&& { return std::move(this->unex); } 606 | 607 | // precondition: has_value() = false 608 | constexpr auto error() && -> E&& { return std::move(this->unex); } 609 | 610 | template 611 | requires 612 | std::is_copy_constructible_v && std::is_convertible_v 613 | constexpr auto value_or(U&& v) const& -> T { 614 | return has_value() ? **this : static_cast(std::forward(v)); 615 | } 616 | 617 | template 618 | requires std::is_move_constructible_v && std::is_convertible_v 619 | constexpr auto value_or(U&& v) && -> T { 620 | return has_value() ? std::move(**this) : static_cast(std::forward(v)); 621 | } 622 | 623 | template >> 625 | requires detail::is_expected && 626 | std::is_same_v && 627 | std::is_copy_constructible_v && std::is_copy_constructible_v 628 | constexpr auto and_then(F&& f) & { 629 | if (has_value()) { 630 | return std::invoke(std::forward(f), **this); 631 | } 632 | return U(unexpect, error()); 633 | } 634 | 635 | template >> 637 | requires detail::is_expected && 638 | std::is_same_v && 639 | std::is_copy_constructible_v && 640 | std::is_copy_constructible_v 641 | constexpr auto and_then(F&& f) const& { 642 | if (has_value()) { 643 | return std::invoke(std::forward(f), **this); 644 | } 645 | return U(unexpect, error()); 646 | } 647 | 648 | template >> 650 | requires detail::is_expected && 651 | std::is_same_v && 652 | std::is_move_constructible_v && 653 | std::is_move_constructible_v 654 | constexpr auto and_then(F&& f) && { 655 | if (has_value()) { 656 | return std::invoke(std::forward(f), std::move(**this)); 657 | } 658 | return U(unexpect, std::move(error())); 659 | } 660 | 661 | template >> 663 | requires detail::is_expected && 664 | std::is_same_v && 665 | std::is_move_constructible_v && 666 | std::is_move_constructible_v 667 | constexpr auto and_then(F&& f) const&& { 668 | if (has_value()) { 669 | return std::invoke(std::forward(f), std::move(**this)); 670 | } 671 | return U(unexpect, std::move(error())); 672 | } 673 | 674 | template >> 676 | requires detail::is_expected && 677 | std::is_same_v && 678 | std::is_copy_constructible_v && 679 | std::is_copy_constructible_v 680 | constexpr auto or_else(F&& f) & { 681 | if (has_value()) { 682 | return G(**this); 683 | } 684 | return std::invoke(std::forward(f), error()); 685 | } 686 | 687 | template >> 689 | requires detail::is_expected && 690 | std::is_same_v && 691 | std::is_copy_constructible_v && 692 | std::is_copy_constructible_v 693 | constexpr auto or_else(F&& f) const& { 694 | if (has_value()) { 695 | return G(**this); 696 | } 697 | return std::invoke(std::forward(f), error()); 698 | } 699 | 700 | template >> 702 | requires detail::is_expected && 703 | std::is_same_v && 704 | std::is_move_constructible_v && 705 | std::is_move_constructible_v 706 | constexpr auto or_else(F&& f) && { 707 | if (has_value()) { 708 | return G(std::move(**this)); 709 | } 710 | return std::invoke(std::forward(f), std::move(error())); 711 | } 712 | 713 | template >> 715 | requires detail::is_expected && 716 | std::is_same_v && 717 | std::is_move_constructible_v && 718 | std::is_move_constructible_v 719 | constexpr auto or_else(F&& f) const&& { 720 | if (has_value()) { 721 | return G(std::move(**this)); 722 | } 723 | return std::invoke(std::forward(f), std::move(error())); 724 | } 725 | 726 | template >> 728 | requires std::is_void_v && 729 | std::is_copy_constructible_v && 730 | std::is_copy_constructible_v 731 | constexpr auto or_else(F&& f) & { 732 | if (has_value()) { 733 | return expected(*this); 734 | } 735 | std::invoke(std::forward(f), error()); 736 | return expected(*this); 737 | } 738 | 739 | template >> 741 | requires std::is_void_v && 742 | std::is_copy_constructible_v && 743 | std::is_copy_constructible_v 744 | constexpr auto or_else(F&& f) const& { 745 | if (has_value()) { 746 | return expected(*this); 747 | } 748 | std::invoke(std::forward(f), error()); 749 | return expected(*this); 750 | } 751 | 752 | template >> 754 | requires std::is_void_v && 755 | std::is_move_constructible_v && 756 | std::is_move_constructible_v && 757 | std::is_copy_constructible_v 758 | constexpr auto or_else(F&& f) && { 759 | if (has_value()) { 760 | return expected(std::move(*this)); 761 | } 762 | // TODO: is this copy necessary, as f can be just read argument function 763 | std::invoke(std::forward(f), error()); 764 | return expected(std::move(*this)); 765 | } 766 | 767 | template >> 769 | requires std::is_void_v && 770 | std::is_move_constructible_v && 771 | std::is_move_constructible_v && 772 | std::is_copy_constructible_v 773 | constexpr auto or_else(F&& f) const&& { 774 | if (!has_value()) { 775 | return expected(std::move(*this)); 776 | } 777 | // TODO: is this copy necessary, as f can be just read argument function 778 | std::invoke(std::forward(f), error()); 779 | return expected(std::move(*this)); 780 | } 781 | 782 | template >> 784 | requires std::is_copy_constructible_v && 785 | std::is_copy_constructible_v 786 | constexpr auto transform(F&& f) & { 787 | if (has_value()) { 788 | if constexpr (!std::same_as) { 789 | return expected(std::invoke(std::forward(f), **this)); 790 | } else { 791 | std::invoke(std::forward(f), std::move(**this)); 792 | return expected(); 793 | } 794 | } 795 | return expected(unexpect, error()); 796 | } 797 | 798 | template >> 800 | requires std::is_copy_constructible_v && 801 | std::is_copy_constructible_v 802 | constexpr auto transform(F&& f) const& { 803 | if (has_value()) { 804 | if constexpr (!std::same_as) { 805 | return expected(std::invoke(std::forward(f), **this)); 806 | } else { 807 | std::invoke(std::forward(f), std::move(**this)); 808 | return expected(); 809 | } 810 | } 811 | return expected(unexpect, error()); 812 | } 813 | 814 | template >> 816 | requires std::is_move_constructible_v && 817 | std::is_move_constructible_v 818 | constexpr auto transform(F&& f) && { 819 | if (has_value()) { 820 | if constexpr (!std::same_as) { 821 | return expected( 822 | std::invoke(std::forward(f), std::move(**this))); 823 | } else { 824 | std::invoke(std::forward(f), std::move(**this)); 825 | return expected(); 826 | } 827 | } 828 | return expected(unexpect, std::move(error())); 829 | } 830 | 831 | template >> 833 | requires std::is_move_constructible_v && 834 | std::is_move_constructible_v 835 | constexpr auto transform(F&& f) const&& { 836 | if (has_value()) { 837 | if constexpr (!std::same_as) { 838 | return expected( 839 | std::invoke(std::forward(f), std::move(**this))); 840 | } else { 841 | std::invoke(std::forward(f), std::move(**this)); 842 | return expected(); 843 | } 844 | } 845 | return expected(unexpect, std::move(error())); 846 | } 847 | 848 | template >> 850 | requires std::is_copy_constructible_v && 851 | std::is_copy_constructible_v 852 | constexpr auto transform_error(F&& f) & { 853 | if (has_value()) { 854 | return expected(**this); 855 | } 856 | return expected(unexpect, std::invoke(std::forward(f), error())); 857 | } 858 | 859 | template >> 861 | requires std::is_copy_constructible_v && 862 | std::is_copy_constructible_v 863 | constexpr auto transform_error(F&& f) const& { 864 | if (has_value()) { 865 | return expected(**this); 866 | } 867 | return expected(unexpect, std::invoke(std::forward(f), error())); 868 | } 869 | 870 | template >> 872 | requires std::is_move_constructible_v && 873 | std::is_move_constructible_v 874 | constexpr auto transform_error(F&& f) && { 875 | if (has_value()) { 876 | return expected(std::move(**this)); 877 | } 878 | return expected(unexpect, 879 | std::invoke(std::forward(f), std::move(error()))); 880 | } 881 | 882 | template >> 884 | requires std::is_move_constructible_v && 885 | std::is_move_constructible_v 886 | constexpr auto transform_error(F&& f) const&& { 887 | if (has_value()) { 888 | return expected(std::move(**this)); 889 | } 890 | return expected(unexpect, 891 | std::invoke(std::forward(f), std::move(error()))); 892 | } 893 | 894 | // equality operators 895 | template 896 | requires(!std::is_void_v) && 897 | requires(T const& t1, T2 const& t2, E const& e1, E2 const& e2) { 898 | { t1 == t2 } -> std::convertible_to; 899 | { e1 == e2 } -> std::convertible_to; 900 | } 901 | friend constexpr auto operator==(expected const& x, expected const& y) 902 | -> bool { 903 | if (x.has_value() != y.has_value()) { 904 | return false; 905 | } 906 | return x.has_value() ? (*x == *y) : (x.error() == y.error()); 907 | } 908 | 909 | template 910 | requires(!detail::is_expected) && requires(T const& x, T2 const& v) { 911 | { x == v } -> std::convertible_to; 912 | } 913 | friend constexpr auto operator==(expected const& x, T2 const& v) -> bool { 914 | return x.has_value() && static_cast(*x == v); 915 | } 916 | 917 | template 918 | requires requires(E const& x, unexpected const& e) { 919 | { x == e.value() } -> std::convertible_to; 920 | } 921 | friend constexpr auto operator==(expected const& x, unexpected const& e) 922 | -> bool { 923 | return !x.has_value() && static_cast(x.error() == e.value()); 924 | } 925 | 926 | // specialized algorithms 927 | friend constexpr void swap(expected& x, 928 | expected& y) noexcept(noexcept(x.swap(y))) { 929 | x.swap(y); 930 | } 931 | 932 | private: 933 | bool has_val{true}; 934 | union { 935 | T val; 936 | E unex; 937 | }; 938 | }; 939 | 940 | template 941 | class expected { 942 | public: 943 | using value_type = void; 944 | using error_type = E; 945 | using unexpected_type = unexpected; 946 | 947 | template 948 | using rebind = expected; 949 | 950 | // constructors 951 | 952 | // postcondition: has_value() = true 953 | constexpr expected() noexcept {} // NOLINT 954 | 955 | constexpr expected( 956 | expected const& rhs) requires std::is_copy_constructible_v && 957 | std::is_trivially_copy_constructible_v 958 | = default; 959 | 960 | constexpr expected( 961 | expected const& rhs) requires std::is_copy_constructible_v 962 | : has_val(rhs.has_value()) { 963 | if (!rhs.has_value()) { 964 | std::construct_at(std::addressof(this->unex), rhs.error()); 965 | } 966 | } 967 | 968 | constexpr expected(expected&&) 969 | noexcept(std::is_nothrow_move_constructible_v) 970 | requires std::is_move_constructible_v && 971 | std::is_trivially_move_constructible_v 972 | = default; 973 | 974 | constexpr expected(expected&& rhs) noexcept(std::is_nothrow_move_constructible_v) 975 | requires std::is_move_constructible_v : has_val(rhs.has_value()) { 976 | if (!rhs.has_value()) { 977 | std::construct_at(std::addressof(this->unex), std::move(rhs.error())); 978 | } 979 | } 980 | 981 | template 982 | requires std::is_void_v 983 | && std::is_constructible_v 984 | &&(!std::is_constructible_v, expected&>) 985 | &&(!std::is_constructible_v, expected>) 986 | &&(!std::is_constructible_v, expected const&>) 987 | &&(!std::is_constructible_v, expected const&>) 988 | constexpr explicit(!std::is_convertible_v) 989 | expected(expected const& rhs) // NOLINT 990 | : has_val(rhs.has_value()) { 991 | if (!rhs.has_value()) { 992 | std::construct_at(std::addressof(this->unex), 993 | std::forward(rhs.error())); 994 | } 995 | } 996 | 997 | template 998 | requires std::is_void_v 999 | && std::is_constructible_v 1000 | &&(!std::is_constructible_v, expected&>) 1001 | &&(!std::is_constructible_v, expected>) 1002 | &&(!std::is_constructible_v, expected const&>) 1003 | &&(!std::is_constructible_v, expected const&>) 1004 | constexpr explicit(!std::is_convertible_v) 1005 | expected(expected&& rhs) // NOLINT 1006 | : has_val(rhs.has_value()) { 1007 | if (!rhs.has_value()) { 1008 | std::construct_at(std::addressof(this->unex), 1009 | std::forward(rhs.error())); 1010 | } 1011 | } 1012 | 1013 | template 1014 | requires std::is_constructible_v 1015 | constexpr explicit(!std::is_convertible_v) 1016 | expected(unexpected const& e) // NOLINT 1017 | : has_val(false), unex(std::forward(e.value())) {} 1018 | 1019 | template 1020 | requires std::is_constructible_v 1021 | constexpr explicit(!std::is_convertible_v) 1022 | expected(unexpected&& e) // NOLINT 1023 | : has_val(false), unex(std::forward(e.value())) {} 1024 | 1025 | constexpr explicit expected(std::in_place_t /*unused*/) noexcept {} 1026 | 1027 | template 1028 | requires std::is_constructible_v 1029 | constexpr explicit expected(unexpect_t /*unused*/, Args&&... args) 1030 | : has_val(false), unex(std::forward(args)...) {} 1031 | 1032 | template 1033 | requires std::is_constructible_v &, Args...> 1034 | constexpr explicit expected(unexpect_t /*unused*/, std::initializer_list il, Args... args) 1035 | : has_val(false), 1036 | unex(il, std::forward(args)...) {} 1037 | 1038 | // destructor 1039 | constexpr ~expected() { 1040 | if constexpr (std::is_trivially_destructible_v) { 1041 | } else { 1042 | if (!has_value()) std::destroy_at(std::addressof(this->unex)); 1043 | } 1044 | } 1045 | 1046 | // assignment 1047 | constexpr auto operator=(expected const& rhs) -> expected& // NOLINT 1048 | requires std::is_copy_assignable_v && 1049 | std::is_copy_constructible_v { 1050 | if (has_value() && rhs.has_value()) { 1051 | } else if (has_value()) { 1052 | std::construct_at(std::addressof(this->unex), rhs.unex); 1053 | has_val = false; 1054 | } else if (rhs.has_value()) { 1055 | std::destroy_at(std::addressof(this->unex)); 1056 | has_val = true; 1057 | } else { 1058 | this->unex = rhs.error(); 1059 | } 1060 | return *this; 1061 | } 1062 | 1063 | constexpr auto operator=(expected&& rhs) 1064 | noexcept(std::is_nothrow_move_constructible_v&& 1065 | std::is_nothrow_move_assignable_v) -> expected& 1066 | requires std::is_move_constructible_v && 1067 | std::is_move_assignable_v { 1068 | if (has_value() && rhs.has_value()) { 1069 | } else if (has_value()) { 1070 | std::construct_at(std::addressof(this->unex), std::move(rhs.unex)); 1071 | has_val = false; 1072 | } else if (rhs.has_value()) { 1073 | std::destroy_at(std::addressof(this->unex)); 1074 | has_val = true; 1075 | } else { 1076 | this->unex = std::move(rhs.error()); 1077 | } 1078 | return *this; 1079 | } 1080 | 1081 | template 1082 | requires std::is_constructible_v and 1083 | std::is_assignable_v 1084 | constexpr auto operator=(unexpected const& e) -> expected& { 1085 | if (has_value()) { 1086 | std::construct_at(std::addressof(this->unex), 1087 | std::forward(e.value())); 1088 | has_val = false; 1089 | } else { 1090 | this->unex = std::forward(e.value()); 1091 | } 1092 | return *this; 1093 | } 1094 | 1095 | template 1096 | requires std::is_constructible_v && 1097 | std::is_assignable_v 1098 | constexpr auto operator=(unexpected&& e) -> expected& { 1099 | if (has_value()) { 1100 | std::construct_at(std::addressof(this->unex), std::forward(e.value())); 1101 | has_val = false; 1102 | } else { 1103 | this->unex = std::forward(e.value()); 1104 | } 1105 | return *this; 1106 | } 1107 | 1108 | // modifiers 1109 | constexpr void emplace() noexcept { 1110 | if (!has_value()) { 1111 | std::destroy_at(std::addressof(this->unex)); 1112 | has_val = true; 1113 | } 1114 | } 1115 | 1116 | // swap 1117 | constexpr void swap(expected& rhs) 1118 | noexcept(std::is_nothrow_move_constructible_v&& 1119 | std::is_nothrow_swappable_v) 1120 | requires std::is_swappable_v && 1121 | std::is_move_constructible_v 1122 | { 1123 | if (rhs.has_value()) { 1124 | if (has_value()) { 1125 | } else { 1126 | rhs.swap(*this); 1127 | } 1128 | } else { 1129 | if (has_value()) { 1130 | std::construct_at(std::addressof(this->unex), std::move(rhs.unex)); 1131 | std::destroy_at(std::addressof(rhs.unex)); 1132 | has_val = false; 1133 | rhs.has_val = true; 1134 | } else { 1135 | using std::swap; 1136 | swap(this->unex, rhs.unex); 1137 | } 1138 | } 1139 | } 1140 | 1141 | // observers 1142 | constexpr explicit operator bool() const noexcept { return has_val; } 1143 | 1144 | [[nodiscard]] constexpr auto has_value() const noexcept -> bool { 1145 | return has_val; 1146 | } 1147 | 1148 | // precondition: has_value() = true 1149 | constexpr void operator*() const noexcept {} 1150 | 1151 | constexpr void value() const& { 1152 | if (!has_value()) { 1153 | throw bad_expected_access(error()); 1154 | } 1155 | } 1156 | 1157 | constexpr void value() && { 1158 | if (!has_value()) { 1159 | throw bad_expected_access(std::move(error())); 1160 | } 1161 | } 1162 | 1163 | // precondition: has_value() = false 1164 | constexpr auto error() const& -> E const& { return this->unex; } 1165 | 1166 | // precondition: has_value() = false 1167 | constexpr auto error() & -> E& { return this->unex; } 1168 | 1169 | // precondition: has_value() = false 1170 | constexpr auto error() const&& -> E const&& { return std::move(this->unex); } 1171 | 1172 | // precondition: has_value() = false 1173 | constexpr auto error() && -> E&& { return std::move(this->unex); } 1174 | 1175 | // monadic 1176 | template >> 1177 | requires detail::is_expected && 1178 | std::is_same_v && 1179 | std::is_copy_constructible_v 1180 | constexpr auto and_then(F&& f) & { 1181 | if (has_value()) { 1182 | return std::invoke(std::forward(f)); 1183 | } 1184 | return U(unexpect, error()); 1185 | } 1186 | 1187 | template >> 1188 | requires detail::is_expected && 1189 | std::is_same_v && 1190 | std::is_copy_constructible_v 1191 | constexpr auto and_then(F&& f) const& { 1192 | if (has_value()) { 1193 | return std::invoke(std::forward(f)); 1194 | } 1195 | return U(unexpect, error()); 1196 | } 1197 | 1198 | template >> 1199 | requires detail::is_expected && 1200 | std::is_same_v && 1201 | std::is_move_constructible_v 1202 | constexpr auto and_then(F&& f) && { 1203 | if (has_value()) { 1204 | return std::invoke(std::forward(f)); 1205 | } 1206 | return U(unexpect, std::move(error())); 1207 | } 1208 | 1209 | template >> 1210 | requires detail::is_expected && 1211 | std::is_same_v && 1212 | std::is_move_constructible_v 1213 | constexpr auto and_then(F&& f) const&& { 1214 | if (has_value()) { 1215 | return std::invoke(std::forward(f)); 1216 | } 1217 | return U(unexpect, std::move(error())); 1218 | } 1219 | 1220 | template >> 1222 | requires detail::is_expected && 1223 | std::is_same_v && 1224 | std::is_copy_constructible_v 1225 | constexpr auto or_else(F&& f) & { 1226 | if (has_value()) { 1227 | return G{}; 1228 | } 1229 | return std::invoke(std::forward(f), error()); 1230 | } 1231 | 1232 | template >> 1234 | requires detail::is_expected && 1235 | std::is_same_v && 1236 | std::is_copy_constructible_v 1237 | constexpr auto or_else(F&& f) const& { 1238 | if (has_value()) { 1239 | return G{}; 1240 | } 1241 | return std::invoke(std::forward(f), error()); 1242 | } 1243 | 1244 | template >> 1246 | requires detail::is_expected && 1247 | std::is_same_v && 1248 | std::is_move_constructible_v 1249 | constexpr auto or_else(F&& f) && { 1250 | if (has_value()) { 1251 | return G{}; 1252 | } 1253 | return std::invoke(std::forward(f), std::move(error())); 1254 | } 1255 | 1256 | template >> 1258 | requires detail::is_expected && 1259 | std::is_same_v && 1260 | std::is_move_constructible_v 1261 | constexpr auto or_else(F&& f) const&& { 1262 | if (has_value()) { 1263 | return G{}; 1264 | } 1265 | return std::invoke(std::forward(f), std::move(error())); 1266 | } 1267 | 1268 | template >> 1270 | requires std::is_void_v && 1271 | std::is_copy_constructible_v 1272 | constexpr auto or_else(F&& f) & { 1273 | if (has_value()) { 1274 | return expected(*this); 1275 | } 1276 | std::invoke(std::forward(f), error()); 1277 | return expected(*this); 1278 | } 1279 | 1280 | template >> 1282 | requires std::is_void_v && 1283 | std::is_copy_constructible_v 1284 | constexpr auto or_else(F&& f) const& { 1285 | if (has_value()) { 1286 | return expected(*this); 1287 | } 1288 | std::invoke(std::forward(f), error()); 1289 | return expected(*this); 1290 | } 1291 | 1292 | template >> 1294 | requires std::is_void_v && 1295 | std::is_move_constructible_v && 1296 | std::is_copy_constructible_v 1297 | constexpr auto or_else(F&& f) && { 1298 | if (has_value()) { 1299 | return expected(std::move(*this)); 1300 | } 1301 | // TODO: is this copy necessary, as f can be just read argument function 1302 | std::invoke(std::forward(f), error()); 1303 | return expected(std::move(*this)); 1304 | } 1305 | 1306 | template >> 1308 | requires std::is_void_v && 1309 | std::is_move_constructible_v && 1310 | std::is_copy_constructible_v 1311 | constexpr auto or_else(F&& f) const&& { 1312 | if (!has_value()) { 1313 | return expected(std::move(*this)); 1314 | } 1315 | // TODO: is this copy necessary, as f can be just read argument function 1316 | std::invoke(std::forward(f), error()); 1317 | return expected(std::move(*this)); 1318 | } 1319 | 1320 | template >> 1321 | requires std::is_copy_constructible_v 1322 | constexpr auto transform(F&& f) & { 1323 | if (has_value()) { 1324 | if constexpr (!std::same_as) { 1325 | return expected(std::invoke(std::forward(f))); 1326 | } else { 1327 | std::invoke(std::forward(f)); 1328 | return expected(); 1329 | } 1330 | } 1331 | return expected(unexpect, error()); 1332 | } 1333 | 1334 | template >> 1335 | requires std::is_copy_constructible_v 1336 | constexpr auto transform(F&& f) const& { 1337 | if (has_value()) { 1338 | if constexpr (!std::same_as) { 1339 | return expected(std::invoke(std::forward(f))); 1340 | } else { 1341 | std::invoke(std::forward(f)); 1342 | return expected(); 1343 | } 1344 | } 1345 | return expected(unexpect, error()); 1346 | } 1347 | 1348 | template >> 1349 | requires std::is_move_constructible_v 1350 | constexpr auto transform(F&& f) && { 1351 | if (has_value()) { 1352 | if constexpr (!std::same_as) { 1353 | return expected(std::invoke(std::forward(f))); 1354 | } else { 1355 | std::invoke(std::forward(f)); 1356 | return expected(); 1357 | } 1358 | } 1359 | return expected(unexpect, std::move(error())); 1360 | } 1361 | 1362 | template >> 1363 | requires std::is_move_constructible_v 1364 | constexpr auto transform(F&& f) const&& { 1365 | if (has_value()) { 1366 | if constexpr (!std::same_as) { 1367 | return expected(std::invoke(std::forward(f))); 1368 | } else { 1369 | std::invoke(std::forward(f)); 1370 | return expected(); 1371 | } 1372 | } 1373 | return expected(unexpect, std::move(error())); 1374 | } 1375 | 1376 | template >> 1378 | requires std::is_copy_constructible_v 1379 | constexpr auto transform_error(F&& f) & { 1380 | if (has_value()) { 1381 | return expected{}; 1382 | } 1383 | return expected(unexpect, 1384 | std::invoke(std::forward(f), error())); 1385 | } 1386 | 1387 | template >> 1389 | requires std::is_copy_constructible_v 1390 | constexpr auto transform_error(F&& f) const& { 1391 | if (has_value()) { 1392 | return expected{}; 1393 | } 1394 | return expected(unexpect, 1395 | std::invoke(std::forward(f), error())); 1396 | } 1397 | 1398 | template >> 1400 | requires std::is_move_constructible_v 1401 | constexpr auto transform_error(F&& f) && { 1402 | if (has_value()) { 1403 | return expected{}; 1404 | } 1405 | return expected( 1406 | unexpect, std::invoke(std::forward(f), std::move(error()))); 1407 | } 1408 | 1409 | template >> 1411 | requires std::is_move_constructible_v 1412 | constexpr auto transform_error(F&& f) const&& { 1413 | if (has_value()) { 1414 | return expected{}; 1415 | } 1416 | return expected( 1417 | unexpect, std::invoke(std::forward(f), std::move(error()))); 1418 | } 1419 | 1420 | // expected equality operators 1421 | template 1422 | requires std::is_void_v && requires(E e, E2 e2) { 1423 | { e == e2 } -> std::convertible_to; 1424 | } 1425 | friend constexpr auto operator==(expected const& x, expected const& y) 1426 | -> bool { 1427 | if (x.has_value() != y.has_value()) return false; 1428 | return x.has_value() or static_cast(x.error() == y.error()); 1429 | } 1430 | 1431 | template 1432 | requires requires(expected const& x, unexpected const& e) { 1433 | { x.error() == e.value() } -> std::convertible_to; 1434 | } 1435 | friend constexpr auto operator==(expected const& x, unexpected const& e) 1436 | -> bool { 1437 | return !x.has_value() && static_cast(x.error() == e.value()); 1438 | } 1439 | 1440 | // specialized algorithms 1441 | friend constexpr void swap(expected& x, 1442 | expected& y) noexcept(noexcept(x.swap(y))) { 1443 | x.swap(y); 1444 | } 1445 | 1446 | private: 1447 | bool has_val{true}; 1448 | union { 1449 | E unex; 1450 | }; 1451 | }; 1452 | 1453 | } // namespace rd 1454 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2022 Rishabh Dwivedi 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | file(GLOB test_sources "*_test.cpp") 24 | add_executable(expected_tests ${test_sources} test_runner.cpp) 25 | target_include_directories(expected_tests PRIVATE ../include) 26 | target_link_libraries(expected_tests PRIVATE project_options) 27 | target_link_libraries(expected_tests PUBLIC CONAN_PKG::doctest) 28 | add_test(NAME "test-expected" COMMAND expected_tests) 29 | -------------------------------------------------------------------------------- /test/bad_expected_access_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("error constructor") { 28 | rd::bad_expected_access ex(2); 29 | REQUIRE(ex.error() == 2); 30 | } 31 | 32 | TEST_CASE("what test") { 33 | rd::bad_expected_access ex(2); 34 | REQUIRE(ex.what() == "bad expected access"); 35 | } 36 | -------------------------------------------------------------------------------- /test/exepcted_monadic_edge_cases_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | auto consume(int /*unused*/) -> void {} 28 | 29 | TEST_CASE("transform & returns void") { 30 | rd::expected ex{2}; 31 | auto e = ex.transform(consume); 32 | REQUIRE(e.has_value()); 33 | } 34 | 35 | TEST_CASE("transform const & returns void") { 36 | rd::expected const ex{2}; 37 | auto e = ex.transform(consume); 38 | REQUIRE(e.has_value()); 39 | } 40 | 41 | TEST_CASE("transform && returns void") { 42 | rd::expected ex{2}; 43 | auto e = std::move(ex).transform(consume); 44 | REQUIRE(e.has_value()); 45 | } 46 | 47 | TEST_CASE("transform & returns void with error") { 48 | rd::expected ex{rd::unexpect, 2}; 49 | auto e = ex.transform(consume); 50 | REQUIRE(!e.has_value()); 51 | REQUIRE(e.error() == 2); 52 | } 53 | 54 | TEST_CASE("transform const & returns void with error") { 55 | rd::expected const ex{rd::unexpect, 2}; 56 | auto e = ex.transform(consume); 57 | REQUIRE(!e.has_value()); 58 | REQUIRE(e.error() == 2); 59 | } 60 | 61 | TEST_CASE("transform && returns void with error") { 62 | rd::expected ex{rd::unexpect, 2}; 63 | auto e = std::move(ex).transform(consume); 64 | REQUIRE(!e.has_value()); 65 | REQUIRE(e.error() == 2); 66 | } 67 | 68 | TEST_CASE("or_else & returns void with error") { 69 | rd::expected ex{rd::unexpect, "error"}; 70 | auto e = ex.or_else([](auto) {}); 71 | REQUIRE(!e.has_value()); 72 | REQUIRE(e.error() == "error"); 73 | } 74 | 75 | TEST_CASE("or_else const& returns void with error") { 76 | rd::expected const ex{rd::unexpect, "error"}; 77 | auto e = ex.or_else([](auto) {}); 78 | REQUIRE(!e.has_value()); 79 | REQUIRE(e.error() == "error"); 80 | } 81 | 82 | TEST_CASE("or_else && returns void with error") { 83 | rd::expected ex{rd::unexpect, "error"}; 84 | auto e = std::move(ex).or_else([](auto) {}); 85 | REQUIRE(!e.has_value()); 86 | REQUIRE(e.error() == "error"); 87 | } 88 | 89 | TEST_CASE("or_else & returns void with value") { 90 | rd::expected ex{"value"}; 91 | auto e = ex.or_else([](auto) {}); 92 | REQUIRE(e.has_value()); 93 | REQUIRE(e.value() == "value"); 94 | } 95 | 96 | TEST_CASE("or_else const& returns void with value") { 97 | rd::expected const ex{"value"}; 98 | auto e = ex.or_else([](auto) {}); 99 | REQUIRE(e.has_value()); 100 | REQUIRE(e.value() == "value"); 101 | } 102 | 103 | TEST_CASE("or_else && returns void with value") { 104 | rd::expected const ex{"value"}; 105 | auto e = std::move(ex).or_else([](auto) {}); 106 | REQUIRE(e.has_value()); 107 | REQUIRE(e.value() == "value"); 108 | } 109 | 110 | TEST_CASE("or_else void & returns void with error") { 111 | rd::expected ex{rd::unexpect, "error"}; 112 | auto e = ex.or_else([](auto) {}); 113 | REQUIRE(!e.has_value()); 114 | REQUIRE(e.error() == "error"); 115 | } 116 | 117 | TEST_CASE("or_else void const& returns void with error") { 118 | rd::expected const ex{rd::unexpect, "error"}; 119 | auto e = ex.or_else([](auto) {}); 120 | REQUIRE(!e.has_value()); 121 | REQUIRE(e.error() == "error"); 122 | } 123 | 124 | TEST_CASE("or_else void && returns void with error") { 125 | rd::expected ex{rd::unexpect, "error"}; 126 | auto e = std::move(ex).or_else([](auto) {}); 127 | REQUIRE(!e.has_value()); 128 | REQUIRE(e.error() == "error"); 129 | } 130 | 131 | TEST_CASE("or_else void & returns void with value") { 132 | rd::expected ex{}; 133 | auto e = ex.or_else([](auto) {}); 134 | REQUIRE(e.has_value()); 135 | } 136 | 137 | TEST_CASE("or_else void const& returns void with value") { 138 | rd::expected const ex{}; 139 | auto e = ex.or_else([](auto) {}); 140 | REQUIRE(e.has_value()); 141 | } 142 | 143 | TEST_CASE("or_else void && returns void with value") { 144 | rd::expected ex{}; 145 | auto e = std::move(ex).or_else([](auto) {}); 146 | REQUIRE(e.has_value()); 147 | } 148 | -------------------------------------------------------------------------------- /test/expected_assignment_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("copy: lhs has value, rhs has error") { 28 | rd::expected const rhs{rd::unexpect, "error"}; 29 | rd::expected lhs{"value"}; 30 | lhs = rhs; 31 | REQUIRE(lhs.has_value() == rhs.has_value()); 32 | REQUIRE(!lhs.has_value()); 33 | REQUIRE(lhs.error() == "error"); 34 | } 35 | 36 | TEST_CASE("copy: lhs has error, rhs has value") { 37 | rd::expected const rhs{"value"}; 38 | rd::expected lhs{rd::unexpect, "error"}; 39 | lhs = rhs; 40 | REQUIRE(lhs.has_value() == rhs.has_value()); 41 | REQUIRE(lhs.has_value()); 42 | REQUIRE(*lhs == "value"); 43 | } 44 | 45 | TEST_CASE("copy: lhs has value, rhs has value") { 46 | rd::expected const rhs{"value"}; 47 | rd::expected lhs{"value1"}; 48 | lhs = rhs; 49 | REQUIRE(lhs.has_value() == rhs.has_value()); 50 | REQUIRE(lhs.has_value()); 51 | REQUIRE(*lhs == "value"); 52 | } 53 | 54 | TEST_CASE("copy: lhs has error, rhs has error") { 55 | rd::expected const rhs{rd::unexpect, "value"}; 56 | rd::expected lhs{rd::unexpect, "value1"}; 57 | lhs = rhs; 58 | REQUIRE(lhs.has_value() == rhs.has_value()); 59 | REQUIRE(!lhs.has_value()); 60 | REQUIRE(lhs.error() == "value"); 61 | } 62 | 63 | TEST_CASE("move: lhs has value, rhs has error") { 64 | rd::expected rhs{rd::unexpect, "error"}; 65 | auto const rhs_has_value = rhs.has_value(); 66 | rd::expected lhs{"value"}; 67 | lhs = std::move(rhs); 68 | REQUIRE(lhs.has_value() == rhs_has_value); 69 | REQUIRE(!lhs.has_value()); 70 | REQUIRE(lhs.error() == "error"); 71 | } 72 | 73 | TEST_CASE("move: lhs has error, rhs has value") { 74 | rd::expected rhs{"value"}; 75 | auto const rhs_has_value = rhs.has_value(); 76 | rd::expected lhs{rd::unexpect, "error"}; 77 | lhs = std::move(rhs); 78 | REQUIRE(lhs.has_value() == rhs_has_value); 79 | REQUIRE(lhs.has_value()); 80 | REQUIRE(*lhs == "value"); 81 | } 82 | 83 | TEST_CASE("move: lhs has value, rhs has value") { 84 | rd::expected rhs{"value"}; 85 | auto const rhs_has_value = rhs.has_value(); 86 | rd::expected lhs{"value1"}; 87 | lhs = std::move(rhs); 88 | REQUIRE(lhs.has_value() == rhs_has_value); 89 | REQUIRE(lhs.has_value()); 90 | REQUIRE(*lhs == "value"); 91 | } 92 | 93 | TEST_CASE("move: lhs has error, rhs has error") { 94 | rd::expected rhs{rd::unexpect, "value"}; 95 | auto const rhs_has_value = rhs.has_value(); 96 | rd::expected lhs{rd::unexpect, "value1"}; 97 | lhs = std::move(rhs); 98 | REQUIRE(lhs.has_value() == rhs_has_value); 99 | REQUIRE(!lhs.has_value()); 100 | REQUIRE(lhs.error() == "value"); 101 | } 102 | 103 | TEST_CASE("assigning values : lhs has value with no conversion") { 104 | rd::expected lhs{"value1"}; 105 | lhs = std::string{"value"}; 106 | REQUIRE(lhs.has_value()); 107 | REQUIRE(*lhs == "value"); 108 | } 109 | 110 | TEST_CASE("assigning values : lhs has value conversion") { 111 | rd::expected lhs{"value1"}; 112 | // TODO: confirm if explicit convertable operation should work 113 | lhs = int_to_str_implicit(2); 114 | REQUIRE(lhs.has_value()); 115 | REQUIRE(*lhs == "2"); 116 | } 117 | 118 | TEST_CASE("assigning values : lhs has error with no conversion") { 119 | rd::expected lhs{rd::unexpect, "value1"}; 120 | lhs = std::string{"value"}; 121 | REQUIRE(lhs.has_value()); 122 | REQUIRE(*lhs == "value"); 123 | } 124 | 125 | TEST_CASE("assigning values : lhs has value conversion") { 126 | rd::expected lhs{rd::unexpect, "value1"}; 127 | // TODO: confirm if explicit convertable operation should work 128 | lhs = int_to_str_implicit(2); 129 | REQUIRE(lhs.has_value()); 130 | REQUIRE(*lhs == "2"); 131 | } 132 | 133 | TEST_CASE("assigning unexpected : lhs has value without conversion") { 134 | rd::expected lhs{"value1"}; 135 | lhs = rd::unexpected{std::string{"value"}}; 136 | REQUIRE(!lhs.has_value()); 137 | REQUIRE(lhs.error() == "value"); 138 | } 139 | 140 | TEST_CASE("assigning unexpected : lhs has error without conversion") { 141 | rd::expected lhs{rd::unexpect, "value1"}; 142 | lhs = rd::unexpected{std::string{"value"}}; 143 | REQUIRE(!lhs.has_value()); 144 | REQUIRE(lhs.error() == "value"); 145 | } 146 | 147 | TEST_CASE("assigning unexpected : lhs has value with conversion") { 148 | rd::expected lhs{"value1"}; 149 | lhs = rd::unexpected{int_to_str_implicit{2}}; 150 | REQUIRE(!lhs.has_value()); 151 | REQUIRE(lhs.error() == "2"); 152 | } 153 | 154 | TEST_CASE("assigning unexpected : lhs has error with conversion") { 155 | rd::expected lhs{rd::unexpect, "value1"}; 156 | lhs = rd::unexpected{int_to_str_implicit{2}}; 157 | REQUIRE(!lhs.has_value()); 158 | REQUIRE(lhs.error() == "2"); 159 | } 160 | 161 | TEST_CASE("assigning unexpected : lhs has value without conversion COPY") { 162 | rd::expected lhs{"value1"}; 163 | rd::unexpected rhs{std::string{"value"}}; 164 | lhs = rd::unexpected{rhs}; 165 | REQUIRE(!lhs.has_value()); 166 | REQUIRE(lhs.error() == "value"); 167 | } 168 | 169 | TEST_CASE("assigning unexpected : lhs has error without conversion COPY") { 170 | rd::expected lhs{rd::unexpect, "value1"}; 171 | rd::unexpected rhs{std::string{"value"}}; 172 | lhs = rd::unexpected{rhs}; 173 | REQUIRE(!lhs.has_value()); 174 | REQUIRE(lhs.error() == "value"); 175 | } 176 | 177 | TEST_CASE("assigning unexpected : lhs has value with conversion COPY") { 178 | rd::expected lhs{"value1"}; 179 | rd::unexpected rhs{int_to_str_implicit{2}}; 180 | lhs = rd::unexpected{rhs}; 181 | REQUIRE(!lhs.has_value()); 182 | REQUIRE(lhs.error() == "2"); 183 | } 184 | 185 | TEST_CASE("assigning unexpected : lhs has error with conversion COPY") { 186 | rd::expected lhs{rd::unexpect, "value1"}; 187 | rd::unexpected rhs{int_to_str_implicit{2}}; 188 | lhs = rd::unexpected{rhs}; 189 | REQUIRE(!lhs.has_value()); 190 | REQUIRE(lhs.error() == "2"); 191 | } 192 | -------------------------------------------------------------------------------- /test/expected_constructor_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | #include "test_include.hpp" 28 | 29 | TEST_CASE("default constructor") { 30 | rd::expected ex; 31 | REQUIRE(ex.has_value()); 32 | REQUIRE(*ex == ""); 33 | } 34 | 35 | TEST_CASE("Value constructor") { 36 | rd::expected const ex{"test value"}; 37 | REQUIRE(ex.has_value()); 38 | REQUIRE(*ex == "test value"); 39 | } 40 | 41 | TEST_CASE("trivial copy constructor with value") { 42 | rd::expected const orig{2}; 43 | auto const ex(orig); 44 | REQUIRE(ex.has_value()); 45 | REQUIRE(ex.has_value() == orig.has_value()); 46 | REQUIRE(*ex == 2); 47 | } 48 | 49 | TEST_CASE("trivial copy constructor with error") { 50 | rd::expected const orig{rd::unexpect, 2}; 51 | auto const ex(orig); 52 | REQUIRE(!ex.has_value()); 53 | REQUIRE(ex.has_value() == orig.has_value()); 54 | REQUIRE(ex.error() == 2); 55 | } 56 | 57 | TEST_CASE("non-trivial copy constructor with value") { 58 | rd::expected const orig{"test value"}; 59 | auto const ex(orig); 60 | REQUIRE(ex.has_value()); 61 | REQUIRE(ex.has_value() == orig.has_value()); 62 | REQUIRE(*ex == "test value"); 63 | } 64 | 65 | TEST_CASE("non-trivial copy constructor with error") { 66 | rd::expected const orig{rd::unexpect, "test value"}; 67 | auto const ex(orig); 68 | REQUIRE(!ex.has_value()); 69 | REQUIRE(ex.has_value() == orig.has_value()); 70 | REQUIRE(ex.error() == "test value"); 71 | } 72 | 73 | TEST_CASE( 74 | "copy constructor with non-trivial error type and non-trival value type " 75 | "with containing value") { 76 | rd::expected const orig{"test value"}; 77 | auto const ex(orig); 78 | REQUIRE(ex.has_value()); 79 | REQUIRE(ex.has_value() == orig.has_value()); 80 | REQUIRE(*ex == "test value"); 81 | } 82 | 83 | TEST_CASE( 84 | "copy constructor with non-trivial error type and non-trival value type " 85 | "with containing error") { 86 | rd::expected const orig{rd::unexpect, "test value"}; 87 | auto const ex(orig); 88 | REQUIRE(!ex.has_value()); 89 | REQUIRE(ex.has_value() == orig.has_value()); 90 | REQUIRE(ex.error() == "test value"); 91 | } 92 | 93 | TEST_CASE( 94 | "move constructor with trivial value and error type with containing " 95 | "value") { 96 | rd::expected orig{2}; 97 | auto const orig_has_value = orig.has_value(); 98 | auto const ex(std::move(orig)); 99 | REQUIRE(ex.has_value()); 100 | REQUIRE(ex.has_value() == orig_has_value); 101 | REQUIRE(*ex == 2); 102 | } 103 | 104 | TEST_CASE( 105 | "move constructor with trivial value and error type with containing " 106 | "error") { 107 | rd::expected orig{rd::unexpect, 2}; 108 | auto const orig_has_value = orig.has_value(); 109 | auto const ex(std::move(orig)); 110 | REQUIRE(!ex.has_value()); 111 | REQUIRE(ex.has_value() == orig_has_value); 112 | REQUIRE(ex.error() == 2); 113 | } 114 | 115 | TEST_CASE( 116 | "move constructor with non-trivial value and trivial error type with " 117 | "containing value") { 118 | rd::expected orig{"test value"}; 119 | auto const orig_has_value = orig.has_value(); 120 | auto const ex(std::move(orig)); 121 | REQUIRE(ex.has_value()); 122 | REQUIRE(ex.has_value() == orig_has_value); 123 | REQUIRE(*ex == "test value"); 124 | } 125 | 126 | TEST_CASE( 127 | "move constructor with trivial value and non-trivial error type with " 128 | "containing error") { 129 | rd::expected orig{rd::unexpect, "test value"}; 130 | auto const orig_has_value = orig.has_value(); 131 | auto const ex(std::move(orig)); 132 | REQUIRE(!ex.has_value()); 133 | REQUIRE(ex.has_value() == orig_has_value); 134 | REQUIRE(ex.error() == "test value"); 135 | } 136 | 137 | TEST_CASE( 138 | "move constructor with non trivial value and error type with " 139 | "containing value") { 140 | rd::expected orig{"test value"}; 141 | auto const orig_has_value = orig.has_value(); 142 | auto const ex(std::move(orig)); 143 | REQUIRE(ex.has_value()); 144 | REQUIRE(ex.has_value() == orig_has_value); 145 | REQUIRE(*ex == "test value"); 146 | } 147 | 148 | TEST_CASE( 149 | "move constructor with non trivial value and error type with " 150 | "containing error") { 151 | rd::expected orig{rd::unexpect, "test value"}; 152 | auto const orig_has_value = orig.has_value(); 153 | auto const ex(std::move(orig)); 154 | REQUIRE(!ex.has_value()); 155 | REQUIRE(ex.has_value() == orig_has_value); 156 | REQUIRE(ex.error() == "test value"); 157 | } 158 | 159 | TEST_CASE("expected conversion-copy-constructor with value") { 160 | rd::expected orig(2); 161 | rd::expected ex(orig); 162 | REQUIRE(ex.has_value()); 163 | REQUIRE(orig.has_value() == ex.has_value()); 164 | REQUIRE(*ex == "2"); 165 | } 166 | 167 | TEST_CASE("expected conversion-move-constructor with value") { 168 | rd::expected orig(2); 169 | auto const orig_val = orig.has_value(); 170 | rd::expected ex(std::move(orig)); 171 | REQUIRE(ex.has_value()); 172 | REQUIRE(orig_val == ex.has_value()); 173 | REQUIRE(*ex == "2"); 174 | } 175 | 176 | TEST_CASE("expected conversion-copy-constructor with error") { 177 | rd::expected orig(rd::unexpect, 2); 178 | rd::expected ex(orig); 179 | REQUIRE(!ex.has_value()); 180 | REQUIRE(orig.has_value() == ex.has_value()); 181 | REQUIRE(ex.error() == "2"); 182 | } 183 | 184 | TEST_CASE("expected conversion-move-constructor with error") { 185 | rd::expected orig(rd::unexpect, 2); 186 | auto const orig_val = orig.has_value(); 187 | rd::expected ex(std::move(orig)); 188 | REQUIRE(!ex.has_value()); 189 | REQUIRE(orig_val == ex.has_value()); 190 | REQUIRE(ex.error() == "2"); 191 | } 192 | 193 | TEST_CASE("value constructor test with no conversion with value") { 194 | rd::expected ex(int_to_str(2)); 195 | REQUIRE(ex.has_value()); 196 | REQUIRE(ex->val() == 2); 197 | } 198 | 199 | TEST_CASE("value constructor test with conversion with value") { 200 | rd::expected ex(int_to_str(2)); 201 | REQUIRE(ex.has_value()); 202 | REQUIRE(*ex == "2"); 203 | } 204 | 205 | TEST_CASE("unexpected constructor with no conversion needed : COPY") { 206 | rd::unexpected e{2}; 207 | rd::expected ex(e); 208 | REQUIRE(!ex.has_value()); 209 | REQUIRE(ex.error() == 2); 210 | } 211 | 212 | TEST_CASE("unexpected constructor with conversion needed : COPY") { 213 | rd::unexpected e{int_to_str(2)}; 214 | rd::expected ex(e); 215 | REQUIRE(!ex.has_value()); 216 | REQUIRE(ex.error() == "2"); 217 | } 218 | 219 | TEST_CASE("unexpected constructor with no conversion needed : MOVE") { 220 | rd::expected ex(rd::unexpected{2}); 221 | REQUIRE(!ex.has_value()); 222 | REQUIRE(ex.error() == 2); 223 | } 224 | 225 | TEST_CASE("unexpected constructor with conversion needed : MOVE") { 226 | rd::expected ex(rd::unexpected{int_to_str(2)}); 227 | REQUIRE(!ex.has_value()); 228 | REQUIRE(ex.error() == "2"); 229 | } 230 | 231 | TEST_CASE("inplace constructor") { 232 | rd::expected, int> ex(std::in_place, 233 | static_cast(2), 2); 234 | REQUIRE(ex.has_value()); 235 | REQUIRE(*ex == std::vector({2, 2})); 236 | } 237 | 238 | TEST_CASE("inplace constructor with initializer list") { 239 | rd::expected, int> ex(std::in_place, {2, 2}); 240 | REQUIRE(ex.has_value()); 241 | REQUIRE(*ex == std::vector({2, 2})); 242 | } 243 | 244 | TEST_CASE("unexpect constructor") { 245 | rd::expected, std::vector> ex( 246 | rd::unexpect, static_cast(2), 2); 247 | REQUIRE(!ex.has_value()); 248 | REQUIRE(ex.error() == std::vector({2, 2})); 249 | } 250 | 251 | TEST_CASE("unexpect constructor with initializer list") { 252 | rd::expected, std::vector> ex(rd::unexpect, {2, 2}); 253 | REQUIRE(!ex.has_value()); 254 | REQUIRE(ex.error() == std::vector({2, 2})); 255 | } 256 | -------------------------------------------------------------------------------- /test/expected_equality_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("expected on lhs and rhs, lhs has value, rhs has value") { 28 | auto const cond = rd::expected("value") == 29 | rd::expected("value"); 30 | REQUIRE(cond); 31 | auto const cond1 = rd::expected("value") == 32 | rd::expected("value1"); 33 | REQUIRE_FALSE(cond1); 34 | } 35 | 36 | TEST_CASE("expected on lhs and rhs, lhs has value, rhs has error") { 37 | auto const cond = 38 | rd::expected("value") == 39 | rd::expected(rd::unexpect, "value"); 40 | REQUIRE_FALSE(cond); 41 | } 42 | 43 | TEST_CASE("expected on lhs and rhs, lhs has error, rhs has value") { 44 | auto const cond = 45 | rd::expected(rd::unexpect, "value") == 46 | rd::expected("value"); 47 | REQUIRE_FALSE(cond); 48 | } 49 | 50 | TEST_CASE("expected on lhs and rhs, lhs has error, rhs has error") { 51 | auto const cond = 52 | rd::expected(rd::unexpect, "value") == 53 | rd::expected(rd::unexpect, "value"); 54 | REQUIRE(cond); 55 | auto const cond1 = 56 | rd::expected(rd::unexpect, "value") == 57 | rd::expected(rd::unexpect, "value1"); 58 | REQUIRE_FALSE(cond1); 59 | } 60 | 61 | TEST_CASE("expected on lhs and rhs has value, lhs has value") { 62 | auto const cond = rd::expected("value") == "value"; 63 | REQUIRE(cond); 64 | auto const cond1 = 65 | rd::expected("value") == "value1"; 66 | REQUIRE_FALSE(cond1); 67 | } 68 | 69 | TEST_CASE("expected on lhs and rhs has value, lhs has error") { 70 | auto const cond = 71 | rd::expected(rd::unexpect, "value") == "value"; 72 | REQUIRE_FALSE(cond); 73 | } 74 | 75 | TEST_CASE("expected on lhs and rhs has unexpected, lhs has value") { 76 | auto const cond = rd::expected("value") == 77 | rd::unexpected{"value"}; 78 | REQUIRE_FALSE(cond); 79 | } 80 | 81 | TEST_CASE("expected on lhs and rhs has unexpected, lhs has error") { 82 | auto const cond = rd::expected( 83 | rd::unexpect, "value") == rd::unexpected{"value"}; 84 | REQUIRE(cond); 85 | auto const cond1 = rd::expected( 86 | rd::unexpect, "value") == rd::unexpected{"value1"}; 87 | REQUIRE_FALSE(cond1); 88 | } 89 | -------------------------------------------------------------------------------- /test/expected_modifier_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("emplace: lhs has value") { 28 | rd::expected ex{"value1"}; 29 | ex.emplace(std::string{"value"}); // T should be nothrow_constructible 30 | REQUIRE(ex.has_value()); 31 | REQUIRE(*ex == "value"); 32 | } 33 | 34 | TEST_CASE("emplace: lhs has error") { 35 | rd::expected ex{rd::unexpect, "value1"}; 36 | ex.emplace(std::string{"value"}); // T should be nothrow_constructible 37 | REQUIRE(ex.has_value()); 38 | REQUIRE(*ex == "value"); 39 | } 40 | -------------------------------------------------------------------------------- /test/expected_monadic_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | #include "test_include.hpp" 28 | 29 | auto to_int(std::string const& str) -> rd::expected { 30 | try { 31 | return std::stoi(str); 32 | } catch (...) { 33 | return rd::unexpected{"error"}; 34 | } 35 | } 36 | 37 | auto error_to_int(std::string const& str) -> rd::expected { 38 | try { 39 | return rd::unexpected{std::stoi(str)}; 40 | } catch (...) { 41 | return "0"; 42 | } 43 | } 44 | 45 | auto add_1(int x) { return x + 1; } 46 | 47 | TEST_CASE("and_then & with value, with success continutation") { 48 | rd::expected pre{"2"}; 49 | auto post = pre.and_then(to_int); 50 | REQUIRE(post.has_value()); 51 | REQUIRE(*post == 2); 52 | } 53 | 54 | TEST_CASE("and_then & with value, with failed continutation") { 55 | rd::expected pre{"a2"}; 56 | auto post = pre.and_then(to_int); 57 | REQUIRE(!post.has_value()); 58 | REQUIRE(post.error() == "error"); 59 | } 60 | 61 | TEST_CASE("and_then & with error, with success continutation on error value") { 62 | rd::expected pre{rd::unexpect, "2"}; 63 | auto post = pre.and_then(to_int); 64 | REQUIRE(!post.has_value()); 65 | REQUIRE(post.error() == "2"); 66 | } 67 | 68 | TEST_CASE("and_then & with error, with failed continutation on error value") { 69 | rd::expected pre{rd::unexpect, "a2"}; 70 | auto post = pre.and_then(to_int); 71 | REQUIRE(!post.has_value()); 72 | REQUIRE(post.error() == "a2"); 73 | } 74 | 75 | TEST_CASE("and_then const& with value, with success continutation") { 76 | rd::expected const pre{"2"}; 77 | auto post = pre.and_then(to_int); 78 | REQUIRE(post.has_value()); 79 | REQUIRE(*post == 2); 80 | } 81 | 82 | TEST_CASE("and_then const& with value, with failed continutation") { 83 | rd::expected const pre{"a2"}; 84 | auto post = pre.and_then(to_int); 85 | REQUIRE(!post.has_value()); 86 | REQUIRE(post.error() == "error"); 87 | } 88 | 89 | TEST_CASE( 90 | "and_then const& with error, with success continutation on error value") { 91 | rd::expected const pre{rd::unexpect, "2"}; 92 | auto post = pre.and_then(to_int); 93 | REQUIRE(!post.has_value()); 94 | REQUIRE(post.error() == "2"); 95 | } 96 | 97 | TEST_CASE( 98 | "and_then const& with error, with failed continutation on error value") { 99 | rd::expected const pre{rd::unexpect, "a2"}; 100 | auto post = pre.and_then(to_int); 101 | REQUIRE(!post.has_value()); 102 | REQUIRE(post.error() == "a2"); 103 | } 104 | 105 | TEST_CASE("and_then && with value, with success continutation") { 106 | rd::expected pre{"2"}; 107 | auto post = std::move(pre).and_then(to_int); 108 | REQUIRE(post.has_value()); 109 | REQUIRE(*post == 2); 110 | } 111 | 112 | TEST_CASE("and_then && with value, with failed continutation") { 113 | rd::expected pre{"a2"}; 114 | auto post = std::move(pre).and_then(to_int); 115 | REQUIRE(!post.has_value()); 116 | REQUIRE(post.error() == "error"); 117 | } 118 | 119 | TEST_CASE("and_then && with error, with success continutation on error value") { 120 | rd::expected pre{rd::unexpect, "2"}; 121 | auto post = std::move(pre).and_then(to_int); 122 | REQUIRE(!post.has_value()); 123 | REQUIRE(post.error() == "2"); 124 | } 125 | 126 | TEST_CASE("and_then && with error, with failed continutation on error value") { 127 | rd::expected pre{rd::unexpect, "a2"}; 128 | auto post = std::move(pre).and_then(to_int); 129 | REQUIRE(!post.has_value()); 130 | REQUIRE(post.error() == "a2"); 131 | } 132 | 133 | TEST_CASE("or_else & with value, with error continuation success on value") { 134 | rd::expected pre{"2"}; 135 | auto post = pre.or_else(error_to_int); 136 | REQUIRE(post.has_value()); 137 | REQUIRE(*post == "2"); 138 | } 139 | 140 | TEST_CASE("or_else & with error, with successfull errorcontinuation") { 141 | rd::expected pre{rd::unexpect, "2"}; 142 | auto post = pre.or_else(error_to_int); 143 | REQUIRE(!post.has_value()); 144 | REQUIRE(post.error() == 2); 145 | } 146 | 147 | TEST_CASE("or_else & with error, with failed error continuation") { 148 | rd::expected pre{rd::unexpect, "a2"}; 149 | auto post = pre.or_else(error_to_int); 150 | REQUIRE(post.has_value()); 151 | REQUIRE(*post == "0"); 152 | } 153 | 154 | TEST_CASE("or_else & with value, with error continuation failed on value") { 155 | rd::expected pre{"a2"}; 156 | auto post = pre.or_else(error_to_int); 157 | REQUIRE(post.has_value()); 158 | REQUIRE(*post == "a2"); 159 | } 160 | 161 | TEST_CASE( 162 | "or_else const& with value, with error continuation success on value") { 163 | rd::expected const pre{"2"}; 164 | auto post = pre.or_else(error_to_int); 165 | REQUIRE(post.has_value()); 166 | REQUIRE(*post == "2"); 167 | } 168 | 169 | TEST_CASE("or_else const& with error, with successfull errorcontinuation") { 170 | rd::expected const pre{rd::unexpect, "2"}; 171 | auto post = pre.or_else(error_to_int); 172 | REQUIRE(!post.has_value()); 173 | REQUIRE(post.error() == 2); 174 | } 175 | 176 | TEST_CASE("or_else const& with error, with failed error continuation") { 177 | rd::expected const pre{rd::unexpect, "a2"}; 178 | auto post = pre.or_else(error_to_int); 179 | REQUIRE(post.has_value()); 180 | REQUIRE(*post == "0"); 181 | } 182 | 183 | TEST_CASE( 184 | "or_else const& with value, with error continuation failed on value") { 185 | rd::expected const pre{"a2"}; 186 | auto post = pre.or_else(error_to_int); 187 | REQUIRE(post.has_value()); 188 | REQUIRE(*post == "a2"); 189 | } 190 | 191 | TEST_CASE("or_else && with value, with error continuation success on value") { 192 | rd::expected pre{"2"}; 193 | auto post = std::move(pre).or_else(error_to_int); 194 | REQUIRE(post.has_value()); 195 | REQUIRE(*post == "2"); 196 | } 197 | 198 | TEST_CASE("or_else && with error, with successfull errorcontinuation") { 199 | rd::expected pre{rd::unexpect, "2"}; 200 | auto post = std::move(pre).or_else(error_to_int); 201 | REQUIRE(!post.has_value()); 202 | REQUIRE(post.error() == 2); 203 | } 204 | 205 | TEST_CASE("or_else && with error, with failed error continuation") { 206 | rd::expected pre{rd::unexpect, "a2"}; 207 | auto post = std::move(pre).or_else(error_to_int); 208 | REQUIRE(post.has_value()); 209 | REQUIRE(*post == "0"); 210 | } 211 | 212 | TEST_CASE("or_else && with value, with error continuation failed on value") { 213 | rd::expected pre{"a2"}; 214 | auto post = std::move(pre).or_else(error_to_int); 215 | REQUIRE(post.has_value()); 216 | REQUIRE(*post == "a2"); 217 | } 218 | 219 | TEST_CASE("transform & with value") { 220 | rd::expected pre{2}; 221 | auto post = pre.transform(add_1); 222 | REQUIRE(post.has_value()); 223 | REQUIRE(*post == 3); 224 | } 225 | 226 | TEST_CASE("transform & with error") { 227 | rd::expected pre{rd::unexpect, 2}; 228 | auto post = pre.transform(add_1); 229 | REQUIRE(!post.has_value()); 230 | REQUIRE(post.error() == 2); 231 | } 232 | 233 | TEST_CASE("transform const& with value") { 234 | rd::expected const pre{2}; 235 | auto post = pre.transform(add_1); 236 | REQUIRE(post.has_value()); 237 | REQUIRE(*post == 3); 238 | } 239 | 240 | TEST_CASE("transform const& with error") { 241 | rd::expected const pre{rd::unexpect, 2}; 242 | auto post = pre.transform(add_1); 243 | REQUIRE(!post.has_value()); 244 | REQUIRE(post.error() == 2); 245 | } 246 | 247 | TEST_CASE("transform && with value") { 248 | rd::expected pre{2}; 249 | auto post = std::move(pre).transform(add_1); 250 | REQUIRE(post.has_value()); 251 | REQUIRE(*post == 3); 252 | } 253 | 254 | TEST_CASE("transform && with error") { 255 | rd::expected pre{rd::unexpect, 2}; 256 | auto post = std::move(pre).transform(add_1); 257 | REQUIRE(!post.has_value()); 258 | REQUIRE(post.error() == 2); 259 | } 260 | 261 | TEST_CASE("transform_error & with value") { 262 | rd::expected pre{2}; 263 | auto post = pre.transform_error(add_1); 264 | REQUIRE(post.has_value()); 265 | REQUIRE(post.value() == 2); 266 | } 267 | 268 | TEST_CASE("transform_error & with error") { 269 | rd::expected pre{rd::unexpect, 2}; 270 | auto post = pre.transform_error(add_1); 271 | REQUIRE(!post.has_value()); 272 | REQUIRE(post.error() == 3); 273 | } 274 | 275 | TEST_CASE("transform_error const& with value") { 276 | rd::expected const pre{2}; 277 | auto post = pre.transform_error(add_1); 278 | REQUIRE(post.has_value()); 279 | REQUIRE(post.value() == 2); 280 | } 281 | 282 | TEST_CASE("transform_error const& with error") { 283 | rd::expected const pre{rd::unexpect, 2}; 284 | auto post = pre.transform_error(add_1); 285 | REQUIRE(!post.has_value()); 286 | REQUIRE(post.error() == 3); 287 | } 288 | 289 | TEST_CASE("transform_error && with value") { 290 | rd::expected pre{2}; 291 | auto post = std::move(pre).transform_error(add_1); 292 | REQUIRE(post.has_value()); 293 | REQUIRE(post.value() == 2); 294 | } 295 | 296 | TEST_CASE("transform_error && with error") { 297 | rd::expected pre{rd::unexpect, 2}; 298 | auto post = std::move(pre).transform_error(add_1); 299 | REQUIRE(!post.has_value()); 300 | REQUIRE(post.error() == 3); 301 | } 302 | -------------------------------------------------------------------------------- /test/expected_observer_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("operator-> non-const") { 28 | rd::expected ex{"hello"}; 29 | REQUIRE(ex->front() == 'h'); 30 | } 31 | 32 | TEST_CASE("operator-> const") { 33 | rd::expected const ex{"hello"}; 34 | REQUIRE(ex->front() == 'h'); 35 | } 36 | 37 | TEST_CASE("operator* non-const lvalue") { 38 | rd::expected ex{"hello"}; 39 | REQUIRE(*ex == "hello"); 40 | } 41 | 42 | TEST_CASE("operator* const lvalue") { 43 | rd::expected const ex{"hello"}; 44 | REQUIRE(*ex == "hello"); 45 | } 46 | 47 | TEST_CASE("operator* rvalue") { 48 | rd::expected ex{"hello"}; 49 | REQUIRE(*(rd::expected{"hello"}) == "hello"); 50 | } 51 | 52 | TEST_CASE("operator bool with value") { 53 | rd::expected ex{"hello"}; 54 | REQUIRE(ex); 55 | } 56 | 57 | TEST_CASE("operator bool with error") { 58 | rd::expected ex{rd::unexpect, "hello"}; 59 | REQUIRE(!ex); 60 | } 61 | 62 | TEST_CASE("has_value with value") { 63 | rd::expected ex{"hello"}; 64 | REQUIRE(ex.has_value()); 65 | } 66 | 67 | TEST_CASE("has_value with error") { 68 | rd::expected ex{rd::unexpect, "hello"}; 69 | REQUIRE(!ex.has_value()); 70 | } 71 | 72 | TEST_CASE(".value") { 73 | rd::expected ex{"hello"}; 74 | REQUIRE(ex.value() == "hello"); 75 | } 76 | 77 | TEST_CASE(".error") { 78 | rd::expected ex{rd::unexpect, "hello"}; 79 | REQUIRE(ex.error() == "hello"); 80 | } 81 | 82 | TEST_CASE(".value_or with value") { 83 | rd::expected ex{"value"}; 84 | REQUIRE(ex.value_or("new value") == "value"); 85 | } 86 | 87 | TEST_CASE(".value_or with value") { 88 | rd::expected ex{rd::unexpect, "value"}; 89 | REQUIRE(ex.value_or("new value") == "new value"); 90 | } 91 | -------------------------------------------------------------------------------- /test/expected_swap_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("swap: lhs has value, rhs has value") { 28 | rd::expected lhs{"lhs"}; 29 | rd::expected rhs{"rhs"}; 30 | using std::swap; 31 | swap(lhs, rhs); 32 | REQUIRE(lhs.has_value()); 33 | REQUIRE(rhs.has_value()); 34 | REQUIRE(*lhs == "rhs"); 35 | REQUIRE(*rhs == "lhs"); 36 | } 37 | 38 | TEST_CASE("swap: lhs has error, rhs has value") { 39 | rd::expected lhs{rd::unexpect, "lhs"}; 40 | rd::expected rhs{"rhs"}; 41 | using std::swap; 42 | swap(lhs, rhs); 43 | REQUIRE(lhs.has_value()); 44 | REQUIRE(!rhs.has_value()); 45 | REQUIRE(*lhs == "rhs"); 46 | REQUIRE(rhs.error() == "lhs"); 47 | } 48 | 49 | TEST_CASE("swap: lhs has value, rhs has error") { 50 | rd::expected lhs{"lhs"}; 51 | rd::expected rhs{rd::unexpect, "rhs"}; 52 | using std::swap; 53 | swap(lhs, rhs); 54 | REQUIRE(!lhs.has_value()); 55 | REQUIRE(rhs.has_value()); 56 | REQUIRE(lhs.error() == "rhs"); 57 | REQUIRE(*rhs == "lhs"); 58 | } 59 | 60 | TEST_CASE("swap: lhs has error, rhs has error") { 61 | rd::expected lhs{rd::unexpect, "lhs"}; 62 | rd::expected rhs{rd::unexpect, "rhs"}; 63 | using std::swap; 64 | swap(lhs, rhs); 65 | REQUIRE(!lhs.has_value()); 66 | REQUIRE(!rhs.has_value()); 67 | REQUIRE(lhs.error() == "rhs"); 68 | REQUIRE(rhs.error() == "lhs"); 69 | } 70 | -------------------------------------------------------------------------------- /test/expected_void_assignment_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("copy assignment: lhs has value, rhs has value") { 28 | rd::expected lhs; 29 | rd::expected const rhs; 30 | lhs = rhs; 31 | REQUIRE(lhs.has_value()); 32 | } 33 | 34 | TEST_CASE("copy assignment: lhs has value, rhs has error") { 35 | rd::expected lhs; 36 | rd::expected const rhs{rd::unexpect, "error"}; 37 | lhs = rhs; 38 | REQUIRE(!lhs.has_value()); 39 | REQUIRE(lhs.error() == "error"); 40 | } 41 | 42 | TEST_CASE("copy assignment: lhs has error, rhs has value") { 43 | rd::expected lhs{rd::unexpect, "error"}; 44 | rd::expected const rhs; 45 | lhs = rhs; 46 | REQUIRE(lhs.has_value()); 47 | } 48 | 49 | TEST_CASE("copy assignment: lhs has error, rhs has error") { 50 | rd::expected lhs{rd::unexpect, "error"}; 51 | rd::expected const rhs{rd::unexpect, "error1"}; 52 | lhs = rhs; 53 | REQUIRE(!lhs.has_value()); 54 | REQUIRE(lhs.error() == "error1"); 55 | } 56 | 57 | TEST_CASE("move assignment: lhs has value, rhs has value") { 58 | rd::expected lhs; 59 | rd::expected rhs; 60 | lhs = rhs; 61 | REQUIRE(lhs.has_value()); 62 | } 63 | 64 | TEST_CASE("move assignment: lhs has value, rhs has error") { 65 | rd::expected lhs; 66 | rd::expected rhs{rd::unexpect, "error"}; 67 | lhs = rhs; 68 | REQUIRE(!lhs.has_value()); 69 | REQUIRE(lhs.error() == "error"); 70 | } 71 | 72 | TEST_CASE("move assignment: lhs has error, rhs has value") { 73 | rd::expected lhs{rd::unexpect, "error"}; 74 | rd::expected rhs; 75 | lhs = rhs; 76 | REQUIRE(lhs.has_value()); 77 | } 78 | 79 | TEST_CASE("move assignment: lhs has error, rhs has error") { 80 | rd::expected lhs{rd::unexpect, "error"}; 81 | rd::expected rhs{rd::unexpect, "error1"}; 82 | lhs = rhs; 83 | REQUIRE(!lhs.has_value()); 84 | REQUIRE(lhs.error() == "error1"); 85 | } 86 | 87 | TEST_CASE("unexpected assignment: lhs has value : COPY") { 88 | rd::expected lhs; 89 | rd::expected const rhs{rd::unexpect, "error"}; 90 | lhs = rhs; 91 | REQUIRE(!lhs.has_value()); 92 | REQUIRE(lhs.error() == "error"); 93 | } 94 | 95 | TEST_CASE("unexpected assignment: lhs has error COPY") { 96 | rd::expected lhs{rd::unexpect, "error1"}; 97 | rd::expected const rhs{rd::unexpect, "error"}; 98 | lhs = rhs; 99 | REQUIRE(!lhs.has_value()); 100 | REQUIRE(lhs.error() == "error"); 101 | } 102 | 103 | TEST_CASE("unexpected assignment: lhs has value : MOVE") { 104 | rd::expected lhs; 105 | rd::expected rhs{rd::unexpect, "error"}; 106 | lhs = std::move(rhs); 107 | REQUIRE(!lhs.has_value()); 108 | REQUIRE(lhs.error() == "error"); 109 | } 110 | 111 | TEST_CASE("unexpected assignment: lhs has error MOVE") { 112 | rd::expected lhs{rd::unexpect, "error1"}; 113 | rd::expected rhs{rd::unexpect, "error"}; 114 | lhs = std::move(rhs); 115 | REQUIRE(!lhs.has_value()); 116 | REQUIRE(lhs.error() == "error"); 117 | } 118 | -------------------------------------------------------------------------------- /test/expected_void_constructor_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | #include "test_include.hpp" 28 | 29 | TEST_CASE("default constructor") { 30 | rd::expected ex; 31 | REQUIRE(ex.has_value()); 32 | } 33 | 34 | TEST_CASE("copy constructor, rhs has value") { 35 | rd::expected rhs; 36 | rd::expected lhs(rhs); 37 | REQUIRE(lhs.has_value()); 38 | } 39 | 40 | TEST_CASE("copy constructor, rhs has error") { 41 | rd::expected rhs{rd::unexpect, "error"}; 42 | rd::expected lhs(rhs); 43 | REQUIRE(!lhs.has_value()); 44 | REQUIRE(lhs.error() == "error"); 45 | } 46 | 47 | TEST_CASE("move constructor, rhs has value") { 48 | rd::expected rhs; 49 | rd::expected lhs(std::move(rhs)); 50 | REQUIRE(lhs.has_value()); 51 | } 52 | 53 | TEST_CASE("move constructor, rhs has error") { 54 | rd::expected rhs{rd::unexpect, "error"}; 55 | rd::expected lhs(std::move(rhs)); 56 | REQUIRE(!lhs.has_value()); 57 | REQUIRE(lhs.error() == "error"); 58 | } 59 | 60 | TEST_CASE("expected conversion-constructor: copy, rhs has value") { 61 | rd::expected rhs; 62 | rd::expected lhs(rhs); 63 | REQUIRE(lhs.has_value()); 64 | } 65 | 66 | TEST_CASE("expected conversion-constructor: copy, rhs has error") { 67 | rd::expected rhs{rd::unexpect, int_to_str{2}}; 68 | rd::expected lhs(rhs); 69 | REQUIRE(!lhs.has_value()); 70 | REQUIRE(lhs.error() == "2"); 71 | } 72 | 73 | TEST_CASE("expected conversion-constructor: move, rhs has value") { 74 | rd::expected rhs; 75 | rd::expected lhs(std::move(rhs)); 76 | REQUIRE(lhs.has_value()); 77 | } 78 | 79 | TEST_CASE("expected conversion-constructor: move, rhs has error") { 80 | rd::expected rhs{rd::unexpect, int_to_str{2}}; 81 | rd::expected lhs(std::move(rhs)); 82 | REQUIRE(!lhs.has_value()); 83 | REQUIRE(lhs.error() == "2"); 84 | } 85 | 86 | TEST_CASE("unexpected conversion constructor: no conversion, COPY") { 87 | rd::unexpected e{"error"}; 88 | rd::expected lhs(e); 89 | REQUIRE(!lhs.has_value()); 90 | REQUIRE(lhs.error() == "error"); 91 | } 92 | 93 | TEST_CASE("unexpected conversion constructor: conversion, COPY") { 94 | rd::unexpected e{2}; 95 | rd::expected lhs(e); 96 | REQUIRE(!lhs.has_value()); 97 | REQUIRE(lhs.error() == "2"); 98 | } 99 | 100 | TEST_CASE("unexpected conversion constructor: no conversion, MOVE") { 101 | rd::unexpected e{"error"}; 102 | rd::expected lhs(std::move(e)); 103 | REQUIRE(!lhs.has_value()); 104 | REQUIRE(lhs.error() == "error"); 105 | } 106 | 107 | TEST_CASE("unexpected conversion constructor: conversion, MOVE") { 108 | rd::expected lhs(rd::unexpected{2}); 109 | REQUIRE(!lhs.has_value()); 110 | REQUIRE(lhs.error() == "2"); 111 | } 112 | 113 | TEST_CASE("inplace_t constructor") { 114 | rd::expected lhs(std::in_place); 115 | REQUIRE(lhs.has_value()); 116 | } 117 | 118 | TEST_CASE("unexpect constructor") { 119 | rd::expected> lhs(rd::unexpect, std::size_t{2}, 2); 120 | REQUIRE(!lhs.has_value()); 121 | REQUIRE(lhs.error() == std::vector({2, 2})); 122 | } 123 | 124 | TEST_CASE("unexpect initializer list constructor") { 125 | rd::expected> lhs(rd::unexpect, {2, 2}); 126 | REQUIRE(!lhs.has_value()); 127 | REQUIRE(lhs.error() == std::vector({2, 2})); 128 | } 129 | -------------------------------------------------------------------------------- /test/expected_void_equality_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("both expected, lhs has value, rhs has value") { 28 | rd::expected lhs; 29 | rd::expected rhs; 30 | auto const res = lhs == rhs; 31 | REQUIRE(res); 32 | } 33 | 34 | TEST_CASE("both expected, lhs has value, rhs has error") { 35 | rd::expected lhs; 36 | rd::expected rhs{rd::unexpect, "error"}; 37 | auto const res = lhs == rhs; 38 | REQUIRE_FALSE(res); 39 | } 40 | 41 | TEST_CASE("both expected, lhs has error, rhs has value") { 42 | rd::expected lhs{rd::unexpect, "error"}; 43 | rd::expected rhs; 44 | auto const res = lhs == rhs; 45 | REQUIRE_FALSE(res); 46 | } 47 | 48 | TEST_CASE("both expected, lhs has error, rhs has error satisfies") { 49 | rd::expected lhs{rd::unexpect, "error"}; 50 | rd::expected rhs{rd::unexpect, "error"}; 51 | auto const res = lhs == rhs; 52 | REQUIRE(res); 53 | } 54 | 55 | TEST_CASE("both expected, lhs has error, rhs has error not-satisfies") { 56 | rd::expected lhs{rd::unexpect, "error"}; 57 | rd::expected rhs{rd::unexpect, "error1"}; 58 | auto const res = lhs == rhs; 59 | REQUIRE_FALSE(res); 60 | } 61 | 62 | TEST_CASE("rhs unepxected, lhs has value") { 63 | rd::expected lhs; 64 | rd::unexpected rhs{"error"}; 65 | auto const res = lhs == rhs; 66 | REQUIRE_FALSE(res); 67 | } 68 | 69 | TEST_CASE("rhs unepxected, lhs has error, satisfies") { 70 | rd::expected lhs{rd::unexpect, "error"}; 71 | rd::unexpected rhs{"error"}; 72 | auto const res = lhs == rhs; 73 | REQUIRE(res); 74 | } 75 | 76 | TEST_CASE("rhs unepxected, lhs has error, not satisfies") { 77 | rd::expected lhs{rd::unexpect, "error1"}; 78 | rd::unexpected rhs{"error"}; 79 | auto const res = lhs == rhs; 80 | REQUIRE_FALSE(res); 81 | } 82 | -------------------------------------------------------------------------------- /test/expected_void_modifier_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("emplace modifier: lhs has value") { 28 | rd::expected lhs; 29 | lhs.emplace(); 30 | REQUIRE(lhs.has_value()); 31 | } 32 | 33 | TEST_CASE("emplace modifier: lhs has value") { 34 | rd::expected lhs{rd::unexpect, "error"}; 35 | lhs.emplace(); 36 | REQUIRE(lhs.has_value()); 37 | } 38 | -------------------------------------------------------------------------------- /test/expected_void_monadic_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | auto create_expected_success() { return rd::expected(2); } 28 | auto create_expected_error() { return rd::expected(rd::unexpect, 2); } 29 | 30 | auto create_void_expected_success(int /*unused*/) { 31 | return rd::expected{}; 32 | } 33 | auto create_void_expected_error(int /*unused*/) { 34 | return rd::expected{rd::unexpect, 2}; 35 | } 36 | 37 | auto sum_1(int n) { return n + 1; } 38 | 39 | auto get_num() { return 1; } 40 | 41 | TEST_CASE("and_then & with value continuation with value") { 42 | rd::expected pre; 43 | auto post = pre.and_then(create_expected_success); 44 | REQUIRE(post.has_value()); 45 | REQUIRE(*post == 2); 46 | } 47 | 48 | TEST_CASE("and_then & with value continuation with error") { 49 | rd::expected pre; 50 | auto post = pre.and_then(create_expected_error); 51 | REQUIRE(!post.has_value()); 52 | REQUIRE(post.error() == 2); 53 | } 54 | 55 | TEST_CASE("and_then & with error continuation with value") { 56 | rd::expected pre{rd::unexpect, 3}; 57 | auto post = pre.and_then(create_expected_success); 58 | REQUIRE(!post.has_value()); 59 | REQUIRE(post.error() == 3); 60 | } 61 | 62 | TEST_CASE("and_then & with error continuation with failure") { 63 | rd::expected pre{rd::unexpect, 3}; 64 | auto post = pre.and_then(create_expected_error); 65 | REQUIRE(!post.has_value()); 66 | REQUIRE(post.error() == 3); 67 | } 68 | 69 | TEST_CASE("and_then const& with value continuation with value") { 70 | rd::expected const pre; 71 | auto post = pre.and_then(create_expected_success); 72 | REQUIRE(post.has_value()); 73 | REQUIRE(*post == 2); 74 | } 75 | 76 | TEST_CASE("and_then const& with value continuation with error") { 77 | rd::expected const pre; 78 | auto post = pre.and_then(create_expected_error); 79 | REQUIRE(!post.has_value()); 80 | REQUIRE(post.error() == 2); 81 | } 82 | 83 | TEST_CASE("and_then const& with error continuation with value") { 84 | rd::expected const pre{rd::unexpect, 3}; 85 | auto post = pre.and_then(create_expected_success); 86 | REQUIRE(!post.has_value()); 87 | REQUIRE(post.error() == 3); 88 | } 89 | 90 | TEST_CASE("and_then const& with error continuation with failure") { 91 | rd::expected const pre{rd::unexpect, 3}; 92 | auto post = pre.and_then(create_expected_error); 93 | REQUIRE(!post.has_value()); 94 | REQUIRE(post.error() == 3); 95 | } 96 | 97 | TEST_CASE("and_then && with value continuation with value") { 98 | rd::expected pre; 99 | auto post = std::move(pre).and_then(create_expected_success); 100 | REQUIRE(post.has_value()); 101 | REQUIRE(*post == 2); 102 | } 103 | 104 | TEST_CASE("and_then && with value continuation with error") { 105 | rd::expected pre; 106 | auto post = std::move(pre).and_then(create_expected_error); 107 | REQUIRE(!post.has_value()); 108 | REQUIRE(post.error() == 2); 109 | } 110 | 111 | TEST_CASE("and_then && with error continuation with value") { 112 | rd::expected pre{rd::unexpect, 3}; 113 | auto post = std::move(pre).and_then(create_expected_success); 114 | REQUIRE(!post.has_value()); 115 | REQUIRE(post.error() == 3); 116 | } 117 | 118 | TEST_CASE("and_then && with error continuation with failure") { 119 | rd::expected pre{rd::unexpect, 3}; 120 | auto post = std::move(pre).and_then(create_expected_error); 121 | REQUIRE(!post.has_value()); 122 | REQUIRE(post.error() == 3); 123 | } 124 | 125 | TEST_CASE("or_else & with value, continuation with value") { 126 | rd::expected pre; 127 | auto post = pre.or_else(create_void_expected_success); 128 | REQUIRE(post.has_value()); 129 | } 130 | 131 | TEST_CASE("or_else & with value, continuation with error") { 132 | rd::expected pre; 133 | auto post = pre.or_else(create_void_expected_error); 134 | REQUIRE(post.has_value()); 135 | } 136 | 137 | TEST_CASE("or_else & with error, continuation with value") { 138 | rd::expected pre{rd::unexpect, 3}; 139 | auto post = pre.or_else(create_void_expected_success); 140 | REQUIRE(post.has_value()); 141 | } 142 | 143 | TEST_CASE("or_else & with error, continuation with error") { 144 | rd::expected pre{rd::unexpect, 3}; 145 | auto post = pre.or_else(create_void_expected_error); 146 | REQUIRE(!post.has_value()); 147 | REQUIRE(post.error() == 2); 148 | } 149 | 150 | TEST_CASE("or_else const& with value, continuation with value") { 151 | rd::expected const pre; 152 | auto post = pre.or_else(create_void_expected_success); 153 | REQUIRE(post.has_value()); 154 | } 155 | 156 | TEST_CASE("or_else const& with value, continuation with error") { 157 | rd::expected const pre; 158 | auto post = pre.or_else(create_void_expected_error); 159 | REQUIRE(post.has_value()); 160 | } 161 | 162 | TEST_CASE("or_else const& with error, continuation with value") { 163 | rd::expected const pre{rd::unexpect, 3}; 164 | auto post = pre.or_else(create_void_expected_success); 165 | REQUIRE(post.has_value()); 166 | } 167 | 168 | TEST_CASE("or_else const& with error, continuation with error") { 169 | rd::expected const pre{rd::unexpect, 3}; 170 | auto post = pre.or_else(create_void_expected_error); 171 | REQUIRE(!post.has_value()); 172 | REQUIRE(post.error() == 2); 173 | } 174 | 175 | TEST_CASE("or_else && with value, continuation with value") { 176 | rd::expected pre; 177 | auto post = std::move(pre).or_else(create_void_expected_success); 178 | REQUIRE(post.has_value()); 179 | } 180 | 181 | TEST_CASE("or_else && with value, continuation with error") { 182 | rd::expected pre; 183 | auto post = std::move(pre).or_else(create_void_expected_error); 184 | REQUIRE(post.has_value()); 185 | } 186 | 187 | TEST_CASE("or_else && with error, continuation with value") { 188 | rd::expected pre{rd::unexpect, 3}; 189 | auto post = std::move(pre).or_else(create_void_expected_success); 190 | REQUIRE(post.has_value()); 191 | } 192 | 193 | TEST_CASE("or_else && with error, continuation with error") { 194 | rd::expected pre{rd::unexpect, 3}; 195 | auto post = std::move(pre).or_else(create_void_expected_error); 196 | REQUIRE(!post.has_value()); 197 | REQUIRE(post.error() == 2); 198 | } 199 | 200 | TEST_CASE("transform & with value") { 201 | rd::expected pre; 202 | auto post = pre.transform(get_num); 203 | REQUIRE(post.has_value()); 204 | REQUIRE(*post == 1); 205 | } 206 | 207 | TEST_CASE("transform & with error") { 208 | rd::expected pre{rd::unexpect, 2}; 209 | auto post = pre.transform(get_num); 210 | REQUIRE(!post.has_value()); 211 | REQUIRE(post.error() == 2); 212 | } 213 | 214 | TEST_CASE("transform const& with value") { 215 | rd::expected const pre; 216 | auto post = pre.transform(get_num); 217 | REQUIRE(post.has_value()); 218 | REQUIRE(*post == 1); 219 | } 220 | 221 | TEST_CASE("transform const& with error") { 222 | rd::expected const pre{rd::unexpect, 2}; 223 | auto post = pre.transform(get_num); 224 | REQUIRE(!post.has_value()); 225 | REQUIRE(post.error() == 2); 226 | } 227 | 228 | TEST_CASE("transform && with value") { 229 | rd::expected pre; 230 | auto post = std::move(pre).transform(get_num); 231 | REQUIRE(post.has_value()); 232 | REQUIRE(*post == 1); 233 | } 234 | 235 | TEST_CASE("transform && with error") { 236 | rd::expected pre{rd::unexpect, 2}; 237 | auto post = std::move(pre).transform(get_num); 238 | REQUIRE(!post.has_value()); 239 | REQUIRE(post.error() == 2); 240 | } 241 | 242 | TEST_CASE("transform_error & with value") { 243 | rd::expected pre{}; 244 | auto post = pre.transform_error(sum_1); 245 | REQUIRE(post.has_value()); 246 | } 247 | 248 | TEST_CASE("transform_error & with error") { 249 | rd::expected pre{rd::unexpect, 2}; 250 | auto post = pre.transform_error(sum_1); 251 | REQUIRE(!post.has_value()); 252 | REQUIRE(post.error() == 3); 253 | } 254 | 255 | TEST_CASE("transform_error const& with value") { 256 | rd::expected const pre{}; 257 | auto post = pre.transform_error(sum_1); 258 | REQUIRE(post.has_value()); 259 | } 260 | 261 | TEST_CASE("transform_error const& with error") { 262 | rd::expected const pre{rd::unexpect, 2}; 263 | auto post = pre.transform_error(sum_1); 264 | REQUIRE(!post.has_value()); 265 | REQUIRE(post.error() == 3); 266 | } 267 | 268 | TEST_CASE("transform_error && with value") { 269 | rd::expected pre{}; 270 | auto post = std::move(pre).transform_error(sum_1); 271 | REQUIRE(post.has_value()); 272 | } 273 | 274 | TEST_CASE("transform_error && with error") { 275 | rd::expected pre{rd::unexpect, 2}; 276 | auto post = std::move(pre).transform_error(sum_1); 277 | REQUIRE(!post.has_value()); 278 | REQUIRE(post.error() == 3); 279 | } 280 | -------------------------------------------------------------------------------- /test/expected_void_observer_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("bool operator: lhs has value") { 28 | rd::expected ex; 29 | REQUIRE(ex); 30 | } 31 | 32 | TEST_CASE("bool operator: lhs has error") { 33 | rd::expected ex{rd::unexpect, "error"}; 34 | REQUIRE(!ex); 35 | } 36 | 37 | TEST_CASE("has value, lhs has value") { 38 | rd::expected ex; 39 | REQUIRE(ex.has_value()); 40 | } 41 | 42 | TEST_CASE("has value: lhs has error") { 43 | rd::expected ex{rd::unexpect, "error"}; 44 | REQUIRE(!ex.has_value()); 45 | } 46 | 47 | TEST_CASE("value: lhs has value") { 48 | rd::expected ex; 49 | REQUIRE_NOTHROW(ex.value()); 50 | } 51 | 52 | TEST_CASE("value: lhs has error") { 53 | rd::expected ex{rd::unexpect, "error"}; 54 | REQUIRE_THROWS(ex.value()); // NOLINT 55 | } 56 | 57 | TEST_CASE("error") { 58 | rd::expected ex{rd::unexpect, "error"}; 59 | REQUIRE(ex.error() == "error"); 60 | } 61 | -------------------------------------------------------------------------------- /test/expected_void_swap_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include "test_include.hpp" 26 | 27 | TEST_CASE("swap: lhs has value, rhs has value") { 28 | rd::expected lhs; 29 | rd::expected rhs; 30 | using std::swap; 31 | swap(lhs, rhs); 32 | REQUIRE(lhs.has_value()); 33 | REQUIRE(rhs.has_value()); 34 | } 35 | 36 | TEST_CASE("swap: lhs has error, rhs has value") { 37 | rd::expected lhs{rd::unexpect, "lhs"}; 38 | rd::expected rhs; 39 | using std::swap; 40 | swap(lhs, rhs); 41 | REQUIRE(lhs.has_value()); 42 | REQUIRE(!rhs.has_value()); 43 | REQUIRE(rhs.error() == "lhs"); 44 | } 45 | 46 | TEST_CASE("swap: lhs has value, rhs has error") { 47 | rd::expected lhs; 48 | rd::expected rhs{rd::unexpect, "rhs"}; 49 | using std::swap; 50 | swap(lhs, rhs); 51 | REQUIRE(!lhs.has_value()); 52 | REQUIRE(rhs.has_value()); 53 | REQUIRE(lhs.error() == "rhs"); 54 | } 55 | 56 | TEST_CASE("swap: lhs has error, rhs has error") { 57 | rd::expected lhs{rd::unexpect, "lhs"}; 58 | rd::expected rhs{rd::unexpect, "rhs"}; 59 | using std::swap; 60 | swap(lhs, rhs); 61 | REQUIRE(!lhs.has_value()); 62 | REQUIRE(!rhs.has_value()); 63 | REQUIRE(lhs.error() == "rhs"); 64 | REQUIRE(rhs.error() == "lhs"); 65 | } 66 | -------------------------------------------------------------------------------- /test/int_to_str.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | 29 | struct int_to_str { 30 | private: 31 | int mem; 32 | 33 | public: 34 | explicit int_to_str(int m) : mem(m) {} 35 | 36 | explicit operator std::string() const { return std::to_string(mem); } 37 | 38 | [[nodiscard]] auto val() const -> int { return mem; } 39 | }; 40 | 41 | struct int_to_str_implicit { 42 | private: 43 | int mem; 44 | 45 | public: 46 | explicit int_to_str_implicit(int m) : mem(m) {} 47 | 48 | operator std::string() const { return std::to_string(mem); } // NOLINT 49 | 50 | [[nodiscard]] auto val() const -> int { return mem; } 51 | }; 52 | -------------------------------------------------------------------------------- /test/test_include.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "int_to_str.hpp" 8 | #include "rd/expected.hpp" 9 | -------------------------------------------------------------------------------- /test/test_runner.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 26 | #include "doctest/doctest.h" 27 | -------------------------------------------------------------------------------- /test/unexpected_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Rishabh Dwivedi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | #include "test_include.hpp" 28 | 29 | TEST_CASE("error constructor test") { 30 | rd::unexpected un(2); 31 | REQUIRE(un.value() == 2); 32 | } 33 | 34 | TEST_CASE("inplace constructor test") { 35 | rd::unexpected un(std::in_place, 2); 36 | REQUIRE(un.value() == 2); 37 | } 38 | 39 | TEST_CASE("copy constructor test") { 40 | rd::unexpected u_orig{2}; 41 | rd::unexpected un(u_orig); 42 | REQUIRE(un.value() == 2); 43 | } 44 | 45 | TEST_CASE("move constructor test") { 46 | rd::unexpected un(rd::unexpected{2}); 47 | REQUIRE(un.value() == 2); 48 | } 49 | 50 | TEST_CASE("swap test") { 51 | rd::unexpected lhs(2); 52 | rd::unexpected rhs(3); 53 | using std::swap; 54 | swap(lhs, rhs); 55 | REQUIRE(lhs.value() == 3); 56 | REQUIRE(rhs.value() == 2); 57 | } 58 | 59 | TEST_CASE("equality operator test") { 60 | rd::unexpected lhs(2); 61 | rd::unexpected rhs(2); 62 | REQUIRE(lhs == rhs); 63 | } 64 | --------------------------------------------------------------------------------