pax_global_header00006660000000000000000000000064151067210650014515gustar00rootroot0000000000000052 comment=3583e95bad46f5af7d8a826632bc68a6f7281551 expected-lite-0.10.0/000077500000000000000000000000001510672106500143275ustar00rootroot00000000000000expected-lite-0.10.0/.editorconfig000066400000000000000000000011341510672106500170030ustar00rootroot00000000000000# Configuration file for EditorConfig, see https://EditorConfig.org # Ignore any other files further up in the file system root = true # All files: [*] # Let git determine line ending: end_of_line = lf charset = utf-8 indent_size = 4 indent_style = space insert_final_newline = true trim_trailing_whitespace = true # Markdown files: keep trailing space-pair as line-break [*.md] trim_trailing_whitespace = false # Python scripts: [*.py] # YAML scripts: [*.yml] indent_size = 2 # Makefiles: Tab indentation (no size specified) [Makefile] indent_style = tab # C, C++ source files: [*.{h,hpp,c,cpp}] expected-lite-0.10.0/.gitattributes000066400000000000000000000010541510672106500172220ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto # Custom for CodeBlocks *.cbp text eol=lf *.workspace text eol=lf # Custom for Visual Studio *.cs diff=csharp *.sln merge=union *.csproj merge=union *.vbproj merge=union *.fsproj merge=union *.dbproj merge=union # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain expected-lite-0.10.0/.github/000077500000000000000000000000001510672106500156675ustar00rootroot00000000000000expected-lite-0.10.0/.github/workflows/000077500000000000000000000000001510672106500177245ustar00rootroot00000000000000expected-lite-0.10.0/.github/workflows/ci.yml000066400000000000000000000050031510672106500210400ustar00rootroot00000000000000name: CI env: PROJECT: EXPECTED_LITE on: push: branches: [ master ] pull_request: branches: [ master ] workflow_dispatch: jobs: gcc: strategy: fail-fast: false matrix: version: [9, 10, 11] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install GCC ${{ matrix.version }} run: sudo apt-get install -y gcc-${{ matrix.version }} g++-${{ matrix.version }} - name: Configure tests env: CXX: g++-${{ matrix.version }} run: cmake -S . -B build -D CMAKE_BUILD_TYPE:STRING=Release -D ${{ env.PROJECT }}_OPT_SELECT_NONSTD=ON -D ${{ env.PROJECT }}_OPT_BUILD_TESTS=ON -D ${{ env.PROJECT }}_OPT_BUILD_EXAMPLES=OFF - name: Build tests run: cmake --build build -j 4 - name: Run tests working-directory: build run: ctest --output-on-failure -j 4 clang: strategy: fail-fast: false matrix: include: - version: 11 os: 'ubuntu-22.04' - version: 12 os: 'ubuntu-22.04' - version: 16 os: 'ubuntu-24.04' - version: 19 os: 'ubuntu-24.04' runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Install Clang ${{ matrix.version }} run: sudo apt-get install -y clang-${{ matrix.version }} - name: Configure tests env: CXX: clang-${{ matrix.version }} run: cmake -S . -B build -D CMAKE_CXX_COMPILER=clang++-${{ matrix.version }} -D CMAKE_BUILD_TYPE:STRING=Release -D ${{ env.PROJECT }}_OPT_SELECT_NONSTD=ON -D ${{ env.PROJECT }}_OPT_BUILD_TESTS=ON -D ${{ env.PROJECT }}_OPT_BUILD_EXAMPLES=OFF - name: Build tests run: cmake --build build -j 4 - name: Run tests working-directory: build run: ctest --output-on-failure -j 4 msvc: strategy: fail-fast: false matrix: os: [windows-2022] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Configure tests run: cmake -S . -B build -D ${{ env.PROJECT }}_OPT_SELECT_NONSTD=ON -D ${{ env.PROJECT }}_OPT_BUILD_TESTS=ON -D ${{ env.PROJECT }}_OPT_BUILD_EXAMPLES=OFF - name: Build tests run: cmake --build build --config Release -j 4 - name: Run tests working-directory: build run: ctest -C Release --output-on-failure -j 4 expected-lite-0.10.0/.gitignore000066400000000000000000000005621510672106500163220ustar00rootroot00000000000000# Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app test/expected.t # Build folder /build/ # CodeBlocks IDE files *.layout # Visual Studio Code /.vscode/ # Visual Studio /.vs/ expected-lite-0.10.0/.tgitconfig000066400000000000000000000002131510672106500164610ustar00rootroot00000000000000[bugtraq] url = https://github.com/martinmoene/expected-lite/issues/%BUGID% number = true logregex = "(\\s*(,|and)?\\s*#\\d+)+\n(\\d+)" expected-lite-0.10.0/CHANGES.txt000066400000000000000000000001121510672106500161320ustar00rootroot00000000000000Changes for expected lite version 0.0 2016-03-13 - Initial code commit. expected-lite-0.10.0/CMakeLists.txt000066400000000000000000000107771510672106500171030ustar00rootroot00000000000000# Copyright 2016-2018 by Martin Moene # # https://github.com/martinmoene/expected-lite # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) cmake_minimum_required( VERSION 3.15 FATAL_ERROR ) # expected-lite project and version, updated by script/update-version.py: project( expected_lite VERSION 0.10.0 LANGUAGES CXX ) set(PROJECT_DESCRIPTION "Expected objects in C++11 and later in a single-file header-only library") set(PROJECT_HOMEPAGE_URL "https://github.com/martinmoene/expected-lite") # Package information: set( unit_name "expected" ) set( package_nspace "nonstd" ) set( package_name "${unit_name}-lite" ) set( package_version "${${PROJECT_NAME}_VERSION}" ) set( CPACK_PACKAGE_NAME "expected-lite" ) set( CPACK_PACKAGECPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}" ) set( CPACK_DEBIAN_PACKAGE_NAME "lib${CPACK_PACKAGE_NAME}-dev" ) set( CPACK_RPM_PACKAGE_NAME "lib${CPACK_PACKAGE_NAME}-devel" ) set( CPACK_PACKAGE_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}" ) set( CPACK_DEBIAN_PACKAGE_ARCHITECTURE "all" ) set( CPACK_PACKAGE_MAINTAINER "Martin Moene" ) set( CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_MAINTAINER}" ) set( CPACK_DEBIAN_COMPRESSION_TYPE "xz" ) set( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt" ) set( CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md" ) set( CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}" ) message( STATUS "Project '${PROJECT_NAME}', package '${package_name}' version: '${package_version}'") # Toplevel or subproject: if ( CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME ) set( expected_IS_TOPLEVEL_PROJECT TRUE ) else() set( expected_IS_TOPLEVEL_PROJECT FALSE ) endif() # If toplevel project, enable building and performing of tests, disable building of examples: option( EXPECTED_LITE_OPT_BUILD_TESTS "Build and perform expected-lite tests" ${expected_IS_TOPLEVEL_PROJECT} ) option( EXPECTED_LITE_OPT_BUILD_EXAMPLES "Build expected-lite examples" OFF ) set( EXPEXTED_P0323R "99" STRING "Specify proposal revision compatibility (99: latest)" ) option( EXPECTED_LITE_OPT_SELECT_STD "Select std::expected" OFF ) option( EXPECTED_LITE_OPT_SELECT_NONSTD "Select nonstd::expected" OFF ) # If requested, build and perform tests, build examples: if ( EXPECTED_LITE_OPT_BUILD_TESTS ) enable_testing() add_subdirectory( test ) endif() if ( EXPECTED_LITE_OPT_BUILD_EXAMPLES ) add_subdirectory( example ) endif() # # Interface, installation and packaging # # CMake helpers: include( GNUInstallDirs ) include( CMakePackageConfigHelpers ) # Interface library: add_library( ${package_name} INTERFACE ) add_library( ${package_nspace}::${package_name} ALIAS ${package_name} ) target_include_directories( ${package_name} INTERFACE "$" "$" ) # Package configuration: # Note: package_name and package_target are used in package_config_in set( package_folder "${package_name}" ) set( package_target "${package_name}-targets" ) set( package_config "${package_name}-config.cmake" ) set( package_config_in "${package_name}-config.cmake.in" ) set( package_config_version "${package_name}-config-version.cmake" ) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${package_config_in}" "${CMAKE_CURRENT_BINARY_DIR}/${package_config}" INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${package_folder}" ) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${package_config_version}.in" "${CMAKE_CURRENT_BINARY_DIR}/${package_config_version}" @ONLY ) # Installation: install( TARGETS ${package_name} EXPORT ${package_target} # INCLUDES DESTINATION "${...}" # already set via target_include_directories() ) install( EXPORT ${package_target} NAMESPACE ${package_nspace}:: DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${package_folder}" ) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/${package_config}" "${CMAKE_CURRENT_BINARY_DIR}/${package_config_version}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${package_folder}" ) install( DIRECTORY "include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" ) export( EXPORT ${package_target} NAMESPACE ${package_nspace}:: FILE "${CMAKE_CURRENT_BINARY_DIR}/${package_name}-targets.cmake" ) include(CPack) # end of file expected-lite-0.10.0/LICENSE.txt000066400000000000000000000024721510672106500161570ustar00rootroot00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. expected-lite-0.10.0/Notes.md000066400000000000000000000003261510672106500157420ustar00rootroot00000000000000Plan ---- - [ ] Implement expected.then() etc. - [x] Write CMake files - [x] Check code against current Dxxxxr0 and adapt - [x] Expand README.md - [x] Expand test/expected.t.cpp - [x] Improve use of travis matrix expected-lite-0.10.0/README.md000066400000000000000000001170651510672106500156200ustar00rootroot00000000000000# expected lite: expected objects for C++11 and later [![Language](https://img.shields.io/badge/C%2B%2B-11-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-BSL-blue.svg)](https://opensource.org/licenses/BSL-1.0) [![Build Status](https://github.com/martinmoene/expected-lite/actions/workflows/ci.yml/badge.svg)](https://github.com/martinmoene/expected-lite/actions/workflows/ci.yml) [![Version](https://badge.fury.io/gh/martinmoene%2Fexpected-lite.svg)](https://github.com/martinmoene/expected-lite/releases) [![download](https://img.shields.io/badge/latest-download-blue.svg)](https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp) [![Conan](https://img.shields.io/badge/on-conan-blue.svg)](https://conan.io/center/expected-lite) [![Vcpkg](https://img.shields.io/badge/on-vcpkg-blue.svg)](https://vcpkg.link/ports/expected-lite) [![Try it online](https://img.shields.io/badge/on-wandbox-blue.svg)](https://wandbox.org/permlink/MnnwqOtE8ZQ4rRsv) [![Try it on godbolt online](https://img.shields.io/badge/on-godbolt-blue.svg)](https://godbolt.org/z/9BuMZx) *expected lite* is a single-file header-only library for objects that either represent a valid value or an error that you can pass by value. It is intended for use with C++11 and later. The library is based on the [std::expected](http://wg21.link/p0323) proposal [1] . **Contents** - [Example usage](#example-usage) - [In a nutshell](#in-a-nutshell) - [License](#license) - [Dependencies](#dependencies) - [Installation](#installation) - [Synopsis](#synopsis) - [Comparison with like types](#comparison) - [Reported to work with](#reported-to-work-with) - [Implementation notes](#implementation-notes) - [Other implementations of expected](#other-implementations-of-expected) - [Notes and references](#notes-and-references) - [Appendix](#appendix) ## Example usage ```Cpp #include "nonstd/expected.hpp" #include #include #include using namespace nonstd; using namespace std::literals; auto to_int( char const * const text ) -> expected { char * pos = nullptr; auto value = strtol( text, &pos, 0 ); if ( pos != text ) return value; else return make_unexpected( "'"s + text + "' isn't a number" ); } int main( int argc, char * argv[] ) { auto text = argc > 1 ? argv[1] : "42"; auto ei = to_int( text ); if ( ei ) std::cout << "'" << text << "' is " << *ei << ", "; else std::cout << "Error: " << ei.error(); } ``` ### Compile and run ``` prompt> g++ -std=c++14 -Wall -I../include -o 01-basic.exe 01-basic.cpp && 01-basic.exe 123 && 01-basic.exe abc '123' is 123, Error: 'abc' isn't a number ``` ## In a nutshell **expected lite** is a single-file header-only library to represent value objects that either contain a valid value or an error. The library is a partly implementation of the proposal for [std::expected](http://wg21.link/p0323) [1,2,3] for use with C++11 and later. **Some Features and properties of expected lite** are ease of installation (single header), default and explicit construction of an expected, construction and assignment from a value that is convertible to the underlying type, copy- and move-construction and copy- and move-assignment from another expected of the same type, testing for the presence of a value, operators for unchecked access to the value or the error (pointer or reference), value() and value_or() for checked access to the value, relational operators, swap() and various factory functions. Version 0.7.0 introduces the monadic operations of propsoal [p2505](http://wg21.link/p2505). *expected lite* shares the approach to in-place tags with [any-lite](https://github.com/martinmoene/any-lite), [optional-lite](https://github.com/martinmoene/optional-lite) and with [variant-lite](https://github.com/martinmoene/variant-lite) and these libraries can be used together. **Not provided** are reference-type expecteds. *expected lite* doesn't honour triviality of value and error types. *expected lite* doesn't handle overloaded *address of* operators. For more examples, see [1]. ## License *expected lite* is distributed under the [Boost Software License](LICENSE.txt). ## Dependencies *expected lite* has no other dependencies than the [C++ standard library](http://en.cppreference.com/w/cpp/header). ## Installation *expected lite* is a single-file header-only library. Put `expected.hpp` directly into the project source tree or somewhere reachable from your project. ## Synopsis **Contents** - [Configuration](#configuration) - [Types in namespace nonstd](#types-in-namespace-nonstd) - [Interface of expected](#interface-of-expected) - [Algorithms for expected](#algorithms-for-expected) - [Interface of unexpected_type](#interface-of-unexpected_type) - [Algorithms for unexpected_type](#algorithms-for-unexpected_type) ### Configuration #### Tweak header If the compiler supports [`__has_include()`](https://en.cppreference.com/w/cpp/preprocessor/include), *expected lite* supports the [tweak header](https://vector-of-bool.github.io/2020/10/04/lib-configuration.html) mechanism. Provide your *tweak header* as `nonstd/expected.tweak.hpp` in a folder in the include-search-path. In the tweak header, provide definitions as documented below, like `#define expected_CPLUSPLUS 201103L`. #### Standard selection macro \-Dnsel\_CPLUSPLUS=199711L Define this macro to override the auto-detection of the supported C++ standard, or if your compiler does not set the `__cplusplus` macro correctly. #### Select `std::expected` or `nonstd::expected` At default, *expected lite* uses `std::expected` if it is available and lets you use it via namespace `nonstd`. You can however override this default and explicitly request to use `std::expected` or expected lite's `nonstd::expected` as `nonstd::expected` via the following macros. -Dnsel\_CONFIG\_SELECT\_EXPECTED=nsel_EXPECTED_DEFAULT Define this to `nsel_EXPECTED_STD` to select `std::expected` as `nonstd::expected`. Define this to `nsel_EXPECTED_NONSTD` to select `nonstd::expected` as `nonstd::expected`. Default is undefined, which has the same effect as defining to `nsel_EXPECTED_DEFAULT`. -Dnsel\_P0323R=7 *(default)* Define this to the proposal revision number to control the presence and behavior of features (see tables). Default is 7 for the latest revision. #### Define `WIN32_LEAN_AND_MEAN` -Dnsel\_CONFIG\_WIN32\_LEAN\_AND\_MEAN=1 Define this to 0 if you want to omit automatic definition of `WIN32_LEAN_AND_MEAN`. Default is 1 when `_MSC_VER` is present. #### Disable C++ exceptions -Dnsel\_CONFIG\_NO\_EXCEPTIONS=0 Define this to 1 if you want to compile without exceptions. If not defined, the header tries and detect if exceptions have been disabled (e.g. via `-fno-exceptions` or `/kernel`). Default determined in header. #### Enable SEH exceptions -Dnsel\_CONFIG\_NO\_EXCEPTIONS\_SEH=0 Define this to 1 or 0 to control the use of SEH when C++ exceptions are disabled (see above). If not defined, the header tries and detect if SEH is available if C++ exceptions have been disabled (e.g. via `-fno-exceptions` or `/kernel`). Default determined in header. #### Disable \[\[nodiscard\]\] -Dnsel\_CONFIG\_NO\_NODISCARD=0 Define this to 1 if you want to compile without \[\[nodiscard\]\]. Note that the default of marking `class expected` with \[\[nodiscard\]\] is not part of the C++23 standard. The rationale to use \[\[nodiscard\]\] is that unnoticed discarded expected error values may break the error handling flow. #### Enable compilation errors \-Dnsel\_CONFIG\_CONFIRMS\_COMPILATION\_ERRORS=0 Define this macro to 1 to experience the by-design compile-time errors of the library in the test suite. Default is 0. #### Configure P2505 monadic operations By default, *expected lite* provides monadic operations as described in [P2505R5](http://wg21.link/p2505r5). You can disable these operations by defining the following macro. -Dnsel\_P2505R=0 You can use the R3 revision of P2505, which lacks `error_or`, and uses `remove_cvref` for transforms, by defining the following macro. -Dnsel\_P2505R=3 ### Types in namespace nonstd | Purpose | Type | Note / Object | |-----------------|------|---------------| | Expected | template<typename T, typename E = std::exception_ptr>
class **expected**; | nsel_P0323 <= 2 | | Expected | template<typename T, typename E>
class **expected**; | nsel_P0323 > 2 | | Error type | template<typename E>
class **unexpected_type**; |   | | Error type | template<>
class **unexpected_type**<std::exception_ptr>; | nsel_P0323 <= 2 | | Error type | template<typename E>
class **unexpected**; | >= C++17 | | Traits | template<typename E>
struct **is_unexpected**; | nsel_P0323 <= 3 | | In-place value construction | struct **in_place_t**; | in_place_t in_place{}; | | In-place error construction | struct **in_place_unexpected_t**; | in_place_unexpected_t
unexpect{}; | | In-place error construction | struct **in_place_unexpected_t**; | in_place_unexpected_t
in_place_unexpected{}; | | Error reporting | class **bad_expected_access**; |  | ### Interface of expected | Kind | Method | Result | |--------------|-------------------------------------------------------------------------|--------| | Construction | [constexpr] **expected**() noexcept(...) | an object with default value | |   | [constexpr] **expected**( expected const & other ) | initialize to contents of other | |   | [constexpr] **expected**( expected && other ) | move contents from other | |   | [constexpr] **expected**( value_type const & value ) | initialize to value | |   | [constexpr] **expected**( value_type && value ) noexcept(...) | move from value | |   | [constexpr] explicit **expected**( in_place_t, Args&&... args ) | construct value in-place from args | |   | [constexpr] explicit **expected**( in_place_t,
 std::initializer_list<U> il, Args&&... args ) | construct value in-place from args | |   | [constexpr] **expected**( unexpected_type const & error ) | initialize to error | |   | [constexpr] **expected**( unexpected_type && error ) | move from error | |   | [constexpr] explicit **expected**( in_place_unexpected_t,
 Args&&... args ) | construct error in-place from args | |   | [constexpr] explicit **expected**( in_place_unexpected_t,
 std::initializer_list<U> il, Args&&... args )| construct error in-place from args | | Destruction | ~**expected**() | destruct current content | | Assignment | expected **operator=**( expected const & other ) | assign contents of other;
destruct current content, if any | |   | expected & **operator=**( expected && other ) noexcept(...) | move contents of other | |   | expected & **operator=**( U && v ) | move value from v | |   | expected & **operator=**( unexpected_type const & u ) | initialize to unexpected | |   | expected & **operator=**( unexpected_type && u ) | move from unexpected | |   | template<typename... Args>
void **emplace**( Args &&... args ) | emplace from args | |   | template<typename U, typename... Args>
void **emplace**( std::initializer_list<U> il, Args &&... args ) | emplace from args | | Swap | void **swap**( expected & other ) noexcept | swap with other | | Observers | constexpr value_type const \* **operator->**() const | pointer to current content (const);
must contain value | |   | value_type \* **operator->**() | pointer to current content (non-const);
must contain value | |   | constexpr value_type const & **operator \***() const & | the current content (const ref);
must contain value | |   | constexpr value_type && **operator \***() && | the current content (non-const ref);
must contain value | |   | constexpr explicit operator **bool**() const noexcept | true if contains value | |   | constexpr **has_value**() const noexcept | true if contains value | |   | constexpr value_type const & **value**() const & | current content (const ref);
see [note 1](#note1) | |   | value_type & **value**() & | current content (non-const ref);
see [note 1](#note1) | |   | constexpr value_type && **value**() && | move from current content;
see [note 1](#note1) | |   | constexpr error_type const & **error**() const & | current error (const ref);
must contain error | |   | error_type & **error**() & | current error (non-const ref);
must contain error | |   | constexpr error_type && **error**() && | move from current error;
must contain error | |   | constexpr unexpected_type **get_unexpected**() const | the error as unexpected<>;
must contain error | |   | template<typename Ex>
bool **has_exception**() const | true of contains exception (as base) | |   | value_type **value_or**( U && v ) const & | value or move from v | |   | value_type **value_or**( U && v ) && | move from value or move from v | |   | constexpr error_type **error_or**( G && e ) const & | return current error or v [requires nsel_P2505R >= 4] | |   | constexpr error_type **error_or**( G && e ) && | move from current error or from v [requires nsel_P2505R >=4] | | Monadic operations
(requires nsel_P2505R >= 3) | constexpr auto **and_then**( F && f ) & G| return f(value()) if has value, otherwise the error | |   | constexpr auto **and_then**( F && f ) const & | return f(value()) if has value, otherwise the error | |   | constexpr auto **and_then**( F && f ) && | return f(std::move(value())) if has value, otherwise the error | |   | constexpr auto **and_then**( F && f ) const && | return f(std::move(value())) if has value, otherwise the error | |   | constexpr auto **or_else**( F && f ) & | return the value, or f(error()) if there is no value | |   | constexpr auto **or_else**( F && f ) const & | return the value, or f(error()) if there is no value | |   | constexpr auto **or_else**( F && f ) && | return the value, or f(std::move(error())) if there is no value | |   | constexpr auto **or_else**( F && f ) const && | return the value, or f(std::move(error())) if there is no value | |   | constexpr auto **transform**( F && f ) & | return f(value()) wrapped if has value, otherwise the error | |   | constexpr auto **transform**( F && f ) const & | return f(value()) wrapped if has value, otherwise the error | |   | constexpr auto **transform**( F && f ) && | return f(std::move(value())) wrapped if has value, otherwise the error | |   | constexpr auto **transform**( F && f ) const && | return f(std::move(value())) wrapped if has value, otherwise the error | |   | constexpr auto **transform_error**( F && f ) & | return the value if has value, or f(error()) otherwise | |   | constexpr auto **transform_error**( F && f ) const & | return the value if has value, or f(error()) otherwise | |   | constexpr auto **transform_error**( F && f ) && | return the value if has value, or f(std::move(error())) otherwise | |   | constexpr auto **transform_error**( F && f ) const && | return the value if has value, or f(std::move(error())) otherwise | |   | ... |   | Note 1: checked access: if no content, for std::exception_ptr rethrows error(), otherwise throws bad_expected_access(error()). ### Algorithms for expected | Kind | Function | |---------------------------------|----------| | Comparison with expected |   | | == != | template<typename T1, typename E1, typename T2, typename E2>
constexpr bool operator ***op***(
 expected<T1,E1> const & x,
 expected<T2,E2> const & y ) | | Comparison with expected | nsel_P0323R <= 2 | | < > <= >= | template<typename T, typename E>
constexpr bool operator ***op***(
 expected<T,E> const & x,
 expected<T,E> const & y ) | | Comparison with unexpected_type |   | | == != | template<typename T1, typename E1, typename E2>
constexpr bool operator ***op***(
 expected<T1,E1> const & x,
 unexpected_type<E2> const & u ) | |   | template<typename T1, typename E1, typename E2>
constexpr bool operator ***op***(
 unexpected_type<E2> const & u,
 expected<T1,E1> const & x ) | | Comparison with unexpected_type | nsel_P0323R <= 2 | | < > <= >= | template<typename T, typename E>
constexpr bool operator ***op***(
 expected<T,E> const & x,
 unexpected_type<E> const & u ) | |   | template<typename T, typename E>
constexpr bool operator ***op***(
 unexpected_type<E> const & u,
 expected<T,E> const & x ) | | Comparison with T |   | | == != | template<typename T, typename E>
constexpr bool operator ***op***(
 expected<T,E> const & x,
 T const & v ) | |   | template<typename T, typename E>
constexpr bool operator ***op***(
 T const & v,
 expected<T,E> const & x ) | | Comparison with T | nsel_P0323R <= 2 | | < > <= >= | template<typename T, typename E>
constexpr bool operator ***op***(
 expected<T,E> const & x,
 T const & v ) | |   | template<typename T, typename E>
constexpr bool operator ***op***(
 T const & v,
 expected<T,E> const & x ) | | Specialized algorithms |   | | Swap | template<typename T, typename E>
void **swap**(
 expected<T,E> & x,
 expected<T,E> & y ) noexcept( noexcept( x.swap(y) ) ) | | Make expected from | nsel_P0323R <= 3 | |  Value | template<typename T>
constexpr auto **make_expected**( T && v ) ->
 expected< typename std::decay<T>::type> | |  Nothing | auto **make_expected**() -> expected<void> | |  Current exception | template<typename T>
constexpr auto **make_expected_from_current_exception**() -> expected<T> | |  Exception | template<typename T>
auto **make_expected_from_exception**( std::exception_ptr v ) -> expected<T>| |  Error | template<typename T, typename E>
constexpr auto **make_expected_from_error**( E e ) ->
 expected<T, typename std::decay<E>::type> | |  Call | template<typename F>
auto **make_expected_from_call**( F f ) ->
 expected< typename std::result_of<F()>::type>| |  Call, void specialization | template<typename F>
auto **make_expected_from_call**( F f ) -> expected<void> | ### Interface of unexpected_type | Kind | Method | Result | |--------------|-----------------------------------------------------------|--------| | Construction | **unexpected_type**() = delete; | no default construction | |   | constexpr explicit **unexpected_type**( E const & error ) | copy-constructed from an E | |   | constexpr explicit **unexpected_type**( E && error ) | move-constructed from an E | | Observers | constexpr error_type const & **error**() const | can observe contained error | |   | error_type & **error**() | can modify contained error | | deprecated | constexpr error_type const & **value**() const | can observe contained error | | deprecated | error_type & **value**() | can modify contained error | ### Algorithms for unexpected_type | Kind | Function | |-------------------------------|----------| | Comparison with unexpected |   | | == != | template<typename E>
constexpr bool operator ***op***(
 unexpected_type<E> const & x,
 unexpected_type<E> const & y ) | | Comparison with unexpected | nsel_P0323R <= 2 | | < > <= >= | template<typename E>
constexpr bool operator ***op***(
 unexpected_type<E> const & x,
 unexpected_type<E> const & y ) | | Comparison with exception_ptr |   | | == != | constexpr bool operator ***op***(
 unexpected_type<std::exception_ptr> const & x,
 unexpected_type<std::exception_ptr> const & y ) | | Comparison with exception_ptr | nsel_P0323R <= 2 | | < > <= >= | constexpr bool operator ***op***(
 unexpected_type<std::exception_ptr> const & x,
 unexpected_type<std::exception_ptr> const & y ) | | Specialized algorithms |   | | Make unexpected from |   | |  Error | template<typename E>
[constexpr] auto **make_unexpected**(E && v) ->
 unexpected_type< typename std::decay<E>::type>| |  Arguments (in-place) | template<typename E, typename... Args>
[constexpr] auto **make_unexpected**(in_place_t, Args &&... args) ->
 unexpected_type< typename std::decay<E>::type>| | Make unexpected from | nsel_P0323R <= 3 | |  Current exception | [constexpr] auto **make_unexpected_from_current_exception**() ->
 unexpected_type< std::exception_ptr>| ## Comparison with like types |Feature |
std::pair|std:: optional |std:: expected |nonstd:: expected |Boost. Expected |Nonco expected |Andrei Expected |Hagan required | |----------------------|-------------|---------------|---------------|------------------|----------------|---------------|----------------|---------------| |More information | see [14] | see [5] | see [1] | this work | see [4] | see [7] | see [8] | see [13] | | | | | | | | | | | | C++03 | yes | no | no | no/not yet | no (union) | no | no | yes | | C++11 | yes | no | no | yes | yes | yes | yes | yes | | C++14 | yes | no | no | yes | yes | yes | yes | yes | | C++17 | yes | yes | no | yes | yes | yes | yes | yes | | | | | | | | | | | |DefaultConstructible | T param | yes | yes | yes | yes | no | no | no | |In-place construction | no | yes | yes | yes | yes | yes | no | no | |Literal type | yes | yes | yes | yes | yes | no | no | no | | | | | | | | | | | |Disengaged information| possible | no | yes | yes | yes | yes | yes | no | |Vary disengaged type | yes | no | yes | yes | yes | no | no | no | |Engaged nonuse throws | no | no | no | no | error_traits | no | no | yes | |Disengaged use throws | no | yes, value() | yes, value() | yes, value() | yes,
value()| yes,
get() | yes,
get() | n/a | | | | | | | | | | | |Proxy (rel.ops) | no | yes | yes | yes | yes | no | no | no | |References | no | yes | no/not yet | no/not yet | no/not yet | yes | no | no | |Chained visitor(s) | no | no | yes | yes | yes | no | no | no | Note 1: std::*experimental*::expected Note 2: sources for [Nonco expected](https://github.com/martinmoene/spike-expected/tree/master/nonco), [Andrei Expected](https://github.com/martinmoene/spike-expected/tree/master/alexandrescu) and [Hagan required](https://github.com/martinmoene/spike-expected/tree/master/hagan) can befound in the [spike-expected](https://github.com/martinmoene/spike-expected) repository. ## Reported to work with TBD ## Implementation notes TBD ## Other implementations of expected - Simon Brand. [C++11/14/17 std::expected with functional-style extensions](https://github.com/TartanLlama/expected). Single-header. - Isabella Muerte. [MNMLSTC Core](https://github.com/mnmlstc/core) (C++11). - Vicente J. Botet Escriba. [stdmake's expected](https://github.com/viboes/std-make/tree/master/include/experimental/fundamental/v3/expected) (C++17). - Facebook. [ Folly's Expected.h](https://github.com/facebook/folly/blob/master/folly/Expected.h) (C++14). ## Notes and references [1] Vicente J. Botet Escriba. [p0323 - A proposal to add a utility class to represent expected object (latest)](http://wg21.link/p0323) (HTML). ([r12](http://wg21.link/p0323r12), [r11](http://wg21.link/p0323r11), [r10](http://wg21.link/p0323r10), [r9](http://wg21.link/p0323r9), [r8](http://wg21.link/p0323r8), [r7](http://wg21.link/p0323r7), [r6](http://wg21.link/p0323r6), [r5](http://wg21.link/p0323r5), [r4](http://wg21.link/p0323r4), [r3](http://wg21.link/p0323r3), [r2](http://wg21.link/p0323r2), [r1](http://wg21.link/n4109), [r0](http://wg21.link/n4015), [draft](https://github.com/viboes/std-make/blob/master/doc/proposal/expected/DXXXXR0_expected.pdf)). [2] Vicente J. Botet Escriba. [JASEL: Just a simple experimental library for C++](https://github.com/viboes/std-make). Reference implementation of [expected](https://github.com/viboes/std-make/tree/master/include/experimental/fundamental/v3/expected). [3] Vicente J. Botet Escriba. [Expected - An exception-friendly Error Monad](https://www.youtube.com/watch?v=Zdlt1rgYdMQ). C++Now 2014. 24 September 2014. [4] Pierre Talbot. [Boost.Expected. Unofficial Boost candidate](http://www.google-melange.com/gsoc/proposal/review/google/gsoc2013/trademark/25002). 5 May 2013. [GitHub](https://github.com/TrademarkPewPew/Boost.Expected), [GSoC 2013 Proposal](http://www.google-melange.com/gsoc/proposal/review/google/gsoc2013/trademark/25002), [boost@lists.boost.org](http://permalink.gmane.org/gmane.comp.lib.boost.devel/240056 ). [5] Fernando Cacciola and Andrzej Krzemieński. [A proposal to add a utility class to represent optional objects (Revision 4)](http://isocpp.org/files/papers/N3672.html). ISO/IEC JTC1 SC22 WG21 N3672 2013-04-19. [6] Andrzej Krzemieński, [Optional library implementation in C++11](https://github.com/akrzemi1/Optional/). [7] Anto Nonco. [Extending expected to deal with references](http://anto-nonco.blogspot.nl/2013/03/extending-expected-to-deal-with.html). 27 May 2013. [8] Andrei Alexandrescu. Systematic Error Handling in C++. Prepared for The C++and Beyond Seminar 2012. [Video](http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C). [Slides](http://sdrv.ms/RXjNPR). [9] Andrei Alexandrescu. [Choose your Poison: Exceptions or Error Codes? (PDF)](http://accu.org/content/conf2007/Alexandrescu-Choose_Your_Poison.pdf). ACCU Conference 2007. [10] Andrei Alexandrescu. [The Power of None (PPT)](http://nwcpp.org/static/talks/2006/The_Power_of_None.ppt). Northwest C++ Users' Group. [May 17th, 2006](http://nwcpp.org/may-2006.html). [11] Jon Jagger. [A Return Type That Doesn't Like Being Ignored](http://accu.org/var/uploads/journals/overload53-FINAL.pdf#page=18). Overload issue 53, February 2003. [12] Andrei Alexandrescu. [Error Handling in C++: Are we inching towards a total solution?](http://accu.org/index.php/conferences/2002/speakers2002). ACCU Conference 2002. [13] Ken Hagan et al. [Exploding return codes](https://groups.google.com/d/msg/comp.lang.c++.moderated/BkZqPfoq3ys/H_PMR8Sat4oJ). comp.lang.c++.moderated. 11 February 2000. [14] [std::pair](http://en.cppreference.com/w/cpp/utility/pair). cppreference.com [15] Niall Douglas. [Outcome](https://ned14.github.io/outcome/). Very lightweight outcome<T> and result<T> (non-Boost edition). [16] Niall Douglas. [p0762 - Concerns about expected<T, E> from the Boost.Outcome peer review](http://wg21.link/p0762). 15 October 2017. [17] Jeff Garland. [p2505 - Monadic Functions for `std::expected`](http://wg21.link/p2505) (HTML). ([r0](http://wg21.link/p2505r0), [r1](http://wg21.link/p2505r1), [r2](http://wg21.link/p2505r2), [r3](http://wg21.link/p2505r3), [r4](http://wg21.link/p2505r4), [r5](http://wg21.link/p2505r5)). ## Appendix ### A.1 Compile-time information The version of *expected lite* is available via tag `[.version]`. The following tags are available for information on the compiler and on the C++ standard library used: `[.compiler]`, `[.stdc++]`, `[.stdlanguage]` and `[.stdlibrary]`. ### A.2 Expected lite test specification
click to expand

```Text unexpected_type: Disallows default construction unexpected_type: Allows to copy-construct from unexpected_type, default unexpected_type: Allows to move-construct from unexpected_type, default unexpected_type: Allows to in-place-construct unexpected_type: Allows to in-place-construct from initializer_list unexpected_type: Allows to copy-construct from error_type unexpected_type: Allows to move-construct from error_type unexpected_type: Allows to copy-construct from unexpected_type, explicit converting unexpected_type: Allows to copy-construct from unexpected_type, non-explicit converting unexpected_type: Allows to move-construct from unexpected_type, explicit converting unexpected_type: Allows to move-construct from unexpected_type, non-explicit converting unexpected_type: Allows to copy-assign from unexpected_type, default unexpected_type: Allows to move-assign from unexpected_type, default unexpected_type: Allows to copy-assign from unexpected_type, converting unexpected_type: Allows to move-assign from unexpected, converting unexpected_type: Allows to observe its value via a l-value reference unexpected_type: Allows to observe its value via a r-value reference unexpected_type: Allows to modify its value via a l-value reference unexpected_type: Allows to be swapped unexpected_type: Disallows default construction unexpected_type: Allows to copy-construct from error_type unexpected_type: Allows to move-construct from error_type unexpected_type: Allows to copy-construct from an exception unexpected_type: Allows to observe its value unexpected_type: Allows to modify its value unexpected_type: Provides relational operators unexpected_type: Provides relational operators, std::exception_ptr specialization make_unexpected(): Allows to create an unexpected_type from an E make_unexpected(): Allows to in-place create an unexpected_type from an E unexpected: C++17 and later provide unexpected_type as unexpected bad_expected_access: Disallows default construction bad_expected_access: Allows construction from error_type bad_expected_access: Allows to observe its error bad_expected_access: Allows to change its error bad_expected_access: Provides non-empty what() expected: Allows to default construct expected: Allows to default construct from noncopyable, noncopyable value type expected: Allows to default construct from noncopyable, noncopyable error type expected: Allows to copy-construct from expected: value expected: Allows to copy-construct from expected: error expected: Allows to move-construct from expected: value expected: Allows to move-construct from expected: error expected: Allows to copy-construct from expected; value, explicit converting expected: Allows to copy-construct from expected; error, explicit converting expected: Allows to copy-construct from expected; value, non-explicit converting expected: Allows to copy-construct from expected; error, non-explicit converting expected: Allows to move-construct from expected; value, explicit converting expected: Allows to move-construct from expected; error, explicit converting expected: Allows to move-construct from expected; value, non-explicit converting expected: Allows to move-construct from expected; error, non-explicit converting expected: Allows to forward-construct from value, explicit converting expected: Allows to forward-construct from value, non-explicit converting expected: Allows to in-place-construct value expected: Allows to in-place-construct value from initializer_list expected: Allows to copy-construct from unexpected, explicit converting expected: Allows to copy-construct from unexpected, non-explicit converting expected: Allows to move-construct from unexpected, explicit converting expected: Allows to move-construct from unexpected, non-explicit converting expected: Allows to in-place-construct error expected: Allows to in-place-construct error from initializer_list expected: Allows to copy-assign from expected, value expected: Allows to copy-assign from expected, error expected: Allows to move-assign from expected, value expected: Allows to move-assign from expected, error expected: Allows to forward-assign from value expected: Allows to copy-assign from unexpected expected: Allows to move-assign from unexpected expected: Allows to move-assign from move-only unexpected expected: Allows to emplace value expected: Allows to emplace value from initializer_list expected: Allows to be swapped expected: Allows to observe its value via a pointer expected: Allows to observe its value via a pointer to constant expected: Allows to modify its value via a pointer expected: Allows to observe its value via a l-value reference expected: Allows to observe its value via a r-value reference expected: Allows to modify its value via a l-value reference expected: Allows to modify its value via a r-value reference expected: Allows to observe if it contains a value (or error) expected: Allows to observe its value expected: Allows to modify its value expected: Allows to move its value expected: Allows to observe its error expected: Allows to modify its error expected: Allows to move its error expected: Allows to observe its error as unexpected expected: Allows to query if it contains an exception of a specific base type expected: Allows to observe its value if available, or obtain a specified value otherwise expected: Allows to move its value if available, or obtain a specified value otherwise expected: Throws bad_expected_access on value access when disengaged expected: Allows to observe its unexpected value, or fallback to the specified value with error_or [monadic p2505r4] expected: Allows to map value with and_then [monadic p2505r3] expected: Allows to map unexpected with or_else [monadic p2505r3] expected: Allows to transform value [monadic p2505r3] expected: Allows to map errors with transform_error [monadic p2505r3] expected: Allows to default-construct expected: Allows to copy-construct from expected: value expected: Allows to copy-construct from expected: error expected: Allows to move-construct from expected: value expected: Allows to move-construct from expected: error expected: Allows to in-place-construct expected: Allows to copy-construct from unexpected, explicit converting expected: Allows to copy-construct from unexpected, non-explicit converting expected: Allows to move-construct from unexpected, explicit converting expected: Allows to move-construct from unexpected, non-explicit converting expected: Allows to in-place-construct unexpected_type expected: Allows to in-place-construct error from initializer_list expected: Allows to copy-assign from expected, value expected: Allows to copy-assign from expected, error expected: Allows to move-assign from expected, value expected: Allows to move-assign from expected, error expected: Allows to emplace value expected: Allows to be swapped expected: Allows to observe if it contains a value (or error) expected: Allows to observe its value expected: Allows to observe its error expected: Allows to modify its error expected: Allows to move its error expected: Allows to observe its error as unexpected expected: Allows to query if it contains an exception of a specific base type expected: Throws bad_expected_access on value access when disengaged expected: Allows to observe unexpected value, or fallback to a default value with error_or [monadic p2505r4] expected: Allows to call argless functions with and_then [monadic p2505r3] expected: Allows to map to expected or unexpected with or_else [monadic p2505r3] expected: Allows to assign a new expected value using transform [monadic p2505r3] expected: Allows to map unexpected error value via transform_error [monadic p2505r3] operators: Provides expected relational operators operators: Provides expected relational operators (void) swap: Allows expected to be swapped std::hash: Allows to compute hash value for expected tweak header: reads tweak header if supported [tweak] ```

expected-lite-0.10.0/cmake/000077500000000000000000000000001510672106500154075ustar00rootroot00000000000000expected-lite-0.10.0/cmake/expected-lite-config-version.cmake.in000066400000000000000000000014231510672106500245000ustar00rootroot00000000000000# Adapted from write_basic_package_version_file(... COMPATIBILITY SameMajorVersion) output # ARCH_INDEPENDENT is only present in cmake 3.14 and onwards set( PACKAGE_VERSION "@package_version@" ) if( PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION ) set( PACKAGE_VERSION_COMPATIBLE FALSE ) else() if( "@package_version@" MATCHES "^([0-9]+)\\." ) set( CVF_VERSION_MAJOR "${CMAKE_MATCH_1}" ) else() set( CVF_VERSION_MAJOR "@package_version@" ) endif() if( PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR ) set( PACKAGE_VERSION_COMPATIBLE TRUE ) else() set( PACKAGE_VERSION_COMPATIBLE FALSE ) endif() if( PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION ) set( PACKAGE_VERSION_EXACT TRUE ) endif() endif() expected-lite-0.10.0/cmake/expected-lite-config.cmake.in000066400000000000000000000002521510672106500230140ustar00rootroot00000000000000@PACKAGE_INIT@ # Only include targets once: if( NOT TARGET @package_nspace@::@package_name@ ) include( "${CMAKE_CURRENT_LIST_DIR}/@package_target@.cmake" ) endif() expected-lite-0.10.0/conanfile.py000066400000000000000000000016431510672106500166430ustar00rootroot00000000000000from conans import ConanFile, CMake class ExpectedLiteConan(ConanFile): version = "0.10.0" name = "expected-lite" description = "Expected objects for C++11 and later" license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt" url = "https://github.com/martinmoene/expected-lite.git" exports_sources = "include/nonstd/*", "CMakeLists.txt", "cmake/*", "LICENSE.txt" settings = "compiler", "build_type", "arch" build_policy = "missing" author = "Martin Moene" def build(self): """Avoid warning on build step""" pass def package(self): """Run CMake install""" cmake = CMake(self) cmake.definitions["EXPECTED_LITE_OPT_BUILD_TESTS"] = "OFF" cmake.definitions["EXPECTED_LITE_OPT_BUILD_EXAMPLES"] = "OFF" cmake.configure() cmake.install() def package_info(self): self.info.header_only() expected-lite-0.10.0/example/000077500000000000000000000000001510672106500157625ustar00rootroot00000000000000expected-lite-0.10.0/example/01-basic.cpp000066400000000000000000000016711510672106500177720ustar00rootroot00000000000000// Convert text to number and yield expected with number or error text. #include "nonstd/expected.hpp" #include #include #include using namespace nonstd; using namespace std::literals; auto to_int( char const * const text ) -> expected { char * pos = nullptr; auto value = strtol( text, &pos, 0 ); if ( pos != text ) return value; else return make_unexpected( "'"s + text + "' isn't a number" ); } int main( int argc, char * argv[] ) { auto text = argc > 1 ? argv[1] : "42"; auto ei = to_int( text ); if ( ei ) std::cout << "'" << text << "' is " << *ei << ", "; else std::cout << "Error: " << ei.error(); } // cl -EHsc -wd4814 -I../include 01-basic.cpp && 01-basic.exe 123 && 01-basic.exe abc // g++ -std=c++14 -Wall -I../include -o 01-basic.exe 01-basic.cpp && 01-basic.exe 123 && 01-basic.exe abc // '123' is 123, Error: 'abc' isn't a number expected-lite-0.10.0/example/02-required.cpp000066400000000000000000000026701510672106500205320ustar00rootroot00000000000000// Use a non-ignorable value with expected. #include "nonstd/expected.hpp" #include using namespace nonstd; template< typename T > class required { public: required( T const & value) : content( value ) {} required( required && other ) : content( other.content ) , ignored( other.ignored ) { other.ignored = false; } required( required const & other ) = delete; ~required() noexcept( false ) { if ( ignored ) throw std::runtime_error("required: content unobserved"); }; T const & operator *() const { ignored = false; return content; } private: T content; mutable bool ignored = true; }; template< typename T > auto make_required( T value ) -> required { return required( std::move(value) ); } using unused_type = char; auto produce( int value ) -> expected< required, unused_type > { return make_required( std::move(value) ); } int main( int argc, char * argv[] ) { try { auto er42 = produce( 42 ); auto er13 = produce( 13 ); std::cout << "value: " << **er42 << "\n"; } catch ( std::exception const & e ) { std::cout << "Error: " << e.what(); } } // cl -EHsc -wd4814 -Zc:implicitNoexcept- -I../include 02-required.cpp && 02-required.exe // g++ -std=c++14 -Wall -I../include -o 02-required.exe 02-required.cpp && 02-required.exe // value: 42 // Error: required: content unobserved expected-lite-0.10.0/example/03-no-exceptions.cpp000066400000000000000000000034441510672106500215060ustar00rootroot00000000000000// Copyright (c) 2016-2020 Martin Moene // // https://github.com/martinmoene/expected-lite // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "nonstd/expected.hpp" #include template< typename T > void use( T const & /*x*/) {} #define expected_PRESENT( x ) \ std::cout << #x << ": " << x << "\n" #define expected_ABSENT( x ) \ std::cout << #x << ": (undefined)\n" void report() { #ifdef __cpp_exceptions expected_PRESENT( __cpp_exceptions ); #else expected_ABSENT( __cpp_exceptions ); #endif #ifdef __EXCEPTIONS expected_PRESENT( __EXCEPTIONS ); #else expected_ABSENT( __EXCEPTIONS ); #endif #ifdef _HAS_EXCEPTIONS expected_PRESENT( _HAS_EXCEPTIONS ); #else expected_ABSENT( _HAS_EXCEPTIONS ); #endif #ifdef _CPPUNWIND expected_PRESENT( _CPPUNWIND ); #else expected_ABSENT( _CPPUNWIND ); #endif } int violate_access() { nonstd::expected eu( nonstd:: make_unexpected('a') ); return eu.value(); } int main() { report(); #if ! nsel_CONFIG_NO_EXCEPTIONS_SEH return violate_access(); #else __try { return violate_access(); } __except( EXCEPTION_EXECUTE_HANDLER ) { std::cerr << "\n*** Executing SEH __except block ***\n"; } #endif } // -Dnsel_CONFIG_NO_EXCEPTIONS=1 automatically determined in expected.hpp // -Dnsel_CONFIG_NO_EXCEPTIONS_SEH=0 default:1 for msvc // cl -nologo -kernel -EHs-c- -GR- -I../include 03-no-exceptions.cpp && 03-no-exceptions // cl -nologo -kernel -EHs-c- -GR- -Dnsel_CONFIG_NO_EXCEPTIONS_SEH=0 -I../include 03-no-exceptions.cpp && 03-no-exceptions // g++ -Wall -fno-exceptions -I../include -o 03-no-exceptions 03-no-exceptions.cpp && 03-no-exceptions expected-lite-0.10.0/example/CMakeLists.txt000066400000000000000000000040011510672106500205150ustar00rootroot00000000000000# Copyright (c) 2016-2022 Martin Moene. # # https://github.com/martinmoene/expected-lite # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) if( NOT DEFINED CMAKE_MINIMUM_REQUIRED_VERSION ) cmake_minimum_required( VERSION 3.15 FATAL_ERROR ) endif() project( example LANGUAGES CXX ) # unit_name provided by toplevel CMakeLists.txt set( PACKAGE ${unit_name}-lite ) message( STATUS "Subproject '${PROJECT_NAME}', various examples") # Target default options and definitions: set( OPTIONS "" ) #set( DEFINITIONS "" ) # Sources (.cpp), normal and no-exception, and their base names: set( SOURCES_CPP11 02-required.cpp ) set( SOURCES_CPP14 01-basic.cpp ) # note: here variable must be quoted to create semicolon separated list: string( REPLACE ".cpp" "" BASENAMES_CPP11 "${SOURCES_CPP11}" ) string( REPLACE ".cpp" "" BASENAMES_CPP14 "${SOURCES_CPP14}" ) set( TARGETS_CPP11 ${BASENAMES_CPP11} ) set( TARGETS_CPP14 ${BASENAMES_CPP14} ) set( TARGETS_ALL ${TARGETS_CPP11} ${TARGETS_CPP14} ) # add targets: foreach( name ${TARGETS_ALL} ) add_executable( ${name} ${name}.cpp ) target_link_libraries( ${name} PRIVATE ${PACKAGE} ) endforeach() # set compiler options: if( ${CMAKE_GENERATOR} MATCHES Visual ) foreach( name ${TARGETS_ALL} ) target_compile_options( ${name} PUBLIC -W3 -EHsc -wd4814 -Zc:implicitNoexcept- ) endforeach() else() foreach( name ${TARGETS_ALL} ) target_compile_options( ${name} PUBLIC -Wall ) endforeach() foreach( name ${TARGETS_CPP11} ) target_compile_options( ${name} PUBLIC -std=c++11 ) endforeach() foreach( name ${TARGETS_CPP14} ) target_compile_options( ${name} PUBLIC -std=c++14 ) endforeach() endif() # configure unit tests via CTest: enable_testing() foreach( name ${TARGETS_ALL} ) add_test ( NAME ${name} COMMAND ${name} ) set_property( TEST ${name} PROPERTY LABELS example ) endforeach() # end of file expected-lite-0.10.0/include/000077500000000000000000000000001510672106500157525ustar00rootroot00000000000000expected-lite-0.10.0/include/nonstd/000077500000000000000000000000001510672106500172575ustar00rootroot00000000000000expected-lite-0.10.0/include/nonstd/expected.hpp000066400000000000000000003322501510672106500215760ustar00rootroot00000000000000// This version targets C++11 and later. // // Copyright (C) 2016-2025 Martin Moene. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // expected lite is based on: // A proposal to add a utility class to represent expected monad // by Vicente J. Botet Escriba and Pierre Talbot. http:://wg21.link/p0323 #ifndef NONSTD_EXPECTED_LITE_HPP #define NONSTD_EXPECTED_LITE_HPP #define expected_lite_MAJOR 0 #define expected_lite_MINOR 10 #define expected_lite_PATCH 0 #define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH) #define expected_STRINGIFY( x ) expected_STRINGIFY_( x ) #define expected_STRINGIFY_( x ) #x // expected-lite configuration: #define nsel_EXPECTED_DEFAULT 0 #define nsel_EXPECTED_NONSTD 1 #define nsel_EXPECTED_STD 2 // tweak header support: #ifdef __has_include # if __has_include() # include # endif #define expected_HAVE_TWEAK_HEADER 1 #else #define expected_HAVE_TWEAK_HEADER 0 //# pragma message("expected.hpp: Note: Tweak header not supported.") #endif // expected selection and configuration: #if !defined( nsel_CONFIG_SELECT_EXPECTED ) # define nsel_CONFIG_SELECT_EXPECTED ( nsel_HAVE_STD_EXPECTED ? nsel_EXPECTED_STD : nsel_EXPECTED_NONSTD ) #endif // Proposal revisions: // // DXXXXR0: -- // N4015 : -2 (2014-05-26) // N4109 : -1 (2014-06-29) // P0323R0: 0 (2016-05-28) // P0323R1: 1 (2016-10-12) // -------: // P0323R2: 2 (2017-06-15) // P0323R3: 3 (2017-10-15) // P0323R4: 4 (2017-11-26) // P0323R5: 5 (2018-02-08) // P0323R6: 6 (2018-04-02) // P0323R7: 7 (2018-06-22) * // // expected-lite uses 2 and higher #ifndef nsel_P0323R # define nsel_P0323R 7 #endif // Monadic operations proposal revisions: // // P2505R0: 0 (2021-12-12) // P2505R1: 1 (2022-02-10) // P2505R2: 2 (2022-04-15) // P2505R3: 3 (2022-06-05) // P2505R4: 4 (2022-06-15) // P2505R5: 5 (2022-09-20) * // // expected-lite uses 5 #ifndef nsel_P2505R # define nsel_P2505R 5 #endif // Lean and mean inclusion of Windows.h, if applicable; default on for MSVC: #if !defined(nsel_CONFIG_WIN32_LEAN_AND_MEAN) && defined(_MSC_VER) # define nsel_CONFIG_WIN32_LEAN_AND_MEAN 1 #else # define nsel_CONFIG_WIN32_LEAN_AND_MEAN 0 #endif // Control marking class expected with [[nodiscard]]]: #if !defined(nsel_CONFIG_NO_NODISCARD) # define nsel_CONFIG_NO_NODISCARD 0 #else # define nsel_CONFIG_NO_NODISCARD 1 #endif // Control presence of C++ exception handling (try and auto discover): #ifndef nsel_CONFIG_NO_EXCEPTIONS # if defined(_MSC_VER) # include // for _HAS_EXCEPTIONS # endif # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) # define nsel_CONFIG_NO_EXCEPTIONS 0 # else # define nsel_CONFIG_NO_EXCEPTIONS 1 # endif #endif // at default use SEH with MSVC for no C++ exceptions #if !defined(nsel_CONFIG_NO_EXCEPTIONS_SEH) && defined(_MSC_VER) # define nsel_CONFIG_NO_EXCEPTIONS_SEH nsel_CONFIG_NO_EXCEPTIONS #else # define nsel_CONFIG_NO_EXCEPTIONS_SEH 0 #endif // C++ language version detection (C++23 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. #ifndef nsel_CPLUSPLUS # if defined(_MSVC_LANG ) && !defined(__clang__) # define nsel_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) # else # define nsel_CPLUSPLUS __cplusplus # endif #endif #define nsel_CPP98_OR_GREATER ( nsel_CPLUSPLUS >= 199711L ) #define nsel_CPP11_OR_GREATER ( nsel_CPLUSPLUS >= 201103L ) #define nsel_CPP14_OR_GREATER ( nsel_CPLUSPLUS >= 201402L ) #define nsel_CPP17_OR_GREATER ( nsel_CPLUSPLUS >= 201703L ) #define nsel_CPP20_OR_GREATER ( nsel_CPLUSPLUS >= 202002L ) #define nsel_CPP23_OR_GREATER ( nsel_CPLUSPLUS >= 202300L ) // Use C++23 std::expected if available and requested: #if nsel_CPP23_OR_GREATER && defined(__has_include ) # if __has_include( ) # define nsel_HAVE_STD_EXPECTED 1 # else # define nsel_HAVE_STD_EXPECTED 0 # endif #else # define nsel_HAVE_STD_EXPECTED 0 #endif #define nsel_USES_STD_EXPECTED ( (nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) || ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && nsel_HAVE_STD_EXPECTED) ) // // in_place: code duplicated in any-lite, expected-lite, expected-lite, value-ptr-lite, variant-lite: // #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES #define nonstd_lite_HAVE_IN_PLACE_TYPES 1 // C++17 std::in_place in : #if nsel_CPP17_OR_GREATER #include namespace nonstd { using std::in_place; using std::in_place_type; using std::in_place_index; using std::in_place_t; using std::in_place_type_t; using std::in_place_index_t; #define nonstd_lite_in_place_t( T) std::in_place_t #define nonstd_lite_in_place_type_t( T) std::in_place_type_t #define nonstd_lite_in_place_index_t(K) std::in_place_index_t #define nonstd_lite_in_place( T) std::in_place_t{} #define nonstd_lite_in_place_type( T) std::in_place_type_t{} #define nonstd_lite_in_place_index(K) std::in_place_index_t{} } // namespace nonstd #else // nsel_CPP17_OR_GREATER #include namespace nonstd { namespace detail { template< class T > struct in_place_type_tag {}; template< std::size_t K > struct in_place_index_tag {}; } // namespace detail struct in_place_t {}; template< class T > inline in_place_t in_place( detail::in_place_type_tag = detail::in_place_type_tag() ) { return in_place_t(); } template< std::size_t K > inline in_place_t in_place( detail::in_place_index_tag = detail::in_place_index_tag() ) { return in_place_t(); } template< class T > inline in_place_t in_place_type( detail::in_place_type_tag = detail::in_place_type_tag() ) { return in_place_t(); } template< std::size_t K > inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_place_index_tag() ) { return in_place_t(); } // mimic templated typedef: #define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) #define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) #define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) #define nonstd_lite_in_place( T) nonstd::in_place_type #define nonstd_lite_in_place_type( T) nonstd::in_place_type #define nonstd_lite_in_place_index(K) nonstd::in_place_index } // namespace nonstd #endif // nsel_CPP17_OR_GREATER #endif // nonstd_lite_HAVE_IN_PLACE_TYPES // // Using std::expected: // #if nsel_USES_STD_EXPECTED #include namespace nonstd { using std::expected; using std::unexpected; using std::bad_expected_access; using std::unexpect_t; using std::unexpect; //[[deprecated("replace unexpected_type with unexpected")]] template< typename E > using unexpected_type = unexpected; // Unconditionally provide make_unexpected(): template< typename E > constexpr auto make_unexpected( E && value ) -> unexpected< typename std::decay::type > { return unexpected< typename std::decay::type >( std::forward(value) ); } template < typename E, typename... Args, typename = std::enable_if< std::is_constructible::value > > constexpr auto make_unexpected( std::in_place_t inplace, Args &&... args ) -> unexpected_type< typename std::decay::type > { return unexpected_type< typename std::decay::type >( inplace, std::forward(args)...); } } // namespace nonstd #else // nsel_USES_STD_EXPECTED #include #include #include #include #include #include #include #include #include // additional includes: #if nsel_CONFIG_WIN32_LEAN_AND_MEAN # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif #endif #if nsel_CONFIG_NO_EXCEPTIONS # if nsel_CONFIG_NO_EXCEPTIONS_SEH # include // for ExceptionCodes # else // already included: # endif #else # include #endif // C++ feature usage: #if nsel_CPP11_OR_GREATER # define nsel_constexpr constexpr #else # define nsel_constexpr /*constexpr*/ #endif #if nsel_CPP14_OR_GREATER # define nsel_constexpr14 constexpr #else # define nsel_constexpr14 /*constexpr*/ #endif #if nsel_CPP17_OR_GREATER # define nsel_inline17 inline #else # define nsel_inline17 /*inline*/ #endif // Compiler versions: // // MSVC++ 6.0 _MSC_VER == 1200 nsel_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) // MSVC++ 7.0 _MSC_VER == 1300 nsel_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) // MSVC++ 7.1 _MSC_VER == 1310 nsel_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) // MSVC++ 8.0 _MSC_VER == 1400 nsel_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) // MSVC++ 9.0 _MSC_VER == 1500 nsel_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) // MSVC++ 10.0 _MSC_VER == 1600 nsel_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) // MSVC++ 11.0 _MSC_VER == 1700 nsel_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) // MSVC++ 12.0 _MSC_VER == 1800 nsel_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) // MSVC++ 14.0 _MSC_VER == 1900 nsel_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) // MSVC++ 14.1 _MSC_VER >= 1910 nsel_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) // MSVC++ 14.2 _MSC_VER >= 1920 nsel_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) #if defined(_MSC_VER) && !defined(__clang__) # define nsel_COMPILER_MSVC_VER (_MSC_VER ) # define nsel_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) ) #else # define nsel_COMPILER_MSVC_VER 0 # define nsel_COMPILER_MSVC_VERSION 0 #endif #define nsel_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) #if defined(__clang__) # define nsel_COMPILER_CLANG_VERSION nsel_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) #else # define nsel_COMPILER_CLANG_VERSION 0 #endif #if defined(__GNUC__) && !defined(__clang__) # define nsel_COMPILER_GNUC_VERSION nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #else # define nsel_COMPILER_GNUC_VERSION 0 #endif // half-open range [lo..hi): //#define nsel_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) // Method enabling #define nsel_REQUIRES_0(...) \ template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > #define nsel_REQUIRES_T(...) \ , typename std::enable_if< (__VA_ARGS__), int >::type = 0 #define nsel_REQUIRES_R(R, ...) \ typename std::enable_if< (__VA_ARGS__), R>::type #define nsel_REQUIRES_A(...) \ , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr // Clang, GNUC, MSVC warning suppression macros: #ifdef __clang__ # pragma clang diagnostic push #elif defined __GNUC__ # pragma GCC diagnostic push #endif // __clang__ #if nsel_COMPILER_MSVC_VERSION >= 140 # define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(push) ) __pragma( warning(disable: codes) ) #else # define nsel_DISABLE_MSVC_WARNINGS(codes) #endif #ifdef __clang__ # define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") # define nsel_RESTORE_MSVC_WARNINGS() #elif defined __GNUC__ # define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") # define nsel_RESTORE_MSVC_WARNINGS() #elif nsel_COMPILER_MSVC_VERSION >= 140 # define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) ) # define nsel_RESTORE_MSVC_WARNINGS() nsel_RESTORE_WARNINGS() #else # define nsel_RESTORE_WARNINGS() # define nsel_RESTORE_MSVC_WARNINGS() #endif // Suppress the following MSVC (GSL) warnings: // - C26409: Avoid calling new and delete explicitly, use std::make_unique instead (r.11) nsel_DISABLE_MSVC_WARNINGS( 26409 ) // Presence of language and library features: #ifdef _HAS_CPP0X # define nsel_HAS_CPP0X _HAS_CPP0X #else # define nsel_HAS_CPP0X 0 #endif // Presence of language and library features: #define nsel_CPP11_000 (nsel_CPP11_OR_GREATER) #define nsel_CPP17_000 (nsel_CPP17_OR_GREATER) // Presence of C++11 library features: #define nsel_HAVE_ADDRESSOF nsel_CPP11_000 // Presence of C++17 language features: #define nsel_HAVE_DEPRECATED nsel_CPP17_000 #define nsel_HAVE_NODISCARD nsel_CPP17_000 // C++ feature usage: #if nsel_HAVE_DEPRECATED # define nsel_deprecated(msg) [[deprecated(msg)]] #else # define nsel_deprecated(msg) /*[[deprecated]]*/ #endif #if nsel_HAVE_NODISCARD && !nsel_CONFIG_NO_NODISCARD # define nsel_NODISCARD [[nodiscard]] #else # define nsel_NODISCARD /*[[nodiscard]]*/ #endif // // expected: // namespace nonstd { namespace expected_lite { // library features C++11: namespace std11 { // #if 0 && nsel_HAVE_ADDRESSOF #if nsel_HAVE_ADDRESSOF using std::addressof; #else template< class T > T * addressof( T & arg ) noexcept { return &arg; } template< class T > const T * addressof( const T && ) = delete; #endif } // namespace std11 // type traits C++17: namespace std17 { #if nsel_CPP17_OR_GREATER using std::conjunction; using std::is_swappable; using std::is_nothrow_swappable; #else // nsel_CPP17_OR_GREATER namespace detail { using std::swap; struct is_swappable { template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > static std::true_type test( int /* unused */); template< typename > static std::false_type test(...); }; struct is_nothrow_swappable { // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): template< typename T > static constexpr bool satisfies() { return noexcept( swap( std::declval(), std::declval() ) ); } template< typename T > static auto test( int ) -> std::integral_constant()>{} template< typename > static auto test(...) -> std::false_type; }; } // namespace detail // is [nothrow] swappable: template< typename T > struct is_swappable : decltype( detail::is_swappable::test(0) ){}; template< typename T > struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; // conjunction: template< typename... > struct conjunction : std::true_type{}; template< typename B1 > struct conjunction : B1{}; template< typename B1, typename... Bn > struct conjunction : std::conditional, B1>::type{}; #endif // nsel_CPP17_OR_GREATER } // namespace std17 // type traits C++20: namespace std20 { #if defined(__cpp_lib_remove_cvref) using std::remove_cvref; #else template< typename T > struct remove_cvref { typedef typename std::remove_cv< typename std::remove_reference::type >::type type; }; #endif } // namespace std20 // forward declaration: template< typename T, typename E > class expected; namespace detail { #if nsel_P2505R >= 3 template< typename T > struct is_expected : std::false_type {}; template< typename T, typename E > struct is_expected< expected< T, E > > : std::true_type {}; #endif // nsel_P2505R >= 3 /// discriminated union to hold value or 'error'. template< typename T, typename E > class storage_t_noncopy_nonmove_impl { template< typename, typename > friend class nonstd::expected_lite::expected; public: using value_type = T; using error_type = E; // no-op construction storage_t_noncopy_nonmove_impl() {} ~storage_t_noncopy_nonmove_impl() {} explicit storage_t_noncopy_nonmove_impl( bool has_value ) : m_has_value( has_value ) {} void construct_value() { new( std11::addressof(m_value) ) value_type(); } // void construct_value( value_type const & e ) // { // new( std11::addressof(m_value) ) value_type( e ); // } // void construct_value( value_type && e ) // { // new( std11::addressof(m_value) ) value_type( std::move( e ) ); // } template< class... Args > void emplace_value( Args&&... args ) { new( std11::addressof(m_value) ) value_type( std::forward(args)...); } template< class U, class... Args > void emplace_value( std::initializer_list il, Args&&... args ) { new( std11::addressof(m_value) ) value_type( il, std::forward(args)... ); } void destruct_value() { m_value.~value_type(); } // void construct_error( error_type const & e ) // { // // new( std11::addressof(m_error) ) error_type( e ); // } // void construct_error( error_type && e ) // { // // new( std11::addressof(m_error) ) error_type( std::move( e ) ); // } template< class... Args > void emplace_error( Args&&... args ) { new( std11::addressof(m_error) ) error_type( std::forward(args)...); } template< class U, class... Args > void emplace_error( std::initializer_list il, Args&&... args ) { new( std11::addressof(m_error) ) error_type( il, std::forward(args)... ); } void destruct_error() { m_error.~error_type(); } constexpr value_type const & value() const & { return m_value; } value_type & value() & { return m_value; } constexpr value_type const && value() const && { return std::move( m_value ); } nsel_constexpr14 value_type && value() && { return std::move( m_value ); } value_type const * value_ptr() const { return std11::addressof(m_value); } value_type * value_ptr() { return std11::addressof(m_value); } error_type const & error() const & { return m_error; } error_type & error() & { return m_error; } constexpr error_type const && error() const && { return std::move( m_error ); } nsel_constexpr14 error_type && error() && { return std::move( m_error ); } bool has_value() const { return m_has_value; } void set_has_value( bool v ) { m_has_value = v; } private: union { value_type m_value; error_type m_error; }; bool m_has_value = false; }; template< typename T, typename E > class storage_t_impl { template< typename, typename > friend class nonstd::expected_lite::expected; public: using value_type = T; using error_type = E; // no-op construction storage_t_impl() {} ~storage_t_impl() {} explicit storage_t_impl( bool has_value ) : m_has_value( has_value ) {} void construct_value() { new( std11::addressof(m_value) ) value_type(); } void construct_value( value_type const & e ) { new( std11::addressof(m_value) ) value_type( e ); } void construct_value( value_type && e ) { new( std11::addressof(m_value) ) value_type( std::move( e ) ); } template< class... Args > void emplace_value( Args&&... args ) { new( std11::addressof(m_value) ) value_type( std::forward(args)...); } template< class U, class... Args > void emplace_value( std::initializer_list il, Args&&... args ) { new( std11::addressof(m_value) ) value_type( il, std::forward(args)... ); } void destruct_value() { m_value.~value_type(); } void construct_error( error_type const & e ) { new( std11::addressof(m_error) ) error_type( e ); } void construct_error( error_type && e ) { new( std11::addressof(m_error) ) error_type( std::move( e ) ); } template< class... Args > void emplace_error( Args&&... args ) { new( std11::addressof(m_error) ) error_type( std::forward(args)...); } template< class U, class... Args > void emplace_error( std::initializer_list il, Args&&... args ) { new( std11::addressof(m_error) ) error_type( il, std::forward(args)... ); } void destruct_error() { m_error.~error_type(); } constexpr value_type const & value() const & { return m_value; } value_type & value() & { return m_value; } constexpr value_type const && value() const && { return std::move( m_value ); } nsel_constexpr14 value_type && value() && { return std::move( m_value ); } value_type const * value_ptr() const { return std11::addressof(m_value); } value_type * value_ptr() { return std11::addressof(m_value); } error_type const & error() const & { return m_error; } error_type & error() & { return m_error; } constexpr error_type const && error() const && { return std::move( m_error ); } nsel_constexpr14 error_type && error() && { return std::move( m_error ); } bool has_value() const { return m_has_value; } void set_has_value( bool v ) { m_has_value = v; } private: union { value_type m_value; error_type m_error; }; bool m_has_value = false; }; /// discriminated union to hold only 'error'. template< typename E > struct storage_t_impl< void, E > { template< typename, typename > friend class nonstd::expected_lite::expected; public: using value_type = void; using error_type = E; // no-op construction storage_t_impl() {} ~storage_t_impl() {} explicit storage_t_impl( bool has_value ) : m_has_value( has_value ) {} void construct_error( error_type const & e ) { new( std11::addressof(m_error) ) error_type( e ); } void construct_error( error_type && e ) { new( std11::addressof(m_error) ) error_type( std::move( e ) ); } template< class... Args > void emplace_error( Args&&... args ) { new( std11::addressof(m_error) ) error_type( std::forward(args)...); } template< class U, class... Args > void emplace_error( std::initializer_list il, Args&&... args ) { new( std11::addressof(m_error) ) error_type( il, std::forward(args)... ); } void destruct_error() { m_error.~error_type(); } error_type const & error() const & { return m_error; } error_type & error() & { return m_error; } constexpr error_type const && error() const && { return std::move( m_error ); } nsel_constexpr14 error_type && error() && { return std::move( m_error ); } bool has_value() const { return m_has_value; } void set_has_value( bool v ) { m_has_value = v; } private: union { char m_dummy; error_type m_error; }; bool m_has_value = false; }; template< typename T, typename E, bool isConstructable, bool isMoveable > class storage_t { public: }; template< typename T, typename E > class storage_t : public storage_t_noncopy_nonmove_impl { public: storage_t() = default; ~storage_t() = default; explicit storage_t( bool has_value ) : storage_t_noncopy_nonmove_impl( has_value ) {} storage_t( storage_t const & other ) = delete; storage_t( storage_t && other ) = delete; }; template< typename T, typename E > class storage_t : public storage_t_impl { public: storage_t() = default; ~storage_t() = default; explicit storage_t( bool has_value ) : storage_t_impl( has_value ) {} storage_t( storage_t const & other ) : storage_t_impl( other.has_value() ) { if ( this->has_value() ) this->construct_value( other.value() ); else this->construct_error( other.error() ); } storage_t(storage_t && other ) : storage_t_impl( other.has_value() ) { if ( this->has_value() ) this->construct_value( std::move( other.value() ) ); else this->construct_error( std::move( other.error() ) ); } }; template< typename E > class storage_t : public storage_t_impl { public: storage_t() = default; ~storage_t() = default; explicit storage_t( bool has_value ) : storage_t_impl( has_value ) {} storage_t( storage_t const & other ) : storage_t_impl( other.has_value() ) { if ( this->has_value() ) ; else this->construct_error( other.error() ); } storage_t(storage_t && other ) : storage_t_impl( other.has_value() ) { if ( this->has_value() ) ; else this->construct_error( std::move( other.error() ) ); } }; template< typename T, typename E > class storage_t : public storage_t_impl { public: storage_t() = default; ~storage_t() = default; explicit storage_t( bool has_value ) : storage_t_impl( has_value ) {} storage_t( storage_t const & other ) : storage_t_impl(other.has_value()) { if ( this->has_value() ) this->construct_value( other.value() ); else this->construct_error( other.error() ); } storage_t( storage_t && other ) = delete; }; template< typename E > class storage_t : public storage_t_impl { public: storage_t() = default; ~storage_t() = default; explicit storage_t( bool has_value ) : storage_t_impl( has_value ) {} storage_t( storage_t const & other ) : storage_t_impl(other.has_value()) { if ( this->has_value() ) ; else this->construct_error( other.error() ); } storage_t( storage_t && other ) = delete; }; template< typename T, typename E > class storage_t : public storage_t_impl { public: storage_t() = default; ~storage_t() = default; explicit storage_t( bool has_value ) : storage_t_impl( has_value ) {} storage_t( storage_t const & other ) = delete; storage_t( storage_t && other ) : storage_t_impl( other.has_value() ) { if ( this->has_value() ) this->construct_value( std::move( other.value() ) ); else this->construct_error( std::move( other.error() ) ); } }; template< typename E > class storage_t : public storage_t_impl { public: storage_t() = default; ~storage_t() = default; explicit storage_t( bool has_value ) : storage_t_impl( has_value ) {} storage_t( storage_t const & other ) = delete; storage_t( storage_t && other ) : storage_t_impl( other.has_value() ) { if ( this->has_value() ) ; else this->construct_error( std::move( other.error() ) ); } }; #if nsel_P2505R >= 3 // C++11 invoke implementation template< typename > struct is_reference_wrapper : std::false_type {}; template< typename T > struct is_reference_wrapper< std::reference_wrapper< T > > : std::true_type {}; template< typename FnT, typename ClassT, typename ObjectT, typename... Args nsel_REQUIRES_T( std::is_function::value && ( std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value ) ) > nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) noexcept( noexcept( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ) ) ) -> decltype( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )...) ) { return (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ); } template< typename FnT, typename ClassT, typename ObjectT, typename... Args nsel_REQUIRES_T( std::is_function::value && is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value ) > nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) noexcept( noexcept( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) ) -> decltype( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) { return (obj.get().*memfnptr)( std::forward< Args >( args ) ... ); } template< typename FnT, typename ClassT, typename ObjectT, typename... Args nsel_REQUIRES_T( std::is_function::value && !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value ) > nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) noexcept( noexcept( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) ) -> decltype( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) { return ((*std::forward(obj)).*memfnptr)( std::forward< Args >( args ) ... ); } template< typename MemberT, typename ClassT, typename ObjectT nsel_REQUIRES_T( std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value ) > nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) noexcept( noexcept( std::forward< ObjectT >( obj ).*memobjptr ) ) -> decltype( std::forward< ObjectT >( obj ).*memobjptr ) { return std::forward< ObjectT >( obj ).*memobjptr; } template< typename MemberT, typename ClassT, typename ObjectT nsel_REQUIRES_T( is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value ) > nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) noexcept( noexcept( obj.get().*memobjptr ) ) -> decltype( obj.get().*memobjptr ) { return obj.get().*memobjptr; } template< typename MemberT, typename ClassT, typename ObjectT nsel_REQUIRES_T( !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value ) > nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) noexcept( noexcept( (*std::forward< ObjectT >( obj )).*memobjptr ) ) -> decltype( (*std::forward< ObjectT >( obj )).*memobjptr ) { return (*std::forward< ObjectT >( obj )).*memobjptr; } template< typename F, typename... Args nsel_REQUIRES_T( std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value ) > nsel_constexpr auto invoke( F && f, Args && ... args ) noexcept( noexcept( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) ) -> decltype( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) { return invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ); } template< typename F, typename... Args nsel_REQUIRES_T( std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value ) > nsel_constexpr auto invoke( F && f, Args && ... args ) noexcept( noexcept( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) ) -> decltype( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) { return invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ); } template< typename F, typename... Args nsel_REQUIRES_T( !std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value && !std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value ) > nsel_constexpr auto invoke( F && f, Args && ... args ) noexcept( noexcept( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) ) -> decltype( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) { return std::forward< F >( f )( std::forward< Args >( args ) ... ); } template< typename F, typename ... Args > using invoke_result_nocvref_t = typename std20::remove_cvref< decltype( ::nonstd::expected_lite::detail::invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type; #if nsel_P2505R >= 5 template< typename F, typename ... Args > using transform_invoke_result_t = typename std::remove_cv< decltype( ::nonstd::expected_lite::detail::invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type; #else template< typename F, typename ... Args > using transform_invoke_result_t = invoke_result_nocvref_t #endif // nsel_P2505R >= 5 template< typename T > struct valid_expected_value_type : std::integral_constant< bool, std::is_destructible< T >::value && !std::is_reference< T >::value && !std::is_array< T >::value > {}; #endif // nsel_P2505R >= 3 } // namespace detail /// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected. #if nsel_P0323R <= 2 template< typename E = std::exception_ptr > class unexpected_type #else template< typename E > class unexpected_type #endif // nsel_P0323R { public: using error_type = E; // x.x.5.2.1 Constructors // unexpected_type() = delete; constexpr unexpected_type( unexpected_type const & ) = default; constexpr unexpected_type( unexpected_type && ) = default; template< typename... Args nsel_REQUIRES_T( std::is_constructible::value ) > constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), Args &&... args ) : m_error( std::forward( args )...) {} template< typename U, typename... Args nsel_REQUIRES_T( std::is_constructible, Args&&...>::value ) > constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), std::initializer_list il, Args &&... args ) : m_error( il, std::forward( args )...) {} template< typename E2 nsel_REQUIRES_T( std::is_constructible::value && !std::is_same< typename std20::remove_cvref::type, nonstd_lite_in_place_t(E2) >::value && !std::is_same< typename std20::remove_cvref::type, unexpected_type >::value ) > constexpr explicit unexpected_type( E2 && error ) : m_error( std::forward( error ) ) {} template< typename E2 nsel_REQUIRES_T( std::is_constructible< E, E2>::value && !std::is_constructible & >::value && !std::is_constructible >::value && !std::is_constructible const & >::value && !std::is_constructible const >::value && !std::is_convertible< unexpected_type &, E>::value && !std::is_convertible< unexpected_type , E>::value && !std::is_convertible< unexpected_type const &, E>::value && !std::is_convertible< unexpected_type const , E>::value && !std::is_convertible< E2 const &, E>::value /*=> explicit */ ) > constexpr explicit unexpected_type( unexpected_type const & error ) : m_error( E{ error.error() } ) {} template< typename E2 nsel_REQUIRES_T( std::is_constructible< E, E2>::value && !std::is_constructible & >::value && !std::is_constructible >::value && !std::is_constructible const & >::value && !std::is_constructible const >::value && !std::is_convertible< unexpected_type &, E>::value && !std::is_convertible< unexpected_type , E>::value && !std::is_convertible< unexpected_type const &, E>::value && !std::is_convertible< unexpected_type const , E>::value && std::is_convertible< E2 const &, E>::value /*=> explicit */ ) > constexpr /*non-explicit*/ unexpected_type( unexpected_type const & error ) : m_error( error.error() ) {} template< typename E2 nsel_REQUIRES_T( std::is_constructible< E, E2>::value && !std::is_constructible & >::value && !std::is_constructible >::value && !std::is_constructible const & >::value && !std::is_constructible const >::value && !std::is_convertible< unexpected_type &, E>::value && !std::is_convertible< unexpected_type , E>::value && !std::is_convertible< unexpected_type const &, E>::value && !std::is_convertible< unexpected_type const , E>::value && !std::is_convertible< E2 const &, E>::value /*=> explicit */ ) > constexpr explicit unexpected_type( unexpected_type && error ) : m_error( E{ std::move( error.error() ) } ) {} template< typename E2 nsel_REQUIRES_T( std::is_constructible< E, E2>::value && !std::is_constructible & >::value && !std::is_constructible >::value && !std::is_constructible const & >::value && !std::is_constructible const >::value && !std::is_convertible< unexpected_type &, E>::value && !std::is_convertible< unexpected_type , E>::value && !std::is_convertible< unexpected_type const &, E>::value && !std::is_convertible< unexpected_type const , E>::value && std::is_convertible< E2 const &, E>::value /*=> non-explicit */ ) > constexpr /*non-explicit*/ unexpected_type( unexpected_type && error ) : m_error( std::move( error.error() ) ) {} // x.x.5.2.2 Assignment nsel_constexpr14 unexpected_type& operator=( unexpected_type const & ) = default; nsel_constexpr14 unexpected_type& operator=( unexpected_type && ) = default; template< typename E2 = E > nsel_constexpr14 unexpected_type & operator=( unexpected_type const & other ) { unexpected_type{ other.error() }.swap( *this ); return *this; } template< typename E2 = E > nsel_constexpr14 unexpected_type & operator=( unexpected_type && other ) { unexpected_type{ std::move( other.error() ) }.swap( *this ); return *this; } // x.x.5.2.3 Observers nsel_constexpr14 E & error() & noexcept { return m_error; } constexpr E const & error() const & noexcept { return m_error; } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 nsel_constexpr14 E && error() && noexcept { return std::move( m_error ); } constexpr E const && error() const && noexcept { return std::move( m_error ); } #endif // x.x.5.2.3 Observers - deprecated nsel_deprecated("replace value() with error()") nsel_constexpr14 E & value() & noexcept { return m_error; } nsel_deprecated("replace value() with error()") constexpr E const & value() const & noexcept { return m_error; } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 nsel_deprecated("replace value() with error()") nsel_constexpr14 E && value() && noexcept { return std::move( m_error ); } nsel_deprecated("replace value() with error()") constexpr E const && value() const && noexcept { return std::move( m_error ); } #endif // x.x.5.2.4 Swap template< typename U=E > nsel_REQUIRES_R( void, std17::is_swappable::value ) swap( unexpected_type & other ) noexcept ( std17::is_nothrow_swappable::value ) { using std::swap; swap( m_error, other.m_error ); } // TODO: ??? unexpected_type: in-class friend operator==, != private: error_type m_error; }; #if nsel_CPP17_OR_GREATER /// template deduction guide: template< typename E > unexpected_type( E ) -> unexpected_type< E >; #endif /// class unexpected_type, std::exception_ptr specialization (P0323R2) #if !nsel_CONFIG_NO_EXCEPTIONS #if nsel_P0323R <= 2 // TODO: Should expected be specialized for particular E types such as exception_ptr and how? // See p0323r7 2.1. Ergonomics, http://wg21.link/p0323 template<> class unexpected_type< std::exception_ptr > { public: using error_type = std::exception_ptr; unexpected_type() = delete; ~unexpected_type(){} explicit unexpected_type( std::exception_ptr const & error ) : m_error( error ) {} explicit unexpected_type(std::exception_ptr && error ) : m_error( std::move( error ) ) {} template< typename E > explicit unexpected_type( E error ) : m_error( std::make_exception_ptr( error ) ) {} std::exception_ptr const & value() const { return m_error; } std::exception_ptr & value() { return m_error; } private: std::exception_ptr m_error; }; #endif // nsel_P0323R #endif // !nsel_CONFIG_NO_EXCEPTIONS /// x.x.4, Unexpected equality operators template< typename E1, typename E2 > constexpr bool operator==( unexpected_type const & x, unexpected_type const & y ) { return x.error() == y.error(); } template< typename E1, typename E2 > constexpr bool operator!=( unexpected_type const & x, unexpected_type const & y ) { return ! ( x == y ); } #if nsel_P0323R <= 2 template< typename E > constexpr bool operator<( unexpected_type const & x, unexpected_type const & y ) { return x.error() < y.error(); } template< typename E > constexpr bool operator>( unexpected_type const & x, unexpected_type const & y ) { return ( y < x ); } template< typename E > constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) { return ! ( y < x ); } template< typename E > constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) { return ! ( x < y ); } #endif // nsel_P0323R /// x.x.5 Specialized algorithms template< typename E nsel_REQUIRES_T( std17::is_swappable::value ) > void swap( unexpected_type & x, unexpected_type & y) noexcept ( noexcept ( x.swap(y) ) ) { x.swap( y ); } #if nsel_P0323R <= 2 // unexpected: relational operators for std::exception_ptr: inline constexpr bool operator<( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) { return false; } inline constexpr bool operator>( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) { return false; } inline constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) { return ( x == y ); } inline constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) { return ( x == y ); } #endif // nsel_P0323R // unexpected: traits #if nsel_P0323R <= 3 template< typename E > struct is_unexpected : std::false_type {}; template< typename E > struct is_unexpected< unexpected_type > : std::true_type {}; #endif // nsel_P0323R // unexpected: factory // keep make_unexpected() removed in p0323r2 for pre-C++17: template< typename E > nsel_constexpr14 auto make_unexpected( E && value ) -> unexpected_type< typename std::decay::type > { return unexpected_type< typename std::decay::type >( std::forward(value) ); } template < typename E, typename... Args, typename = std::enable_if< std::is_constructible::value > > nsel_constexpr14 auto make_unexpected( nonstd_lite_in_place_t(E), Args &&... args ) -> unexpected_type< typename std::decay::type > { return std::move( unexpected_type< typename std::decay::type >( nonstd_lite_in_place(E), std::forward(args)...) ); } #if nsel_P0323R <= 3 /*nsel_constexpr14*/ auto inline make_unexpected_from_current_exception() -> unexpected_type< std::exception_ptr > { return unexpected_type< std::exception_ptr >( std::current_exception() ); } #endif // nsel_P0323R /// x.x.6, x.x.7 expected access error template< typename E > class nsel_NODISCARD bad_expected_access; /// x.x.7 bad_expected_access: expected access error template <> class nsel_NODISCARD bad_expected_access< void > : public std::exception { public: explicit bad_expected_access() : std::exception() {} }; /// x.x.6 bad_expected_access: expected access error #if !nsel_CONFIG_NO_EXCEPTIONS template< typename E > class nsel_NODISCARD bad_expected_access : public bad_expected_access< void > { public: using error_type = E; explicit bad_expected_access( error_type error ) : m_error( error ) {} virtual char const * what() const noexcept override { return "bad_expected_access"; } nsel_constexpr14 error_type & error() & { return m_error; } constexpr error_type const & error() const & { return m_error; } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 nsel_constexpr14 error_type && error() && { return std::move( m_error ); } constexpr error_type const && error() const && { return std::move( m_error ); } #endif private: error_type m_error; }; #endif // nsel_CONFIG_NO_EXCEPTIONS /// x.x.8 unexpect tag, in_place_unexpected tag: construct an error struct unexpect_t{}; using in_place_unexpected_t = unexpect_t; nsel_inline17 constexpr unexpect_t unexpect{}; nsel_inline17 constexpr unexpect_t in_place_unexpected{}; /// class error_traits #if nsel_CONFIG_NO_EXCEPTIONS namespace detail { inline bool text( char const * /*text*/ ) { return true; } } template< typename Error > struct error_traits { static void rethrow( Error const & /*e*/ ) { #if nsel_CONFIG_NO_EXCEPTIONS_SEH RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); #else assert( false && detail::text("throw bad_expected_access{ e };") ); #endif } }; template<> struct error_traits< std::exception_ptr > { static void rethrow( std::exception_ptr const & /*e*/ ) { #if nsel_CONFIG_NO_EXCEPTIONS_SEH RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); #else assert( false && detail::text("throw bad_expected_access{ e };") ); #endif } }; template<> struct error_traits< std::error_code > { static void rethrow( std::error_code const & /*e*/ ) { #if nsel_CONFIG_NO_EXCEPTIONS_SEH RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); #else assert( false && detail::text("throw std::system_error( e );") ); #endif } }; #else // nsel_CONFIG_NO_EXCEPTIONS template< typename Error > struct error_traits { static void rethrow( Error const & e ) { throw bad_expected_access{ e }; } }; template<> struct error_traits< std::exception_ptr > { static void rethrow( std::exception_ptr const & e ) { std::rethrow_exception( e ); } }; template<> struct error_traits< std::error_code > { static void rethrow( std::error_code const & e ) { throw std::system_error( e ); } }; #endif // nsel_CONFIG_NO_EXCEPTIONS #if nsel_P2505R >= 3 namespace detail { // from https://en.cppreference.com/w/cpp/utility/expected/unexpected: // "the type of the unexpected value. The type must not be an array type, a non-object type, a specialization of std::unexpected, or a cv-qualified type." template< typename T > struct valid_unexpected_type : std::integral_constant< bool, std::is_same< T, typename std20::remove_cvref< T >::type >::value && std::is_object< T >::value && !std::is_array< T >::value > {}; template< typename T > struct valid_unexpected_type< unexpected_type< T > > : std::false_type {}; } // namespace detail #endif // nsel_P2505R >= 3 } // namespace expected_lite // provide nonstd::unexpected_type: using expected_lite::unexpected_type; namespace expected_lite { /// class expected #if nsel_P0323R <= 2 template< typename T, typename E = std::exception_ptr > class nsel_NODISCARD expected #else template< typename T, typename E > class nsel_NODISCARD expected #endif // nsel_P0323R { private: template< typename, typename > friend class expected; public: using value_type = T; using error_type = E; using unexpected_type = nonstd::unexpected_type; template< typename U > struct rebind { using type = expected; }; // x.x.4.1 constructors nsel_REQUIRES_0( std::is_default_constructible::value ) nsel_constexpr14 expected() : contained( true ) { contained.construct_value(); } nsel_constexpr14 expected( expected const & ) = default; nsel_constexpr14 expected( expected && ) = default; template< typename U, typename G nsel_REQUIRES_T( std::is_constructible< T, U const &>::value && std::is_constructible::value && !std::is_constructible & >::value && !std::is_constructible && >::value && !std::is_constructible const & >::value && !std::is_constructible const && >::value && !std::is_convertible< expected & , T>::value && !std::is_convertible< expected &&, T>::value && !std::is_convertible< expected const & , T>::value && !std::is_convertible< expected const &&, T>::value && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ ) > nsel_constexpr14 explicit expected( expected const & other ) : contained( other.has_value() ) { if ( has_value() ) contained.construct_value( T{ other.contained.value() } ); else contained.construct_error( E{ other.contained.error() } ); } template< typename U, typename G nsel_REQUIRES_T( std::is_constructible< T, U const &>::value && std::is_constructible::value && !std::is_constructible & >::value && !std::is_constructible && >::value && !std::is_constructible const & >::value && !std::is_constructible const && >::value && !std::is_convertible< expected & , T>::value && !std::is_convertible< expected &&, T>::value && !std::is_convertible< expected const &, T>::value && !std::is_convertible< expected const &&, T>::value && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ ) > nsel_constexpr14 /*non-explicit*/ expected( expected const & other ) : contained( other.has_value() ) { if ( has_value() ) contained.construct_value( other.contained.value() ); else contained.construct_error( other.contained.error() ); } template< typename U, typename G nsel_REQUIRES_T( std::is_constructible< T, U>::value && std::is_constructible::value && !std::is_constructible & >::value && !std::is_constructible && >::value && !std::is_constructible const & >::value && !std::is_constructible const && >::value && !std::is_convertible< expected & , T>::value && !std::is_convertible< expected &&, T>::value && !std::is_convertible< expected const & , T>::value && !std::is_convertible< expected const &&, T>::value && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ ) > nsel_constexpr14 explicit expected( expected && other ) : contained( other.has_value() ) { if ( has_value() ) contained.construct_value( T{ std::move( other.contained.value() ) } ); else contained.construct_error( E{ std::move( other.contained.error() ) } ); } template< typename U, typename G nsel_REQUIRES_T( std::is_constructible< T, U>::value && std::is_constructible::value && !std::is_constructible & >::value && !std::is_constructible && >::value && !std::is_constructible const & >::value && !std::is_constructible const && >::value && !std::is_convertible< expected & , T>::value && !std::is_convertible< expected &&, T>::value && !std::is_convertible< expected const & , T>::value && !std::is_convertible< expected const &&, T>::value && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ ) > nsel_constexpr14 /*non-explicit*/ expected( expected && other ) : contained( other.has_value() ) { if ( has_value() ) contained.construct_value( std::move( other.contained.value() ) ); else contained.construct_error( std::move( other.contained.error() ) ); } template< typename U = T nsel_REQUIRES_T( std::is_copy_constructible::value ) > nsel_constexpr14 expected( value_type const & value ) : contained( true ) { contained.construct_value( value ); } template< typename U = T nsel_REQUIRES_T( std::is_constructible::value && !std::is_same::type, nonstd_lite_in_place_t(U)>::value && !std::is_same< expected , typename std20::remove_cvref::type>::value && !std::is_same, typename std20::remove_cvref::type>::value && !std::is_convertible::value /*=> explicit */ ) > nsel_constexpr14 explicit expected( U && value ) noexcept ( std::is_nothrow_move_constructible::value && std::is_nothrow_move_constructible::value ) : contained( true ) { contained.construct_value( T{ std::forward( value ) } ); } template< typename U = T nsel_REQUIRES_T( std::is_constructible::value && !std::is_same::type, nonstd_lite_in_place_t(U)>::value && !std::is_same< expected , typename std20::remove_cvref::type>::value && !std::is_same, typename std20::remove_cvref::type>::value && std::is_convertible::value /*=> non-explicit */ ) > nsel_constexpr14 /*non-explicit*/ expected( U && value ) noexcept ( std::is_nothrow_move_constructible::value && std::is_nothrow_move_constructible::value ) : contained( true ) { contained.construct_value( std::forward( value ) ); } // construct error: template< typename G = E nsel_REQUIRES_T( std::is_constructible::value && !std::is_convertible< G const &, E>::value /*=> explicit */ ) > nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) : contained( false ) { contained.construct_error( E{ error.error() } ); } template< typename G = E nsel_REQUIRES_T( std::is_constructible::value && std::is_convertible< G const &, E>::value /*=> non-explicit */ ) > nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) : contained( false ) { contained.construct_error( error.error() ); } template< typename G = E nsel_REQUIRES_T( std::is_constructible::value && !std::is_convertible< G&&, E>::value /*=> explicit */ ) > nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) : contained( false ) { contained.construct_error( E{ std::move( error.error() ) } ); } template< typename G = E nsel_REQUIRES_T( std::is_constructible::value && std::is_convertible< G&&, E>::value /*=> non-explicit */ ) > nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) : contained( false ) { contained.construct_error( std::move( error.error() ) ); } // in-place construction, value template< typename... Args nsel_REQUIRES_T( std::is_constructible::value ) > nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), Args&&... args ) : contained( true ) { contained.emplace_value( std::forward( args )... ); } template< typename U, typename... Args nsel_REQUIRES_T( std::is_constructible, Args&&...>::value ) > nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) : contained( true ) { contained.emplace_value( il, std::forward( args )... ); } // in-place construction, error template< typename... Args nsel_REQUIRES_T( std::is_constructible::value ) > nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) : contained( false ) { contained.emplace_error( std::forward( args )... ); } template< typename U, typename... Args nsel_REQUIRES_T( std::is_constructible, Args&&...>::value ) > nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) : contained( false ) { contained.emplace_error( il, std::forward( args )... ); } // x.x.4.2 destructor // TODO: ~expected: triviality // Effects: If T is not cv void and is_trivially_destructible_v is false and bool(*this), calls val.~T(). If is_trivially_destructible_v is false and !bool(*this), calls unexpect.~unexpected(). // Remarks: If either T is cv void or is_trivially_destructible_v is true, and is_trivially_destructible_v is true, then this destructor shall be a trivial destructor. ~expected() { if ( has_value() ) contained.destruct_value(); else contained.destruct_error(); } // x.x.4.3 assignment expected & operator=( expected const & other ) { expected( other ).swap( *this ); return *this; } expected & operator=( expected && other ) noexcept ( std::is_nothrow_move_constructible< T>::value && std::is_nothrow_move_assignable< T>::value && std::is_nothrow_move_constructible::value // added for missing && std::is_nothrow_move_assignable< E>::value ) // nothrow above { expected( std::move( other ) ).swap( *this ); return *this; } template< typename U nsel_REQUIRES_T( !std::is_same, typename std20::remove_cvref::type>::value && std17::conjunction, std::is_same> >::value && std::is_constructible::value && std::is_assignable< T&,U>::value && std::is_nothrow_move_constructible::value ) > expected & operator=( U && value ) { expected( std::forward( value ) ).swap( *this ); return *this; } template< typename G = E nsel_REQUIRES_T( std::is_constructible::value && std::is_copy_constructible::value // TODO: std::is_nothrow_copy_constructible && std::is_copy_assignable::value ) > expected & operator=( nonstd::unexpected_type const & error ) { expected( unexpect, error.error() ).swap( *this ); return *this; } template< typename G = E nsel_REQUIRES_T( std::is_constructible::value && std::is_move_constructible::value // TODO: std::is_nothrow_move_constructible && std::is_move_assignable::value ) > expected & operator=( nonstd::unexpected_type && error ) { expected( unexpect, std::move( error.error() ) ).swap( *this ); return *this; } template< typename... Args nsel_REQUIRES_T( std::is_nothrow_constructible::value ) > value_type & emplace( Args &&... args ) { expected( nonstd_lite_in_place(T), std::forward(args)... ).swap( *this ); return value(); } template< typename U, typename... Args nsel_REQUIRES_T( std::is_nothrow_constructible&, Args&&...>::value ) > value_type & emplace( std::initializer_list il, Args &&... args ) { expected( nonstd_lite_in_place(T), il, std::forward(args)... ).swap( *this ); return value(); } // x.x.4.4 swap template< typename U=T, typename G=E > nsel_REQUIRES_R( void, std17::is_swappable< U>::value && std17::is_swappable::value && ( std::is_move_constructible::value || std::is_move_constructible::value ) ) swap( expected & other ) noexcept ( std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value ) { using std::swap; if ( bool(*this) && bool(other) ) { swap( contained.value(), other.contained.value() ); } else if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); } else if ( bool(*this) && ! bool(other) ) { error_type t( std::move( other.error() ) ); other.contained.destruct_error(); other.contained.construct_value( std::move( contained.value() ) ); contained.destruct_value(); contained.construct_error( std::move( t ) ); bool has_value = contained.has_value(); bool other_has_value = other.has_value(); other.contained.set_has_value(has_value); contained.set_has_value(other_has_value); } else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); } } // x.x.4.5 observers constexpr value_type const * operator ->() const { return assert( has_value() ), contained.value_ptr(); } value_type * operator ->() { return assert( has_value() ), contained.value_ptr(); } constexpr value_type const & operator *() const & { return assert( has_value() ), contained.value(); } value_type & operator *() & { return assert( has_value() ), contained.value(); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 constexpr value_type const && operator *() const && { return std::move( ( assert( has_value() ), contained.value() ) ); } nsel_constexpr14 value_type && operator *() && { return std::move( ( assert( has_value() ), contained.value() ) ); } #endif constexpr explicit operator bool() const noexcept { return has_value(); } constexpr bool has_value() const noexcept { return contained.has_value(); } nsel_DISABLE_MSVC_WARNINGS( 4702 ) // warning C4702: unreachable code, see issue 65. constexpr value_type const & value() const & { return has_value() ? ( contained.value() ) : ( error_traits::rethrow( contained.error() ), contained.value() ); } value_type & value() & { return has_value() ? ( contained.value() ) : ( error_traits::rethrow( contained.error() ), contained.value() ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 constexpr value_type const && value() const && { return std::move( has_value() ? ( contained.value() ) : ( error_traits::rethrow( contained.error() ), contained.value() ) ); } nsel_constexpr14 value_type && value() && { return std::move( has_value() ? ( contained.value() ) : ( error_traits::rethrow( contained.error() ), contained.value() ) ); } #endif nsel_RESTORE_MSVC_WARNINGS() constexpr error_type const & error() const & { return assert( ! has_value() ), contained.error(); } error_type & error() & { return assert( ! has_value() ), contained.error(); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 constexpr error_type const && error() const && { return std::move( ( assert( ! has_value() ), contained.error() ) ); } error_type && error() && { return std::move( ( assert( ! has_value() ), contained.error() ) ); } #endif constexpr unexpected_type get_unexpected() const { return make_unexpected( contained.error() ); } template< typename Ex > bool has_exception() const { using ContainedEx = typename std::remove_reference< decltype( get_unexpected().error() ) >::type; return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; } template< typename U nsel_REQUIRES_T( std::is_copy_constructible< T>::value && std::is_convertible::value ) > value_type value_or( U && v ) const & { return has_value() ? contained.value() : static_cast( std::forward( v ) ); } template< typename U nsel_REQUIRES_T( std::is_move_constructible< T>::value && std::is_convertible::value ) > value_type value_or( U && v ) && { return has_value() ? std::move( contained.value() ) : static_cast( std::forward( v ) ); } #if nsel_P2505R >= 4 template< typename G = E nsel_REQUIRES_T( std::is_copy_constructible< E >::value && std::is_convertible< G, E >::value ) > nsel_constexpr error_type error_or( G && e ) const & { return has_value() ? static_cast< E >( std::forward< G >( e ) ) : contained.error(); } template< typename G = E nsel_REQUIRES_T( std::is_move_constructible< E >::value && std::is_convertible< G, E >::value ) > nsel_constexpr14 error_type error_or( G && e ) && { return has_value() ? static_cast< E >( std::forward< G >( e ) ) : std::move( contained.error() ); } #endif // nsel_P2505R >= 4 #if nsel_P2505R >= 3 // Monadic operations (P2505) template< typename F nsel_REQUIRES_T( detail::is_expected < detail::invoke_result_nocvref_t< F, value_type & > > ::value && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type & >::error_type, error_type >::value && std::is_constructible< error_type, error_type & >::value ) > nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type & > and_then( F && f ) & { return has_value() ? detail::invoke_result_nocvref_t< F, value_type & >( detail::invoke( std::forward< F >( f ), value() ) ) : detail::invoke_result_nocvref_t< F, value_type & >( unexpect, error() ); } template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value && std::is_constructible< error_type, const error_type & >::value ) > nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type & > and_then( F && f ) const & { return has_value() ? detail::invoke_result_nocvref_t< F, const value_type & >( detail::invoke( std::forward< F >( f ), value() ) ) : detail::invoke_result_nocvref_t< F, const value_type & >( unexpect, error() ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type && >::error_type, error_type >::value && std::is_constructible< error_type, error_type && >::value ) > nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type && > and_then( F && f ) && { return has_value() ? detail::invoke_result_nocvref_t< F, value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) ) : detail::invoke_result_nocvref_t< F, value_type && >( unexpect, std::move( error() ) ); } template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value && std::is_constructible< error_type, const error_type && >::value ) > nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type && > and_then( F && f ) const && { return has_value() ? detail::invoke_result_nocvref_t< F, const value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) ) : detail::invoke_result_nocvref_t< F, const value_type && >( unexpect, std::move( error() ) ); } #endif template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type, value_type >::value && std::is_constructible< value_type, value_type & >::value ) > nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) & { return has_value() ? detail::invoke_result_nocvref_t< F, error_type & >( value() ) : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); } template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type, value_type >::value && std::is_constructible< value_type, const value_type & >::value ) > nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const & { return has_value() ? detail::invoke_result_nocvref_t< F, const error_type & >( value() ) : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type, value_type >::value && std::is_constructible< value_type, value_type && >::value ) > nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) && { return has_value() ? detail::invoke_result_nocvref_t< F, error_type && >( std::move( value() ) ) : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); } template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type, value_type >::value && std::is_constructible< value_type, const value_type && >::value ) > nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const && { return has_value() ? detail::invoke_result_nocvref_t< F, const error_type && >( std::move( value() ) ) : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); } #endif template::value && !std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type & > >::value ) > nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type & >, error_type > transform( F && f ) & { return has_value() ? expected< detail::transform_invoke_result_t< F, value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) ) : make_unexpected( error() ); } template::value && std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value ) > nsel_constexpr14 expected< void, error_type > transform( F && f ) & { return has_value() ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) : make_unexpected( error() ); } template::value && !std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type & > >::value ) > nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type & >, error_type > transform( F && f ) const & { return has_value() ? expected< detail::transform_invoke_result_t< F, const value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) ) : make_unexpected( error() ); } template::value && std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value ) > nsel_constexpr expected< void, error_type > transform( F && f ) const & { return has_value() ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) : make_unexpected( error() ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 template::value && !std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type && > >::value ) > nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type && >, error_type > transform( F && f ) && { return has_value() ? expected< detail::transform_invoke_result_t< F, value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) ) : make_unexpected( std::move( error() ) ); } template::value && std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value ) > nsel_constexpr14 expected< void, error_type > transform( F && f ) && { return has_value() ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) : make_unexpected( std::move( error() ) ); } template::value && !std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type && > >::value ) > nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type && >, error_type > transform( F && f ) const && { return has_value() ? expected< detail::transform_invoke_result_t< F, const value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) ) : make_unexpected( std::move( error() ) ); } template::value && std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value ) > nsel_constexpr expected< void, error_type > transform( F && f ) const && { return has_value() ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) : make_unexpected( std::move( error() ) ); } #endif template >::value && std::is_constructible< value_type, value_type & >::value ) > nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) & { return has_value() ? expected< value_type, detail::transform_invoke_result_t< F, error_type & > >( in_place, **this ) : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); } template >::value && std::is_constructible< value_type, const value_type & >::value ) > nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const & { return has_value() ? expected< value_type, detail::transform_invoke_result_t< F, const error_type & > >( in_place, **this ) : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 template >::value && std::is_constructible< value_type, value_type && >::value ) > nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) && { return has_value() ? expected< value_type, detail::transform_invoke_result_t< F, error_type && > >( in_place, std::move( **this ) ) : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); } template >::value && std::is_constructible< value_type, const value_type && >::value ) > nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const && { return has_value() ? expected< value_type, detail::transform_invoke_result_t< F, const error_type && > >( in_place, std::move( **this ) ) : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); } #endif #endif // nsel_P2505R >= 3 // unwrap() // template // constexpr expected expected,E>::unwrap() const&; // template // constexpr expected expected::unwrap() const&; // template // expected expected, E>::unwrap() &&; // template // template expected expected::unwrap() &&; // factories // template< typename Ex, typename F> // expected catch_exception(F&& f); // template< typename F> // expected())),E> map(F&& func) ; // template< typename F> // 'see below' bind(F&& func); // template< typename F> // expected catch_error(F&& f); // template< typename F> // 'see below' then(F&& func); private: detail::storage_t < T ,E , std::is_copy_constructible::value && std::is_copy_constructible::value , std::is_move_constructible::value && std::is_move_constructible::value > contained; }; /// class expected, void specialization template< typename E > class nsel_NODISCARD expected< void, E > { private: template< typename, typename > friend class expected; public: using value_type = void; using error_type = E; using unexpected_type = nonstd::unexpected_type; // x.x.4.1 constructors constexpr expected() noexcept : contained( true ) {} nsel_constexpr14 expected( expected const & other ) = default; nsel_constexpr14 expected( expected && other ) = default; constexpr explicit expected( nonstd_lite_in_place_t(void) ) : contained( true ) {} template< typename G = E nsel_REQUIRES_T( !std::is_convertible::value /*=> explicit */ ) > nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) : contained( false ) { contained.construct_error( E{ error.error() } ); } template< typename G = E nsel_REQUIRES_T( std::is_convertible::value /*=> non-explicit */ ) > nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) : contained( false ) { contained.construct_error( error.error() ); } template< typename G = E nsel_REQUIRES_T( !std::is_convertible::value /*=> explicit */ ) > nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) : contained( false ) { contained.construct_error( E{ std::move( error.error() ) } ); } template< typename G = E nsel_REQUIRES_T( std::is_convertible::value /*=> non-explicit */ ) > nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) : contained( false ) { contained.construct_error( std::move( error.error() ) ); } template< typename... Args nsel_REQUIRES_T( std::is_constructible::value ) > nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) : contained( false ) { contained.emplace_error( std::forward( args )... ); } template< typename U, typename... Args nsel_REQUIRES_T( std::is_constructible, Args&&...>::value ) > nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) : contained( false ) { contained.emplace_error( il, std::forward( args )... ); } // destructor ~expected() { if ( ! has_value() ) { contained.destruct_error(); } } // x.x.4.3 assignment expected & operator=( expected const & other ) { expected( other ).swap( *this ); return *this; } expected & operator=( expected && other ) noexcept ( std::is_nothrow_move_assignable::value && std::is_nothrow_move_constructible::value ) { expected( std::move( other ) ).swap( *this ); return *this; } void emplace() { expected().swap( *this ); } // x.x.4.4 swap template< typename G = E > nsel_REQUIRES_R( void, std17::is_swappable::value && std::is_move_constructible::value ) swap( expected & other ) noexcept ( std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value ) { using std::swap; if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); } else if ( bool(*this) && ! bool(other) ) { contained.construct_error( std::move( other.error() ) ); bool has_value = contained.has_value(); bool other_has_value = other.has_value(); other.contained.set_has_value(has_value); contained.set_has_value(other_has_value); } else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); } } // x.x.4.5 observers constexpr explicit operator bool() const noexcept { return has_value(); } constexpr bool has_value() const noexcept { return contained.has_value(); } void value() const { if ( ! has_value() ) { error_traits::rethrow( contained.error() ); } } constexpr error_type const & error() const & { return assert( ! has_value() ), contained.error(); } error_type & error() & { return assert( ! has_value() ), contained.error(); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 constexpr error_type const && error() const && { return std::move( ( assert( ! has_value() ), contained.error() ) ); } error_type && error() && { return std::move( ( assert( ! has_value() ), contained.error() ) ); } #endif constexpr unexpected_type get_unexpected() const { return make_unexpected( contained.error() ); } template< typename Ex > bool has_exception() const { using ContainedEx = typename std::remove_reference< decltype( get_unexpected().error() ) >::type; return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; } #if nsel_P2505R >= 4 template< typename G = E nsel_REQUIRES_T( std::is_copy_constructible< E >::value && std::is_convertible< G, E >::value ) > nsel_constexpr error_type error_or( G && e ) const & { return has_value() ? static_cast< E >( std::forward< G >( e ) ) : contained.error(); } template< typename G = E nsel_REQUIRES_T( std::is_move_constructible< E >::value && std::is_convertible< G, E >::value ) > nsel_constexpr14 error_type error_or( G && e ) && { return has_value() ? static_cast< E >( std::forward< G >( e ) ) : std::move( contained.error() ); } #endif // nsel_P2505R >= 4 #if nsel_P2505R >= 3 // Monadic operations (P2505) template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value && std::is_constructible< error_type, error_type & >::value ) > nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) & { return has_value() ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) : detail::invoke_result_nocvref_t< F >( unexpect, error() ); } template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value && std::is_constructible< error_type, const error_type & >::value ) > nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const & { return has_value() ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) : detail::invoke_result_nocvref_t< F >( unexpect, error() ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value && std::is_constructible< error_type, error_type && >::value ) > nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) && { return has_value() ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) ); } template >::value && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value && std::is_constructible< error_type, const error_type && >::value ) > nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const && { return has_value() ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) ); } #endif template >::value && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type >::value ) > nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) & { return has_value() ? detail::invoke_result_nocvref_t< F, error_type & >() : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); } template >::value && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type >::value ) > nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const & { return has_value() ? detail::invoke_result_nocvref_t< F, const error_type & >() : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 template >::value && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type >::value ) > nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) && { return has_value() ? detail::invoke_result_nocvref_t< F, error_type && >() : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); } template >::value && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type >::value ) > nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const && { return has_value() ? detail::invoke_result_nocvref_t< F, const error_type && >() : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); } #endif template::value && !std::is_void< detail::transform_invoke_result_t< F > >::value ) > nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) & { return has_value() ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) : make_unexpected( error() ); } template::value && std::is_void< detail::transform_invoke_result_t< F > >::value ) > nsel_constexpr14 expected< void, error_type > transform( F && f ) & { return has_value() ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) : make_unexpected( error() ); } template::value && !std::is_void< detail::transform_invoke_result_t< F > >::value ) > nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const & { return has_value() ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) : make_unexpected( error() ); } template::value && std::is_void< detail::transform_invoke_result_t< F > >::value ) > nsel_constexpr expected< void, error_type > transform( F && f ) const & { return has_value() ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) : make_unexpected( error() ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 template::value && !std::is_void< detail::transform_invoke_result_t< F > >::value ) > nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) && { return has_value() ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) : make_unexpected( error() ); } template::value && std::is_void< detail::transform_invoke_result_t< F > >::value ) > nsel_constexpr14 expected< void, error_type > transform( F && f ) && { return has_value() ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) : make_unexpected( error() ); } template::value && !std::is_void< detail::transform_invoke_result_t< F > >::value ) > nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const && { return has_value() ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) : make_unexpected( error() ); } template::value && std::is_void< detail::transform_invoke_result_t< F > >::value ) > nsel_constexpr expected< void, error_type > transform( F && f ) const && { return has_value() ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) : make_unexpected( error() ); } #endif template >::value ) > nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) & { return has_value() ? expected< void, detail::transform_invoke_result_t< F, error_type & > >() : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); } template >::value ) > nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const & { return has_value() ? expected< void, detail::transform_invoke_result_t< F, const error_type & > >() : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 template >::value ) > nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) && { return has_value() ? expected< void, detail::transform_invoke_result_t< F, error_type && > >() : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); } template >::value ) > nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const && { return has_value() ? expected< void, detail::transform_invoke_result_t< F, const error_type && > >() : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); } #endif #endif // nsel_P2505R >= 3 // template constexpr 'see below' unwrap() const&; // // template 'see below' unwrap() &&; // factories // template< typename Ex, typename F> // expected catch_exception(F&& f); // // template< typename F> // expected map(F&& func) ; // // template< typename F> // 'see below' bind(F&& func) ; // // template< typename F> // expected catch_error(F&& f); // // template< typename F> // 'see below' then(F&& func); private: detail::storage_t < void , E , std::is_copy_constructible::value , std::is_move_constructible::value > contained; }; // x.x.4.6 expected<>: comparison operators template< typename T1, typename E1, typename T2, typename E2 nsel_REQUIRES_T( !std::is_void::value && !std::is_void::value ) > constexpr bool operator==( expected const & x, expected const & y ) { return bool(x) != bool(y) ? false : bool(x) ? *x == *y : x.error() == y.error(); } template< typename T1, typename E1, typename T2, typename E2 nsel_REQUIRES_T( std::is_void::value && std::is_void::value ) > constexpr bool operator==( expected const & x, expected const & y ) { return bool(x) != bool(y) ? false : bool(x) || static_cast( x.error() == y.error() ); } template< typename T1, typename E1, typename T2, typename E2 > constexpr bool operator!=( expected const & x, expected const & y ) { return !(x == y); } #if nsel_P0323R <= 2 template< typename T, typename E > constexpr bool operator<( expected const & x, expected const & y ) { return (!y) ? false : (!x) ? true : *x < *y; } template< typename T, typename E > constexpr bool operator>( expected const & x, expected const & y ) { return (y < x); } template< typename T, typename E > constexpr bool operator<=( expected const & x, expected const & y ) { return !(y < x); } template< typename T, typename E > constexpr bool operator>=( expected const & x, expected const & y ) { return !(x < y); } #endif // x.x.4.7 expected: comparison with T template< typename T1, typename E1, typename T2 nsel_REQUIRES_T( !std::is_void::value ) > constexpr bool operator==( expected const & x, T2 const & v ) { return bool(x) ? *x == v : false; } template< typename T1, typename E1, typename T2 nsel_REQUIRES_T( !std::is_void::value ) > constexpr bool operator==(T2 const & v, expected const & x ) { return bool(x) ? v == *x : false; } template< typename T1, typename E1, typename T2 > constexpr bool operator!=( expected const & x, T2 const & v ) { return bool(x) ? *x != v : true; } template< typename T1, typename E1, typename T2 > constexpr bool operator!=( T2 const & v, expected const & x ) { return bool(x) ? v != *x : true; } #if nsel_P0323R <= 2 template< typename T, typename E > constexpr bool operator<( expected const & x, T const & v ) { return bool(x) ? *x < v : true; } template< typename T, typename E > constexpr bool operator<( T const & v, expected const & x ) { return bool(x) ? v < *x : false; } template< typename T, typename E > constexpr bool operator>( T const & v, expected const & x ) { return bool(x) ? *x < v : false; } template< typename T, typename E > constexpr bool operator>( expected const & x, T const & v ) { return bool(x) ? v < *x : false; } template< typename T, typename E > constexpr bool operator<=( T const & v, expected const & x ) { return bool(x) ? ! ( *x < v ) : false; } template< typename T, typename E > constexpr bool operator<=( expected const & x, T const & v ) { return bool(x) ? ! ( v < *x ) : true; } template< typename T, typename E > constexpr bool operator>=( expected const & x, T const & v ) { return bool(x) ? ! ( *x < v ) : false; } template< typename T, typename E > constexpr bool operator>=( T const & v, expected const & x ) { return bool(x) ? ! ( v < *x ) : true; } #endif // nsel_P0323R // x.x.4.8 expected: comparison with unexpected_type template< typename T1, typename E1 , typename E2 > constexpr bool operator==( expected const & x, unexpected_type const & u ) { return (!x) ? x.get_unexpected() == u : false; } template< typename T1, typename E1 , typename E2 > constexpr bool operator==( unexpected_type const & u, expected const & x ) { return ( x == u ); } template< typename T1, typename E1 , typename E2 > constexpr bool operator!=( expected const & x, unexpected_type const & u ) { return ! ( x == u ); } template< typename T1, typename E1 , typename E2 > constexpr bool operator!=( unexpected_type const & u, expected const & x ) { return ! ( x == u ); } #if nsel_P0323R <= 2 template< typename T, typename E > constexpr bool operator<( expected const & x, unexpected_type const & u ) { return (!x) ? ( x.get_unexpected() < u ) : false; } template< typename T, typename E > constexpr bool operator<( unexpected_type const & u, expected const & x ) { return (!x) ? ( u < x.get_unexpected() ) : true ; } template< typename T, typename E > constexpr bool operator>( expected const & x, unexpected_type const & u ) { return ( u < x ); } template< typename T, typename E > constexpr bool operator>( unexpected_type const & u, expected const & x ) { return ( x < u ); } template< typename T, typename E > constexpr bool operator<=( expected const & x, unexpected_type const & u ) { return ! ( u < x ); } template< typename T, typename E > constexpr bool operator<=( unexpected_type const & u, expected const & x) { return ! ( x < u ); } template< typename T, typename E > constexpr bool operator>=( expected const & x, unexpected_type const & u ) { return ! ( u > x ); } template< typename T, typename E > constexpr bool operator>=( unexpected_type const & u, expected const & x ) { return ! ( x > u ); } #endif // nsel_P0323R /// x.x.x Specialized algorithms template< typename T, typename E nsel_REQUIRES_T( ( std::is_void::value || std::is_move_constructible::value ) && std::is_move_constructible::value && std17::is_swappable::value && std17::is_swappable::value ) > void swap( expected & x, expected & y ) noexcept ( noexcept ( x.swap(y) ) ) { x.swap( y ); } #if nsel_P0323R <= 3 template< typename T > constexpr auto make_expected( T && v ) -> expected< typename std::decay::type > { return expected< typename std::decay::type >( std::forward( v ) ); } // expected specialization: auto inline make_expected() -> expected { return expected( in_place ); } template< typename T > constexpr auto make_expected_from_current_exception() -> expected { return expected( make_unexpected_from_current_exception() ); } template< typename T > auto make_expected_from_exception( std::exception_ptr v ) -> expected { return expected( unexpected_type( std::forward( v ) ) ); } template< typename T, typename E > constexpr auto make_expected_from_error( E e ) -> expected::type> { return expected::type>( make_unexpected( e ) ); } template< typename F nsel_REQUIRES_T( ! std::is_same::type, void>::value ) > /*nsel_constexpr14*/ auto make_expected_from_call( F f ) -> expected< typename std::result_of::type > { try { return make_expected( f() ); } catch (...) { return make_unexpected_from_current_exception(); } } template< typename F nsel_REQUIRES_T( std::is_same::type, void>::value ) > /*nsel_constexpr14*/ auto make_expected_from_call( F f ) -> expected { try { f(); return make_expected(); } catch (...) { return make_unexpected_from_current_exception(); } } #endif // nsel_P0323R } // namespace expected_lite using namespace expected_lite; // using expected_lite::expected; // using ... } // namespace nonstd namespace std { // expected: hash support template< typename T, typename E > struct hash< nonstd::expected > { using result_type = std::size_t; using argument_type = nonstd::expected; constexpr result_type operator()(argument_type const & arg) const { return arg ? std::hash{}(*arg) : result_type{}; } }; // TBD - ?? remove? see spec. template< typename T, typename E > struct hash< nonstd::expected > { using result_type = std::size_t; using argument_type = nonstd::expected; constexpr result_type operator()(argument_type const & arg) const { return arg ? std::hash{}(*arg) : result_type{}; } }; // TBD - implement // bool(e), hash>()(e) shall evaluate to the hashing true; // otherwise it evaluates to an unspecified value if E is exception_ptr or // a combination of hashing false and hash()(e.error()). template< typename E > struct hash< nonstd::expected > { }; } // namespace std namespace nonstd { // void unexpected() is deprecated && removed in C++17 #if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141 template< typename E > using unexpected = unexpected_type; #endif } // namespace nonstd #undef nsel_REQUIRES #undef nsel_REQUIRES_0 #undef nsel_REQUIRES_T nsel_RESTORE_WARNINGS() #endif // nsel_USES_STD_EXPECTED #endif // NONSTD_EXPECTED_LITE_HPP expected-lite-0.10.0/project/000077500000000000000000000000001510672106500157755ustar00rootroot00000000000000expected-lite-0.10.0/project/CodeBlocks/000077500000000000000000000000001510672106500200055ustar00rootroot00000000000000expected-lite-0.10.0/project/CodeBlocks/expected-lite.cbp000066400000000000000000000042131510672106500232270ustar00rootroot00000000000000 expected-lite-0.10.0/project/CodeBlocks/expected-lite.workspace000066400000000000000000000006261510672106500244650ustar00rootroot00000000000000 expected-lite-0.10.0/script/000077500000000000000000000000001510672106500156335ustar00rootroot00000000000000expected-lite-0.10.0/script/create-cov-rpt.py000066400000000000000000000060511510672106500210420ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2019-2019 by Martin Moene # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # # script/create-cov-rpt.py, Python 3.4 and later # import argparse import os import re import sys import subprocess # Configuration: cfg_github_project = 'expected-lite' cfg_github_user = 'martinmoene' cfg_prj_folder_level = 3 tpl_coverage_cmd = 'opencppcoverage --no_aggregate_by_file --sources {src} -- {exe}' # End configuration. def project_folder( f, args ): """Project root""" if args.prj_folder: return args.prj_folder return os.path.normpath( os.path.join( os.path.dirname( os.path.abspath(f) ), '../' * args.prj_folder_level ) ) def executable_folder( f ): """Folder where the xecutable is""" return os.path.dirname( os.path.abspath(f) ) def executable_name( f ): """Folder where the executable is""" return os.path.basename( f ) def createCoverageReport( f, args ): print( "Creating coverage report for project '{usr}/{prj}', '{file}':". format( usr=args.user, prj=args.project, file=f ) ) cmd = tpl_coverage_cmd.format( folder=executable_folder(f), src=project_folder(f, args), exe=executable_name(f) ) if args.verbose: print( "> {}".format(cmd) ) if not args.dry_run: os.chdir( executable_folder(f) ) subprocess.call( cmd, shell=False ) os.chdir( project_folder(f, args) ) def createCoverageReports( args ): for f in args.executable: createCoverageReport( f, args ) def createCoverageReportFromCommandLine(): """Collect arguments from the commandline and create coverage report.""" parser = argparse.ArgumentParser( description='Create coverage report.', epilog="""""", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( 'executable', metavar='executable', type=str, nargs=1, help='executable to report on') parser.add_argument( '-n', '--dry-run', action='store_true', help='do not execute conan commands') parser.add_argument( '-v', '--verbose', action='count', default=0, help='level of progress reporting') parser.add_argument( '--user', metavar='u', type=str, default=cfg_github_user, help='github user name') parser.add_argument( '--project', metavar='p', type=str, default=cfg_github_project, help='github project name') parser.add_argument( '--prj-folder', metavar='f', type=str, default=None, help='project root folder') parser.add_argument( '--prj-folder-level', metavar='n', type=int, default=cfg_prj_folder_level, help='project root folder level from executable') createCoverageReports( parser.parse_args() ) if __name__ == '__main__': createCoverageReportFromCommandLine() # end of file expected-lite-0.10.0/script/create-vcpkg.py000066400000000000000000000140261510672106500205630ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2019-2019 by Martin Moene # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # # script/upload-conan.py, Python 3.4 and later # import argparse import os import re import sys import subprocess # Configuration: cfg_github_project = 'expected-lite' cfg_github_user = 'martinmoene' cfg_description = '(unused)' cfg_cmakelists = 'CMakeLists.txt' cfg_readme = 'Readme.md' cfg_license = 'LICENSE.txt' cfg_ref_prefix = 'v' cfg_sha512 = 'dadeda' cfg_vcpkg_description = '(no description found)' cfg_vcpkg_root = os.environ['VCPKG_ROOT'] cfg_cmake_optpfx = "EXPECTED_LITE" # End configuration. # vcpkg control and port templates: tpl_path_vcpkg_control = '{vcpkg}/ports/{prj}/CONTROL' tpl_path_vcpkg_portfile = '{vcpkg}/ports/{prj}/portfile.cmake' tpl_vcpkg_control =\ """Source: {prj} Version: {ver} Description: {desc}""" tpl_vcpkg_portfile =\ """include(vcpkg_common_functions) vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO {usr}/{prj} REF {ref} SHA512 {sha} ) vcpkg_configure_cmake( SOURCE_PATH ${{SOURCE_PATH}} PREFER_NINJA OPTIONS -D{optpfx}_OPT_BUILD_TESTS=OFF -D{optpfx}_OPT_BUILD_EXAMPLES=OFF ) vcpkg_install_cmake() vcpkg_fixup_cmake_targets( CONFIG_PATH lib/cmake/${{PORT}} ) file(REMOVE_RECURSE ${{CURRENT_PACKAGES_DIR}}/debug ${{CURRENT_PACKAGES_DIR}}/lib ) file(INSTALL ${{SOURCE_PATH}}/{lic} DESTINATION ${{CURRENT_PACKAGES_DIR}}/share/${{PORT}} RENAME copyright )""" tpl_vcpkg_note_sha =\ """ Next actions: - Obtain package SHA: 'vcpkg install {prj}', copy SHA mentioned in 'Actual hash: [...]' - Add SHA to package: 'script\create-vcpkg --sha={sha}' - Install package : 'vcpkg install {prj}'""" tpl_vcpkg_note_install =\ """ Next actions: - Install package: 'vcpkg install {prj}'""" # End of vcpkg templates def versionFrom( filename ): """Obtain version from CMakeLists.txt""" with open( filename, 'r' ) as f: content = f.read() version = re.search(r'VERSION\s(\d+\.\d+\.\d+)', content).group(1) return version def descriptionFrom( filename ): """Obtain description from CMakeLists.txt""" with open( filename, 'r' ) as f: content = f.read() description = re.search(r'DESCRIPTION\s"(.*)"', content).group(1) return description if description else cfg_vcpkg_description def vcpkgRootFrom( path ): return path if path else './vcpkg' def to_ref( version ): """Add prefix to version/tag, like v1.2.3""" return cfg_ref_prefix + version def control_path( args ): """Create path like vcpks/ports/_project_/CONTROL""" return tpl_path_vcpkg_control.format( vcpkg=args.vcpkg_root, prj=args.project ) def portfile_path( args ): """Create path like vcpks/ports/_project_/portfile.cmake""" return tpl_path_vcpkg_portfile.format( vcpkg=args.vcpkg_root, prj=args.project ) def createControl( args ): """Create vcpkg CONTROL file""" output = tpl_vcpkg_control.format( prj=args.project, ver=args.version, desc=args.description ) if args.verbose: print( "Creating control file '{f}':".format( f=control_path( args ) ) ) if args.verbose > 1: print( output ) os.makedirs( os.path.dirname( control_path( args ) ), exist_ok=True ) with open( control_path( args ), 'w') as f: print( output, file=f ) def createPortfile( args ): """Create vcpkg portfile""" output = tpl_vcpkg_portfile.format( optpfx=cfg_cmake_optpfx, usr=args.user, prj=args.project, ref=to_ref(args.version), sha=args.sha, lic=cfg_license ) if args.verbose: print( "Creating portfile '{f}':".format( f=portfile_path( args ) ) ) if args.verbose > 1: print( output ) os.makedirs( os.path.dirname( portfile_path( args ) ), exist_ok=True ) with open( portfile_path( args ), 'w') as f: print( output, file=f ) def printNotes( args ): if args.sha == cfg_sha512: print( tpl_vcpkg_note_sha. format( prj=args.project, sha='...' ) ) else: print( tpl_vcpkg_note_install. format( prj=args.project ) ) def createVcpkg( args ): print( "Creating vcpkg for '{usr}/{prj}', version '{ver}' in folder '{vcpkg}':". format( usr=args.user, prj=args.project, ver=args.version, vcpkg=args.vcpkg_root, ) ) createControl( args ) createPortfile( args ) printNotes( args ) def createVcpkgFromCommandLine(): """Collect arguments from the commandline and create vcpkg.""" parser = argparse.ArgumentParser( description='Create microsoft vcpkg.', epilog="""""", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( '-v', '--verbose', action='count', default=0, help='level of progress reporting') parser.add_argument( '--user', metavar='u', type=str, default=cfg_github_user, help='github user name') parser.add_argument( '--project', metavar='p', type=str, default=cfg_github_project, help='github project name') parser.add_argument( '--description', metavar='d', type=str, # default=cfg_description, default=descriptionFrom( cfg_cmakelists ), help='vcpkg description [from ' + cfg_cmakelists + ']') parser.add_argument( '--version', metavar='v', type=str, default=versionFrom( cfg_cmakelists ), help='version number [from ' + cfg_cmakelists + ']') parser.add_argument( '--sha', metavar='s', type=str, default=cfg_sha512, help='sha of package') parser.add_argument( '--vcpkg-root', metavar='r', type=str, default=vcpkgRootFrom( cfg_vcpkg_root ), help='parent folder containing ports to write files to') createVcpkg( parser.parse_args() ) if __name__ == '__main__': createVcpkgFromCommandLine() # end of file expected-lite-0.10.0/script/update-version.py000066400000000000000000000074451510672106500211640ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2017-2018 by Martin Moene # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # # script/update-version.py # from __future__ import print_function import argparse import os import re import sys # Configuration: table = ( # path, substitute find, substitute format ( 'CMakeLists.txt' , r'\W{2,4}VERSION\W+([0-9]+\.[0-9]+\.[0-9]+)\W*$' , ' VERSION {major}.{minor}.{patch}' ) , ( 'CMakeLists.txt' , r'set\W+expected_lite_version\W+"([0-9]+\.[0-9]+\.[0-9]+)"\W+$' , 'set( expected_lite_version "{major}.{minor}.{patch}" )\n' ) # , ( 'example/cmake-pkg/CMakeLists.txt' # , r'set\W+expected_lite_version\W+"([0-9]+\.[0-9]+(\.[0-9]+)?)"\W+$' # , 'set( expected_lite_version "{major}.{minor}" )\n' ) # # , ( 'script/install-xxx-pkg.py' # , r'\expected_lite_version\s+=\s+"([0-9]+\.[0-9]+\.[0-9]+)"\s*$' # , 'expected_lite_version = "{major}.{minor}.{patch}"\n' ) , ( 'conanfile.py' , r'version\s+=\s+"([0-9]+\.[0-9]+\.[0-9]+)"\s*$' , 'version = "{major}.{minor}.{patch}"' ) , ( 'include/nonstd/expected.hpp' , r'\#define\s+expected_lite_MAJOR\s+[0-9]+\s*$' , '#define expected_lite_MAJOR {major}' ) , ( 'include/nonstd/expected.hpp' , r'\#define\s+expected_lite_MINOR\s+[0-9]+\s*$' , '#define expected_lite_MINOR {minor}' ) , ( 'include/nonstd/expected.hpp' , r'\#define\s+expected_lite_PATCH\s+[0-9]+\s*$' , '#define expected_lite_PATCH {patch}\n' ) ) # End configuration. def readFile( in_path ): """Return content of file at given path""" with open( in_path, 'r' ) as in_file: contents = in_file.read() return contents def writeFile( out_path, contents ): """Write contents to file at given path""" with open( out_path, 'w' ) as out_file: out_file.write( contents ) def replaceFile( output_path, input_path ): # prevent race-condition (Python 3.3): if sys.version_info >= (3, 3): os.replace( output_path, input_path ) else: os.remove( input_path ) os.rename( output_path, input_path ) def editFileToVersion( version, info, verbose ): """Update version given file path, version regexp and new version format in info""" major, minor, patch = version.split('.') in_path, ver_re, ver_fmt = info out_path = in_path + '.tmp' new_text = ver_fmt.format( major=major, minor=minor, patch=patch ) if verbose: print( "- {path} => '{text}':".format( path=in_path, text=new_text.strip('\n') ) ) writeFile( out_path, re.sub( ver_re, new_text, readFile( in_path ) , count=0, flags=re.MULTILINE ) ) replaceFile( out_path, in_path ) def editFilesToVersion( version, table, verbose ): if verbose: print( "Editing files to version {v}:".format(v=version) ) for item in table: editFileToVersion( version, item, verbose ) def editFilesToVersionFromCommandLine(): """Update version number given on command line in paths from configuration table.""" parser = argparse.ArgumentParser( description='Update version number in files.', epilog="""""", formatter_class=argparse.RawTextHelpFormatter) parser.add_argument( 'version', metavar='version', type=str, nargs=1, help='new version number, like 1.2.3') parser.add_argument( '-v', '--verbose', action='store_true', help='report the name of the file being processed') args = parser.parse_args() editFilesToVersion( args.version[0], table, args.verbose ) if __name__ == '__main__': editFilesToVersionFromCommandLine() # end of file expected-lite-0.10.0/script/upload-conan.py000066400000000000000000000060231510672106500205660ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2019-2019 by Martin Moene # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # # script/upload-conan.py # from __future__ import print_function import argparse import os import re import sys import subprocess # Configuration: def_conan_project = 'expected-lite' def_conan_user = 'nonstd-lite' def_conan_channel = 'stable' cfg_conanfile = 'conanfile.py' tpl_conan_create = 'conan create . {usr}/{chn}' tpl_conan_upload = 'conan upload --remote {usr} {prj}/{ver}@{usr}/{chn}' # End configuration. def versionFrom( filename ): """Obtain version from conanfile.py""" with open( filename ) as f: content = f.read() version = re.search(r'version\s=\s"(.*)"', content).group(1) return version def createConanPackage( args ): """Create conan package and upload it.""" cmd = tpl_conan_create.format(usr=args.user, chn=args.channel) if args.verbose: print( "> {}".format(cmd) ) if not args.dry_run: subprocess.call( cmd, shell=False ) def uploadConanPackage( args ): """Create conan package and upload it.""" cmd = tpl_conan_upload.format(prj=args.project, usr=args.user, chn=args.channel, ver=args.version) if args.verbose: print( "> {}".format(cmd) ) if not args.dry_run: subprocess.call( cmd, shell=False ) def uploadToConan( args ): """Create conan package and upload it.""" print( "Updating project '{prj}' to user '{usr}', channel '{chn}', version {ver}:". format(prj=args.project, usr=args.user, chn=args.channel, ver=args.version) ) createConanPackage( args ) uploadConanPackage( args ) def uploadToConanFromCommandLine(): """Collect arguments from the commandline and create conan package and upload it.""" parser = argparse.ArgumentParser( description='Create conan package and upload it to conan.', epilog="""""", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( '-n', '--dry-run', action='store_true', help='do not execute conan commands') parser.add_argument( '-v', '--verbose', action='count', default=0, help='level of progress reporting') parser.add_argument( '--project', metavar='p', type=str, default=def_conan_project, help='conan project') parser.add_argument( '--user', metavar='u', type=str, default=def_conan_user, help='conan user') parser.add_argument( '--channel', metavar='c', type=str, default=def_conan_channel, help='conan channel') parser.add_argument( '--version', metavar='v', type=str, default=versionFrom( cfg_conanfile ), help='version number [from conanfile.py]') uploadToConan( parser.parse_args() ) if __name__ == '__main__': uploadToConanFromCommandLine() # end of file expected-lite-0.10.0/test/000077500000000000000000000000001510672106500153065ustar00rootroot00000000000000expected-lite-0.10.0/test/CMakeLists.txt000066400000000000000000000175121510672106500200540ustar00rootroot00000000000000# Copyright 2016-2022 by Martin Moene # # https://github.com/martinmoene/expected-lite # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) if( NOT DEFINED CMAKE_MINIMUM_REQUIRED_VERSION ) cmake_minimum_required( VERSION 3.15 FATAL_ERROR ) endif() project( test LANGUAGES CXX ) # unit_name provided by toplevel CMakeLists.txt [set( unit_name "xxx" )] set( PACKAGE ${unit_name}-lite ) set( PROGRAM ${unit_name}-lite ) set( SOURCES ${unit_name}-main.t.cpp ${unit_name}.t.cpp ) set( TWEAKD "." ) message( STATUS "Subproject '${PROJECT_NAME}', programs '${PROGRAM}-*'") set( OPTIONS "" ) set( DEFCMN "-Dlest_FEATURE_AUTO_REGISTER=1" ) set( HAS_STD_FLAGS FALSE ) set( HAS_CPP98_FLAG FALSE ) set( HAS_CPP11_FLAG FALSE ) set( HAS_CPP14_FLAG FALSE ) set( HAS_CPP17_FLAG FALSE ) set( HAS_CPP20_FLAG FALSE ) set( HAS_CPPLATEST_FLAG FALSE ) if ( EXPEXTED_P0323R LESS "99" ) set( DEFCMN ${DEFCMN} "-Dnsel_P0323R=${EXPEXTED_P0323R}" ) endif() if( MSVC ) message( STATUS "Matched: MSVC") set( HAS_STD_FLAGS TRUE ) set( OPTIONS -W3 -EHsc ) set( DEFINITIONS -D_SCL_SECURE_NO_WARNINGS ${DEFCMN} ) if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.00 ) set( HAS_CPP14_FLAG TRUE ) set( HAS_CPPLATEST_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.11 ) set( HAS_CPP17_FLAG TRUE ) endif() elseif( CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang" ) message( STATUS "CompilerId: '${CMAKE_CXX_COMPILER_ID}'") set( HAS_STD_FLAGS TRUE ) set( HAS_CPP98_FLAG TRUE ) set( OPTIONS -Wall -Wextra -Wconversion -Wsign-conversion -Wno-missing-braces -fno-elide-constructors ) set( DEFINITIONS ${DEFCMN} ) # GNU: available -std flags depends on version if( CMAKE_CXX_COMPILER_ID MATCHES "GNU" ) message( STATUS "Matched: GNU") if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.0 ) set( HAS_CPP11_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.2 ) set( HAS_CPP14_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.1.0 ) set( HAS_CPP17_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0.0 ) set( HAS_CPP20_FLAG TRUE ) endif() # AppleClang: available -std flags depends on version elseif( CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" ) message( STATUS "Matched: AppleClang") if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 ) set( HAS_CPP11_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1.0 ) set( HAS_CPP14_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.2.0 ) set( HAS_CPP17_FLAG TRUE ) endif() # if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS x.x.x ) # set( HAS_CPP20_FLAG TRUE ) # endif() # Clang: available -std flags depends on version elseif( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) message( STATUS "Matched: Clang") if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3.0 ) set( HAS_CPP11_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4.0 ) set( HAS_CPP14_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 ) set( HAS_CPP17_FLAG TRUE ) endif() if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0.0 ) set( HAS_CPP20_FLAG TRUE ) endif() endif() elseif( CMAKE_CXX_COMPILER_ID MATCHES "Intel" ) # as is message( STATUS "Matched: Intel") else() # as is message( STATUS "Matched: nothing") endif() # enable MS C++ Core Guidelines checker if MSVC: function( enable_msvs_guideline_checker target ) if( MSVC ) set_target_properties( ${target} PROPERTIES VS_GLOBAL_EnableCppCoreCheck true VS_GLOBAL_CodeAnalysisRuleSet CppCoreCheckRules.ruleset VS_GLOBAL_RunCodeAnalysis true ) endif() endfunction() # make target, compile for given standard if specified: function( make_target target std ) message( STATUS "Make target: '${std}'" ) add_executable ( ${target} ${SOURCES} ) target_include_directories( ${target} SYSTEM PRIVATE lest ) target_include_directories( ${target} PRIVATE ${TWEAKD} ) target_link_libraries ( ${target} PRIVATE ${PACKAGE} ) target_compile_options ( ${target} PRIVATE ${OPTIONS} ) target_compile_definitions( ${target} PRIVATE ${DEFINITIONS} ) if( std ) if( MSVC ) target_compile_options( ${target} PRIVATE -std:c++${std} ) else() # Necessary for clang 3.x: target_compile_options( ${target} PRIVATE -std=c++${std} ) # Ok for clang 4 and later: # set( CMAKE_CXX_STANDARD ${std} ) # set( CMAKE_CXX_STANDARD_REQUIRED ON ) # set( CMAKE_CXX_EXTENSIONS OFF ) endif() endif() endfunction() # add generic executable, unless -std flags can be specified: if( NOT HAS_STD_FLAGS ) make_target( ${PROGRAM}.t "" ) else() # # unconditionally add C++98 variant as MSVC has no option for it: # if( HAS_CPP98_FLAG ) # make_target( ${PROGRAM}-cpp98.t 98 ) # else() # make_target( ${PROGRAM}-cpp98.t "" ) # endif() # unconditionally add C++11 variant as MSVC has no option for it: if( HAS_CPP11_FLAG ) make_target( ${PROGRAM}-cpp11.t 11 ) else() make_target( ${PROGRAM}-cpp11.t "" ) endif() if( HAS_CPP14_FLAG ) make_target( ${PROGRAM}-cpp14.t 14 ) endif() if( HAS_CPP17_FLAG ) set( std17 17 ) if( CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" ) set( std17 1z ) endif() make_target( ${PROGRAM}-cpp17.t ${std17} ) enable_msvs_guideline_checker( ${PROGRAM}-cpp17.t ) endif() if( HAS_CPP20_FLAG ) make_target( ${PROGRAM}-cpp20.t 20 ) endif() if( HAS_CPPLATEST_FLAG ) make_target( ${PROGRAM}-cpplatest.t latest ) endif() endif() # with C++20, honour explicit request for std::expected or nonstd::expected: if( HAS_CPP20_FLAG ) set( WHICH nsel_EXPECTED_DEFAULT ) if( EXPECTED_LITE_OPT_SELECT_STD ) set( WHICH nsel_EXPECTED_STD ) elseif( EXPECTED_LITE_OPT_SELECT_NONSTD ) set( WHICH nsel_EXPECTED_NONSTD ) endif() target_compile_definitions( ${PROGRAM}-cpp17.t PRIVATE nsel_CONFIG_SELECT_EXPECTED=${WHICH} ) target_compile_definitions( ${PROGRAM}-cpp20.t PRIVATE nsel_CONFIG_SELECT_EXPECTED=${WHICH} ) if( HAS_CPPLATEST_FLAG ) target_compile_definitions( ${PROGRAM}-cpplatest.t PRIVATE nsel_CONFIG_SELECT_EXPECTED=${WHICH} ) endif() endif() # configure unit tests via CTest: enable_testing() if( HAS_STD_FLAGS ) # # unconditionally add C++98 variant for MSVC: # add_test( NAME test-cpp98 COMMAND ${PROGRAM}-cpp98.t ) # # unconditionally add C++11 variant for MSVC: add_test( NAME test-cpp11 COMMAND ${PROGRAM}-cpp11.t ) if( HAS_CPP14_FLAG ) add_test( NAME test-cpp14 COMMAND ${PROGRAM}-cpp14.t ) endif() if( HAS_CPP17_FLAG ) add_test( NAME test-cpp17 COMMAND ${PROGRAM}-cpp17.t ) endif() if( HAS_CPP20_FLAG ) add_test( NAME test-cpp20 COMMAND ${PROGRAM}-cpp20.t ) endif() if( HAS_CPPLATEST_FLAG ) add_test( NAME test-cpplatest COMMAND ${PROGRAM}-cpplatest.t ) endif() else() add_test( NAME test COMMAND ${PROGRAM}.t --pass ) add_test( NAME list_version COMMAND ${PROGRAM}.t --version ) add_test( NAME list_tags COMMAND ${PROGRAM}.t --list-tags ) add_test( NAME list_tests COMMAND ${PROGRAM}.t --list-tests ) endif() # end of file expected-lite-0.10.0/test/expected-main.t.cpp000066400000000000000000000077211510672106500210060ustar00rootroot00000000000000// Copyright (c) 2016-2018 Martin Moene // // https://github.com/martinmoene/expected-lite // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "expected-main.t.hpp" #define expected_PRESENT( x ) \ std::cout << #x << ": " << x << "\n" #define expected_DEFINED( x ) \ std::cout << #x << ": (defined)\n" #define expected_ABSENT( x ) \ std::cout << #x << ": (undefined)\n" // Suppress: // - unused parameter, for cases without assertions such as [.std...] #if defined(__clang__) # pragma clang diagnostic ignored "-Wunused-parameter" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wunused-parameter" #endif lest::tests & specification() { static lest::tests tests; return tests; } CASE( "expected-lite version" "[.expected][.version]" ) { expected_PRESENT( expected_lite_MAJOR ); expected_PRESENT( expected_lite_MINOR ); expected_PRESENT( expected_lite_PATCH ); expected_PRESENT( expected_lite_VERSION ); } CASE( "expected-lite configuration" "[.expected][.config]" ) { expected_PRESENT( nsel_HAVE_STD_EXPECTED ); expected_PRESENT( nsel_USES_STD_EXPECTED ); expected_PRESENT( nsel_EXPECTED_DEFAULT ); expected_PRESENT( nsel_EXPECTED_NONSTD ); expected_PRESENT( nsel_EXPECTED_STD ); expected_PRESENT( nsel_CONFIG_SELECT_EXPECTED ); expected_PRESENT( nsel_CONFIG_WIN32_LEAN_AND_MEAN ); expected_PRESENT( nsel_CONFIG_NO_EXCEPTIONS ); expected_PRESENT( nsel_CONFIG_NO_EXCEPTIONS_SEH ); expected_PRESENT( nsel_CPLUSPLUS ); } CASE( "__cplusplus" "[.stdc++]" ) { expected_PRESENT( __cplusplus ); #ifdef _MSVC_LANG expected_PRESENT( _MSVC_LANG ); #else expected_ABSENT( _MSVC_LANG ); #endif } CASE( "Compiler version" "[.compiler]" ) { #if nsel_USES_STD_EXPECTED std::cout << "(Compiler version not available: using std::expected)\n"; #else expected_PRESENT( nsel_COMPILER_CLANG_VERSION ); expected_PRESENT( nsel_COMPILER_GNUC_VERSION ); expected_PRESENT( nsel_COMPILER_MSVC_VERSION ); #endif } CASE( "presence of C++ language features" "[.stdlanguage]" ) { #if nsel_USES_STD_EXPECTED std::cout << "(Presence of C++ language features not available: using std::expected)\n"; #else std::cout << "[.stdlanguage]: none\n"; #endif } CASE( "presence of C++ library features" "[.stdlibrary]" ) { #if nsel_USES_STD_EXPECTED std::cout << "(Presence of C++ library features not available: using std::expected)\n"; #else #ifdef WIN32_LEAN_AND_MEAN expected_DEFINED( WIN32_LEAN_AND_MEAN ); #else expected_ABSENT( WIN32_LEAN_AND_MEAN ); #endif #ifdef __cpp_exceptions expected_PRESENT( __cpp_exceptions ); #else expected_ABSENT( __cpp_exceptions ); #endif #ifdef __EXCEPTIONS expected_PRESENT( __EXCEPTIONS ); #else expected_ABSENT( __EXCEPTIONS ); #endif #ifdef _HAS_EXCEPTIONS expected_PRESENT( _HAS_EXCEPTIONS ); #else expected_ABSENT( _HAS_EXCEPTIONS ); #endif #ifdef _CPPUNWIND expected_PRESENT( _CPPUNWIND ); #else expected_ABSENT( _CPPUNWIND ); #endif #endif } int main( int argc, char * argv[] ) { return lest::run( specification(), argc, argv ); } #if 0 g++ -I../include -o expected-lite.t.exe expected-lite.t.cpp && expected-lite.t.exe --pass g++ -std=c++98 -I../include -o expected-lite.t.exe expected-lite.t.cpp && expected-lite.t.exe --pass g++ -std=c++03 -I../include -o expected-lite.t.exe expected-lite.t.cpp && expected-lite.t.exe --pass g++ -std=c++0x -I../include -o expected-lite.t.exe expected-lite.t.cpp && expected-lite.t.exe --pass g++ -std=c++11 -I../include -o expected-lite.t.exe expected-lite.t.cpp && expected-lite.t.exe --pass g++ -std=c++14 -I../include -o expected-lite.t.exe expected-lite.t.cpp && expected-lite.t.exe --pass g++ -std=c++17 -I../include -o expected-lite.t.exe expected-lite.t.cpp && expected-lite.t.exe --pass cl -EHsc -I../include expected-lite.t.cpp && expected-lite.t.exe --pass #endif // end of file expected-lite-0.10.0/test/expected-main.t.hpp000066400000000000000000000040501510672106500210030ustar00rootroot00000000000000// Copyright (c) 2016-2018 Martin Moene // // https://github.com/martinmoene/expected-lite // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #pragma once #ifndef TEST_EXPECTED_LITE_H_INCLUDED #define TEST_EXPECTED_LITE_H_INCLUDED // Limit C++ Core Guidelines checking to expected-lite: #include "nonstd/expected.hpp" #if nsel_COMPILER_MSVC_VER >= 1910 # include # pragma warning(disable: ALL_CPPCORECHECK_WARNINGS) #endif #include namespace lest { template< typename T, typename E > std::ostream & operator<<( std::ostream & os, nonstd::expected const & ); template< typename E > std::ostream & operator<<( std::ostream & os, nonstd::expected const & ); } // namespace lest // Compiler warning suppression for usage of lest: #ifdef __clang__ # pragma clang diagnostic ignored "-Wstring-conversion" # pragma clang diagnostic ignored "-Wunused-parameter" # pragma clang diagnostic ignored "-Wunused-template" # pragma clang diagnostic ignored "-Wunused-function" # pragma clang diagnostic ignored "-Wunused-member-function" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wunused-parameter" # pragma GCC diagnostic ignored "-Wunused-function" #endif #include "lest.hpp" #define CASE( name ) lest_CASE( specification(), name ) extern lest::tests & specification(); namespace lest { // use oparator<< instead of to_string() overload; // see http://stackoverflow.com/a/10651752/437272 template< typename T, typename E > inline std::ostream & operator<<( std::ostream & os, nonstd::expected const & v ) { using lest::to_string; return os << "[expected:" << (v ? to_string(*v) : "[empty]") << "]"; } template< typename E > inline std::ostream & operator<<( std::ostream & os, nonstd::expected const & v ) { using lest::to_string; return os << "[expected:" << (v ? "[non-empty]" : "[empty]") << "]"; } } // namespace lest #endif // TEST_EXPECTED_LITE_H_INCLUDED // end of file expected-lite-0.10.0/test/expected-noexcept.t.cpp000066400000000000000000000027171510672106500217070ustar00rootroot00000000000000// Copyright (c) 2016-2020 Martin Moene // // https://github.com/martinmoene/expected-lite // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "nonstd/expected.hpp" #include template< typename T > void use( T const & /*x*/) {} #define expected_PRESENT( x ) \ std::cout << #x << ": " << x << "\n" #define expected_ABSENT( x ) \ std::cout << #x << ": (undefined)\n" void report() { #ifdef __cpp_exceptions expected_PRESENT( __cpp_exceptions ); #else expected_ABSENT( __cpp_exceptions ); #endif #ifdef __EXCEPTIONS expected_PRESENT( __EXCEPTIONS ); #else expected_ABSENT( __EXCEPTIONS ); #endif #ifdef _HAS_EXCEPTIONS expected_PRESENT( _HAS_EXCEPTIONS ); #else expected_ABSENT( _HAS_EXCEPTIONS ); #endif #ifdef _CPPUNWIND expected_PRESENT( _CPPUNWIND ); #else expected_ABSENT( _CPPUNWIND ); #endif #ifdef _CPPRTTI expected_PRESENT( _CPPRTTI ); #else expected_ABSENT( _CPPRTTI ); #endif } int violate_access() { nonstd::expected eu( nonstd:: make_unexpected('a') ); return eu.value(); } int main() { report(); #if ! nsel_CONFIG_NO_EXCEPTIONS_SEH return violate_access(); #else __try { return violate_access(); } __except( EXCEPTION_EXECUTE_HANDLER ) { std::cerr << "\n*** Executing SEH __except block ***\n"; } #endif } // end of file expected-lite-0.10.0/test/expected.t.cpp000066400000000000000000001747611510672106500200750ustar00rootroot00000000000000// This version targets C++11 and later. // // Copyright (c) 2016-2018 Martin Moene. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // expected lite is based on: // A proposal to add a utility class to represent expected monad // by Vicente J. Botet Escriba and Pierre Talbot, http:://wg21.link/p0323 #include #include "expected-main.t.hpp" #ifndef nsel_CONFIG_CONFIRMS_COMPILATION_ERRORS #define nsel_CONFIG_CONFIRMS_COMPILATION_ERRORS 0 #endif #define nsel_HAVE_MAYBE_UNUSED nsel_CPP17_000 #if nsel_HAVE_MAYBE_UNUSED # define nsel_MAYBE_UNUSED [[maybe_unused]] #else # define nsel_MAYBE_UNUSED /*[[maybe_unused]]*/ #endif // Suppress: // - unused parameter, for cases without assertions such as [.std...] #if defined(__clang__) # pragma clang diagnostic ignored "-Wunused-parameter" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wunused-parameter" #endif //namespace { using namespace nonstd; struct Implicit { int x; Implicit(int v) : x(v) {} }; struct Explicit { int x; explicit Explicit(int v) : x(v) {} }; struct MoveOnly { int x; explicit MoveOnly(int x) :x{x} {} MoveOnly( MoveOnly const & ) = delete; MoveOnly( MoveOnly && other ) noexcept : x{ other.x } {} MoveOnly& operator=( MoveOnly const & ) = delete; MoveOnly& operator=( MoveOnly && other ) noexcept { if (&other == this) return *this; x = other.x; return *this; } }; struct NonMovableNonCopyable { NonMovableNonCopyable() = default; NonMovableNonCopyable( NonMovableNonCopyable const & ) = delete; NonMovableNonCopyable( NonMovableNonCopyable && ) = delete; NonMovableNonCopyable& operator=( NonMovableNonCopyable const & ) = delete; NonMovableNonCopyable& operator=( NonMovableNonCopyable && ) = delete; }; bool operator==( Implicit a, Implicit b ) { return a.x == b.x; } bool operator==( Explicit a, Explicit b ) { return a.x == b.x; } template< typename R > bool operator==( MoveOnly const & a, R const & r ) { return a.x == r; } std::ostream & operator<<( std::ostream & os, Implicit i ) { return os << "Implicit:" << i.x; } std::ostream & operator<<( std::ostream & os, Explicit e ) { return os << "Explicit:" << e.x; } std::ostream & operator<<( std::ostream & os, MoveOnly const & m ) { return os << "MoveOnly:" << m.x; } struct InitList { std::vector vec; char c; InitList( std::initializer_list il, char k ) noexcept : vec( il ), c( k ) {} // InitList( InitList const & ) noexcept = default; // InitList( InitList && ) noexcept = default; // // InitList & operator=( InitList const & ) noexcept = default; // InitList & operator=( InitList && ) noexcept = default; }; enum State { sDefaultConstructed, sValueCopyConstructed, sValueMoveConstructed, sCopyConstructed, sMoveConstructed, sMoveAssigned, sCopyAssigned, sValueCopyAssigned, sValueMoveAssigned, sMovedFrom, sValueConstructed }; struct OracleVal { State s; int i; OracleVal(int i_ = 0) : s(sValueConstructed), i(i_) {} bool operator==( OracleVal const & other ) const { return s==other.s && i==other.i; } }; struct Oracle { State s; OracleVal val; Oracle() : s(sDefaultConstructed) {} Oracle(const OracleVal& v) : s(sValueCopyConstructed), val(v) {} Oracle(OracleVal&& v) : s(sValueMoveConstructed), val(std::move(v)) {v.s = sMovedFrom;} Oracle(const Oracle& o) : s(sCopyConstructed), val(o.val) {} Oracle(Oracle&& o) : s(sMoveConstructed), val(std::move(o.val)) {o.s = sMovedFrom;} Oracle& operator=(const OracleVal& v) { s = sValueCopyConstructed; val = v; return *this; } Oracle& operator=(OracleVal&& v) { s = sValueMoveConstructed; val = std::move(v); v.s = sMovedFrom; return *this; } Oracle& operator=(const Oracle& o) { s = sCopyConstructed; val = o.val; return *this; } Oracle& operator=(Oracle&& o) { s = sMoveConstructed; val = std::move(o.val); o.s = sMovedFrom; return *this; } bool operator==( Oracle const & other ) const { return s == other.s && val == other.val;} }; std::ostream & operator<<( std::ostream & os, OracleVal const & o ) { using lest::to_string; return os << "[oracle:" << to_string( o.i ) << "]"; } //} // anonymous namespace namespace nonstd { template< typename T, typename E > std::ostream & operator<<( std::ostream & os, expected const & e ) { using lest::to_string; return os << ( e ? to_string( *e ) : "[error:" + to_string( e.error() ) + "]" ); } template< typename E > std::ostream & operator<<( std::ostream & os, unexpected_type const & u ) { using lest::to_string; return os << "[unexp:" << to_string( u.value() ) << "]"; } } using namespace nonstd; // // test specification: // CASE( "A C++11 union can contain non-POD types" "[.]" ) { struct nonpod { nonpod(){} }; union U { char c; nonpod np; }; } // ----------------------------------------------------------------------- // storage_t<> CASE( "[storage_t]" "[.implement]" ) { } // ----------------------------------------------------------------------- // unexpected_type, unexpected_type CASE( "unexpected_type: Disallows default construction" ) { #if nsel_CONFIG_CONFIRMS_COMPILATION_ERRORS unexpected_type u; #endif } CASE( "unexpected_type: Allows to copy-construct from unexpected_type, default" ) { unexpected_type a{ 7 }; unexpected_type b( a ); EXPECT( a.error() == 7 ); EXPECT( b.error() == 7 ); } CASE( "unexpected_type: Allows to move-construct from unexpected_type, default" ) { unexpected_type a{ 7 }; unexpected_type b( std::move( a ) ); EXPECT( a.error() == 7 ); EXPECT( b.error() == 7 ); } CASE( "unexpected_type: Allows to in-place-construct" ) { unexpected_type ue( in_place, 5 ); unexpected_type ui( in_place, 7 ); EXPECT( ue.error() == Explicit{5} ); EXPECT( ui.error() == Implicit{7} ); } CASE( "unexpected_type: Allows to in-place-construct from initializer_list" ) { unexpected_type u( in_place, { 7, 8, 9 }, 'a' ); EXPECT( u.error().vec[0] == 7 ); EXPECT( u.error().vec[1] == 8 ); EXPECT( u.error().vec[2] == 9 ); EXPECT( u.error().c == 'a'); } CASE( "unexpected_type: Allows to copy-construct from error_type" ) { unexpected_type u{ 7 }; EXPECT( u.error() == 7 ); } CASE( "unexpected_type: Allows to move-construct from error_type" ) { unexpected_type u{ std::move( 7 ) }; EXPECT( u.error() == 7 ); } CASE( "unexpected_type: Allows to copy-construct from unexpected_type, explicit converting" ) { #if !nsel_USES_STD_EXPECTED // TODO unexpected_type a{ 7 }; unexpected_type b{ a }; EXPECT( b.error() == Explicit{7} ); #else EXPECT( !!"no explicit converting copy-construct for std::unexpected (C++23)." "TODO" ); #endif } CASE( "unexpected_type: Allows to copy-construct from unexpected_type, non-explicit converting" ) { #if !nsel_USES_STD_EXPECTED // TODO unexpected_type a{ 7 }; unexpected_type b( a ); EXPECT( b.error() == Implicit{7} ); #else EXPECT( !!"no non-explicit converting copy-construct for std::unexpected (C++23)." "TODO" ); #endif } CASE( "unexpected_type: Allows to move-construct from unexpected_type, explicit converting" ) { #if !nsel_USES_STD_EXPECTED // TODO unexpected_type a{ 7 }; unexpected_type b{ std::move( a ) }; EXPECT( b.error() == Explicit{7} ); #else EXPECT( !!"no explicit converting move-construct for std::unexpected (C++23)." "TODO" ); #endif } CASE( "unexpected_type: Allows to move-construct from unexpected_type, non-explicit converting" ) { #if !nsel_USES_STD_EXPECTED // TODO unexpected_type a{ 7 }; unexpected_type b( std::move( a ) ); EXPECT( b.error() == Implicit{7} ); #else EXPECT( !!"no non-explicit converting move-construct for std::unexpected (C++23)." "TODO" ); #endif } CASE( "unexpected_type: Allows to copy-assign from unexpected_type, default" ) { unexpected_type a{ 7 }; unexpected_type b{ 0 }; b = a; EXPECT( b.error() == 7 ); } CASE( "unexpected_type: Allows to move-assign from unexpected_type, default" ) { unexpected_type a{ 7 }; unexpected_type b{ 0 }; b = std::move( a ); EXPECT( b.error() == 7 ); } CASE( "unexpected_type: Allows to copy-assign from unexpected_type, converting" ) { #if !nsel_USES_STD_EXPECTED unexpected_type u{ 7 }; unexpected_type ue{ 0 }; unexpected_type ui{ 0 }; ue = u; ui = u; EXPECT( ue.error() == Explicit{7} ); EXPECT( ui.error() == Implicit{7} ); #else EXPECT( !!"no copy-assignment for std::unexpected (C++23)." ); #endif } CASE( "unexpected_type: Allows to move-assign from unexpected, converting" ) { #if !nsel_USES_STD_EXPECTED unexpected_type u{ 7 }; unexpected_type v{ 7 }; unexpected_type ue{ 0 }; unexpected_type ui{ 0 }; ue = std::move( u ); ui = std::move( v ); EXPECT( ue.error() == Explicit{7} ); EXPECT( ui.error() == Implicit{7} ); #else EXPECT( !!"no move-assignment for std::unexpected (C++23)." ); #endif } CASE( "unexpected_type: Allows to observe its value via a l-value reference" ) { unexpected_type u{ 7 }; unexpected_type uc{ 7 }; EXPECT( u.error() == 7 ); EXPECT( uc.error() == 7 ); } CASE( "unexpected_type: Allows to observe its value via a r-value reference" ) { unexpected_type u{ 7 }; unexpected_type uc{ 7 }; EXPECT( std::move( u).error() == 7 ); EXPECT( std::move(uc).error() == 7 ); } CASE( "unexpected_type: Allows to modify its value via a l-value reference" ) { unexpected_type u{ 5 }; u.error() = 7; EXPECT( u.error() == 7 ); } //CASE( "unexpected_type: Allows to modify its value via a r-value reference" ) //{ // const auto v = 9; // unexpected_type u{ 7 }; // // std::move( u.error() ) = v; // // EXPECT( u.error() == v ); //} CASE( "unexpected_type: Allows to be swapped" ) { unexpected_type a{ 5 }; unexpected_type b{ 7 }; a.swap( b ); EXPECT( a.error() == 7 ); EXPECT( b.error() == 5 ); } //CASE( "unexpected_type: Allows reset via = {}" ) //{ // unexpected_type u( 3 ); // // u = {}; //} // ----------------------------------------------------------------------- // unexpected_type // TODO: unexpected_type: Should expected be specialized for particular E types such as exception_ptr and how? // See p0323r7 2.1. Ergonomics, http://wg21.link/p0323 namespace { std::exception_ptr make_ep() { try { // this generates an std::out_of_range: (void) std::string().at(1); } catch(...) { return std::current_exception(); } return nullptr; } } // anonymous namespace CASE( "unexpected_type: Disallows default construction" ) { #if nsel_CONFIG_CONFIRMS_COMPILATION_ERRORS unexpected_type u; #endif } CASE( "unexpected_type: Allows to copy-construct from error_type" ) { auto ep = make_ep(); unexpected_type u{ ep }; EXPECT( u.error() == ep ); } CASE( "unexpected_type: Allows to move-construct from error_type" ) { auto ep_move = make_ep(); const auto ep_copy = ep_move; unexpected_type u{ std::move( ep_move ) }; EXPECT( u.error() == ep_copy ); } CASE( "unexpected_type: Allows to copy-construct from an exception" ) { std::string text = "hello, world"; unexpected_type u{ std::make_exception_ptr( std::logic_error( text.c_str() ) ) }; try { std::rethrow_exception( u.error() ); } catch( std::exception const & e ) { EXPECT( e.what() == text ); } } CASE( "unexpected_type: Allows to observe its value" ) { const auto ep = make_ep(); unexpected_type u{ ep }; EXPECT( u.error() == ep ); } CASE( "unexpected_type: Allows to modify its value" ) { const auto ep1 = make_ep(); const auto ep2 = make_ep(); unexpected_type u{ ep1 }; u.error() = ep2; EXPECT( u.error() == ep2 ); } //CASE( "unexpected_type: Allows reset via = {}, std::exception_ptr specialization" ) //{ // unexpected_type u( 3 ); // // u = {}; //} // ----------------------------------------------------------------------- // unexpected_type relational operators CASE( "unexpected_type: Provides relational operators" ) { SETUP( "" ) { unexpected_type u1( 6 ); unexpected_type u2( 7 ); // compare engaged expected with engaged expected SECTION( "==" ) { EXPECT( u1 == u1 ); } SECTION( "!=" ) { EXPECT( u1 != u2 ); } #if nsel_P0323R <= 2 SECTION( "< " ) { EXPECT( u1 < u2 ); } SECTION( "> " ) { EXPECT( u2 > u1 ); } SECTION( "<=" ) { EXPECT( u1 <= u1 ); } SECTION( "<=" ) { EXPECT( u1 <= u2 ); } SECTION( ">=" ) { EXPECT( u1 >= u1 ); } SECTION( ">=" ) { EXPECT( u2 >= u1 ); } #endif } } CASE( "unexpected_type: Provides relational operators, std::exception_ptr specialization" ) { SETUP( "" ) { unexpected_type u( make_ep() ); unexpected_type u2( make_ep() ); // compare engaged expected with engaged expected SECTION( "==" ) { EXPECT ( u == u ); } SECTION( "!=" ) { EXPECT ( u != u2); } #if nsel_P0323R <= 2 SECTION( "< " ) { EXPECT_NOT( u < u ); } SECTION( "> " ) { EXPECT_NOT( u > u ); } SECTION( "< " ) { EXPECT_NOT( u < u2); } SECTION( "> " ) { EXPECT_NOT( u > u2); } SECTION( "<=" ) { EXPECT ( u <= u ); } SECTION( ">=" ) { EXPECT ( u >= u ); } #endif } } // unexpected: traits CASE( "is_unexpected: Is true for unexpected_type" "[.deprecated]" ) { #if nsel_P0323R <= 3 EXPECT( is_unexpected>::value ); #else EXPECT( !!"is_unexpected<> is not available (nsel_P0323R > 3)" ); #endif } CASE( "is_unexpected: Is false for non-unexpected_type (int)" "[.deprecated]" ) { #if nsel_P0323R <= 3 EXPECT_NOT( is_unexpected::value ); #else EXPECT( !!"is_unexpected<> is not available (nsel_P0323R > 3)" ); #endif } // unexpected: factory CASE( "make_unexpected(): Allows to create an unexpected_type from an E" ) { const auto error = 7; auto u = make_unexpected( error ); EXPECT( u.error() == error ); } CASE( "make_unexpected(): Allows to in-place create an unexpected_type from an E" ) { const auto a = 'a'; const auto b = 7; auto u = make_unexpected< std::pair >( in_place, a, b ); EXPECT( u.error().first == a ); EXPECT( u.error().second == b ); } CASE( "make_unexpected_from_current_exception(): Allows to create an unexpected_type from the current exception" "[.deprecated]" ) { #if nsel_P0323R <= 2 std::string text = "hello, world"; try { throw std::logic_error( text.c_str() ); } catch( std::exception const & ) { auto u = make_unexpected_from_current_exception() ; try { std::rethrow_exception( u.error() ); } catch( std::exception const & e ) { EXPECT( e.what() == text ); } } #else EXPECT( !!"make_unexpected_from_current_exception() is not available (nsel_P0323R > 2)" ); #endif } CASE( "unexpected: C++17 and later provide unexpected_type as unexpected" ) { #if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141 nsel_MAYBE_UNUSED nonstd::unexpected u{7}; #else EXPECT( !!"unexpected is not available (no C++17)." ); #endif } // ----------------------------------------------------------------------- // x.x.6 bad_expected_access<> CASE( "bad_expected_access: Disallows default construction" ) { #if nsel_CONFIG_CONFIRMS_COMPILATION_ERRORS bad_expected_access bad; #endif } CASE( "bad_expected_access: Allows construction from error_type" ) { bad_expected_access bea( 123 ); } CASE( "bad_expected_access: Allows to observe its error" ) { const int error = 7; bad_expected_access bea( error ); bad_expected_access const beac( error ); EXPECT( bea.error() == error ); EXPECT( beac.error() == error ); EXPECT( std::move( bea.error() ) == error ); EXPECT( std::move( beac.error() ) == error ); } CASE( "bad_expected_access: Allows to change its error" ) { const int old_error = 0; const int new_error = 7; bad_expected_access bea( old_error ); bea.error() = new_error; EXPECT( bea.error() == new_error ); } CASE( "bad_expected_access: Provides non-empty what()" ) { bad_expected_access bea( 123 ); EXPECT( ! std::string( bea.what() ).empty() ); } // ----------------------------------------------------------------------- // expected<> // x.x.4.1 expected<> constructors (value) CASE( "expected: Allows to default construct" ) { expected e; EXPECT( e.has_value() ); } CASE( "expected: Allows to default construct from noncopyable, noncopyable value type" ) { expected e; EXPECT( e.has_value() ); } CASE( "expected: Allows to default construct from noncopyable, noncopyable error type" ) { expected e{ unexpect_t{} }; EXPECT( !e.has_value() ); } CASE( "expected: Allows to copy-construct from expected: value" ) { expected a = 7; expected b{ a }; EXPECT( b ); EXPECT( b.value() == 7 ); } CASE( "expected: Allows to copy-construct from expected: error" ) { expected a{ unexpect, 7 }; expected b{ a }; EXPECT( !b ); EXPECT( b.error() == 7 ); } CASE( "expected: Allows to move-construct from expected: value" ) { expected a = 7; expected b{ std::move( a ) }; EXPECT( b ); EXPECT( b.value() == 7 ); EXPECT( a ); // postcondition: unchanged! } CASE( "expected: Allows to move-construct from expected: error" ) { expected a{ unexpect, 7 }; expected b{ std::move( a ) }; EXPECT( !b ); EXPECT( b.error() == 7 ); } CASE( "expected: Allows to copy-construct from expected; value, explicit converting" ) { expected a = 7; expected b{ a }; EXPECT( b ); EXPECT( b.value() == Explicit{7} ); } CASE( "expected: Allows to copy-construct from expected; error, explicit converting" ) { expected a{ unexpect, 7 }; expected b{ a }; EXPECT( !b ); EXPECT( b.error() == Explicit{7} ); } CASE( "expected: Allows to copy-construct from expected; value, non-explicit converting" ) { expected a = 7; expected b( a ); EXPECT( b ); EXPECT( b.value() == Implicit{7} ); } CASE( "expected: Allows to copy-construct from expected; error, non-explicit converting" ) { expected a{ unexpect, 7 }; expected b( a ); EXPECT( !b ); EXPECT( b.error() == Implicit{7} ); } CASE( "expected: Allows to move-construct from expected; value, explicit converting" ) { expected a = 7; expected b{ std::move( a ) }; EXPECT( b ); EXPECT( b.value() == Explicit{7} ); } CASE( "expected: Allows to move-construct from expected; error, explicit converting" ) { expected a{ unexpect, 7 }; expected b{ std::move( a ) }; EXPECT( !b ); EXPECT( b.error() == Explicit{7} ); } CASE( "expected: Allows to move-construct from expected; value, non-explicit converting" ) { expected a = 7; expected b( std::move( a ) ); EXPECT( b ); EXPECT( b.value() == Implicit{7} ); } CASE( "expected: Allows to move-construct from expected; error, non-explicit converting" ) { expected a{ unexpect, 7 }; expected b( std::move( a ) ); EXPECT( !b ); EXPECT( b.error() == Implicit{7} ); } CASE( "expected: Allows to forward-construct from value, explicit converting" ) { auto v = 7; expected b{ std::move( v ) }; EXPECT( b ); EXPECT( b.value() == Explicit{7} ); } CASE( "expected: Allows to forward-construct from value, non-explicit converting" ) { auto v = 7; expected b{ std::move( v ) }; EXPECT( b ); EXPECT( b.value() == Implicit{7} ); } CASE( "expected: Allows to in-place-construct value" ) { auto v = 7; expected b{ in_place, v }; EXPECT( b ); EXPECT( b.value() == Implicit{7} ); } CASE( "expected: Allows to in-place-construct value from initializer_list" ) { expected b{ in_place, { 7, 8, 9 }, 'a' }; EXPECT( b ); EXPECT( b->vec[0] == 7 ); EXPECT( b->vec[1] == 8 ); EXPECT( b->vec[2] == 9 ); EXPECT( b->c == 'a'); } // x.x.4.1 expected<> constructors (error) CASE( "expected: Allows to copy-construct from unexpected, explicit converting" ) { unexpected_type u{ 7 }; expected e{ u }; EXPECT( e.error() == Explicit{7} ); } CASE( "expected: Allows to copy-construct from unexpected, non-explicit converting" ) { unexpected_type u{ 7 }; expected e{ u }; EXPECT( e.error() == Implicit{7} ); } CASE( "expected: Allows to move-construct from unexpected, explicit converting" ) { unexpected_type u{ 7 }; expected e{ std::move( u ) }; EXPECT( e.error() == Explicit{7} ); } CASE( "expected: Allows to move-construct from unexpected, non-explicit converting" ) { unexpected_type u{ 7 }; expected e{ std::move( u ) }; EXPECT( e.error() == Implicit{7} ); } CASE( "expected: Allows to in-place-construct error" ) { expected e{ unexpect, 7 }; expected i{ unexpect, 7 }; EXPECT( e.error() == Explicit{7} ); EXPECT( i.error() == Implicit{7} ); } CASE( "expected: Allows to in-place-construct error from initializer_list" ) { expected e{ unexpect, { 7, 8, 9 }, 'a' }; EXPECT( !e ); EXPECT( e.error().vec[0] == 7 ); EXPECT( e.error().vec[1] == 8 ); EXPECT( e.error().vec[2] == 9 ); EXPECT( e.error().c == 'a'); } // x.x.4.3 expected<> assignment CASE( "expected: Allows to copy-assign from expected, value" ) { expected a{ 7 }; expected b; b = a; EXPECT( b ); EXPECT( b.value() == 7 ); } CASE( "expected: Allows to copy-assign from expected, error" ) { expected a{ unexpect, 7 }; expected b; b = a; EXPECT( !b ); EXPECT( b.error() == 7 ); } CASE( "expected: Allows to move-assign from expected, value" ) { expected a{ 7 }; expected b; b = std::move( a ); EXPECT( b ); EXPECT( b.value() == 7 ); } CASE( "expected: Allows to move-assign from expected, error" ) { expected a{ unexpect, 7 }; expected b; b = std::move( a ); EXPECT( !b ); EXPECT( b.error() == 7 ); } CASE( "expected: Allows to forward-assign from value" ) { expected a; expected b; a = '7'; b = 7; EXPECT( a ); EXPECT( b ); EXPECT( a.value() == '7' ); EXPECT( b.value() == 7 ); } CASE( "expected: Allows to copy-assign from unexpected" ) { expected e; unexpected_type u{ 7 } ; e = u; EXPECT( e.error() == 7 ); } CASE( "expected: Allows to move-assign from unexpected" ) { expected e; unexpected_type u{ 7 } ; e = std::move( u ); EXPECT( e.error() == 7 ); } CASE( "expected: Allows to move-assign from move-only unexpected" ) { expected e; unexpected_type u{7}; e = std::move( u ); EXPECT( e.error() == 7 ); } CASE( "expected: Allows to emplace value" ) { expected a; expected b; auto va = a.emplace( '7' ); auto vb = b.emplace( 7 ); EXPECT( va == '7' ); EXPECT( vb == 7 ); EXPECT( a.value() == '7' ); EXPECT( b.value() == 7 ); } CASE( "expected: Allows to emplace value from initializer_list" ) { expected e{ in_place, std::initializer_list{}, 'x'}; auto ve = e.emplace( { 7, 8, 9 }, 'a' ); EXPECT( e ); EXPECT( ve.vec[0] == 7 ); EXPECT( ve.vec[1] == 8 ); EXPECT( ve.vec[2] == 9 ); EXPECT( ve.c == 'a'); EXPECT( e.value().vec[0] == 7 ); EXPECT( e.value().vec[1] == 8 ); EXPECT( e.value().vec[2] == 9 ); EXPECT( e.value().c == 'a'); } // x.x.4.4 expected<> swap CASE( "expected: Allows to be swapped" ) { using std::swap; SETUP("") { expected e1{ 1 }; expected e2{ 2 }; expected u1{ unexpect, '1' }; expected u2{ unexpect, '2' }; SECTION("value-value, member swap") { e1.swap( e2 ); EXPECT( e1.value() == 2 ); EXPECT( e2.value() == 1 ); } SECTION("error-error, member swap") { u1.swap( u2 ); EXPECT( u1.error() == '2' ); EXPECT( u2.error() == '1' ); } SECTION("value-error, member swap") { e1.swap( u1 ); EXPECT( e1.error() == '1' ); EXPECT( u1.value() == 1 ); } SECTION("error-value, member swap") { u1.swap( e1 ); EXPECT( u1.value() == 1 ); EXPECT( e1.error() == '1' ); } } } // x.x.4.5 expected<> observers CASE( "expected: Allows to observe its value via a pointer" ) { const auto v = 7; expected e{ v }; EXPECT( e->x == v ); } CASE( "expected: Allows to observe its value via a pointer to constant" ) { const auto v = 7; const expected e{ v }; EXPECT( e->x == v ); } CASE( "expected: Allows to modify its value via a pointer" ) { const auto v1 = 7; const auto v2 = 42; expected e{ v1 }; e->x = v2; EXPECT( e->x == v2 ); } CASE( "expected: Allows to observe its value via a l-value reference" ) { const auto v = 7; expected e{ v }; expected const ec{ v }; EXPECT( *e == Implicit{v} ); EXPECT( *ec == Implicit{v} ); } CASE( "expected: Allows to observe its value via a r-value reference" ) { const auto v = 7; expected e{ v }; expected const ec{ v }; EXPECT( *std::move( e) == Implicit{v} ); EXPECT( *std::move(ec) == Implicit{v} ); } CASE( "expected: Allows to modify its value via a l-value reference" ) { const auto v1 = 7; const auto v2 = 42; expected e{ v1 }; *e = Implicit{v2}; EXPECT( *e == Implicit{v2} ); } CASE( "expected: Allows to modify its value via a r-value reference" ) { const auto v1 = 7; const auto v2 = 42; expected e{ v1 }; #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 *std::move(e) = Implicit{v2}; #else *e = Implicit{v2}; // non-r-value #endif EXPECT( *e == Implicit{v2} ); } CASE( "expected: Allows to observe if it contains a value (or error)" ) { expected e; expected u{ unexpect, 3 }; EXPECT( e ); EXPECT( !u ); } CASE( "expected: Allows to observe its value" ) { const auto v = 7; expected e{ v }; expected const ec{ v }; EXPECT( e.value() == Implicit{v} ); EXPECT( ec.value() == Implicit{v} ); } CASE( "expected: Allows to modify its value" ) { const auto v1 = 7; const auto v2 = 42; expected e{ v1 }; e.value() = Implicit{v2}; EXPECT( e.value() == Implicit{v2} ); } CASE( "expected: Allows to move its value" ) { const auto v = 7; expected m{ v }; expected const mc{ v }; expected e{ std::move(m ).value() }; expected ec{ std::move(mc).value() }; EXPECT( e.value() == Implicit{v} ); EXPECT( ec.value() == Implicit{v} ); } CASE( "expected: Allows to observe its error" ) { const auto v = 7; expected e{ unexpect, v }; expected const ec{ unexpect, v }; EXPECT( e.error() == Implicit{v} ); EXPECT( ec.error() == Implicit{v} ); } CASE( "expected: Allows to modify its error" ) { const auto v1 = 7; const auto v2 = 42; expected e{ unexpect, v1 }; e.error() = Implicit{v2}; EXPECT( e.error() == Implicit{v2} ); } CASE( "expected: Allows to move its error" ) { const auto v = 7; expected m{ unexpect, v }; expected const mc{ unexpect, v }; expected e{ unexpect, std::move(m ).error() }; expected ec{ unexpect, std::move(mc).error() }; EXPECT( e.error() == Implicit{v} ); EXPECT( ec.error() == Implicit{v} ); } CASE( "expected: Allows to observe its error as unexpected" ) { #if !nsel_USES_STD_EXPECTED const auto v = 7; expected e{ unexpect, v }; EXPECT( e.get_unexpected().error() == v ); #else EXPECT( !!"expected::get_unexpected() is not available (using C++23 std::expected)" ); #endif } CASE( "expected: Allows to query if it contains an exception of a specific base type" ) { #if !nsel_USES_STD_EXPECTED expected e{ unexpect, std::out_of_range( "oor" ) }; EXPECT( e.has_exception< std::logic_error >() ); EXPECT( !e.has_exception< std::runtime_error >() ); #else EXPECT( !!"expected::has_exception() is not available (using C++23 std::expected)" ); #endif } CASE( "expected: Allows to observe its value if available, or obtain a specified value otherwise" ) { const auto ve = 3; const auto vu = 7; expected e{ ve }; expected u{ unexpect, 0 }; EXPECT( e.value_or( vu ) == ve ); EXPECT( u.value_or( vu ) == vu ); } CASE( "expected: Allows to move its value if available, or obtain a specified value otherwise" ) { const auto ve = 3; const auto vu = 7; expected mv{ ve }; expected mu{ unexpect, 0 }; EXPECT( std::move( mv ).value_or( vu ) == ve ); EXPECT( std::move( mu ).value_or( vu ) == vu ); } CASE( "expected: Throws bad_expected_access on value access when disengaged" ) { expected e{ unexpect, 7 }; expected ec{ unexpect, 7 }; EXPECT_THROWS( e.value() ); EXPECT_THROWS_AS( e.value(), bad_expected_access ); EXPECT_THROWS( ec.value() ); EXPECT_THROWS_AS( ec.value(), bad_expected_access ); EXPECT_THROWS( std::move( e).value() ); EXPECT_THROWS_AS( std::move( e).value(), bad_expected_access ); EXPECT_THROWS( std::move(ec).value() ); EXPECT_THROWS_AS( std::move(ec).value(), bad_expected_access ); } #if nsel_P2505R >= 4 CASE( "expected: Allows to observe its unexpected value, or fallback to the specified value with error_or" " [monadic p2505r4]") { const auto ve = 3; const auto vu = 7; expected e{ ve }; expected u{ unexpect, 0 }; EXPECT( e.error_or( vu ) == vu ); EXPECT( u.error_or( vu ) == 0 ); } #endif // nsel_P2505R >= 4 #if nsel_P2505R >= 3 CASE( "expected: Allows to map value with and_then" " [monadic p2505r3]" ) { const auto mul2 = []( int n ) -> expected { return n * 2; }; const auto to_unexpect42 = []( int ) -> expected { return make_unexpected( 42 ); }; { expected e{ 11 }; const expected ce{ 21 }; expected ue{ unexpect, 42 }; EXPECT( e.and_then( mul2 ).value() == 22 ); EXPECT( ce.and_then( mul2 ).value() == 42 ); EXPECT( !ue.and_then( mul2 ).has_value()); EXPECT( ue.and_then( mul2 ).error() == 42 ); EXPECT( !e.and_then( to_unexpect42 ).has_value()); EXPECT( e.and_then( to_unexpect42 ).error() == 42 ); EXPECT( ce.and_then( to_unexpect42 ).error() == 42 ); } const auto moveonly_x_mul2 = [](MoveOnly val) -> expected { return val.x * 2; }; EXPECT( (expected{ MoveOnly{ 33 } }).and_then( moveonly_x_mul2 ).value() == 66 ); EXPECT( (expected{ MoveOnly{ 15 } }).and_then( [](MoveOnly&&) -> expected { return make_unexpected( 42 ); } ).error() == 42 ); const auto map_to_void = [](int) -> expected { return {}; }; const auto map_to_void_unexpect42 = [](int) -> expected { return make_unexpected( 42 ); }; static_assert( std::is_same< expected, decltype( expected( 3 ).and_then( map_to_void ) ) >::value, "and_then mapping to void results in expected"); EXPECT( (expected(3)).and_then( map_to_void ).has_value() ); EXPECT( !(expected(3)).and_then( map_to_void_unexpect42 ).has_value() ); EXPECT( (expected(3)).and_then( map_to_void_unexpect42 ).error() == 42 ); } CASE( "expected: Allows to map unexpected with or_else" " [monadic p2505r3]" ) { const auto to_unexpect43 = []( int ) -> expected { return make_unexpected( 43 ); }; { expected e{ 11 }; const expected ce{ 21 }; expected ue{ unexpect, 42 }; EXPECT( e.or_else( to_unexpect43 ).has_value()); EXPECT( e.or_else( to_unexpect43 ).value() == 11 ); EXPECT( ce.or_else( to_unexpect43 ).value() == 21 ); EXPECT( !ue.or_else( to_unexpect43 ).has_value()); EXPECT( ue.or_else( to_unexpect43 ).error() == 43 ); } const auto fallback_throw = []( int ) -> expected { throw std::runtime_error( "or_else" ); }; EXPECT_THROWS_AS( (void)(expected{ unexpect, 42 }).or_else( fallback_throw ), std::runtime_error ); const auto moveonly_fallback_to_66 = [](int) -> expected { return MoveOnly{ 66 }; }; EXPECT( (expected{ MoveOnly{ 33 } }).or_else( moveonly_fallback_to_66 ).value() == 33 ); EXPECT( (expected{ unexpect, 15 }).or_else(moveonly_fallback_to_66).value() == 66 ); } CASE( "expected: Allows to transform value" " [monadic p2505r3]" ) { const auto mul2 = []( int n ) -> int { return n * 2; }; { expected e{ 11 }; const expected ce{ 21 }; expected ue{ unexpect, 42 }; EXPECT( e.transform( mul2 ).value() == 22 ); EXPECT( ce.transform( mul2 ).value() == 42 ); EXPECT( !ue.transform( mul2 ).has_value()); EXPECT( ue.transform( mul2 ).error() == 42 ); } expected, int>{std::vector{}}.transform([](const std::vector&) { }); #if nsel_P2505R >= 5 // R5 changed remove_cvref_t to remove_cv_t in transform/transform_error, which broke data member pointer transforms, // because the result type must be a valid expected value type, but expressions with reference types are not. const auto moveonly_map_to_x = [](MoveOnly val) { return val.x; }; #else const auto moveonly_map_to_x = &MoveOnly::x; #endif // nsel_P2505R >= 5 const auto moveonly_x_mul2 = [](MoveOnly val) -> int { return val.x * 2; }; EXPECT( (expected{ MoveOnly{ 33 } }).transform( moveonly_map_to_x ).value() == 33 ); EXPECT( (expected{ MoveOnly{ 33 } }).transform( moveonly_map_to_x ).transform( mul2 ).value() == 66 ); EXPECT( (expected{ MoveOnly{ 33 } }).transform( moveonly_x_mul2 ).has_value() ); EXPECT( (expected{ MoveOnly{ 33 } }).transform( moveonly_x_mul2 ).value() == 66 ); EXPECT( !(expected{ unexpect, 15 }).transform( [](MoveOnly&&) -> int { return 42; } ).has_value() ); EXPECT( (expected{ unexpect, 15 }).transform( [](MoveOnly&&) -> int { return 42; } ).error() == 15 ); const auto map_to_void = [](int) -> void { }; static_assert( std::is_same< expected, decltype( expected( 3 ).transform( map_to_void ) ) >::value, "transform to void results in expected" ); EXPECT( (expected(3)).transform( map_to_void ).has_value() ); static_assert( std::is_same< decltype( (expected(3)).transform( map_to_void ).value() ), void >::value, "transform to void results in void value" ); } CASE( "expected: Allows to map errors with transform_error" " [monadic p2505r3]" ) { const auto to_43 = []( int ) -> int { return 43; }; { expected e{ 11 }; const expected ce{ 21 }; expected ue{ unexpect, 42 }; EXPECT( e.transform_error( to_43 ).has_value()); EXPECT( e.transform_error( to_43 ).value() == 11 ); EXPECT( ce.transform_error( to_43 ).value() == 21 ); EXPECT( !ue.transform_error( to_43 ).has_value()); EXPECT( ue.transform_error( to_43 ).error() == 43 ); } } #endif // nsel_P2505R >= 3 // ----------------------------------------------------------------------- // expected specialization // x.x.4.1 expected constructors CASE( "expected: Allows to default-construct" ) { expected e; EXPECT( e.has_value() ); } CASE( "expected: Allows to copy-construct from expected: value" ) { expected a; expected b{ a }; EXPECT( b ); } CASE( "expected: Allows to copy-construct from expected: error" ) { expected a{ unexpect, 7 }; expected b{ a }; EXPECT( !b ); EXPECT( b.error() == 7 ); } CASE( "expected: Allows to move-construct from expected: value" ) { expected a; expected b{ std::move( a ) }; EXPECT( b ); EXPECT( a ); // postcondition: unchanged! } CASE( "expected: Allows to move-construct from expected: error" ) { expected a{ unexpect, 7 }; expected b{ std::move( a ) }; EXPECT( !b ); EXPECT( b.error() == 7 ); } CASE( "expected: Allows to in-place-construct" ) { expected e{ in_place }; EXPECT( e ); } CASE( "expected: Allows to copy-construct from unexpected, explicit converting" ) { unexpected_type u{ 7 }; expected e{ u }; EXPECT( e.error() == Explicit{7} ); } CASE( "expected: Allows to copy-construct from unexpected, non-explicit converting" ) { unexpected_type u{ 7 }; expected e{ u }; EXPECT( e.error() == Implicit{7} ); } CASE( "expected: Allows to move-construct from unexpected, explicit converting" ) { unexpected_type u{ 7 }; expected e{ std::move( u ) }; EXPECT( e.error() == Explicit{7} ); } CASE( "expected: Allows to move-construct from unexpected, non-explicit converting" ) { unexpected_type u{ 7 }; expected e{ std::move( u ) }; EXPECT( e.error() == Implicit{7} ); } CASE( "expected: Allows to in-place-construct unexpected_type" ) { expected e{ unexpect, 7 }; expected i{ unexpect, 7 }; EXPECT( e.error() == Explicit{7} ); EXPECT( i.error() == Implicit{7} ); } CASE( "expected: Allows to in-place-construct error from initializer_list" ) { expected e{ unexpect, { 7, 8, 9 }, 'a' }; EXPECT( !e ); EXPECT( e.error().vec[0] == 7 ); EXPECT( e.error().vec[1] == 8 ); EXPECT( e.error().vec[2] == 9 ); EXPECT( e.error().c == 'a'); } // x.x.4.3 expected assignment CASE( "expected: Allows to copy-assign from expected, value" ) { expected a; expected b; b = a; EXPECT( b ); } CASE( "expected: Allows to copy-assign from expected, error" ) { expected a{ unexpect, 7 }; expected b; b = a; EXPECT( !b ); EXPECT( b.error() == 7 ); } CASE( "expected: Allows to move-assign from expected, value" ) { expected a; expected b; b = std::move( a ); EXPECT( b ); } CASE( "expected: Allows to move-assign from expected, error" ) { expected a{ unexpect, 7 }; expected b; b = std::move( a ); EXPECT( !b ); EXPECT( b.error() == 7 ); } CASE( "expected: Allows to emplace value" ) { expected a{ unexpect, 7 }; a.emplace(); EXPECT( a ); } // x.x.4.4 expected swap CASE( "expected: Allows to be swapped" ) { using std::swap; SETUP("") { expected e1; expected e2; expected u1{ unexpect, '1' }; expected u2{ unexpect, '2' }; SECTION("value-value, member swap") { e1.swap( e2 ); EXPECT( e1 ); EXPECT( e2 ); } SECTION("error-error, member swap") { u1.swap( u2 ); EXPECT( u1.error() == '2' ); EXPECT( u2.error() == '1' ); } SECTION("value-error, member swap") { e1.swap( u1 ); EXPECT( e1.error() == '1' ); EXPECT( u1 ); } SECTION("error-value, member swap") { u1.swap( e1 ); EXPECT( u1 ); EXPECT( e1.error() == '1' ); } } } // x.x.4.5 expected observers CASE( "expected: Allows to observe if it contains a value (or error)" ) { expected e; expected u{ unexpect, 3 }; EXPECT( e ); EXPECT( !u ); } CASE( "expected: Allows to observe its value" ) { expected e; expected const ec; EXPECT( ( e.value(), true ) ); EXPECT( ( ec.value(), true ) ); } CASE( "expected: Allows to observe its error" ) { const auto v = 7; expected e{ unexpect, v }; expected const ec{ unexpect, v }; EXPECT( e.error() == Implicit{v} ); EXPECT( ec.error() == Implicit{v} ); } CASE( "expected: Allows to modify its error" ) { const auto v1 = 7; const auto v2 = 42; expected e{ unexpect, v1 }; e.error() = Implicit{v2}; EXPECT( e.error() == Implicit{v2} ); } CASE( "expected: Allows to move its error" ) { const auto v = 7; expected m{ unexpect, v }; expected const mc{ unexpect, v }; expected e{ unexpect, std::move(m ).error() }; expected ec{ unexpect, std::move(mc).error() }; EXPECT( e.error() == Implicit{v} ); EXPECT( ec.error() == Implicit{v} ); } CASE( "expected: Allows to observe its error as unexpected" ) { #if !nsel_USES_STD_EXPECTED const auto value = 7; expected e{ unexpect, value }; EXPECT( e.get_unexpected().error() == value ); #else EXPECT( !!"expected::get_unexpected() is not available (using C++23 std::expected)" ); #endif } CASE( "expected: Allows to query if it contains an exception of a specific base type" ) { #if !nsel_USES_STD_EXPECTED expected e{ unexpect, std::out_of_range( "oor" ) }; EXPECT( e.has_exception< std::logic_error >() ); EXPECT( !e.has_exception< std::runtime_error >() ); #else EXPECT( !!"expected::has_exception() is not available (using C++23 std::expected)" ); #endif } CASE( "expected: Throws bad_expected_access on value access when disengaged" ) { expected e{ unexpect, 7 }; expected ec{ unexpect, 7 }; EXPECT_THROWS( e.value() ); EXPECT_THROWS_AS( e.value(), bad_expected_access ); EXPECT_THROWS( ec.value() ); EXPECT_THROWS_AS( ec.value(), bad_expected_access ); EXPECT_THROWS( std::move( e).value() ); EXPECT_THROWS_AS( std::move( e).value(), bad_expected_access ); EXPECT_THROWS( std::move(ec).value() ); EXPECT_THROWS_AS( std::move(ec).value(), bad_expected_access ); } #if nsel_P2505R >= 4 CASE( "expected: Allows to observe unexpected value, or fallback to a default value with error_or" " [monadic p2505r4]" ) { const auto vu = 7; expected e; expected u{ unexpect, 0 }; EXPECT( e.error_or( vu ) == vu ); EXPECT( u.error_or( vu ) == 0 ); } #endif // nsel_P2505R >= 4 #if nsel_P2505R >= 3 CASE( "expected: Allows to call argless functions with and_then" " [monadic p2505r3]" ) { const auto ret22 = []() -> expected { return 22; }; const auto unexpect32 = []() -> expected { return make_unexpected( 32 ); }; { expected e; const expected ce; expected ue{ unexpect, 42 }; EXPECT( e.has_value() ); EXPECT( ce.has_value() ); EXPECT( e.and_then( ret22 ).value() == 22 ); EXPECT( ce.and_then( ret22 ).value() == 22 ); EXPECT( !ue.and_then( ret22 ).has_value()); EXPECT( ue.and_then( ret22 ).error() == 42 ); EXPECT( !e.and_then( unexpect32 ).has_value()); EXPECT( e.and_then( unexpect32 ).error() == 32 ); EXPECT( ce.and_then( unexpect32 ).error() == 32 ); } { bool called = false; expected e; e.and_then( [&called]() -> expected { called = true; return {}; } ); EXPECT( called ); } { bool called = false; expected{}.and_then( [&called]() -> expected { called = true; return {}; } ); EXPECT( called ); } { bool called = false; expected{ unexpect, 42 }.and_then( [&called]() -> expected { called = true; return {}; } ); EXPECT( !called ); } const bool map_to_unexpect_success = !expected{}.and_then( []() -> expected { return make_unexpected( 42 ); } ).has_value(); EXPECT( map_to_unexpect_success ); } CASE( "expected: Allows to map to expected or unexpected with or_else" " [monadic p2505r3]" ) { const auto make_valid = [](int) -> expected { return {}; }; const auto unexpect32 = [](int) -> expected { return make_unexpected( 32 ); }; { expected e; const expected ce; expected ue{ unexpect, 42 }; EXPECT( e.has_value() ); EXPECT( ce.has_value() ); EXPECT( e.or_else( unexpect32 ).has_value()); static_assert( std::is_same< decltype( e.or_else( unexpect32 ).value() ), void >::value, "or_else mapping to void results in void value" ); EXPECT( ce.or_else( unexpect32 ).has_value()); EXPECT( !ue.or_else( unexpect32 ).has_value()); EXPECT( ue.or_else( make_valid ).has_value() ); static_assert( std::is_same< decltype( ue.or_else( make_valid ).value() ), void >::value, "or_else mapping to void results in void value" ); EXPECT( ue.or_else( unexpect32 ).error() == 32 ); } } CASE( "expected: Allows to assign a new expected value using transform" " [monadic p2505r3]" ) { const auto make_int_32 = [] { return 32; }; const auto mul2 = [](int v) { return v * 2; }; expected e; static_assert( std::is_same< decltype( e.transform( make_int_32 ) )::value_type, int >::value, "" ); EXPECT( e.transform( make_int_32 ).value() == 32 ); EXPECT( e.transform( make_int_32 ).transform( mul2 ).value() == 64 ); } CASE( "expected: Allows to map unexpected error value via transform_error" " [monadic p2505r3]" ) { const auto mul2 = []( int v ) -> int { return v * 2; }; enum class my_error { einval }; const auto map_to_my_error = [](int) { return my_error::einval; }; { expected e; const expected ce; expected ue{ unexpect, 42 }; EXPECT( e.transform_error( mul2 ).has_value()); EXPECT( ce.transform_error( mul2 ).has_value()); EXPECT( !ue.transform_error( mul2 ).has_value()); EXPECT( ue.transform_error( mul2 ).error() == 84 ); EXPECT( ue.transform_error( map_to_my_error ).error() == my_error::einval ); } } #endif // nsel_P2505R >= 3 // [expected<> unwrap()] // [expected<> factories] // x.x.4.7 expected<>: relational operators CASE( "operators: Provides expected relational operators" ) { SETUP( "" ) { auto v1 = 6; auto v2 = 7; expected e1( v1 ); expected e2( v2 ); unexpected_type u( 'u' ); expected d( u ); // compare engaged expected with engaged expected SECTION( "engaged == engaged" ) { EXPECT( e1 == e1 ); } SECTION( "engaged != engaged" ) { EXPECT( e1 != e2 ); } #if nsel_P0323R <= 2 SECTION( "engaged < engaged" ) { EXPECT( e1 < e2 ); } SECTION( "engaged > engaged" ) { EXPECT( e2 > e1 ); } SECTION( "engaged <= engaged" ) { EXPECT( e1 <= e1 ); } SECTION( "engaged <= engaged" ) { EXPECT( e1 <= e2 ); } SECTION( "engaged >= engaged" ) { EXPECT( e1 >= e1 ); } SECTION( "engaged >= engaged" ) { EXPECT( e2 >= e1 ); } #endif // compare engaged expected with value SECTION( "engaged == value" ) { EXPECT( e1 == v1 ); } SECTION( "value == engaged" ) { EXPECT( v1 == e1 ); } SECTION( "engaged != value" ) { EXPECT( e1 != v2 ); } SECTION( "value != engaged" ) { EXPECT( v1 != e2 ); } #if nsel_P0323R <= 2 SECTION( "engaged < value" ) { EXPECT( e1 < v2 ); } SECTION( "value < engaged" ) { EXPECT( v1 < e2 ); } SECTION( "engaged > value" ) { EXPECT( e2 > v1 ); } SECTION( "value > engaged" ) { EXPECT( v2 > e1 ); } SECTION( "engaged <= value" ) { EXPECT( e1 <= v2 ); } SECTION( "value <= engaged" ) { EXPECT( v1 <= e2 ); } SECTION( "engaged >= value" ) { EXPECT( e2 >= v1 ); } SECTION( "value >= engaged" ) { EXPECT( v2 >= e1 ); } #endif // compare engaged expected with disengaged expected SECTION( "engaged == disengaged" ) { EXPECT_NOT( e1 == d ); } SECTION( "disengaged == engaged" ) { EXPECT_NOT( d == e1 ); } SECTION( "engaged != disengaged" ) { EXPECT ( e1 != d ); } SECTION( "disengaged != engaged" ) { EXPECT ( d != e2 ); } #if nsel_P0323R <= 2 SECTION( "engaged < disengaged" ) { EXPECT_NOT( e1 < d ); } SECTION( "disengaged < engaged" ) { EXPECT ( d < e2 ); } SECTION( "engaged > disengaged" ) { EXPECT ( e2 > d ); } SECTION( "disengaged > engaged" ) { EXPECT_NOT( d > e1 ); } SECTION( "engaged <= disengaged" ) { EXPECT_NOT( e1 <= d ); } SECTION( "disengaged <= engaged" ) { EXPECT ( d <= e2 ); } SECTION( "engaged >= disengaged" ) { EXPECT ( e2 >= d ); } SECTION( "disengaged >= engaged" ) { EXPECT_NOT( d >= e1 ); } #endif // compare engaged expected with unexpected SECTION( "disengaged == unexpected" ) { EXPECT ( d == u ); } SECTION( "unexpected == disengaged" ) { EXPECT ( u == d ); } SECTION( "engaged != unexpected" ) { EXPECT ( e1 != u ); } SECTION( "unexpected != engaged" ) { EXPECT ( u != e1 ); } #if nsel_P0323R <= 2 SECTION( "disengaged < unexpected" ) { EXPECT_NOT( d < u ); } SECTION( "unexpected < disengaged" ) { EXPECT_NOT( u < d ); } SECTION( "disengaged <= unexpected" ) { EXPECT ( d <= u ); } SECTION( "unexpected <= disengaged" ) { EXPECT ( u <= d ); } SECTION( "disengaged > unexpected" ) { EXPECT_NOT( d > u ); } SECTION( "unexpected > disengaged" ) { EXPECT_NOT( u > d ); } SECTION( "disengaged >= unexpected" ) { EXPECT ( d >= u ); } SECTION( "unexpected >= disengaged" ) { EXPECT ( u >= d ); } #endif } } CASE( "operators: Provides expected relational operators (void)" ) { SETUP( "" ) { expected ev1; expected ev2; expected evu{ unexpect }; // compare engaged expected with engaged expected SECTION( " engaged == engaged" ) { EXPECT( ev1 == ev2 ); } SECTION( "!(engaged != engaged)" ) { EXPECT_NOT( ev1 != ev2 ); } // compare engaged expected with disengaged expected SECTION( " engaged != disengaged" ) { EXPECT( ev1 != evu ); } SECTION( "!(engaged == disengaged)" ) { EXPECT_NOT( ev1 == evu ); } } } // ----------------------------------------------------------------------- // expected: specialized algorithms // ----------------------------------------------------------------------- // Other CASE( "swap: Allows expected to be swapped" ) { using std::swap; SETUP("") { expected e1{ 1 }; expected e2{ 2 }; expected u1{ unexpect, '1' }; expected u2{ unexpect, '2' }; SECTION("value-value, std::swap") { swap( e1, e2 ); EXPECT( e1.value() == 2 ); EXPECT( e2.value() == 1 ); } SECTION("error-error, std::swap") { swap( u1, u2 ); EXPECT( u1.error() == '2' ); EXPECT( u2.error() == '1' ); } SECTION("value-error, std::swap") { swap( e1, u1 ); EXPECT( e1.error() == '1' ); EXPECT( u1.value() == 1 ); } SECTION("error-value, std::swap") { swap( u1, e1 ); EXPECT( u1.value() == 1 ); EXPECT( e1.error() == '1' ); } } } CASE( "std::hash: Allows to compute hash value for expected" ) { #if !nsel_USES_STD_EXPECTED expected a{ 7 }; expected b{ 7 }; EXPECT( (std::hash< expected >{}( a )) == (std::hash< expected >{}( b )) ); #else EXPECT( !!"std::hash> is not available for std::unexpected (C++23)." ); #endif } #if nsel_P0323R <= 3 #include void vfoo() {} expected foo() { return make_expected( 7 ); } expected> bar() { return make_expected( std::unique_ptr( new int(7) ) ); } #endif // nsel_P0323R CASE( "make_expected(): create expected from given value" "[.deprecated]" ) { #if nsel_P0323R <= 3 auto e = make_expected( 7 ); EXPECT( e ); EXPECT( *e == 7 ); #else EXPECT( !!"make_expected() is not available (nsel_P0323R > 3)" ); #endif } CASE( "make_expected(): create expected" "[.deprecated]" ) { #if nsel_P0323R <= 3 auto e = make_expected(); EXPECT( e ); #else EXPECT( !!"make_expected() is not available (nsel_P0323R > 3)" ); #endif } CASE( "make_expected_from_current_exception(): create expected from current exception" "[.deprecated]" ) { #if nsel_P0323R <= 3 EXPECT( !!"Implement" ); #else EXPECT( !!"make_expected() is not available (nsel_P0323R > 3)" ); #endif } CASE( "make_expected_from_exception(): create expected from given exception" "[.deprecated]" ) { #if nsel_P0323R <= 3 EXPECT( !!"Implement" ); #else EXPECT( !!"make_expected() is not available (nsel_P0323R > 3)" ); #endif } CASE( "make_expected_from_call(): non-void return type" "[.deprecated]" ) { #if nsel_P0323R <= 3 expected ei = foo(); expected> eup = bar(); auto e2 = make_expected_from_call( foo ); auto eup2 = make_expected_from_call( bar ); EXPECT( e2 ); EXPECT( eup2 ); #else EXPECT( !!"make_expected_from_call() is not available (nsel_P0323R > 3)" ); #endif } CASE( "make_expected_from_call(): void return type" "[.deprecated]" ) { #if nsel_P0323R <= 3 auto ev = make_expected_from_call( vfoo ); EXPECT( ev ); #else EXPECT( !!"make_expected_from_call() is not available (nsel_P0323R > 3)" ); #endif } CASE( "tweak header: reads tweak header if supported " "[tweak]" ) { #if expected_HAVE_TWEAK_HEADER EXPECT( EXPECTED_TWEAK_VALUE == 42 ); #else EXPECT( !!"Tweak header is not available (expected_HAVE_TWEAK_HEADER: 0)." ); #endif } // ----------------------------------------------------------------------- // expected: issues // issue #15, https://github.com/martinmoene/expected-dark/issues/15 CASE( "issue-15d" ) { nonstd::expected< int, std::error_code > e = 12; (void)e.value(); } // issue #15, https://github.com/martinmoene/expected-lite/issues/15 CASE( "issue-15" ) { (void) nonstd::expected< int, int >( 12).value(); } // issue #29, https://github.com/martinmoene/expected-lite/issues/29 // issue #32, https://github.com/martinmoene/expected-lite/issues/32 namespace issue_32 { enum class Error { Bad }; class MyNonMoveableObject { public: MyNonMoveableObject() = default; MyNonMoveableObject( MyNonMoveableObject const & ) = default; MyNonMoveableObject( MyNonMoveableObject && ) = delete; MyNonMoveableObject& operator=( MyNonMoveableObject const &) = default; MyNonMoveableObject& operator=( MyNonMoveableObject &&) = delete; ~MyNonMoveableObject() = default; }; nonstd::expected< MyNonMoveableObject, Error > create_copyable() { return nonstd::expected< MyNonMoveableObject, Error >{}; } class MyNonCopyableObject { public: MyNonCopyableObject() = default; MyNonCopyableObject( MyNonCopyableObject const & ) = delete; MyNonCopyableObject( MyNonCopyableObject && ) = default; MyNonCopyableObject& operator=( MyNonCopyableObject const & ) = delete; MyNonCopyableObject& operator=( MyNonCopyableObject && ) = default; ~MyNonCopyableObject() = default; }; nonstd::expected< MyNonCopyableObject, Error > create_moveable() { return MyNonCopyableObject{}; } } // namespace issue_32 CASE( "pr-41" ) { expected a{7}; const expected ca{7}; expected b{unexpect, 7}; const expected cb{unexpect, 7}; expected c{unexpect, 7}; const expected cc{unexpect, 7}; EXPECT( *std::move(a) == 7 ); EXPECT( *std::move(ca) == 7 ); EXPECT( std::move(b).error() == 7 ); EXPECT( std::move(cb).error() == 7 ); EXPECT( std::move(c).error() == 7 ); EXPECT( std::move(cc).error() == 7 ); } // issue #50, https://github.com/martinmoene/expected-lite/issues/50 namespace issue_50 { struct MyConstMemberNonMoveableObject { const int x; MyConstMemberNonMoveableObject( int x_ ) : x( x_ ) {} MyConstMemberNonMoveableObject( MyConstMemberNonMoveableObject const & ) = default; }; nonstd::unexpected_type create_nonmoveable() { return nonstd::make_unexpected( MyConstMemberNonMoveableObject(3) ); } } // namespace issue_50 namespace issue_51 { int compare_equal_with_expected_void() { auto ev1 = nonstd::expected{}; auto ev2 = nonstd::expected{}; return ev1 == ev2; } int compare_not_equal_with_expected_void() { auto ev1 = nonstd::expected{}; auto ev2 = nonstd::expected{}; return ev1 != ev2; } } // namespace issue_51 namespace issue_59 { struct NonMovableNonCopyable { NonMovableNonCopyable() = default; NonMovableNonCopyable( NonMovableNonCopyable const & ) = delete; NonMovableNonCopyable( NonMovableNonCopyable && ) = delete; NonMovableNonCopyable& operator=( NonMovableNonCopyable const & ) = delete; NonMovableNonCopyable& operator=( NonMovableNonCopyable && ) = delete; }; } // namespace issue_59 CASE( "issue-58" ) { static_assert( !std::is_copy_constructible::value, "is not copy constructible" ); static_assert( !std::is_move_constructible::value, "is not move constructible" ); nonstd::expected expected; nonstd::expected unexpected( nonstd::unexpect_t{} ); EXPECT( expected.has_value() ); EXPECT( !unexpected.has_value() ); } namespace issue_70 { struct overload_addressof { overload_addressof * operator & () { assert( 0 && "operator&() called"); return this; } }; } // namespace issue_70 CASE("issue-70") { nonstd::expected e; } #if !nsel_USES_STD_EXPECTED && nsel_P2505R >= 3 CASE( "invoke" ) { struct A { int x; constexpr int get() const { return x; } constexpr int get2(char) const { return x; } }; static_assert( nonstd::expected_lite::detail::invoke( &A::x, A{21} ) == 21, "" ); EXPECT( nonstd::expected_lite::detail::invoke( &MoveOnly::x, MoveOnly(42) ) == 42 ); constexpr A lval{ 7 }; static_assert( nonstd::expected_lite::detail::invoke( &A::x, lval ) == 7, "" ); A mut_lval{ 12 }; std::reference_wrapper ref{ mut_lval }; const std::reference_wrapper cref{ lval }; EXPECT( nonstd::expected_lite::detail::invoke( &A::x, ref ) == 12 ); EXPECT( nonstd::expected_lite::detail::invoke( &A::x, cref ) == 7 ); static_assert( nonstd::expected_lite::detail::invoke(&A::x, &lval) == 7, "" ); static_assert( nonstd::expected_lite::detail::invoke(&A::get, &lval) == 7, "" ); static_assert( nonstd::expected_lite::detail::invoke(&A::get, A{77}) == 77, "" ); EXPECT( nonstd::expected_lite::detail::invoke(&A::get, ref) == 12 ); EXPECT( nonstd::expected_lite::detail::invoke(&A::get, cref) == 7 ); static_assert( nonstd::expected_lite::detail::invoke(&A::get2, &lval, 'a') == 7, "" ); static_assert( nonstd::expected_lite::detail::invoke(&A::get2, A{77}, 'a') == 77, "" ); EXPECT( nonstd::expected_lite::detail::invoke(&A::get2, ref, 'a') == 12 ); EXPECT( nonstd::expected_lite::detail::invoke(&A::get2, cref, 'a') == 7 ); } #endif // nsel_USES_STD_EXPECTED && nsel_P2505R >= 3 // ----------------------------------------------------------------------- // using as optional #if 1 /// disengaged optional state tag struct nullopt_t{}; nsel_MAYBE_UNUSED const nullopt_t nullopt{}; /// optional expressed in expected template< typename T > using optional = expected; #endif expected-lite-0.10.0/test/lest/000077500000000000000000000000001510672106500162555ustar00rootroot00000000000000expected-lite-0.10.0/test/lest/lest.hpp000066400000000000000000001267551510672106500177550ustar00rootroot00000000000000// Copyright 2013-2018 by Martin Moene // // lest is based on ideas by Kevlin Henney, see video at // http://skillsmatter.com/podcast/agile-testing/kevlin-henney-rethinking-unit-testing-in-c-plus-plus // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef LEST_LEST_HPP_INCLUDED #define LEST_LEST_HPP_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define lest_MAJOR 1 #define lest_MINOR 35 #define lest_PATCH 1 #define lest_VERSION lest_STRINGIFY(lest_MAJOR) "." lest_STRINGIFY(lest_MINOR) "." lest_STRINGIFY(lest_PATCH) #ifndef lest_FEATURE_AUTO_REGISTER # define lest_FEATURE_AUTO_REGISTER 0 #endif #ifndef lest_FEATURE_COLOURISE # define lest_FEATURE_COLOURISE 0 #endif #ifndef lest_FEATURE_LITERAL_SUFFIX # define lest_FEATURE_LITERAL_SUFFIX 0 #endif #ifndef lest_FEATURE_REGEX_SEARCH # define lest_FEATURE_REGEX_SEARCH 0 #endif #ifndef lest_FEATURE_TIME_PRECISION # define lest_FEATURE_TIME_PRECISION 0 #endif #ifndef lest_FEATURE_WSTRING # define lest_FEATURE_WSTRING 1 #endif #ifdef lest_FEATURE_RTTI # define lest__cpp_rtti lest_FEATURE_RTTI #elif defined(__cpp_rtti) # define lest__cpp_rtti __cpp_rtti #elif defined(__GXX_RTTI) || defined (_CPPRTTI) # define lest__cpp_rtti 1 #else # define lest__cpp_rtti 0 #endif #if lest_FEATURE_REGEX_SEARCH # include #endif // Stringify: #define lest_STRINGIFY( x ) lest_STRINGIFY_( x ) #define lest_STRINGIFY_( x ) #x // Compiler warning suppression: #if defined (__clang__) # pragma clang diagnostic ignored "-Waggregate-return" # pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunused-comparison" #elif defined (__GNUC__) # pragma GCC diagnostic ignored "-Waggregate-return" # pragma GCC diagnostic push #endif // Suppress shadow and unused-value warning for sections: #if defined (__clang__) # define lest_SUPPRESS_WSHADOW _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wshadow\"" ) # define lest_SUPPRESS_WUNUSED _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wunused-value\"" ) # define lest_RESTORE_WARNINGS _Pragma( "clang diagnostic pop" ) #elif defined (__GNUC__) # define lest_SUPPRESS_WSHADOW _Pragma( "GCC diagnostic push" ) \ _Pragma( "GCC diagnostic ignored \"-Wshadow\"" ) # define lest_SUPPRESS_WUNUSED _Pragma( "GCC diagnostic push" ) \ _Pragma( "GCC diagnostic ignored \"-Wunused-value\"" ) # define lest_RESTORE_WARNINGS _Pragma( "GCC diagnostic pop" ) #else # define lest_SUPPRESS_WSHADOW /*empty*/ # define lest_SUPPRESS_WUNUSED /*empty*/ # define lest_RESTORE_WARNINGS /*empty*/ #endif // C++ language version detection (C++20 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. #ifndef lest_CPLUSPLUS # if defined(_MSVC_LANG ) && !defined(__clang__) # define lest_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) # else # define lest_CPLUSPLUS __cplusplus # endif #endif #define lest_CPP98_OR_GREATER ( lest_CPLUSPLUS >= 199711L ) #define lest_CPP11_OR_GREATER ( lest_CPLUSPLUS >= 201103L ) #define lest_CPP14_OR_GREATER ( lest_CPLUSPLUS >= 201402L ) #define lest_CPP17_OR_GREATER ( lest_CPLUSPLUS >= 201703L ) #define lest_CPP20_OR_GREATER ( lest_CPLUSPLUS >= 202000L ) #if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES ) # define MODULE lest_MODULE # if ! lest_FEATURE_AUTO_REGISTER # define CASE lest_CASE # define CASE_ON lest_CASE_ON # define SCENARIO lest_SCENARIO # endif # define SETUP lest_SETUP # define SECTION lest_SECTION # define EXPECT lest_EXPECT # define EXPECT_NOT lest_EXPECT_NOT # define EXPECT_NO_THROW lest_EXPECT_NO_THROW # define EXPECT_THROWS lest_EXPECT_THROWS # define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS # define GIVEN lest_GIVEN # define WHEN lest_WHEN # define THEN lest_THEN # define AND_WHEN lest_AND_WHEN # define AND_THEN lest_AND_THEN #endif #if lest_FEATURE_AUTO_REGISTER #define lest_SCENARIO( specification, sketch ) lest_CASE( specification, lest::text("Scenario: ") + sketch ) #else #define lest_SCENARIO( sketch ) lest_CASE( lest::text("Scenario: ") + sketch ) #endif #define lest_GIVEN( context ) lest_SETUP( lest::text(" Given: ") + context ) #define lest_WHEN( story ) lest_SECTION( lest::text(" When: ") + story ) #define lest_THEN( story ) lest_SECTION( lest::text(" Then: ") + story ) #define lest_AND_WHEN( story ) lest_SECTION( lest::text("And then: ") + story ) #define lest_AND_THEN( story ) lest_SECTION( lest::text("And then: ") + story ) #if lest_FEATURE_AUTO_REGISTER # define lest_CASE( specification, proposition ) \ static void lest_FUNCTION( lest::env & ); \ namespace { lest::add_test lest_REGISTRAR( specification, lest::test( proposition, lest_FUNCTION ) ); } \ static void lest_FUNCTION( lest::env & lest_env ) #else // lest_FEATURE_AUTO_REGISTER # define lest_CASE( proposition ) \ proposition, []( lest::env & lest_env ) # define lest_CASE_ON( proposition, ... ) \ proposition, [__VA_ARGS__]( lest::env & lest_env ) # define lest_MODULE( specification, module ) \ namespace { lest::add_module _( specification, module ); } #endif //lest_FEATURE_AUTO_REGISTER #define lest_SETUP( context ) \ for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \ for ( lest::ctx lest__ctx_setup( lest_env, context ); lest__ctx_setup; ) #define lest_SECTION( proposition ) \ lest_SUPPRESS_WSHADOW \ static int lest_UNIQUE( id ) = 0; \ if ( lest::guard( lest_UNIQUE( id ), lest__section, lest__count ) ) \ for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \ for ( lest::ctx lest__ctx_section( lest_env, proposition ); lest__ctx_section; ) \ lest_RESTORE_WARNINGS #define lest_EXPECT( expr ) \ do { \ try \ { \ if ( lest::result score = lest_DECOMPOSE( expr ) ) \ throw lest::failure{ lest_LOCATION, #expr, score.decomposition }; \ else if ( lest_env.pass() ) \ lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition, lest_env.zen() }, lest_env.context() ); \ } \ catch(...) \ { \ lest::inform( lest_LOCATION, #expr ); \ } \ } while ( lest::is_false() ) #define lest_EXPECT_NOT( expr ) \ do { \ try \ { \ if ( lest::result score = lest_DECOMPOSE( expr ) ) \ { \ if ( lest_env.pass() ) \ lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ), lest_env.zen() }, lest_env.context() ); \ } \ else \ throw lest::failure{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }; \ } \ catch(...) \ { \ lest::inform( lest_LOCATION, lest::not_expr( #expr ) ); \ } \ } while ( lest::is_false() ) #define lest_EXPECT_NO_THROW( expr ) \ do \ { \ try \ { \ lest_SUPPRESS_WUNUSED \ expr; \ lest_RESTORE_WARNINGS \ } \ catch (...) \ { \ lest::inform( lest_LOCATION, #expr ); \ } \ if ( lest_env.pass() ) \ lest::report( lest_env.os, lest::got_none( lest_LOCATION, #expr ), lest_env.context() ); \ } while ( lest::is_false() ) #define lest_EXPECT_THROWS( expr ) \ do \ { \ try \ { \ lest_SUPPRESS_WUNUSED \ expr; \ lest_RESTORE_WARNINGS \ } \ catch (...) \ { \ if ( lest_env.pass() ) \ lest::report( lest_env.os, lest::got{ lest_LOCATION, #expr }, lest_env.context() ); \ break; \ } \ throw lest::expected{ lest_LOCATION, #expr }; \ } \ while ( lest::is_false() ) #define lest_EXPECT_THROWS_AS( expr, excpt ) \ do \ { \ try \ { \ lest_SUPPRESS_WUNUSED \ expr; \ lest_RESTORE_WARNINGS \ } \ catch ( excpt & ) \ { \ if ( lest_env.pass() ) \ lest::report( lest_env.os, lest::got{ lest_LOCATION, #expr, lest::of_type( #excpt ) }, lest_env.context() ); \ break; \ } \ catch (...) {} \ throw lest::expected{ lest_LOCATION, #expr, lest::of_type( #excpt ) }; \ } \ while ( lest::is_false() ) #define lest_UNIQUE( name ) lest_UNIQUE2( name, __LINE__ ) #define lest_UNIQUE2( name, line ) lest_UNIQUE3( name, line ) #define lest_UNIQUE3( name, line ) name ## line #define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << expr ) #define lest_FUNCTION lest_UNIQUE(__lest_function__ ) #define lest_REGISTRAR lest_UNIQUE(__lest_registrar__ ) #define lest_LOCATION lest::location{__FILE__, __LINE__} namespace lest { const int exit_max_value = 255; using text = std::string; using texts = std::vector; struct env; struct test { text name; std::function behaviour; #if lest_FEATURE_AUTO_REGISTER test( text name_, std::function behaviour_ ) : name( name_), behaviour( behaviour_) {} #endif }; using tests = std::vector; #if lest_FEATURE_AUTO_REGISTER struct add_test { add_test( tests & specification, test const & test_case ) { specification.push_back( test_case ); } }; #else struct add_module { template< std::size_t N > add_module( tests & specification, test const (&module)[N] ) { specification.insert( specification.end(), std::begin( module ), std::end( module ) ); } }; #endif struct result { const bool passed; const text decomposition; template< typename T > result( T const & passed_, text decomposition_) : passed( !!passed_), decomposition( decomposition_) {} explicit operator bool() { return ! passed; } }; struct location { const text file; const int line; location( text file_, int line_) : file( file_), line( line_) {} }; struct comment { const text info; comment( text info_) : info( info_) {} explicit operator bool() { return ! info.empty(); } }; struct message : std::runtime_error { const text kind; const location where; const comment note; ~message() throw() {} // GCC 4.6 message( text kind_, location where_, text expr_, text note_ = "" ) : std::runtime_error( expr_), kind( kind_), where( where_), note( note_) {} }; struct failure : message { failure( location where_, text expr_, text decomposition_) : message{ "failed", where_, expr_ + " for " + decomposition_ } {} }; struct success : message { // using message::message; // VC is lagging here success( text kind_, location where_, text expr_, text note_ = "" ) : message( kind_, where_, expr_, note_ ) {} }; struct passing : success { passing( location where_, text expr_, text decomposition_, bool zen ) : success( "passed", where_, expr_ + (zen ? "":" for " + decomposition_) ) {} }; struct got_none : success { got_none( location where_, text expr_ ) : success( "passed: got no exception", where_, expr_ ) {} }; struct got : success { got( location where_, text expr_) : success( "passed: got exception", where_, expr_) {} got( location where_, text expr_, text excpt_) : success( "passed: got exception " + excpt_, where_, expr_) {} }; struct expected : message { expected( location where_, text expr_, text excpt_ = "" ) : message{ "failed: didn't get exception", where_, expr_, excpt_ } {} }; struct unexpected : message { unexpected( location where_, text expr_, text note_ = "" ) : message{ "failed: got unexpected exception", where_, expr_, note_ } {} }; struct guard { int & id; int const & section; guard( int & id_, int const & section_, int & count ) : id( id_), section( section_) { if ( section == 0 ) id = count++ - 1; } operator bool() { return id == section; } }; class approx { public: explicit approx ( double magnitude ) : epsilon_ { std::numeric_limits::epsilon() * 100 } , scale_ { 1.0 } , magnitude_{ magnitude } {} approx( approx const & other ) = default; static approx custom() { return approx( 0 ); } approx operator()( double new_magnitude ) { approx appr( new_magnitude ); appr.epsilon( epsilon_ ); appr.scale ( scale_ ); return appr; } double magnitude() const { return magnitude_; } approx & epsilon( double epsilon ) { epsilon_ = epsilon; return *this; } approx & scale ( double scale ) { scale_ = scale; return *this; } friend bool operator == ( double lhs, approx const & rhs ) { // Thanks to Richard Harris for his help refining this formula. return std::abs( lhs - rhs.magnitude_ ) < rhs.epsilon_ * ( rhs.scale_ + (std::min)( std::abs( lhs ), std::abs( rhs.magnitude_ ) ) ); } friend bool operator == ( approx const & lhs, double rhs ) { return operator==( rhs, lhs ); } friend bool operator != ( double lhs, approx const & rhs ) { return !operator==( lhs, rhs ); } friend bool operator != ( approx const & lhs, double rhs ) { return !operator==( rhs, lhs ); } friend bool operator <= ( double lhs, approx const & rhs ) { return lhs < rhs.magnitude_ || lhs == rhs; } friend bool operator <= ( approx const & lhs, double rhs ) { return lhs.magnitude_ < rhs || lhs == rhs; } friend bool operator >= ( double lhs, approx const & rhs ) { return lhs > rhs.magnitude_ || lhs == rhs; } friend bool operator >= ( approx const & lhs, double rhs ) { return lhs.magnitude_ > rhs || lhs == rhs; } private: double epsilon_; double scale_; double magnitude_; }; inline bool is_false( ) { return false; } inline bool is_true ( bool flag ) { return flag; } inline text not_expr( text message ) { return "! ( " + message + " )"; } inline text with_message( text message ) { return "with message \"" + message + "\""; } inline text of_type( text type ) { return "of type " + type; } inline void inform( location where, text expr ) { try { throw; } catch( message const & ) { throw; } catch( std::exception const & e ) { throw unexpected{ where, expr, with_message( e.what() ) }; \ } catch(...) { throw unexpected{ where, expr, "of unknown type" }; \ } } // Expression decomposition: template< typename T > auto make_value_string( T const & value ) -> std::string; template< typename T > auto make_memory_string( T const & item ) -> std::string; #if lest_FEATURE_LITERAL_SUFFIX inline char const * sfx( char const * txt ) { return txt; } #else inline char const * sfx( char const * ) { return ""; } #endif inline std::string transformed( char chr ) { struct Tr { char chr; char const * str; } table[] = { {'\\', "\\\\" }, {'\r', "\\r" }, {'\f', "\\f" }, {'\n', "\\n" }, {'\t', "\\t" }, }; for ( auto tr : table ) { if ( chr == tr.chr ) return tr.str; } auto unprintable = [](char c){ return 0 <= c && c < ' '; }; auto to_hex_string = [](char c) { std::ostringstream os; os << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast( static_cast(c) ); return os.str(); }; return unprintable( chr ) ? to_hex_string( chr ) : std::string( 1, chr ); } inline std::string make_tran_string( std::string const & txt ) { std::ostringstream os; for(auto c:txt) os << transformed(c); return os.str(); } inline std::string make_strg_string( std::string const & txt ) { return "\"" + make_tran_string( txt ) + "\"" ; } inline std::string make_char_string( char chr ) { return "\'" + make_tran_string( std::string( 1, chr ) ) + "\'" ; } inline std::string to_string( std::nullptr_t ) { return "nullptr"; } inline std::string to_string( std::string const & txt ) { return make_strg_string( txt ); } #if lest_FEATURE_WSTRING inline std::string to_string( std::wstring const & txt ) ; #endif inline std::string to_string( char const * const txt ) { return txt ? make_strg_string( txt ) : "{null string}"; } inline std::string to_string( char * const txt ) { return txt ? make_strg_string( txt ) : "{null string}"; } #if lest_FEATURE_WSTRING inline std::string to_string( wchar_t const * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; } inline std::string to_string( wchar_t * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; } #endif inline std::string to_string( bool flag ) { return flag ? "true" : "false"; } inline std::string to_string( signed short value ) { return make_value_string( value ) ; } inline std::string to_string( unsigned short value ) { return make_value_string( value ) + sfx("u" ); } inline std::string to_string( signed int value ) { return make_value_string( value ) ; } inline std::string to_string( unsigned int value ) { return make_value_string( value ) + sfx("u" ); } inline std::string to_string( signed long value ) { return make_value_string( value ) + sfx("l" ); } inline std::string to_string( unsigned long value ) { return make_value_string( value ) + sfx("ul" ); } inline std::string to_string( signed long long value ) { return make_value_string( value ) + sfx("ll" ); } inline std::string to_string( unsigned long long value ) { return make_value_string( value ) + sfx("ull"); } inline std::string to_string( double value ) { return make_value_string( value ) ; } inline std::string to_string( float value ) { return make_value_string( value ) + sfx("f" ); } inline std::string to_string( signed char chr ) { return make_char_string( static_cast( chr ) ); } inline std::string to_string( unsigned char chr ) { return make_char_string( static_cast( chr ) ); } inline std::string to_string( char chr ) { return make_char_string( chr ); } template< typename T > struct is_streamable { template< typename U > static auto test( int ) -> decltype( std::declval() << std::declval(), std::true_type() ); template< typename > static auto test( ... ) -> std::false_type; #ifdef _MSC_VER enum { value = std::is_same< decltype( test(0) ), std::true_type >::value }; #else static constexpr bool value = std::is_same< decltype( test(0) ), std::true_type >::value; #endif }; template< typename T > struct is_container { template< typename U > static auto test( int ) -> decltype( std::declval().begin() == std::declval().end(), std::true_type() ); template< typename > static auto test( ... ) -> std::false_type; #ifdef _MSC_VER enum { value = std::is_same< decltype( test(0) ), std::true_type >::value }; #else static constexpr bool value = std::is_same< decltype( test(0) ), std::true_type >::value; #endif }; template< typename T, typename R > using ForEnum = typename std::enable_if< std::is_enum::value, R>::type; template< typename T, typename R > using ForNonEnum = typename std::enable_if< ! std::is_enum::value, R>::type; template< typename T, typename R > using ForStreamable = typename std::enable_if< is_streamable::value, R>::type; template< typename T, typename R > using ForNonStreamable = typename std::enable_if< ! is_streamable::value, R>::type; template< typename T, typename R > using ForContainer = typename std::enable_if< is_container::value, R>::type; template< typename T, typename R > using ForNonContainerNonPointer = typename std::enable_if< ! (is_container::value || std::is_pointer::value), R>::type; template< typename T > auto make_enum_string( T const & item ) -> ForNonEnum { #if lest__cpp_rtti return text("[type: ") + typeid(T).name() + "]: " + make_memory_string( item ); #else return text("[type: (no RTTI)]: ") + make_memory_string( item ); #endif } template< typename T > auto make_enum_string( T const & item ) -> ForEnum { return to_string( static_cast::type>( item ) ); } template< typename T > auto make_string( T const & item ) -> ForNonStreamable { return make_enum_string( item ); } template< typename T > auto make_string( T const & item ) -> ForStreamable { std::ostringstream os; os << item; return os.str(); } template auto make_string( std::pair const & pair ) -> std::string { std::ostringstream oss; oss << "{ " << to_string( pair.first ) << ", " << to_string( pair.second ) << " }"; return oss.str(); } template< typename TU, std::size_t N > struct make_tuple_string { static std::string make( TU const & tuple ) { std::ostringstream os; os << to_string( std::get( tuple ) ) << ( N < std::tuple_size::value ? ", ": " "); return make_tuple_string::make( tuple ) + os.str(); } }; template< typename TU > struct make_tuple_string { static std::string make( TU const & ) { return ""; } }; template< typename ...TS > auto make_string( std::tuple const & tuple ) -> std::string { return "{ " + make_tuple_string, sizeof...(TS)>::make( tuple ) + "}"; } template< typename T > inline std::string make_string( T const * ptr ) { // Note showbase affects the behavior of /integer/ output; std::ostringstream os; os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(T*) ) << std::setfill('0') << reinterpret_cast( ptr ); return os.str(); } template< typename C, typename R > inline std::string make_string( R C::* ptr ) { std::ostringstream os; os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(R C::* ) ) << std::setfill('0') << ptr; return os.str(); } template< typename T > auto to_string( T const * ptr ) -> std::string { return ! ptr ? "nullptr" : make_string( ptr ); } template auto to_string( R C::* ptr ) -> std::string { return ! ptr ? "nullptr" : make_string( ptr ); } template< typename T > auto to_string( T const & item ) -> ForNonContainerNonPointer { return make_string( item ); } template< typename C > auto to_string( C const & cont ) -> ForContainer { std::ostringstream os; os << "{ "; for ( auto & x : cont ) { os << to_string( x ) << ", "; } os << "}"; return os.str(); } #if lest_FEATURE_WSTRING inline auto to_string( std::wstring const & txt ) -> std::string { std::string result; result.reserve( txt.size() ); for( auto & chr : txt ) { result += chr <= 0xff ? static_cast( chr ) : '?'; } return to_string( result ); } #endif template< typename T > auto make_value_string( T const & value ) -> std::string { std::ostringstream os; os << value; return os.str(); } inline auto make_memory_string( void const * item, std::size_t size ) -> std::string { // reverse order for little endian architectures: auto is_little_endian = [] { union U { int i = 1; char c[ sizeof(int) ]; }; return 1 != U{}.c[ sizeof(int) - 1 ]; }; int i = 0, end = static_cast( size ), inc = 1; if ( is_little_endian() ) { i = end - 1; end = inc = -1; } unsigned char const * bytes = static_cast( item ); std::ostringstream os; os << "0x" << std::setfill( '0' ) << std::hex; for ( ; i != end; i += inc ) { os << std::setw(2) << static_cast( bytes[i] ) << " "; } return os.str(); } template< typename T > auto make_memory_string( T const & item ) -> std::string { return make_memory_string( &item, sizeof item ); } inline auto to_string( approx const & appr ) -> std::string { return to_string( appr.magnitude() ); } template< typename L, typename R > auto to_string( L const & lhs, std::string op, R const & rhs ) -> std::string { std::ostringstream os; os << to_string( lhs ) << " " << op << " " << to_string( rhs ); return os.str(); } template< typename L > struct expression_lhs { const L lhs; expression_lhs( L lhs_) : lhs( lhs_) {} operator result() { return result{ !!lhs, to_string( lhs ) }; } template< typename R > result operator==( R const & rhs ) { return result{ lhs == rhs, to_string( lhs, "==", rhs ) }; } template< typename R > result operator!=( R const & rhs ) { return result{ lhs != rhs, to_string( lhs, "!=", rhs ) }; } template< typename R > result operator< ( R const & rhs ) { return result{ lhs < rhs, to_string( lhs, "<" , rhs ) }; } template< typename R > result operator<=( R const & rhs ) { return result{ lhs <= rhs, to_string( lhs, "<=", rhs ) }; } template< typename R > result operator> ( R const & rhs ) { return result{ lhs > rhs, to_string( lhs, ">" , rhs ) }; } template< typename R > result operator>=( R const & rhs ) { return result{ lhs >= rhs, to_string( lhs, ">=", rhs ) }; } }; struct expression_decomposer { template expression_lhs operator<< ( L const & operand ) { return expression_lhs( operand ); } }; // Reporter: #if lest_FEATURE_COLOURISE inline text red ( text words ) { return "\033[1;31m" + words + "\033[0m"; } inline text green( text words ) { return "\033[1;32m" + words + "\033[0m"; } inline text gray ( text words ) { return "\033[1;30m" + words + "\033[0m"; } inline bool starts_with( text words, text with ) { return 0 == words.find( with ); } inline text replace( text words, text from, text to ) { size_t pos = words.find( from ); return pos == std::string::npos ? words : words.replace( pos, from.length(), to ); } inline text colour( text words ) { if ( starts_with( words, "failed" ) ) return replace( words, "failed", red ( "failed" ) ); else if ( starts_with( words, "passed" ) ) return replace( words, "passed", green( "passed" ) ); return replace( words, "for", gray( "for" ) ); } inline bool is_cout( std::ostream & os ) { return &os == &std::cout; } struct colourise { const text words; colourise( text words ) : words( words ) {} // only colourise for std::cout, not for a stringstream as used in tests: std::ostream & operator()( std::ostream & os ) const { return is_cout( os ) ? os << colour( words ) : os << words; } }; inline std::ostream & operator<<( std::ostream & os, colourise words ) { return words( os ); } #else inline text colourise( text words ) { return words; } #endif inline text pluralise( text word, int n ) { return n == 1 ? word : word + "s"; } inline std::ostream & operator<<( std::ostream & os, comment note ) { return os << (note ? " " + note.info : "" ); } inline std::ostream & operator<<( std::ostream & os, location where ) { #ifdef __GNUG__ return os << where.file << ":" << where.line; #else return os << where.file << "(" << where.line << ")"; #endif } inline void report( std::ostream & os, message const & e, text test ) { os << e.where << ": " << colourise( e.kind ) << e.note << ": " << test << ": " << colourise( e.what() ) << std::endl; } // Test runner: #if lest_FEATURE_REGEX_SEARCH inline bool search( text re, text line ) { return std::regex_search( line, std::regex( re ) ); } #else inline bool search( text part, text line ) { auto case_insensitive_equal = []( char a, char b ) { return tolower( a ) == tolower( b ); }; return std::search( line.begin(), line.end(), part.begin(), part.end(), case_insensitive_equal ) != line.end(); } #endif inline bool match( texts whats, text line ) { for ( auto & what : whats ) { if ( search( what, line ) ) return true; } return false; } inline bool select( text name, texts include ) { auto none = []( texts args ) { return args.size() == 0; }; #if lest_FEATURE_REGEX_SEARCH auto hidden = []( text arg ){ return match( { "\\[\\..*", "\\[hide\\]" }, arg ); }; #else auto hidden = []( text arg ){ return match( { "[.", "[hide]" }, arg ); }; #endif if ( none( include ) ) { return ! hidden( name ); } bool any = false; for ( auto pos = include.rbegin(); pos != include.rend(); ++pos ) { auto & part = *pos; if ( part == "@" || part == "*" ) return true; if ( search( part, name ) ) return true; if ( '!' == part[0] ) { any = true; if ( search( part.substr(1), name ) ) return false; } else { any = false; } } return any && ! hidden( name ); } inline int indefinite( int repeat ) { return repeat == -1; } using seed_t = std::mt19937::result_type; struct options { bool help = false; bool abort = false; bool count = false; bool list = false; bool tags = false; bool time = false; bool pass = false; bool zen = false; bool lexical = false; bool random = false; bool verbose = false; bool version = false; int repeat = 1; seed_t seed = 0; }; struct env { std::ostream & os; options opt; text testing; std::vector< text > ctx; env( std::ostream & out, options option ) : os( out ), opt( option ), testing(), ctx() {} env & operator()( text test ) { clear(); testing = test; return *this; } bool abort() { return opt.abort; } bool pass() { return opt.pass; } bool zen() { return opt.zen; } void clear() { ctx.clear(); } void pop() { ctx.pop_back(); } void push( text proposition ) { ctx.emplace_back( proposition ); } text context() { return testing + sections(); } text sections() { if ( ! opt.verbose ) return ""; text msg; for( auto section : ctx ) { msg += "\n " + section; } return msg; } }; struct ctx { env & environment; bool once; ctx( env & environment_, text proposition_ ) : environment( environment_), once( true ) { environment.push( proposition_); } ~ctx() { #if lest_CPP17_OR_GREATER if ( std::uncaught_exceptions() == 0 ) #else if ( ! std::uncaught_exception() ) #endif { environment.pop(); } } explicit operator bool() { bool result = once; once = false; return result; } }; struct action { std::ostream & os; action( std::ostream & out ) : os( out ) {} action( action const & ) = delete; void operator=( action const & ) = delete; operator int() { return 0; } bool abort() { return false; } action & operator()( test ) { return *this; } }; struct print : action { print( std::ostream & out ) : action( out ) {} print & operator()( test testing ) { os << testing.name << "\n"; return *this; } }; inline texts tags( text name, texts result = {} ) { auto none = std::string::npos; auto lb = name.find_first_of( "[" ); auto rb = name.find_first_of( "]" ); if ( lb == none || rb == none ) return result; result.emplace_back( name.substr( lb, rb - lb + 1 ) ); return tags( name.substr( rb + 1 ), result ); } struct ptags : action { std::set result; ptags( std::ostream & out ) : action( out ), result() {} ptags & operator()( test testing ) { for ( auto & tag : tags( testing.name ) ) result.insert( tag ); return *this; } ~ptags() { std::copy( result.begin(), result.end(), std::ostream_iterator( os, "\n" ) ); } }; struct count : action { int n = 0; count( std::ostream & out ) : action( out ) {} count & operator()( test ) { ++n; return *this; } ~count() { os << n << " selected " << pluralise("test", n) << "\n"; } }; struct timer { using time = std::chrono::high_resolution_clock; time::time_point start = time::now(); double elapsed_seconds() const { return 1e-6 * static_cast( std::chrono::duration_cast< std::chrono::microseconds >( time::now() - start ).count() ); } }; struct times : action { env output; int selected = 0; int failures = 0; timer total; times( std::ostream & out, options option ) : action( out ), output( out, option ), total() { os << std::setfill(' ') << std::fixed << std::setprecision( lest_FEATURE_TIME_PRECISION ); } operator int() { return failures; } bool abort() { return output.abort() && failures > 0; } times & operator()( test testing ) { timer t; try { testing.behaviour( output( testing.name ) ); } catch( message const & ) { ++failures; } os << std::setw(3) << ( 1000 * t.elapsed_seconds() ) << " ms: " << testing.name << "\n"; return *this; } ~times() { os << "Elapsed time: " << std::setprecision(1) << total.elapsed_seconds() << " s\n"; } }; struct confirm : action { env output; int selected = 0; int failures = 0; confirm( std::ostream & out, options option ) : action( out ), output( out, option ) {} operator int() { return failures; } bool abort() { return output.abort() && failures > 0; } confirm & operator()( test testing ) { try { ++selected; testing.behaviour( output( testing.name ) ); } catch( message const & e ) { ++failures; report( os, e, output.context() ); } return *this; } ~confirm() { if ( failures > 0 ) { os << failures << " out of " << selected << " selected " << pluralise("test", selected) << " " << colourise( "failed.\n" ); } else if ( output.pass() ) { os << "All " << selected << " selected " << pluralise("test", selected) << " " << colourise( "passed.\n" ); } } }; template< typename Action > bool abort( Action & perform ) { return perform.abort(); } template< typename Action > Action && for_test( tests specification, texts in, Action && perform, int n = 1 ) { for ( int i = 0; indefinite( n ) || i < n; ++i ) { for ( auto & testing : specification ) { if ( select( testing.name, in ) ) if ( abort( perform( testing ) ) ) return std::move( perform ); } } return std::move( perform ); } inline void sort( tests & specification ) { auto test_less = []( test const & a, test const & b ) { return a.name < b.name; }; std::sort( specification.begin(), specification.end(), test_less ); } inline void shuffle( tests & specification, options option ) { std::shuffle( specification.begin(), specification.end(), std::mt19937( option.seed ) ); } // workaround MinGW bug, http://stackoverflow.com/a/16132279: inline int stoi( text num ) { return static_cast( std::strtol( num.c_str(), nullptr, 10 ) ); } inline bool is_number( text arg ) { return std::all_of( arg.begin(), arg.end(), ::isdigit ); } inline seed_t seed( text opt, text arg ) { if ( is_number( arg ) ) return static_cast( lest::stoi( arg ) ); if ( arg == "time" ) return static_cast( std::chrono::high_resolution_clock::now().time_since_epoch().count() ); throw std::runtime_error( "expecting 'time' or positive number with option '" + opt + "', got '" + arg + "' (try option --help)" ); } inline int repeat( text opt, text arg ) { const int num = lest::stoi( arg ); if ( indefinite( num ) || num >= 0 ) return num; throw std::runtime_error( "expecting '-1' or positive number with option '" + opt + "', got '" + arg + "' (try option --help)" ); } inline auto split_option( text arg ) -> std::tuple { auto pos = arg.rfind( '=' ); return pos == text::npos ? std::make_tuple( arg, "" ) : std::make_tuple( arg.substr( 0, pos ), arg.substr( pos + 1 ) ); } inline auto split_arguments( texts args ) -> std::tuple { options option; texts in; bool in_options = true; for ( auto & arg : args ) { if ( in_options ) { text opt, val; std::tie( opt, val ) = split_option( arg ); if ( opt[0] != '-' ) { in_options = false; } else if ( opt == "--" ) { in_options = false; continue; } else if ( opt == "-h" || "--help" == opt ) { option.help = true; continue; } else if ( opt == "-a" || "--abort" == opt ) { option.abort = true; continue; } else if ( opt == "-c" || "--count" == opt ) { option.count = true; continue; } else if ( opt == "-g" || "--list-tags" == opt ) { option.tags = true; continue; } else if ( opt == "-l" || "--list-tests" == opt ) { option.list = true; continue; } else if ( opt == "-t" || "--time" == opt ) { option.time = true; continue; } else if ( opt == "-p" || "--pass" == opt ) { option.pass = true; continue; } else if ( opt == "-z" || "--pass-zen" == opt ) { option.zen = true; continue; } else if ( opt == "-v" || "--verbose" == opt ) { option.verbose = true; continue; } else if ( "--version" == opt ) { option.version = true; continue; } else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; } else if ( opt == "--order" && "lexical" == val ) { option.lexical = true; continue; } else if ( opt == "--order" && "random" == val ) { option.random = true; continue; } else if ( opt == "--random-seed" ) { option.seed = seed ( "--random-seed", val ); continue; } else if ( opt == "--repeat" ) { option.repeat = repeat( "--repeat" , val ); continue; } else throw std::runtime_error( "unrecognised option '" + arg + "' (try option --help)" ); } in.push_back( arg ); } option.pass = option.pass || option.zen; return std::make_tuple( option, in ); } inline int usage( std::ostream & os ) { os << "\nUsage: test [options] [test-spec ...]\n" "\n" "Options:\n" " -h, --help this help message\n" " -a, --abort abort at first failure\n" " -c, --count count selected tests\n" " -g, --list-tags list tags of selected tests\n" " -l, --list-tests list selected tests\n" " -p, --pass also report passing tests\n" " -z, --pass-zen ... without expansion\n" " -t, --time list duration of selected tests\n" " -v, --verbose also report passing or failing sections\n" " --order=declared use source code test order (default)\n" " --order=lexical use lexical sort test order\n" " --order=random use random test order\n" " --random-seed=n use n for random generator seed\n" " --random-seed=time use time for random generator seed\n" " --repeat=n repeat selected tests n times (-1: indefinite)\n" " --version report lest version and compiler used\n" " -- end options\n" "\n" "Test specification:\n" " \"@\", \"*\" all tests, unless excluded\n" " empty all tests, unless tagged [hide] or [.optional-name]\n" #if lest_FEATURE_REGEX_SEARCH " \"re\" select tests that match regular expression\n" " \"!re\" omit tests that match regular expression\n" #else " \"text\" select tests that contain text (case insensitive)\n" " \"!text\" omit tests that contain text (case insensitive)\n" #endif ; return 0; } inline text compiler() { std::ostringstream os; #if defined (__clang__ ) os << "clang " << __clang_version__; #elif defined (__GNUC__ ) os << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__; #elif defined ( _MSC_VER ) os << "MSVC " << (_MSC_VER / 100 - 5 - (_MSC_VER < 1900)) << " (" << _MSC_VER << ")"; #else os << "[compiler]"; #endif return os.str(); } inline int version( std::ostream & os ) { os << "lest version " << lest_VERSION << "\n" << "Compiled with " << compiler() << " on " << __DATE__ << " at " << __TIME__ << ".\n" << "For more information, see https://github.com/martinmoene/lest.\n"; return 0; } inline int run( tests specification, texts arguments, std::ostream & os = std::cout ) { try { options option; texts in; std::tie( option, in ) = split_arguments( arguments ); if ( option.lexical ) { sort( specification ); } if ( option.random ) { shuffle( specification, option ); } if ( option.help ) { return usage ( os ); } if ( option.version ) { return version ( os ); } if ( option.count ) { return for_test( specification, in, count( os ) ); } if ( option.list ) { return for_test( specification, in, print( os ) ); } if ( option.tags ) { return for_test( specification, in, ptags( os ) ); } if ( option.time ) { return for_test( specification, in, times( os, option ) ); } return for_test( specification, in, confirm( os, option ), option.repeat ); } catch ( std::exception const & e ) { os << "Error: " << e.what() << "\n"; return 1; } } inline int run( tests specification, int argc, char * argv[], std::ostream & os = std::cout ) { return run( specification, texts( argv + 1, argv + argc ), os ); } template< std::size_t N > int run( test const (&specification)[N], texts arguments, std::ostream & os = std::cout ) { std::cout.sync_with_stdio( false ); return (std::min)( run( tests( specification, specification + N ), arguments, os ), exit_max_value ); } template< std::size_t N > int run( test const (&specification)[N], std::ostream & os = std::cout ) { return run( tests( specification, specification + N ), {}, os ); } template< std::size_t N > int run( test const (&specification)[N], int argc, char * argv[], std::ostream & os = std::cout ) { return run( tests( specification, specification + N ), texts( argv + 1, argv + argc ), os ); } } // namespace lest #if defined (__clang__) # pragma clang diagnostic pop #elif defined (__GNUC__) # pragma GCC diagnostic pop #endif #endif // LEST_LEST_HPP_INCLUDED expected-lite-0.10.0/test/nonstd/000077500000000000000000000000001510672106500166135ustar00rootroot00000000000000expected-lite-0.10.0/test/nonstd/expected.tweak.hpp000066400000000000000000000000401510672106500222310ustar00rootroot00000000000000#define EXPECTED_TWEAK_VALUE 42 expected-lite-0.10.0/test/odr.cpp000066400000000000000000000000451510672106500165750ustar00rootroot00000000000000#include "nonstd/expected.hpp" MAIN expected-lite-0.10.0/test/t-noexcept.bat000066400000000000000000000035201510672106500200640ustar00rootroot00000000000000@echo off & setlocal enableextensions enabledelayedexpansion :: :: t.bat - compile & run tests (MSVC). :: set unit=expected :: if no std is given, use compiler default set std=%1 if not "%std%"=="" set std=-std:%std% call :CompilerVersion version echo VC%version%: %args% set UCAP=%unit% call :toupper UCAP set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_DEFAULT ::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_NONSTD ::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_STD set unit_config= set msvc_defines=^ -Dlest_FEATURE_AUTO_REGISTER=1 ^ -D_CRT_SECURE_NO_WARNINGS ^ -D_SCL_SECURE_NO_WARNINGS ^ -D_HAS_EXCEPTIONS=0 ^ -Dnsel_CONFIG_NO_SEH=0 :: -Dnsel_CONFIG_NO_EXCEPTIONS=1 set CppCoreCheckInclude=%VCINSTALLDIR%\Auxiliary\VS\include :: -EHsc ::cl -kernel -GR- -W3 %std% %unit_select% %unit_config% %msvc_defines% -I"%CppCoreCheckInclude%" -I../include -I. %unit%-noexcept.t.cpp && %unit%-noexcept.t.exe cl -EHs -GR- -W3 %std% %unit_select% %unit_config% %msvc_defines% -I"%CppCoreCheckInclude%" -Ilest -I../include -I. %unit%-noexcept.t.cpp && %unit%-noexcept.t.exe endlocal & goto :EOF :: subroutines: :CompilerVersion version @echo off & setlocal enableextensions set tmpprogram=_getcompilerversion.tmp set tmpsource=%tmpprogram%.c echo #include ^ >%tmpsource% echo int main(){printf("%%d\n",_MSC_VER);} >>%tmpsource% cl /nologo %tmpsource% >nul for /f %%x in ('%tmpprogram%') do set version=%%x del %tmpprogram%.* >nul set offset=0 if %version% LSS 1900 set /a offset=1 set /a version="version / 10 - 10 * ( 5 + offset )" endlocal & set %1=%version%& goto :EOF :: toupper; makes use of the fact that string :: replacement (via SET) is not case sensitive :toupper for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! goto :EOF expected-lite-0.10.0/test/t-odr.bat000066400000000000000000000003051510672106500170210ustar00rootroot00000000000000cl -EHsc -DMAIN="" -Dnsel_P0323R=-2 -I../include -I. -Foodr1.obj -c odr.cpp cl -EHsc -DMAIN="int main(){}" -Dnsel_P0323R=-2 -I../include -I. -Foodr2.obj -c odr.cpp cl odr1.obj odr2.obj expected-lite-0.10.0/test/t.bat000066400000000000000000000031071510672106500162420ustar00rootroot00000000000000@echo off & setlocal enableextensions enabledelayedexpansion :: :: t.bat - compile & run tests (MSVC). :: set unit=expected :: if no std is given, use compiler default set std=%1 if not "%std%"=="" set std=-std:%std% call :CompilerVersion version echo VC%version%: %args% set UCAP=%unit% call :toupper UCAP set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_DEFAULT ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_NONSTD ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_STD set unit_config= set msvc_defines=^ -Dlest_FEATURE_AUTO_REGISTER=1 ^ -D_CRT_SECURE_NO_WARNINGS ^ -D_SCL_SECURE_NO_WARNINGS set CppCoreCheckInclude=%VCINSTALLDIR%\Auxiliary\VS\include cl -nologo -W3 -EHsc %std% %unit_select% %unit_config% %msvc_defines% -I"%CppCoreCheckInclude%" -Ilest -I../include -I. %unit%-main.t.cpp %unit%.t.cpp && %unit%-main.t.exe endlocal & goto :EOF :: subroutines: :CompilerVersion version @echo off & setlocal enableextensions set tmpprogram=_getcompilerversion.tmp set tmpsource=%tmpprogram%.c echo #include ^ >%tmpsource% echo int main(){printf("%%d\n",_MSC_VER);} >>%tmpsource% cl /nologo %tmpsource% >nul for /f %%x in ('%tmpprogram%') do set version=%%x del %tmpprogram%.* >nul set offset=0 if %version% LSS 1900 set /a offset=1 set /a version="version / 10 - 10 * ( 5 + offset )" endlocal & set %1=%version%& goto :EOF :: toupper; makes use of the fact that string :: replacement (via SET) is not case sensitive :toupper for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! goto :EOF expected-lite-0.10.0/test/tc-cl.bat000066400000000000000000000041561510672106500170060ustar00rootroot00000000000000@echo off & setlocal enableextensions enabledelayedexpansion :: :: tc-cl.bat - compile & run tests (clang-cl). :: set unit=expected set unit_file=%unit% :: if no std is given, use c++14 set std=c++14 if NOT "%1" == "" set std=%1 & shift set UCAP=%unit% call :toupper UCAP set unit_select=nsel_%UCAP%_NONSTD ::set unit_select=nsel_%UCAP%_STD if NOT "%1" == "" set unit_select=%1 & shift set args=%1 %2 %3 %4 %5 %6 %7 %8 %9 set clang=clang-cl call :CompilerVersion version echo %clang% %version%: %std% %unit_select% %args% set unit_config=^ -Dlest_FEATURE_AUTO_REGISTER=1 ^ -D%unit%_%UCAP%_HEADER=\"nonstd/%unit%.hpp\" ^ -D%unit%_TEST_NODISCARD=0 ^ -Dnsel_CONFIG_SELECT_%UCAP%=%unit_select% rem -flto / -fwhole-program set optflags=-O2 set warnflags=-Wall -Wextra -Wpedantic -Weverything -Wshadow -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-missing-noreturn -Wno-documentation-unknown-command -Wno-documentation-deprecated-sync -Wno-documentation -Wno-weak-vtables -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-global-constructors -Wno-sign-conversion -Wno-sign-compare -Wno-implicit-int-conversion -Wno-deprecated-declarations -Wno-date-time "%clang%" -EHsc -std:%std% %optflags% %warnflags% %unit_config% -fms-compatibility-version=19.00 /imsvc lest -I../include -Ics_string -I. -o %unit_file%-main.t.exe %unit_file%-main.t.cpp %unit_file%.t.cpp && %unit_file%-main.t.exe endlocal & goto :EOF :: subroutines: :CompilerVersion version echo off & setlocal enableextensions set tmpprogram=_getcompilerversion.tmp set tmpsource=%tmpprogram%.c echo #include ^ > %tmpsource% echo int main(){printf("%%d.%%d.%%d\n",__clang_major__,__clang_minor__,__clang_patchlevel__);} >> %tmpsource% "%clang%" -m32 -o %tmpprogram% %tmpsource% >nul for /f %%x in ('%tmpprogram%') do set version=%%x del %tmpprogram%.* >nul endlocal & set %1=%version%& goto :EOF :: toupper; makes use of the fact that string :: replacement (via SET) is not case sensitive :toupper for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! goto :EOF expected-lite-0.10.0/test/tc-noexcept.bat000066400000000000000000000036051510672106500202330ustar00rootroot00000000000000@echo off & setlocal enableextensions enabledelayedexpansion :: :: tc.bat - compile & run tests (clang). :: set unit=expected :: if no std is given, use c++14 set std=%1 if "%std%"=="" set std=c++14 set clang=clang call :CompilerVersion version echo %clang% %version%: %std% set UCAP=%unit% call :toupper UCAP set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_DEFAULT ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_NONSTD ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_STD set unit_config= rem -flto / -fwhole-program set optflags=-O2 -fno-exceptions set warnflags=-Wall -Wextra -Wpedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-missing-noreturn -Wno-documentation-unknown-command -Wno-documentation-deprecated-sync -Wno-documentation -Wno-weak-vtables -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-global-constructors "%clang%" -m32 -std=%std% %optflags% %warnflags% %unit_select% %unit_config% -Dlest_FEATURE_AUTO_REGISTER=1 -fms-compatibility-version=19.00 -isystem "%VCInstallDir%include" -isystem "%WindowsSdkDir_71A%include" -I../include -I. -o %unit%-main.t.exe %unit%-noexcept.t.cpp && %unit%-noexcept.t.exe endlocal & goto :EOF :: subroutines: :CompilerVersion version echo off & setlocal enableextensions set tmpprogram=_getcompilerversion.tmp set tmpsource=%tmpprogram%.c echo #include ^ > %tmpsource% echo int main(){printf("%%d.%%d.%%d\n",__clang_major__,__clang_minor__,__clang_patchlevel__);} >> %tmpsource% "%clang%" -m32 -o %tmpprogram% %tmpsource% >nul for /f %%x in ('%tmpprogram%') do set version=%%x del %tmpprogram%.* >nul endlocal & set %1=%version%& goto :EOF :: toupper; makes use of the fact that string :: replacement (via SET) is not case sensitive :toupper for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! goto :EOF expected-lite-0.10.0/test/tc.bat000066400000000000000000000036101510672106500164040ustar00rootroot00000000000000@echo off & setlocal enableextensions enabledelayedexpansion :: :: tc.bat - compile & run tests (clang). :: set unit=expected :: if no std is given, use c++14 set std=%1 if "%std%"=="" set std=c++14 set clang=clang call :CompilerVersion version echo %clang% %version%: %std% set UCAP=%unit% call :toupper UCAP set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_DEFAULT ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_NONSTD ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_STD set unit_config= rem -flto / -fwhole-program set optflags=-O2 set warnflags=-Wall -Wextra -Wpedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-missing-noreturn -Wno-documentation-unknown-command -Wno-documentation-deprecated-sync -Wno-documentation -Wno-weak-vtables -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-global-constructors "%clang%" -m32 -std=%std% %optflags% %warnflags% %unit_select% %unit_config% -Dlest_FEATURE_AUTO_REGISTER=1 -fms-compatibility-version=19.00 -isystem "%VCInstallDir%include" -isystem "%WindowsSdkDir_71A%include" -isystem lest -I../include -I. -o %unit%-main.t.exe %unit%-main.t.cpp %unit%.t.cpp && %unit%-main.t.exe endlocal & goto :EOF :: subroutines: :CompilerVersion version echo off & setlocal enableextensions set tmpprogram=_getcompilerversion.tmp set tmpsource=%tmpprogram%.c echo #include ^ > %tmpsource% echo int main(){printf("%%d.%%d.%%d\n",__clang_major__,__clang_minor__,__clang_patchlevel__);} >> %tmpsource% "%clang%" -m32 -o %tmpprogram% %tmpsource% >nul for /f %%x in ('%tmpprogram%') do set version=%%x del %tmpprogram%.* >nul endlocal & set %1=%version%& goto :EOF :: toupper; makes use of the fact that string :: replacement (via SET) is not case sensitive :toupper for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! goto :EOF expected-lite-0.10.0/test/tg-all.bat000066400000000000000000000001171510672106500171550ustar00rootroot00000000000000@rem c++98 c++03 @for %%s in ( c++11 c++14 c++17 ) do ( call tg.bat %%s ) expected-lite-0.10.0/test/tg-noexcept.bat000066400000000000000000000031061510672106500202330ustar00rootroot00000000000000@echo off & setlocal enableextensions enabledelayedexpansion :: :: tg.bat - compile & run tests (GNUC). :: set unit=expected :: if no std is given, use c++11 set std=%1 set args=%2 %3 %4 %5 %6 %7 %8 %9 if "%1" == "" set std=c++11 set gpp=g++ call :CompilerVersion version echo %gpp% %version%: %std% %args% set UCAP=%unit% call :toupper UCAP set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_DEFAULT ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_NONSTD ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_STD set unit_config=-Dnsel_CONFIG_NO_EXCEPTIONS=1 rem -flto / -fwhole-program set optflags=-O2 -fno-exceptions set warnflags=-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wno-padded -Wno-missing-noreturn %gpp% -std=%std% %optflags% %warnflags% %unit_select% %unit_config% -o %unit%-main.t.exe -Dlest_FEATURE_AUTO_REGISTER=1 -I../include -I. %unit%-noexcept.t.cpp && %unit%-main.t.exe endlocal & goto :EOF :: subroutines: :CompilerVersion version echo off & setlocal enableextensions set tmpprogram=_getcompilerversion.tmp set tmpsource=%tmpprogram%.c echo #include ^ > %tmpsource% echo int main(){printf("%%d.%%d.%%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__);} >> %tmpsource% %gpp% -o %tmpprogram% %tmpsource% >nul for /f %%x in ('%tmpprogram%') do set version=%%x del %tmpprogram%.* >nul endlocal & set %1=%version%& goto :EOF :: toupper; makes use of the fact that string :: replacement (via SET) is not case sensitive :toupper for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! goto :EOF expected-lite-0.10.0/test/tg.bat000066400000000000000000000030601510672106500164070ustar00rootroot00000000000000@echo off & setlocal enableextensions enabledelayedexpansion :: :: tg.bat - compile & run tests (GNUC). :: set unit=expected :: if no std is given, use c++11 set std=%1 set args=%2 %3 %4 %5 %6 %7 %8 %9 if "%1" == "" set std=c++11 set gpp=g++ call :CompilerVersion version echo %gpp% %version%: %std% %args% set UCAP=%unit% call :toupper UCAP set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_DEFAULT ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_NONSTD ::set unit_select=-Dnsel_CONFIG_SELECT_%UCAP%=nsel_%UCAP%_STD set unit_config= rem -flto / -fwhole-program set optflags=-O2 set warnflags=-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wno-padded -Wno-missing-noreturn %gpp% -std=%std% %optflags% %warnflags% %unit_select% %unit_config% -o %unit%-main.t.exe -Dlest_FEATURE_AUTO_REGISTER=1 -isystem lest -I../include -I. %unit%-main.t.cpp %unit%.t.cpp && %unit%-main.t.exe endlocal & goto :EOF :: subroutines: :CompilerVersion version echo off & setlocal enableextensions set tmpprogram=_getcompilerversion.tmp set tmpsource=%tmpprogram%.c echo #include ^ > %tmpsource% echo int main(){printf("%%d.%%d.%%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__);} >> %tmpsource% %gpp% -o %tmpprogram% %tmpsource% >nul for /f %%x in ('%tmpprogram%') do set version=%%x del %tmpprogram%.* >nul endlocal & set %1=%version%& goto :EOF :: toupper; makes use of the fact that string :: replacement (via SET) is not case sensitive :toupper for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! goto :EOF