diff --git a/CMakeLists.txt b/CMakeLists.txt index 76788888..7de1a05b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,6 @@ +# /CMakeLists.txt -*-makefile-*- +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + cmake_minimum_required(VERSION 3.10) project(beman_optional26 VERSION 0.0.0 LANGUAGES CXX) diff --git a/Makefile b/Makefile index b7083a8f..f675d76b 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ #! /usr/bin/make -f -# -*-makefile-*- +# /Makefile -*-makefile-*- +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception INSTALL_PREFIX?=.install/ PROJECT?=$(shell basename $(CURDIR)) diff --git a/README.md b/README.md index f2c77a56..8ec56989 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,16 @@ # Beman.Optional26: C++26 Extensions for std::optional + + This implementation incorporates the C++26 extensions added for `std::optional`. The `Beman.Optional26` library aims to evaluate the stability, the usability, and the performance of these proposed changes before they are officially adopted by WG21 into the C++ Working Draft. Additionally, it allows developers to use these new features before they are implemented in major standard library compilers. **Implements**: +* [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1) * [`std::optional` (P2988R5)](https://wg21.link/P2988R5) -* [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1). +## License Source is licensed with the Apache 2.0 license with LLVM exceptions @@ -21,8 +26,74 @@ The README itself is licesed with CC0 1.0 Universal. Copy the contents and incor // SPDX-License-Identifier: CC0-1.0 +## Examples + +Full runable examples can be found in `examples/` - please check [./examples/README.md](./examples/README.md). + +### range_loop + +The next code snippet shows optional range support added in [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1): + +```cpp +#include +... + +// Example from P3168R1: basic range loop over C++26 optional. + +beman::optional26::optional empty_opt{}; +for ([[maybe_unused]] const auto& i : empty_opt) { + // Should not see this in console. + std::cout << "\"for each loop\" over C++26 optional: empty_opt\n"; +} + +beman::optional26::optional opt{26}; +for (const auto& i : opt) { + // Should see this in console. + std::cout << "\"for each loop\" over C++26 optional: opt = " << i << "\n"; +} +``` + +Full code can be found in [./examples/range_loop.cpp](./examples/range_loop.cpp). Build and run instructions in [./examples/README.md](./examples/README.md). + +### optional_ref + +The next code snippet shows optional reference support added in [`std::optional` (P2988R5)](https://wg21.link/P2988R5): + +```cpp +#include +... + +{ + // Empty optional example. + std::optional std_empty_opt; + beman::optional26::optional beman_empty_opt; + assert(!std_empty_opt.has_value() && + !beman_empty_opt.has_value()); // or assert(!std_empty_opt && !beman_empty_opt); + std::cout << "std_vs_beman: .has_value() matches?: " + << (std_empty_opt.has_value() == beman_empty_opt.has_value() ? "yes" : "no") << "\n"; +} + +{ + // Optional with value example. + std::optional std_opt = 26; + beman::optional26::optional beman_opt = 26; + assert(std_opt.has_value() && beman_opt.has_value()); // or assert(std_opt && beman_opt); + assert(std_opt.value() == beman_opt.value()); // or assert(*std_opt == *beman_opt); + std::cout << "std_vs_beman: .value() matches?: " << (std_opt.value() == beman_opt.value() ? "yes" : "no") + << "\n"; +} +``` + +Full code can be found in [./examples/optional_ref.cpp](./examples/optional_ref.cpp). Build and run instructions in [./examples/README.md](./examples/README.md). + ## How to Build +### Compiler Support + +This is a modern C++ project which can be compiled with the latest C++ standards (**C++20 or later**). + +Default build: `C++23`. Please check `etc/${compiler}-flags.cmake`. + ### Dependencies This project is mainly tested on `Ubuntu 22.04` and `Ubuntu 24.04`, but it should be as portable as CMake is. This project has zero C or C++ dependencies. @@ -52,6 +123,8 @@ This project strives to be as normal and simple a CMake project as possible. Thi ```shell cmake --workflow --preset gcc-14 +cmake --workflow --preset clang-18 +cmake --workflow --preset systems # uses c++ set tool ``` This should build and run the tests with GCC 14 with the address and undefined behavior sanitizers enabled. @@ -69,6 +142,14 @@ The makefile will use your system compiler, `c++`, if no toolchain name is provi ## Papers Latest revision(s) of the papers can be built / found at: -* [./papers/P2988/README.md](./papers/P2988/README.md) for `std::optional (P2988)`. * [give-std-optional-range-support](https://github.com/neatudarius/give-std-optional-range-support/) for `Give *std::optional* Range Support (P3168)` - + * issue: [#1831](https://github.com/cplusplus/papers/issues/1831) + * LEWG: + * Reviewed in Tokyo 2024. + * Forwarded by LEWG April electronic poll to LWG. + * LWG: + * To be reviewed in Saint Louis 2024. +* [./papers/P2988/README.md](./papers/P2988/README.md) for `std::optional (P2988)`. + * issue: [#1661](https://github.com/cplusplus/papers/issues/1661) + * LEWG: + * Reviewed in Tokyo 2024. diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in index 38bbde7b..050aedbf 100644 --- a/cmake/Config.cmake.in +++ b/cmake/Config.cmake.in @@ -1,3 +1,6 @@ +# cmake/Config.cmake.in -*-makefile-*- +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + @PACKAGE_INIT@ include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") diff --git a/etc/gcc-flags.cmake b/etc/gcc-flags.cmake index 3ada9762..60d6f634 100644 --- a/etc/gcc-flags.cmake +++ b/etc/gcc-flags.cmake @@ -3,7 +3,7 @@ include_guard(GLOBAL) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_FLAGS - "-Wall -Wextra " + "-std=c++23 -Wall -Wextra " CACHE STRING "CXX_FLAGS" FORCE) set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline -g3" CACHE STRING "C++ DEBUG Flags" FORCE) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index aff0f99f..f1781006 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,12 +1,17 @@ +# examples/CMakeLists.txt -*-makefile-*- +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + set(BEMAN_OPTIONAL26_LIBRARY "beman_optional26") include(GNUInstallDirs) # List of all buildable examples. set(EXAMPLES - sample - range_loop optional_ref + pythagorean_triples + range_loop + sample + std_vs_beman ) foreach(EXAMPLE ${EXAMPLES}) diff --git a/examples/README.md b/examples/README.md index b43db0be..a8b6827a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,7 +1,26 @@ # Beman.Optional26 Examples + + List of usage examples for `Beman.Optional26`. +## License +Source is licensed with the Apache 2.0 license with LLVM exceptions + +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +Documentation and associated papers are licensed with the Creative Commons Attribution 4.0 International license. + +// SPDX-License-Identifier: CC-BY-4.0 + +The intent is that the source and documentation are available for use by people implementing their own optional types as well as people using the optional presented here as-is. + +The README itself is licesed with CC0 1.0 Universal. Copy the contents and incorporate in your own work as you see fit. + +// SPDX-License-Identifier: CC0-1.0 + ## Sample Check [sample](sample.cpp) for basic `Beman.Optional26` library usage. @@ -11,28 +30,48 @@ Build and run instructions: # build $ cmake --workflow --preset gcc-14 -# run sample +# run sample.cpp $ .build/gcc-14/examples/RelWithDebInfo/sample empty_opt is empty! opt = 26 + +# run std_vs_beman.cpp +$ .build/gcc-14/examples/RelWithDebInfo/std_vs_beman +std_vs_beman: .has_value() matches?: yes +std_vs_beman: .value() matches?: yes ``` ## Range Support (P3168R1) Range support added in [*Give std::optional Range Support* (P3168R1)](https://wg21.link/P3168R1) examples: * [./range_loop.cpp](./range_loop.cpp) +* [./pythagorean_triples.cpp](./pythagorean_triples.cpp) Build and run instructions: ```shell -# build -$ cmake --workflow --preset gcc-14 -# run range_loop + +# run range_loop.cpp $ .build/gcc-14/examples/RelWithDebInfo/range_loop # note: 1st log (empty_opt) is missing from console! "for each loop" over C++26 optional: opt = 26 # 2nd log (non empty opt) + +# run pythagorean_triples.cpp +$ .build/gcc-14/examples/RelWithDebInfo/pythagorean_triples +First 10 Pythagorean triples: +(3, 4, 5) +(6, 8, 10) +(5, 12, 13) +(9, 12, 15) +(8, 15, 17) +(12, 16, 20) +(7, 24, 25) +(15, 20, 25) +(10, 24, 26) +(20, 21, 29) +100th Pythagorean triple (x, y, z <= 200): (26, 168, 170) ``` ## Optional Reference (P2988R5) @@ -40,3 +79,13 @@ $ .build/gcc-14/examples/RelWithDebInfo/range_loop Reference support added in [*std::optional*(P2988R5)](https://wg21.link/P2988R5) examples: * [./optional_ref.cpp](./optional_ref.cpp) + +Build and run instructions: + +```shell +# build +$ cmake --workflow --preset gcc-14 + +# run optional_ref.cpp +$ .build/gcc-14/examples/RelWithDebInfo/optional_ref +``` diff --git a/examples/optional_ref.cpp b/examples/optional_ref.cpp index aaa25dfc..e29d2de4 100644 --- a/examples/optional_ref.cpp +++ b/examples/optional_ref.cpp @@ -1,34 +1,59 @@ +// examples/optional_ref.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #include #include -using beman::optional::optional; - struct Cat { int catalog_index{0}; }; -auto find_cat_old(std::string) -> Cat* { return nullptr; } +namespace std17 { + +// Prior to C++26, the code would look like this. +// Using raw pointers to represent optional references. +// Note: Using smart pointers would also be a choice, but it involves ownership semantics. -auto find_cat_new(std::string) -> optional { return optional{}; } +Cat* find_cat(std::string) { return nullptr; } -Cat* doit_old(Cat& cat) { return &cat; } -optional doit(Cat& cat) { return optional{cat}; } +Cat* do_it(Cat& cat) { return &cat; } -Cat* before1() { - Cat* cat = find_cat_old("Fido"); +Cat* api() { + Cat* cat = find_cat("Fido"); if (cat != nullptr) { - return doit_old(*cat); + return do_it(*cat); } return nullptr; } -optional after1() { - optional cat = find_cat_new("Fido"); - return cat.and_then(doit); +} // namespace std17 + +namespace std26 { +// After C++26 with P2988R5, the code would look like this. +// Using directly optional to represent optional references. + +beman::optional26::optional find_cat(std::string) { return {}; } + +beman::optional26::optional do_it(Cat& cat) { return {cat}; } + +beman::optional26::optional api() { + beman::optional26::optional cat = find_cat("Fido"); + return cat.and_then(do_it); } +} // namespace std26 + int main() { - Cat* cat_p = before1(); - optional cat_r = after1(); + // Example from P2988R5: optional reference. + [[maybe_unused]] Cat* old_cat = std17::api(); + [[maybe_unused]] beman::optional26::optional new_cat = std26::api(); + + return 0; } + +// # build example: +// $ cmake --workflow --preset gcc-14 +// +// # run example: +// $ .build/gcc-14/examples/RelWithDebInfo/optional_ref diff --git a/examples/pythagorean_triples.cpp b/examples/pythagorean_triples.cpp new file mode 100644 index 00000000..ce4b508b --- /dev/null +++ b/examples/pythagorean_triples.cpp @@ -0,0 +1,105 @@ +// examples/pythagorean_triples.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include +#include +#include +#include + +int main() { + // Example from P3168R1: generate an infinite sequence of Pythagorean triples. + // (x, y, z) is a Pythagorean triple if 1 <= x <= y <= z and x^2 + y^2 = z^2. + constexpr auto yield_if = [](bool b, T x) -> beman::optional26::optional { + return b ? beman::optional26::optional{std::move(x)} : beman::optional26::nullopt; + }; + constexpr auto and_then = [](T&& r, auto fun) { + return decltype(r)(r) | std::views::transform(std::move(fun)) | std::views::join; + }; + auto triples = and_then(std::views::iota(1), [=](int z) { + return and_then(std::views::iota(1, z + 1), [=](int x) { + return and_then(std::views::iota(x, z + 1), + [=](int y) { return yield_if(x * x + y * y == z * z, std::make_tuple(x, y, z)); }); + }); + }); + + { + // Generate first 10 Pythagorean triples. + // https://mathworld.wolfram.com/PythagoreanTriple.html + [[maybe_unused]] auto&& r = triples | std::views::take(10); + assert(std::ranges::equal(r, + std::vector{ + std::tuple{3, 4, 5}, + std::tuple{6, 8, 10}, + std::tuple{5, 12, 13}, + std::tuple{9, 12, 15}, + std::tuple{8, 15, 17}, + std::tuple{12, 16, 20}, + std::tuple{7, 24, 25}, + std::tuple{15, 20, 25}, + std::tuple{10, 24, 26}, + std::tuple{20, 21, 29}, + })); + + std::cout << "First 10 Pythagorean triples:\n"; + for (const auto& [x, y, z] : r) { + std::cout << "(" << x << ", " << y << ", " << z << ")\n"; + } + } + + { + // Generate the nth Pythagorean triple (x, y, z) where: + // 1 <= x <= y <= z <= max_value and x^2 + y^2 = z^2 + + // Generate the nth Pythagorean triple with brute force. + [[maybe_unused]] auto bruteforce_generate_nth = [](int n, int max_value) -> std::tuple { + int count = 0; // Count the number of Pythagorean triples. + for (int z = 1; z <= max_value; ++z) { + for (int x = 1; x <= max_value; ++x) { + for (int y = 1; y <= max_value; ++y) { + if (!(x <= y && y <= z) || x * x + y * y != z * z) { + continue; + } + + if (++count == n) { + return std::make_tuple(x, y, z); + } + } + } + } + + return {}; // Should not reach here. + }; + [[maybe_unused]] constexpr const std::tuple k100th_triple = { + 26, 168, 170}; // The 100th Pythagorean triple with x, y, z <= 200. + assert(bruteforce_generate_nth(100, 200) == k100th_triple); + + // Generate the 100th Pythagorean triple with ranges. + [[maybe_unused]] auto&& r = triples | std::views::drop(99) | std::views::take(1); + assert(std::ranges::equal(r, std::vector{k100th_triple})); + + const auto& [x100, y100, z100] = *std::ranges::begin(r); + std::cout << "100th Pythagorean triple (x, y, z <= 200): (" << x100 << ", " << y100 << ", " << z100 << ")\n"; + } + + return 0; +} + +// # build example: +// $ cmake --workflow --preset gcc-14 +// +// # run example: +// $ .build/gcc-14/examples/RelWithDebInfo/pythagorean_triples +// First 10 Pythagorean triples: +// (3, 4, 5) +// (6, 8, 10) +// (5, 12, 13) +// (9, 12, 15) +// (8, 15, 17) +// (12, 16, 20) +// (7, 24, 25) +// (15, 20, 25) +// (10, 24, 26) +// (20, 21, 29) +// 100th Pythagorean triple (x, y, z <= 200): (26, 168, 170) diff --git a/examples/range_loop.cpp b/examples/range_loop.cpp index 27a827a2..6830a183 100644 --- a/examples/range_loop.cpp +++ b/examples/range_loop.cpp @@ -1,17 +1,31 @@ +// examples/range_loop.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #include #include int main() { - beman::optional::optional empty_opt{}; + // Example from P3168R1: basic range loop over C++26 optional. + + beman::optional26::optional empty_opt{}; for ([[maybe_unused]] const auto& i : empty_opt) { // Should not see this in console. std::cout << "\"for each loop\" over C++26 optional: empty_opt\n"; } - beman::optional::optional opt{26}; + beman::optional26::optional opt{26}; for (const auto& i : opt) { // Should see this in console. std::cout << "\"for each loop\" over C++26 optional: opt = " << i << "\n"; } + return 0; } + +// # build example: +// $ cmake --workflow --preset gcc-14 +// +// # run example: +// $ .build/gcc-14/examples/RelWithDebInfo/range_loop +// # note: 1st log (empty_opt) is missing from console! +// "for each loop" over C++26 optional: opt = 26 # 2nd log (non empty opt) diff --git a/examples/sample.cpp b/examples/sample.cpp index 3d3499bb..e0766288 100644 --- a/examples/sample.cpp +++ b/examples/sample.cpp @@ -1,16 +1,27 @@ +// examples/sample.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #include #include int main() { - beman::optional::optional empty_opt{}; + beman::optional26::optional empty_opt{}; if (!empty_opt) { std::cout << "empty_opt is empty!\n"; } - beman::optional::optional opt{26}; + beman::optional26::optional opt{26}; if (opt) { std::cout << "opt = " << *opt << "\n"; } return 0; } + +// # build example: +// $ cmake --workflow --preset gcc-14 +// +// # run example: +// $ .build/gcc-14/examples/RelWithDebInfo/sample +// empty_opt is empty! +// opt = 26 diff --git a/examples/std_vs_beman.cpp b/examples/std_vs_beman.cpp new file mode 100644 index 00000000..2485ea62 --- /dev/null +++ b/examples/std_vs_beman.cpp @@ -0,0 +1,43 @@ +// examples/std_vs_beman.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +#include +#include + +int main() { + { + // Empty optional example. + std::optional std_empty_opt; + beman::optional26::optional beman_empty_opt; + assert(!std_empty_opt.has_value() && + !beman_empty_opt.has_value()); // or assert(!std_empty_opt && !beman_empty_opt); + std::cout << "std_vs_beman: .has_value() matches?: " + << (std_empty_opt.has_value() == beman_empty_opt.has_value() ? "yes" : "no") << "\n"; + } + + { + // Optional with value example. + std::optional std_opt = 26; + beman::optional26::optional beman_opt = 26; + assert(std_opt.has_value() && beman_opt.has_value()); // or assert(std_opt && beman_opt); + assert(std_opt.value() == beman_opt.value()); // or assert(*std_opt == *beman_opt); + std::cout << "std_vs_beman: .value() matches?: " << (std_opt.value() == beman_opt.value() ? "yes" : "no") + << "\n"; + } + + // Note: std_empty_opt == beman_empty_opt and std_opt == beman_opt won't compile + // (no implementation of operator== for std::optional and beman::optional26::optional). + + return 0; +} + +// # build example: +// $ cmake --workflow --preset gcc-14 +// +// # run example: +// $ .build/gcc-14/examples/RelWithDebInfo/std_vs_beman +// std_vs_beman: .has_value() matches?: yes +// std_vs_beman: .value() matches?: yes diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index a2177fb3..d9c9f462 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -1 +1,4 @@ +# extern/CMakeLists.txt -*-makefile-*- +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + add_subdirectory(googletest EXCLUDE_FROM_ALL) diff --git a/include/Beman/Optional26/detail/iterator.hpp b/include/Beman/Optional26/detail/iterator.hpp new file mode 100644 index 00000000..98ac581e --- /dev/null +++ b/include/Beman/Optional26/detail/iterator.hpp @@ -0,0 +1,65 @@ +// include/Beman/Optional26/detail/iterator.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef BEMAN_OPTIONAL26_DETAIL_ITERATOR_HPP +#define BEMAN_OPTIONAL26_DETAIL_ITERATOR_HPP + +#include + +#include +#include + +namespace beman::optional26::detail { + +// Forward declaration. +template +struct contiguous_iterator; + +// Base class for contiguous iterator types with Boost stl_interfaces library. +// Current implementation based on P2727R4: std::iterator_interface. +template +using base_contiguous_iterator = stl_interfaces::iterator_interface< +#if !BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS + contiguous_iterator, // Required for P2727R4 to work with C++20/C++23. TODO: Do more experiments. +#endif + std::contiguous_iterator_tag, + T>; + +// This is a minimal contiguous iterator. It uses stl_interfaces library from Boost +// (current implementation based on https://wg21.link/P2727R4). +// +// TODO: Change this to use the stl_interfaces library from Beman if/when available. +// +// @tparam T - The type of the elements the iterator points to. +// @tparam Container - The type of the container the iterator points to. This parameter exists solely so that different +// containers using this template can instantiate different types, even if the T parameter is the same. +template +struct contiguous_iterator : public base_contiguous_iterator { + // Alias for the base class. + using base_type = base_contiguous_iterator; + // Alias for types from the base class. + using typename base_type::difference_type; + using typename base_type::pointer; + using typename base_type::reference; + + // Default constructor. + contiguous_iterator() noexcept : m_current() {} + + // Pointer to iterator constructor. + contiguous_iterator(pointer it) noexcept : m_current(it) {} + + // As per P2727R4, for contiguous iterator we only need to provide operator*, operator+= and operator-. + reference operator*() const noexcept { return *m_current; } + auto& operator+=(difference_type pos) noexcept { + m_current += pos; + return *this; + } + difference_type operator-(contiguous_iterator other) const noexcept { return m_current - other.m_current; } + + private: + T* m_current; +}; + +} // namespace beman::optional26::detail + +#endif // BEMAN_OPTIONAL26_DETAIL_ITERATOR_HPP diff --git a/include/Beman/Optional26/detail/stl_interfaces/config.hpp b/include/Beman/Optional26/detail/stl_interfaces/config.hpp new file mode 100644 index 00000000..e48ac01f --- /dev/null +++ b/include/Beman/Optional26/detail/stl_interfaces/config.hpp @@ -0,0 +1,49 @@ +// include/Beman/Optional26/detail/stl_interfaces/config.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Copyright (C) 2020 T. Zachary Laine +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_CONFIG_HPP +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_CONFIG_HPP + +// Included for definition of __cpp_lib_concepts. +#include + +#if defined(__cpp_lib_concepts) && defined(__cpp_lib_ranges) && \ + !defined(BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_DISABLE_CONCEPTS) +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_CONCEPTS 1 +#else +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_CONCEPTS 0 +#endif + +#if defined(__cpp_explicit_this_parameter) && BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_CONCEPTS && \ + !defined(BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_DISABLE_DEDUCED_THIS) +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS 1 +#else +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS 0 +#endif + +// The inline namespaces v1, v2, and v3 represent C++14, C++20, and C++23 and +// later, respectively. v1 is inline for standards before C++20, and v2 is +// inline for C++20 and later. Note that this only applies to code for which +// multiple vI namespace alternatives exist. For example, some instances of +// the v1 namespace may still be inline, if there is no v2 version of its +// contents. +#if !BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_CONCEPTS && !BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V1 inline namespace v1 +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V2 namespace v2 +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V3 namespace v3 +#elif BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_CONCEPTS && !BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V1 namespace v1 +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V2 inline namespace v2 +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V3 namespace v3 +#else +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V1 namespace v1 +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V2 namespace v2 +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V3 inline namespace v3 +#endif + +#endif diff --git a/include/Beman/Optional26/detail/stl_interfaces/fwd.hpp b/include/Beman/Optional26/detail/stl_interfaces/fwd.hpp new file mode 100644 index 00000000..da0f1ab5 --- /dev/null +++ b/include/Beman/Optional26/detail/stl_interfaces/fwd.hpp @@ -0,0 +1,88 @@ +// include/Beman/Optional26/detail/stl_interfaces/fwd.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Copyright (C) 2019 T. Zachary Laine +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_FWD_HPP +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_FWD_HPP + +#include + +#if BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_CONCEPTS +#include +#endif +#if defined(__cpp_lib_three_way_comparison) +#include +#endif + +#ifndef BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_DOXYGEN + +#if defined(_MSC_VER) || defined(__GNUC__) && __GNUC__ < 8 +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NO_HIDDEN_FRIEND_CONSTEXPR +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR +#else +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR constexpr +#endif + +#if defined(__GNUC__) && __GNUC__ < 9 +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_CONCEPT concept bool +#else +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_CONCEPT concept +#endif + +#endif + +namespace beman::optional26::detail { +namespace stl_interfaces { + +/** An enumeration used to indicate whether the underlying data have a + contiguous or discontiguous layout when instantiating `view_interface` + and `sequence_container_interface`. */ +enum class element_layout : bool { discontiguous = false, contiguous = true }; + +BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_NAMESPACE_V1 { + + namespace v1_dtl { + template + using void_t = void; + + template + using iter_difference_t = typename std::iterator_traits::difference_type; + + template + struct iterator; + template + struct iterator().begin())>> { + using type = decltype(std::declval().begin()); + }; + template + using iterator_t = typename iterator::type; + + template + struct sentinel; + template + struct sentinel().end())>> { + using type = decltype(std::declval().end()); + }; + template + using sentinel_t = typename sentinel::type; + + template + using range_difference_t = iter_difference_t>; + + template + using common_range = std::is_same, sentinel_t>; + + template + struct decrementable_sentinel : std::false_type {}; + template + struct decrementable_sentinel&>())>> : std::true_type {}; + } // namespace v1_dtl +} +} // namespace stl_interfaces +} // namespace beman::optional26::detail + +#endif diff --git a/include/Beman/Optional26/detail/stl_interfaces/iterator_interface.hpp b/include/Beman/Optional26/detail/stl_interfaces/iterator_interface.hpp new file mode 100644 index 00000000..534dc566 --- /dev/null +++ b/include/Beman/Optional26/detail/stl_interfaces/iterator_interface.hpp @@ -0,0 +1,986 @@ +// include/Beman/Optional26/detail/stl_interfaces/iterator_interface.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Copyright (C) 2019 T. Zachary Laine +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_ITERATOR_INTERFACE_HPP +#define BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_ITERATOR_INTERFACE_HPP + +#include + +#include +#include +#if defined(__cpp_lib_three_way_comparison) +#include +#endif + +namespace beman::optional26::detail { +namespace stl_interfaces { + +/** A type for granting access to the private members of an iterator + derived from `iterator_interface`. */ +struct access { +#ifndef BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_DOXYGEN + + template + static constexpr auto base(D& d) noexcept -> decltype(d.base_reference()) { + return d.base_reference(); + } + template + static constexpr auto base(const D& d) noexcept -> decltype(d.base_reference()) { + return d.base_reference(); + } + +#endif +}; + +/** The return type of `operator->()` in a proxy iterator. + + This template is used as the default `Pointer` template parameter in + the `proxy_iterator_interface` template alias. Note that the use of + this template implies a copy or move of the underlying object of type + `T`. */ +template +#if defined(BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_DOXYGEN) || BEMAN_OPTIONAL26_DETAIL_STL_INTERFACES_USE_CONCEPTS +// clang-format off + requires std::is_object_v +#endif + struct proxy_arrow_result +// clang-format on +{ + constexpr proxy_arrow_result(const T& value) noexcept(noexcept(T(value))) : value_(value) {} + constexpr proxy_arrow_result(T&& value) noexcept(noexcept(T(std::move(value)))) : value_(std::move(value)) {} + + constexpr const T* operator->() const noexcept { return &value_; } + constexpr T* operator->() noexcept { return &value_; } + + private: + T value_; +}; + +namespace detail { +template +auto make_pointer(T&& value, + std::enable_if_t::value && std::is_reference::value, int> = 0) + -> decltype(std::addressof(value)) { + return std::addressof(value); +} + +template +auto make_pointer(T&& value, + std::enable_if_t::value && !std::is_same::value && + std::is_reference::value, + int> = 0) { + return Pointer(std::forward(value)); +} + +template +struct pointer { + using type = Pointer; +}; +template +struct pointer { + using type = void; +}; +template +using pointer_t = typename pointer::type; + +template +using interoperable = + std::integral_constant::value || std::is_convertible::value)>; + +template +using common_t = std::conditional_t::value, U, T>; + +template +using use_base = decltype(access::base(std::declval())); + +template +using void_t = void; + +template class Template, typename... Args> +struct detector : std::false_type {}; + +template