diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cea7c40..7ce9081 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -31,4 +31,3 @@ updates: directory: / schedule: interval: daily - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e67735e..1d260d0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,39 +4,42 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-added-large-files + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files - # Clang-format for C++ - # This brings in a portable version of clang-format. - # See also: https://github.com/ssciwr/clang-format-wheel + # Clang-format for C++ + # This brings in a portable version of clang-format. + # See also: https://github.com/ssciwr/clang-format-wheel - repo: https://github.com/pre-commit/mirrors-clang-format rev: v21.1.8 hooks: - - id: clang-format - types_or: [c++, c] + - id: clang-format + types_or: [c++, c] - # CMake linting and formatting + # CMake linting and formatting - repo: https://github.com/BlankSpruce/gersemi rev: 0.25.1 hooks: - - id: gersemi - name: CMake linting - exclude: ^.*/tests/.*/data/ # Exclude test data directories + - id: gersemi + name: CMake linting + exclude: ^.*/tests/.*/data/ # Exclude test data directories - # Markdown linting - # Config file: .markdownlint.yaml - # Commented out to disable this by default. Uncomment to enable markdown linting. + # Markdown linting + # Config file: .markdownlint.yaml + # Commented out to disable this by default. + # Uncomment to enable markdown linting. # - repo: https://github.com/igorshubovych/markdownlint-cli # rev: v0.42.0 # hooks: - # - id: markdownlint + # - id: markdownlint - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: - id: codespell + additional_dependencies: + - tomli exclude: 'cookiecutter/|infra/' diff --git a/include/beman/expected/CMakeLists.txt b/include/beman/expected/CMakeLists.txt index fee3999..cc05a2c 100644 --- a/include/beman/expected/CMakeLists.txt +++ b/include/beman/expected/CMakeLists.txt @@ -3,5 +3,7 @@ target_sources( beman.expected - PUBLIC FILE_SET HEADERS FILES expected.hpp unexpected.hpp + PUBLIC + FILE_SET HEADERS + FILES expected.hpp unexpected.hpp bad_expected_access.hpp ) diff --git a/include/beman/expected/bad_expected_access.hpp b/include/beman/expected/bad_expected_access.hpp new file mode 100644 index 0000000..0c2dc01 --- /dev/null +++ b/include/beman/expected/bad_expected_access.hpp @@ -0,0 +1,51 @@ +// beman/expected/bad_expected_access.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#ifndef BEMAN_EXPECTED_BAD_EXPECTED_ACCESS +#define BEMAN_EXPECTED_BAD_EXPECTED_ACCESS + +/*** +22.8.4 Class template bad_expected_access[expected.bad] + +namespace std { + template + class bad_expected_access : public bad_expected_access { + public: + constexpr explicit bad_expected_access(E); + constexpr const char* what() const noexcept override; + constexpr E& error() & noexcept; + constexpr const E& error() const & noexcept; + constexpr E&& error() && noexcept; + constexpr const E&& error() const && noexcept; + + private: + E unex; // exposition only + }; +} + */ + +/*** +22.8.5 Class template specialization bad_expected_access[expected.bad.void] +namespace std { + template<> + class bad_expected_access : public exception { + protected: + constexpr bad_expected_access() noexcept; + constexpr bad_expected_access(const bad_expected_access&) noexcept; + constexpr bad_expected_access(bad_expected_access&&) noexcept; + constexpr bad_expected_access& operator=(const bad_expected_access&) noexcept; + constexpr bad_expected_access& operator=(bad_expected_access&&) noexcept; + constexpr ~bad_expected_access(); + + public: + constexpr const char* what() const noexcept override; + }; +} +pcc*/ +namespace beman { +namespace expected { + + +} +} + +#endif diff --git a/include/beman/expected/expected.hpp b/include/beman/expected/expected.hpp index 373f7b6..1b2679d 100644 --- a/include/beman/expected/expected.hpp +++ b/include/beman/expected/expected.hpp @@ -3,6 +3,251 @@ #ifndef BEMAN_EXPECTED_EXPECTED_HPP #define BEMAN_EXPECTED_EXPECTED_HPP +#include +#include + +/*** +22.8.2 Header synopsis[expected.syn] + +// mostly freestanding +namespace std { + // [expected.unexpected], class template unexpected + template class unexpected; + + // [expected.bad], class template bad_expected_access + template class bad_expected_access; + + // [expected.bad.void], specialization for void + template<> class bad_expected_access; + + // in-place construction of unexpected values + struct unexpect_t { + explicit unexpect_t() = default; + }; + inline constexpr unexpect_t unexpect{}; + + // [expected.expected], class template expected + template class expected; // partially freestanding + + // [expected.void], partial specialization of expected for void types + template requires is_void_v class expected; // partially freestanding +} + */ + +/*** +22.8.6 Class template expected[expected.expected] +22.8.6.1 General[expected.object.general] +namespace std { + template + class expected { + public: + using value_type = T; + using error_type = E; + using unexpected_type = unexpected; + + template + using rebind = expected; + + // [expected.object.cons], constructors + constexpr expected(); + constexpr expected(const expected&); + constexpr expected(expected&&) noexcept(see below); + template + constexpr explicit(see below) expected(const expected&); + template + constexpr explicit(see below) expected(expected&&); + + template> + constexpr explicit(see below) expected(U&& v); + + template + constexpr explicit(see below) expected(const unexpected&); + template + constexpr explicit(see below) expected(unexpected&&); + + template + constexpr explicit expected(in_place_t, Args&&...); + template + constexpr explicit expected(in_place_t, initializer_list, Args&&...); + template + constexpr explicit expected(unexpect_t, Args&&...); + template + constexpr explicit expected(unexpect_t, initializer_list, Args&&...); + + // [expected.object.dtor], destructor + constexpr ~expected(); + + // [expected.object.assign], assignment + constexpr expected& operator=(const expected&); + constexpr expected& operator=(expected&&) noexcept(see below); + template> constexpr expected& operator=(U&&); + template + constexpr expected& operator=(const unexpected&); + template + constexpr expected& operator=(unexpected&&); + + template + constexpr T& emplace(Args&&...) noexcept; + template + constexpr T& emplace(initializer_list, Args&&...) noexcept; + + // [expected.object.swap], swap + constexpr void swap(expected&) noexcept(see below); + friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); + + // [expected.object.obs], observers + constexpr const T* operator->() const noexcept; + constexpr T* operator->() noexcept; + constexpr const T& operator*() const & noexcept; + constexpr T& operator*() & noexcept; + constexpr const T&& operator*() const && noexcept; + constexpr T&& operator*() && noexcept; + constexpr explicit operator bool() const noexcept; + constexpr bool has_value() const noexcept; + constexpr const T& value() const &; // freestanding-deleted + constexpr T& value() &; // freestanding-deleted + constexpr const T&& value() const &&; // freestanding-deleted + constexpr T&& value() &&; // freestanding-deleted + constexpr const E& error() const & noexcept; + constexpr E& error() & noexcept; + constexpr const E&& error() const && noexcept; + constexpr E&& error() && noexcept; + template> constexpr T value_or(U&&) const &; + template> constexpr T value_or(U&&) &&; + template constexpr E error_or(G&&) const &; + template constexpr E error_or(G&&) &&; + + // [expected.object.monadic], monadic operations + template constexpr auto and_then(F&& f) &; + template constexpr auto and_then(F&& f) &&; + template constexpr auto and_then(F&& f) const &; + template constexpr auto and_then(F&& f) const &&; + template constexpr auto or_else(F&& f) &; + template constexpr auto or_else(F&& f) &&; + template constexpr auto or_else(F&& f) const &; + template constexpr auto or_else(F&& f) const &&; + template constexpr auto transform(F&& f) &; + template constexpr auto transform(F&& f) &&; + template constexpr auto transform(F&& f) const &; + template constexpr auto transform(F&& f) const &&; + template constexpr auto transform_error(F&& f) &; + template constexpr auto transform_error(F&& f) &&; + template constexpr auto transform_error(F&& f) const &; + template constexpr auto transform_error(F&& f) const &&; + + // [expected.object.eq], equality operators + template requires (!is_void_v) + friend constexpr bool operator==(const expected& x, const expected& y); + template + friend constexpr bool operator==(const expected&, const T2&); + template + friend constexpr bool operator==(const expected&, const unexpected&); + + private: + bool has_val; // exposition only + union { + T val; // exposition only + E unex; // exposition only + }; + }; +} +*/ + +/*** +22.8.7 Partial specialization of expected for void types[expected.void] +22.8.7.1 General[expected.void.general] +template requires is_void_v +class expected { +public: + using value_type = T; + using error_type = E; + using unexpected_type = unexpected; + + template + using rebind = expected; + + // [expected.void.cons], constructors + constexpr expected() noexcept; + constexpr expected(const expected&); + constexpr expected(expected&&) noexcept(see below); + template + constexpr explicit(see below) expected(const expected&); + template + constexpr explicit(see below) expected(expected&&); + + template + constexpr explicit(see below) expected(const unexpected&); + template + constexpr explicit(see below) expected(unexpected&&); + + constexpr explicit expected(in_place_t) noexcept; + template + constexpr explicit expected(unexpect_t, Args&&...); + template + constexpr explicit expected(unexpect_t, initializer_list, Args&&...); + + + // [expected.void.dtor], destructor + constexpr ~expected(); + + // [expected.void.assign], assignment + constexpr expected& operator=(const expected&); + constexpr expected& operator=(expected&&) noexcept(see below); + template + constexpr expected& operator=(const unexpected&); + template + constexpr expected& operator=(unexpected&&); + constexpr void emplace() noexcept; + + // [expected.void.swap], swap + constexpr void swap(expected&) noexcept(see below); + friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); + + // [expected.void.obs], observers + constexpr explicit operator bool() const noexcept; + constexpr bool has_value() const noexcept; + constexpr void operator*() const noexcept; + constexpr void value() const &; // freestanding-deleted + constexpr void value() &&; // freestanding-deleted + constexpr const E& error() const & noexcept; + constexpr E& error() & noexcept; + constexpr const E&& error() const && noexcept; + constexpr E&& error() && noexcept; + template constexpr E error_or(G&&) const &; + template constexpr E error_or(G&&) &&; + + // [expected.void.monadic], monadic operations + template constexpr auto and_then(F&& f) &; + template constexpr auto and_then(F&& f) &&; + template constexpr auto and_then(F&& f) const &; + template constexpr auto and_then(F&& f) const &&; + template constexpr auto or_else(F&& f) &; + template constexpr auto or_else(F&& f) &&; + template constexpr auto or_else(F&& f) const &; + template constexpr auto or_else(F&& f) const &&; + template constexpr auto transform(F&& f) &; + template constexpr auto transform(F&& f) &&; + template constexpr auto transform(F&& f) const &; + template constexpr auto transform(F&& f) const &&; + template constexpr auto transform_error(F&& f) &; + template constexpr auto transform_error(F&& f) &&; + template constexpr auto transform_error(F&& f) const &; + template constexpr auto transform_error(F&& f) const &&; + + // [expected.void.eq], equality operators + template requires is_void_v + friend constexpr bool operator==(const expected& x, const expected& y); + template + friend constexpr bool operator==(const expected&, const unexpected&); + +private: + bool has_val; // exposition only + union { + E unex; // exposition only + }; +}; +*/ + namespace beman { namespace expected {} } // namespace beman diff --git a/include/beman/expected/unexpected.hpp b/include/beman/expected/unexpected.hpp index ddbaa8f..26dba51 100644 --- a/include/beman/expected/unexpected.hpp +++ b/include/beman/expected/unexpected.hpp @@ -3,6 +3,51 @@ #ifndef BEMAN_EXPECTED_UNEXPECTED_HPP #define BEMAN_EXPECTED_UNEXPECTED_HPP +/*** +22.8.3 Class template unexpected[expected.unexpected] +22.8.3.1 General[expected.un.general] +1 +# +Subclause [expected.unexpected] describes the class template unexpected that represents unexpected objects stored in +expected objects. + +namespace std { + template + class unexpected { + public: + // [expected.un.cons], constructors + constexpr unexpected(const unexpected&) = default; + constexpr unexpected(unexpected&&) = default; + template + constexpr explicit unexpected(Err&&); + template + constexpr explicit unexpected(in_place_t, Args&&...); + template + constexpr explicit unexpected(in_place_t, initializer_list, Args&&...); + + constexpr unexpected& operator=(const unexpected&) = default; + constexpr unexpected& operator=(unexpected&&) = default; + + constexpr const E& error() const & noexcept; + constexpr E& error() & noexcept; + constexpr const E&& error() const && noexcept; + constexpr E&& error() && noexcept; + + constexpr void swap(unexpected& other) noexcept(see below); + + template + friend constexpr bool operator==(const unexpected&, const unexpected&); + + friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y))); + + private: + E unex; // exposition only + }; + + template unexpected(E) -> unexpected; +} +*/ + namespace beman { namespace expected {} } // namespace beman diff --git a/pyproject.toml b/pyproject.toml index e83d376..36107b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,3 +13,6 @@ dev = [ "gcovr>=7.2", "pre-commit>=3.7.1", ] + +[tool.codespell] +ignore-words-list = 'unexpect' diff --git a/tests/beman/expected/CMakeLists.txt b/tests/beman/expected/CMakeLists.txt index 8573982..935721f 100644 --- a/tests/beman/expected/CMakeLists.txt +++ b/tests/beman/expected/CMakeLists.txt @@ -4,7 +4,7 @@ add_executable(beman.expected.tests.expected) target_sources( beman.expected.tests.expected - PRIVATE unexpected.test.cpp expected.test.cpp + PRIVATE bad_expected_access.test.cpp unexpected.test.cpp expected.test.cpp ) target_link_libraries( beman.expected.tests.expected diff --git a/tests/beman/expected/bad_expected_access.test.cpp b/tests/beman/expected/bad_expected_access.test.cpp new file mode 100644 index 0000000..473f86a --- /dev/null +++ b/tests/beman/expected/bad_expected_access.test.cpp @@ -0,0 +1,11 @@ +// tests/beman/expected/bad_expected_access.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include // test 2nd include OK + +#include + +namespace expt = beman::expected; + +TEST(BadExpectedAccessTest, breathing) { SUCCEED(); }