summaryrefslogtreecommitdiffhomepage
path: root/64x0/cc2/include
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-01-09 21:47:33 +0100
committerAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-01-09 21:47:33 +0100
commit9cef856478cebe4bfe00e1d39c9e2d49015dd0e4 (patch)
treef04c6b6b1156057748c7044a766120485c45c885 /64x0/cc2/include
parenta8a55bc93e06cd8f75f7d397c013f7a312ea29a4 (diff)
MP-UX/hCore Assembler for 64x0, Release I.
Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to '64x0/cc2/include')
-rw-r--r--64x0/cc2/include/cpp2util.h1999
1 files changed, 0 insertions, 1999 deletions
diff --git a/64x0/cc2/include/cpp2util.h b/64x0/cc2/include/cpp2util.h
deleted file mode 100644
index 463dd99..0000000
--- a/64x0/cc2/include/cpp2util.h
+++ /dev/null
@@ -1,1999 +0,0 @@
-
-// Copyright (c) Herb Sutter
-// SPDX-License-Identifier: CC-BY-NC-ND-4.0
-
-// 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-//===========================================================================
-// Cpp2 utilities:
-// Language support implementations
-// #include'd by generated Cpp1 code
-//===========================================================================
-
-#ifndef CPP2_UTIL_H
-#define CPP2_UTIL_H
-
-// If this implementation doesn't support source_location yet, disable it
-#include <version>
-#if !defined(_MSC_VER) && !defined(__cpp_lib_source_location)
- #undef CPP2_USE_SOURCE_LOCATION
-#endif
-
-// If the cppfront user requested making the entire C++ standard library
-// available via module import or header include, do that
-#if defined(CPP2_IMPORT_STD) || defined(CPP2_INCLUDE_STD)
-
- // If C++23 'import std;' was requested and is available, use that
- #if defined(CPP2_IMPORT_STD) && defined(__cpp_lib_modules)
-
- #ifndef _MSC_VER
- // This is the ideal -- note that we just voted "import std;"
- // into draft C++23 in late July 2022, so implementers haven't
- // had time to catch up yet
- import std;
- #else // MSVC
- // Note: When C++23 "import std;" is available, we will switch to that here
- // In the meantime, this is what works on MSVC which is the only compiler
- // I've been able to get access to that implements modules enough to demo
- // (but we'll have more full-C++20 compilers soon!)
- #ifdef _MSC_VER
- #include "intrin.h"
- #endif
- import std.core;
- import std.filesystem;
- import std.memory;
- import std.regex;
- import std.threading;
-
- // Suppress spurious MSVC modules warning
- #pragma warning(disable:5050)
- #endif
-
- // Otherwise, as a fallback if 'import std;' was requested, or else
- // because 'include all std' was requested, include all the standard
- // headers, with a feature test #ifdef for each header that
- // isn't yet supported by all of { VS 2022, g++-10, clang++-12 }
- #else
- #ifdef _MSC_VER
- #include "intrin.h"
- #endif
- #include <algorithm>
- #include <any>
- #include <array>
- #include <atomic>
- #ifdef __cpp_lib_barrier
- #include <barrier>
- #endif
- #include <bit>
- #include <bitset>
- #include <cassert>
- #include <cctype>
- #include <cerrno>
- #include <cfenv>
- #include <cfloat>
- #include <charconv>
- #include <chrono>
- #include <cinttypes>
- #include <climits>
- #include <clocale>
- #include <cmath>
- #include <codecvt>
- #include <compare>
- #include <complex>
- #include <concepts>
- #include <condition_variable>
- #ifdef __cpp_lib_coroutine
- #include <coroutine>
- #endif
- #include <csetjmp>
- #include <csignal>
- #include <cstdarg>
- #include <cstddef>
- #include <cstdint>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <ctime>
- #if __has_include(<cuchar>)
- #include <cuchar>
- #endif
- #include <cwchar>
- #include <cwctype>
- #include <deque>
- #ifndef CPP2_NO_EXCEPTIONS
- #include <exception>
- #endif
- // libstdc++ currently has a dependency on linking TBB if <execution> is
- // included, and TBB seems to be not automatically installed and linkable
- // on some GCC installations, so let's not pull in that little-used header
- // in our -pure-cpp2 "import std;" simulation mode... if you need this,
- // use mixed mode (not -pure-cpp2) and #include all the headers you need
- // including this one
- //
- // #include <execution>
- #ifdef __cpp_lib_expected
- #include <expected>
- #endif
- #include <filesystem>
- #if defined(__cpp_lib_format) || (defined(_MSC_VER) && _MSC_VER >= 1929)
- #include <format>
- #endif
- #ifdef __cpp_lib_flat_map
- #include <flat_map>
- #endif
- #ifdef __cpp_lib_flat_set
- #include <flat_set>
- #endif
- #include <forward_list>
- #include <fstream>
- #include <functional>
- #include <future>
- #ifdef __cpp_lib_generator
- #include <generator>
- #endif
- #include <initializer_list>
- #include <iomanip>
- #include <ios>
- #include <iosfwd>
- #include <iostream>
- #include <iso646.h>
- #include <istream>
- #include <iterator>
- #ifdef __cpp_lib_latch
- #include <latch>
- #endif
- #include <limits>
- #include <list>
- #include <locale>
- #include <map>
- #ifdef __cpp_lib_mdspan
- #include <mdspan>
- #endif
- #include <memory>
- #ifdef __cpp_lib_memory_resource
- #include <memory_resource>
- #endif
- #include <mutex>
- #include <new>
- #include <numbers>
- #include <numeric>
- #include <optional>
- #include <ostream>
- #ifdef __cpp_lib_print
- #include <print>
- #endif
- #include <queue>
- #include <random>
- #include <ranges>
- #include <ratio>
- #include <regex>
- #include <scoped_allocator>
- #ifdef __cpp_lib_semaphore
- #include <semaphore>
- #endif
- #include <set>
- #include <shared_mutex>
- #ifdef __cpp_lib_source_location
- #include <source_location>
- #endif
- #include <span>
- #ifdef __cpp_lib_spanstream
- #include <spanstream>
- #endif
- #include <sstream>
- #include <stack>
- #ifdef __cpp_lib_stacktrace
- #include <stacktrace>
- #endif
- #ifdef __cpp_lib_stdatomic_h
- #include <stdatomic.h>
- #endif
- #include <stdexcept>
- #if __has_include(<stdfloat>)
- #include <stdfloat>
- #endif
- #ifdef __cpp_lib_jthread
- #include <stop_token>
- #endif
- #include <streambuf>
- #include <string>
- #include <string_view>
- #ifdef __cpp_lib_syncstream
- #include <syncstream>
- #endif
- #include <system_error>
- #include <thread>
- #include <tuple>
- #include <type_traits>
- #include <typeindex>
- #ifndef CPP2_NO_RTTI
- #include <typeinfo>
- #endif
- #include <unordered_map>
- #include <unordered_set>
- #include <utility>
- #include <valarray>
- #include <variant>
- #include <vector>
- #endif
-
-// Otherwise, just #include the facilities used in this header
-#else
- #ifdef _MSC_VER
- #include "intrin.h"
- #endif
- #include <algorithm>
- #include <any>
- #include <compare>
- #include <concepts>
- #include <cstddef>
- #include <cstdint>
- #include <cstdio>
- #ifndef CPP2_NO_EXCEPTIONS
- #include <exception>
- #endif
- #if defined(__cpp_lib_format) || (defined(_MSC_VER) && _MSC_VER >= 1929)
- #include <format>
- #endif
- #include <functional>
- #include <iostream>
- #include <iterator>
- #include <limits>
- #include <memory>
- #include <new>
- #include <random>
- #include <optional>
- #if defined(CPP2_USE_SOURCE_LOCATION)
- #include <source_location>
- #endif
- #include <span>
- #include <string>
- #include <string_view>
- #include <system_error>
- #include <tuple>
- #include <type_traits>
- #ifndef CPP2_NO_RTTI
- #include <typeinfo>
- #endif
- #include <utility>
- #include <variant>
- #include <vector>
-#endif
-
-
-#define CPP2_TYPEOF(x) std::remove_cvref_t<decltype(x)>
-#define CPP2_FORWARD(x) std::forward<decltype(x)>(x)
-#define CPP2_PACK_EMPTY(x) (sizeof...(x) == 0)
-#define CPP2_CONTINUE_BREAK(NAME) goto CONTINUE_##NAME; CONTINUE_##NAME: continue; goto BREAK_##NAME; BREAK_##NAME: break;
- // these redundant goto's to avoid 'unused label' warnings
-
-
-#if defined(_MSC_VER)
- // MSVC can't handle 'inline constexpr' yet in all cases
- #define CPP2_CONSTEXPR const
-#else
- #define CPP2_CONSTEXPR constexpr
-#endif
-
-
-namespace cpp2 {
-
-
-//-----------------------------------------------------------------------
-//
-// Convenience names for fundamental types
-//
-// Note: De jure, some of these are optional per the C and C++ standards
-// De facto, all of these are supported in all implementations I know of
-//
-//-----------------------------------------------------------------------
-//
-
-// Encouraged by default: Fixed-precision names
-using i8 = std::int8_t ;
-using i16 = std::int16_t ;
-using i32 = std::int32_t ;
-using i64 = std::int64_t ;
-using u8 = std::uint8_t ;
-using u16 = std::uint16_t ;
-using u32 = std::uint32_t ;
-using u64 = std::uint64_t ;
-
-// Discouraged: Variable precision names
-// short
-using ushort = unsigned short;
-// int
-using uint = unsigned int;
-// long
-using ulong = unsigned long;
-using longlong = long long;
-using ulonglong = unsigned long long;
-using longdouble = long double;
-
-// Strongly discouraged, for compatibility/interop only
-using _schar = signed char; // normally use i8 instead
-using _uchar = unsigned char; // normally use u8 instead
-
-
-//-----------------------------------------------------------------------
-//
-// General helpers
-//
-//-----------------------------------------------------------------------
-//
-
-inline constexpr auto max(auto... values) {
- return std::max( { values... } );
-}
-
-template <class T, class... Ts>
-inline constexpr auto is_any = std::disjunction_v<std::is_same<T, Ts>...>;
-
-template <std::size_t Len, std::size_t Align>
-struct aligned_storage {
- alignas(Align) unsigned char data[Len];
-};
-
-
-//-----------------------------------------------------------------------
-//
-// String: A helper workaround for passing a string literal as a
-// template argument
-//
-//-----------------------------------------------------------------------
-//
-template<std::size_t N>
-struct String
-{
- constexpr String(const char (&str)[N])
- {
- std::copy_n(str, N, value);
- }
-
- auto operator<=>(String const&) const = default;
-
- char value[N] = {};
-};
-
-
-//-----------------------------------------------------------------------
-//
-// contract_group
-//
-//-----------------------------------------------------------------------
-//
-
-#ifdef CPP2_USE_SOURCE_LOCATION
- #define CPP2_SOURCE_LOCATION_PARAM , std::source_location where
- #define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT , std::source_location where = std::source_location::current()
- #define CPP2_SOURCE_LOCATION_PARAM_SOLO std::source_location where
- #define CPP2_SOURCE_LOCATION_ARG , where
-#else
- #define CPP2_SOURCE_LOCATION_PARAM
- #define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT
- #define CPP2_SOURCE_LOCATION_PARAM_SOLO
- #define CPP2_SOURCE_LOCATION_ARG
-#endif
-
-// For C++23: make this std::string_view and drop the macro
-// Before C++23 std::string_view was not guaranteed to be trivially copyable,
-// and so in<T> will pass it by const& and really it should be by value
-#define CPP2_MESSAGE_PARAM char const*
-#define CPP2_CONTRACT_MSG cpp2::message_to_cstr_adapter
-
-auto message_to_cstr_adapter( CPP2_MESSAGE_PARAM msg ) -> CPP2_MESSAGE_PARAM { return msg ? msg : ""; }
-auto message_to_cstr_adapter( std::string const& msg ) -> CPP2_MESSAGE_PARAM { return msg.c_str(); }
-
-class contract_group {
-public:
- using handler = void (*)(CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM);
-
- constexpr contract_group (handler h = {}) : reporter{h} { }
- constexpr auto set_handler(handler h = {}) { reporter = h; }
- constexpr auto get_handler() const -> handler { return reporter; }
- constexpr auto has_handler() const -> bool { return reporter != handler{}; }
-
- constexpr auto enforce(bool b, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
- -> void { if (!b) report_violation(msg CPP2_SOURCE_LOCATION_ARG); }
- constexpr auto report_violation(CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
- -> void { if (reporter) reporter(msg CPP2_SOURCE_LOCATION_ARG); }
-private:
- handler reporter;
-};
-
-[[noreturn]] inline auto report_and_terminate(std::string_view group, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) noexcept -> void {
- std::cerr
-#ifdef CPP2_USE_SOURCE_LOCATION
- << where.file_name() << "("
- << where.line() << ") "
- << where.function_name() << ": "
-#endif
- << group << " violation";
- if (msg && msg[0] != '\0') {
- std::cerr << ": " << msg;
- }
- std::cerr << "\n";
- std::terminate();
-}
-
-auto inline Default = contract_group(
- [](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
- report_and_terminate("Contract", msg CPP2_SOURCE_LOCATION_ARG);
- }
-);
-auto inline Bounds = contract_group(
- [](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
- report_and_terminate("Bounds safety", msg CPP2_SOURCE_LOCATION_ARG);
- }
-);
-auto inline Null = contract_group(
- [](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
- report_and_terminate("Null safety", msg CPP2_SOURCE_LOCATION_ARG);
- }
-);
-auto inline Type = contract_group(
- [](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
- report_and_terminate("Type safety", msg CPP2_SOURCE_LOCATION_ARG);
- }
-);
-auto inline Testing = contract_group(
- [](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
- report_and_terminate("Testing", msg CPP2_SOURCE_LOCATION_ARG);
- }
-);
-
-
-// Null pointer deref checking
-//
-auto assert_not_null(auto&& p CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> decltype(auto)
-{
- // NOTE: This "!= T{}" test may or may not work for STL iterators. The standard
- // doesn't guarantee that using == and != will reliably report whether an
- // STL iterator has the default-constructed value. So use it only for raw *...
- if constexpr (std::is_pointer_v<CPP2_TYPEOF(p)>) {
- if (p == CPP2_TYPEOF(p){}) {
- Null.report_violation("dynamic null dereference attempt detected" CPP2_SOURCE_LOCATION_ARG);
- };
- }
- return CPP2_FORWARD(p);
-}
-
-// Subscript bounds checking
-//
-auto assert_in_bounds_impl(auto&& x, auto&& arg CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> void
- requires (std::is_integral_v<CPP2_TYPEOF(arg)> &&
- requires { std::size(x); std::ssize(x); x[arg]; std::begin(x) + 2; })
-{
- auto max = [&]() -> auto {
- if constexpr (std::is_signed_v<CPP2_TYPEOF(arg)>) { return std::ssize(x); }
- else { return std::size(x); }
- };
- auto msg = "out of bounds access attempt detected - attempted access at index " + std::to_string(arg) + ", ";
- if (max() > 0 ) {
- msg += "[min,max] range is [0," + std::to_string(max()-1) + "]";
- }
- else {
- msg += "but container is empty";
- }
- if (!(0 <= arg && arg < max())) {
- Bounds.report_violation(msg.c_str() CPP2_SOURCE_LOCATION_ARG);
- }
-}
-
-auto assert_in_bounds_impl(auto&&, auto&& CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> void
-{
-}
-
-#define CPP2_ASSERT_IN_BOUNDS(x, arg) (cpp2::assert_in_bounds_impl((x),(arg)), (x)[(arg)])
-
-
-//-----------------------------------------------------------------------
-//
-// Support wrappers that unblock using this file in environments that
-// disable EH or RTTI
-//
-// Note: This is not endorsing disabling those features, it's just
-// recognizing that disabling them is popular (e.g., games, WASM)
-// and so we should remove a potential adoption blocker... only a
-// few features in this file depend on EH or RTTI anyway, and
-// wouldn't be exercised in such an environment anyway so there
-// is no real net loss here
-//
-//-----------------------------------------------------------------------
-//
-
-[[noreturn]] auto Throw(auto&& x, [[maybe_unused]] char const* msg) -> void {
-#ifdef CPP2_NO_EXCEPTIONS
- auto err = std::string{"exceptions are disabled with -fno-exceptions - attempted to throw exception with type \"" + typeid(decltype(x)).name() + "\""};
- if (msg) {
- err += " and the message \"" + msg + "\"";
- }
- Type.report_violation( err );
- std::terminate();
-#else
- throw CPP2_FORWARD(x);
-#endif
-}
-
-inline auto Uncaught_exceptions() -> int {
-#ifdef CPP2_NO_EXCEPTIONS
- return 0;
-#else
- return std::uncaught_exceptions();
-#endif
-}
-
-template<typename T>
-auto Dynamic_cast( [[maybe_unused]] auto&& x ) -> decltype(auto) {
-#ifdef CPP2_NO_RTTI
- Type.report_violation( "'as' dynamic casting is disabled with -fno-rtti" );
- return nullptr;
-#else
- return dynamic_cast<T>(CPP2_FORWARD(x));
-#endif
-}
-
-template<typename T>
-auto Typeid() -> decltype(auto) {
-#ifdef CPP2_NO_RTTI
- Type.report_violation( "'any' dynamic casting is disabled with -fno-rtti" );
-#else
- return typeid(T);
-#endif
-}
-
-auto Typeid( [[maybe_unused]] auto&& x ) -> decltype(auto) {
-#ifdef CPP2_NO_RTTI
- Type.report_violation( "'typeid' is disabled with -fno-rtti" );
-#else
- return typeid(CPP2_FORWARD(x));
-#endif
-}
-
-
-//-----------------------------------------------------------------------
-//
-// Arena objects for std::allocators
-//
-// Note: cppfront translates "new" to "cpp2_new", so in Cpp2 code
-// these are invoked by simply "unique.new<T>" etc.
-//
-//-----------------------------------------------------------------------
-//
-struct {
- template<typename T>
- [[nodiscard]] auto cpp2_new(auto&& ...args) const -> std::unique_ptr<T> {
- // Prefer { } to ( ) so that initializing a vector<int> with
- // (10), (10, 20), and (10, 20, 30) is consistent
- if constexpr (requires { T{CPP2_FORWARD(args)...}; }) {
- // This is because apparently make_unique can't deal with list
- // initialization of aggregates, even after P0960
- return std::unique_ptr<T>( new T{CPP2_FORWARD(args)...} );
- }
- else {
- return std::make_unique<T>(CPP2_FORWARD(args)...);
- }
- }
-} inline unique;
-
-[[maybe_unused]] struct {
- template<typename T>
- [[nodiscard]] auto cpp2_new(auto&& ...args) const -> std::shared_ptr<T> {
- // Prefer { } to ( ) as noted for unique.new
- //
- // Note this does mean we don't get the make_shared optimization a lot
- // of the time -- we can restore that as soon as make_shared improves to
- // allow list initialization. But the make_shared optimization isn't a
- // huge deal anyway: it saves one allocation, but most of the cost of
- // shared_ptrs is copying them and the allocation cost saving is probably
- // outweighed by just a couple of shared_ptr copies; also, the make_shared
- // optimization has the potential downside of keeping the raw storage
- // alive longer when there are weak_ptrs. So, yes, we can and should
- // restore the make_shared optimization as soon as make_shared supports
- // list init, but I don't think it's all that important AFAIK
- if constexpr (requires { T{CPP2_FORWARD(args)...}; }) {
- // Why this calls 'unique.new': The workaround to use { } initialization
- // requires calling naked 'new' to allocate the object separately anyway,
- // so reuse the unique.new path that already does that (less code
- // duplication, plus encapsulate the naked 'new' in one place)
- return unique.cpp2_new<T>(CPP2_FORWARD(args)...);
- }
- else {
- return std::make_shared<T>(CPP2_FORWARD(args)...);
- }
- }
-} inline shared;
-
-template<typename T>
-[[nodiscard]] auto cpp2_new(auto&& ...args) -> std::unique_ptr<T> {
- return unique.cpp2_new<T>(CPP2_FORWARD(args)...);
-}
-
-
-//-----------------------------------------------------------------------
-//
-// in<T> For "in" parameter
-//
-//-----------------------------------------------------------------------
-//
-template<typename T>
-constexpr bool prefer_pass_by_value =
- sizeof(T) <= 2*sizeof(void*)
- && std::is_trivially_copy_constructible_v<T>;
-
-template<typename T>
- requires std::is_class_v<T> || std::is_union_v<T> || std::is_array_v<T> || std::is_function_v<T>
-constexpr bool prefer_pass_by_value<T> = false;
-
-template<typename T>
- requires (!std::is_void_v<T>)
-using in =
- std::conditional_t <
- prefer_pass_by_value<T>,
- T const,
- T const&
- >;
-
-
-//-----------------------------------------------------------------------
-//
-// Initialization: These are closely related...
-//
-// deferred_init<T> For deferred-initialized local object
-//
-// out<T> For out parameter
-//
-//-----------------------------------------------------------------------
-//
-template<typename T>
-class deferred_init {
- alignas(T) std::byte data[sizeof(T)];
- bool init = false;
-
- auto t() -> T& { return *std::launder(reinterpret_cast<T*>(&data)); }
-
- template<typename U>
- friend class out;
-
- auto destroy() -> void { if (init) { t().~T(); } init = false; }
-
-public:
- deferred_init() noexcept { }
- ~deferred_init() noexcept { destroy(); }
- auto value() noexcept -> T& { Default.enforce(init); return t(); }
-
- auto construct(auto&& ...args) -> void { Default.enforce(!init); new (&data) T{CPP2_FORWARD(args)...}; init = true; }
-};
-
-
-template<typename T>
-class out {
- // Not going to bother with std::variant here
- union {
- T* t;
- deferred_init<T>* dt;
- };
- out<T>* ot = {};
- bool has_t;
-
- // Each out in a chain contains its own uncaught_count ...
- int uncaught_count = Uncaught_exceptions();
- // ... but all in a chain share the topmost called_construct_
- bool called_construct_ = false;
-
-public:
- out(T* t_) noexcept : t{ t_}, has_t{true} { Default.enforce( t); }
- out(deferred_init<T>* dt_) noexcept : dt{dt_}, has_t{false} { Default.enforce(dt); }
- out(out<T>* ot_) noexcept : ot{ot_}, has_t{ot_->has_t} { Default.enforce(ot);
- if (has_t) { t = ot->t; }
- else { dt = ot->dt; }
- }
-
- auto called_construct() -> bool& {
- if (ot) { return ot->called_construct(); }
- else { return called_construct_; }
- }
-
- // In the case of an exception, if the parameter was uninitialized
- // then leave it in the same state on exit (strong guarantee)
- ~out() {
- if (called_construct() && uncaught_count != Uncaught_exceptions()) {
- Default.enforce(!has_t);
- dt->destroy();
- called_construct() = false;
- }
- }
-
- auto construct(auto&& ...args) -> void {
- if (has_t || called_construct()) {
- if constexpr (requires { *t = T(CPP2_FORWARD(args)...); }) {
- Default.enforce( t );
- *t = T(CPP2_FORWARD(args)...);
- }
- else {
- Default.report_violation("attempted to copy assign, but copy assignment is not available");
- }
- }
- else {
- Default.enforce( dt );
- if (dt->init) {
- if constexpr (requires { *t = T(CPP2_FORWARD(args)...); }) {
- dt->value() = T(CPP2_FORWARD(args)...);
- }
- else {
- Default.report_violation("attempted to copy assign, but copy assignment is not available");
- }
- }
- else {
- dt->construct(CPP2_FORWARD(args)...);
- called_construct() = true;
- }
- }
- }
-
- auto value() noexcept -> T& {
- if (has_t) {
- Default.enforce( t );
- return *t;
- }
- else {
- Default.enforce( dt );
- return dt->value();
- }
- }
-};
-
-
-//-----------------------------------------------------------------------
-//
-// CPP2_UFCS: Variadic macro generating a variadic lamba, oh my...
-//
-//-----------------------------------------------------------------------
-//
-// Workaround <https://github.com/llvm/llvm-project/issues/70556>.
-#define CPP2_FORCE_INLINE_LAMBDA_CLANG /* empty */
-
-#if defined(_MSC_VER) && !defined(__clang_major__)
- #define CPP2_FORCE_INLINE __forceinline
- #define CPP2_FORCE_INLINE_LAMBDA [[msvc::forceinline]]
- #define CPP2_LAMBDA_NO_DISCARD
-#else
- #define CPP2_FORCE_INLINE __attribute__((always_inline))
- #if defined(__clang__)
- #define CPP2_FORCE_INLINE_LAMBDA /* empty */
- #undef CPP2_FORCE_INLINE_LAMBDA_CLANG
- #define CPP2_FORCE_INLINE_LAMBDA_CLANG __attribute__((always_inline))
- #else
- #define CPP2_FORCE_INLINE_LAMBDA __attribute__((always_inline))
- #endif
-
- #if defined(__clang_major__)
- // Also check __cplusplus, only to satisfy Clang -pedantic-errors
- #if __cplusplus >= 202302L && (__clang_major__ > 13 || (__clang_major__ == 13 && __clang_minor__ >= 2))
- #define CPP2_LAMBDA_NO_DISCARD [[nodiscard]]
- #else
- #define CPP2_LAMBDA_NO_DISCARD
- #endif
- #elif defined(__GNUC__)
- #if __GNUC__ >= 9
- #define CPP2_LAMBDA_NO_DISCARD [[nodiscard]]
- #else
- #define CPP2_LAMBDA_NO_DISCARD
- #endif
- #if ((__GNUC__ * 100) + __GNUC_MINOR__) < 1003
- // GCC 10.2 doesn't support this feature (10.3 is fine)
- #undef CPP2_FORCE_INLINE_LAMBDA
- #define CPP2_FORCE_INLINE_LAMBDA
- #endif
- #else
- #define CPP2_LAMBDA_NO_DISCARD
- #endif
-#endif
-
-#define CPP2_UFCS_REMPARENS(...) __VA_ARGS__
-
-// Ideally, the expression `CPP2_UFCS_IS_NOTHROW` expands to
-// is in the _noexcept-specifier_ of the UFCS lambda, but without 'std::declval'.
-// To workaround [GCC bug 101043](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101043),
-// we instead make it a template parameter of the UFCS lambda.
-// But using a template parameter, Clang also ICEs on an application.
-// So we use these `NOTHROW` macros to fall back to the ideal for when not using GCC.
-#define CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,...) \
- requires { requires requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...); }; \
- requires noexcept(std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...)); } \
-|| requires { requires !requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...); }; \
- requires noexcept(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(std::declval<Obj>(), std::declval<Params>()...)); }
-#define CPP2_UFCS_IS_NOTHROW_PARAM(...) /*empty*/
-#define CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,...) CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,__VA_ARGS__)
-#if defined(__GNUC__) && !defined(__clang__)
- #undef CPP2_UFCS_IS_NOTHROW_PARAM
- #undef CPP2_UFCS_IS_NOTHROW_ARG
- #define CPP2_UFCS_IS_NOTHROW_PARAM(QUALID,TEMPKW,...) , bool IsNothrow = CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,__VA_ARGS__)
- #define CPP2_UFCS_IS_NOTHROW_ARG(...) IsNothrow
- #if __GNUC__ < 11
- #undef CPP2_UFCS_IS_NOTHROW_PARAM
- #undef CPP2_UFCS_IS_NOTHROW_ARG
- #define CPP2_UFCS_IS_NOTHROW_PARAM(...) /*empty*/
- #define CPP2_UFCS_IS_NOTHROW_ARG(...) false // GCC 10 UFCS is always potentially-throwing.
- #endif
-#endif
-
-// Ideally, the expression `CPP2_UFCS_CONSTRAINT_ARG` expands to
-// is in the _requires-clause_ of the UFCS lambda.
-// To workaround an MSVC bug within a member function 'F' where UFCS is also for 'F'
-// (<https://github.com/hsutter/cppfront/pull/506#issuecomment-1826086952>),
-// we instead make it a template parameter of the UFCS lambda.
-// But using a template parameter, Clang also ICEs and GCC rejects a local 'F'.
-// Also, Clang rejects the SFINAE test case when using 'std::declval'.
-// So we use these `CONSTRAINT` macros to fall back to the ideal for when not using MSVC.
-#define CPP2_UFCS_CONSTRAINT_PARAM(...) /*empty*/
-#define CPP2_UFCS_CONSTRAINT_ARG(QUALID,TEMPKW,...) \
- requires { CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); } \
-|| requires { CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); }
-#if defined(_MSC_VER)
- #undef CPP2_UFCS_CONSTRAINT_PARAM
- #undef CPP2_UFCS_CONSTRAINT_ARG
- #define CPP2_UFCS_CONSTRAINT_PARAM(QUALID,TEMPKW,...) , bool IsViable = \
- requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...); } \
-|| requires { CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(std::declval<Obj>(), std::declval<Params>()...); }
- #define CPP2_UFCS_CONSTRAINT_ARG(...) IsViable
-#endif
-
-#define CPP2_UFCS_(LAMBDADEFCAPT,QUALID,TEMPKW,...) \
-[LAMBDADEFCAPT]< \
- typename Obj, typename... Params \
- CPP2_UFCS_IS_NOTHROW_PARAM(QUALID,TEMPKW,__VA_ARGS__) \
- CPP2_UFCS_CONSTRAINT_PARAM(QUALID,TEMPKW,__VA_ARGS__) \
- > \
- CPP2_LAMBDA_NO_DISCARD (Obj&& obj, Params&& ...params) CPP2_FORCE_INLINE_LAMBDA_CLANG \
- noexcept(CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,__VA_ARGS__)) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) \
- requires CPP2_UFCS_CONSTRAINT_ARG(QUALID,TEMPKW,__VA_ARGS__) { \
- if constexpr (requires{ CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); }) { \
- return CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); \
- } else { \
- return CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \
- } \
-}
-
-#define CPP2_UFCS(...) CPP2_UFCS_(&,(),,__VA_ARGS__)
-#define CPP2_UFCS_TEMPLATE(...) CPP2_UFCS_(&,(),template,__VA_ARGS__)
-#define CPP2_UFCS_QUALIFIED_TEMPLATE(QUALID,...) CPP2_UFCS_(&,QUALID,template,__VA_ARGS__)
-#define CPP2_UFCS_NONLOCAL(...) CPP2_UFCS_(,(),,__VA_ARGS__)
-#define CPP2_UFCS_TEMPLATE_NONLOCAL(...) CPP2_UFCS_(,(),template,__VA_ARGS__)
-#define CPP2_UFCS_QUALIFIED_TEMPLATE_NONLOCAL(QUALID,...) CPP2_UFCS_(,QUALID,template,__VA_ARGS__)
-
-
-//-----------------------------------------------------------------------
-//
-// to_string for string interpolation
-//
-//-----------------------------------------------------------------------
-//
-// For use when returning "no such thing", such as
-// when customizing "as" for std::variant
-struct nonesuch_ {
- auto operator==(auto const&) -> bool { return false; }
-};
-constexpr inline nonesuch_ nonesuch;
-
-inline auto to_string(...) -> std::string
-{
- return "(customize me - no cpp2::to_string overload exists for this type)";
-}
-
-inline auto to_string(nonesuch_) -> std::string
-{
- return "(invalid type)";
-}
-
-inline auto to_string(std::same_as<std::any> auto const&) -> std::string
-{
- return "std::any";
-}
-
-inline auto to_string(bool b) -> std::string
-{
- return b ? "true" : "false";
-}
-
-template<typename T>
-inline auto to_string(T const& t) -> std::string
- requires requires { std::to_string(t); }
-{
- return std::to_string(t);
-}
-
-inline auto to_string(char const& t) -> std::string
-{
- return std::string{t};
-}
-
-inline auto to_string(char const* s) -> std::string
-{
- return std::string{s};
-}
-
-inline auto to_string(std::string const& s) -> std::string const&
-{
- return s;
-}
-
-template<typename T>
-inline auto to_string(T const& sv) -> std::string
- requires (std::is_convertible_v<T, std::string_view>
- && !std::is_convertible_v<T, const char*>)
-{
- return std::string{sv};
-}
-
-template <typename... Ts>
-inline auto to_string(std::variant<Ts...> const& v) -> std::string;
-
-template < typename T, typename U>
-inline auto to_string(std::pair<T,U> const& p) -> std::string;
-
-template < typename... Ts>
-inline auto to_string(std::tuple<Ts...> const& t) -> std::string;
-
-template<typename T>
-inline auto to_string(std::optional<T> const& o) -> std::string {
- if (o.has_value()) {
- return cpp2::to_string(o.value());
- }
- return "(empty)";
-}
-
-template <typename... Ts>
-inline auto to_string(std::variant<Ts...> const& v) -> std::string
-{
- if (v.valueless_by_exception()) return "(empty)";
- // Need to guard this with is_any otherwise the get_if is illegal
- if constexpr (is_any<std::monostate, Ts...>) if (std::get_if<std::monostate>(&v) != nullptr) return "(empty)";
-
- return std::visit([](auto&& arg) -> std::string {
- return cpp2::to_string(arg);
- }, v);
-}
-
-template < typename T, typename U>
-inline auto to_string(std::pair<T,U> const& p) -> std::string
-{
- return "(" + cpp2::to_string(p.first) + ", " + cpp2::to_string(p.second) + ")";
-}
-
-template < typename... Ts>
-inline auto to_string(std::tuple<Ts...> const& t) -> std::string
-{
- if constexpr (sizeof...(Ts) == 0) {
- return "()";
- } else {
- std::string out = "(" + cpp2::to_string(std::get<0>(t));
- std::apply([&out](auto&&, auto&&... args) {
- ((out += ", " + cpp2::to_string(args)), ...);
- }, t);
- out += ")";
- return out;
- }
-}
-
-// MSVC supports it but doesn't define __cpp_lib_format until the ABI stablizes, but here
-// don't care about that, so consider it as supported since VS 2019 16.10 (_MSC_VER 1929)
-#if defined(__cpp_lib_format) || (defined(_MSC_VER) && _MSC_VER >= 1929)
-inline auto to_string(auto&& value, std::string_view fmt) -> std::string
-{
- return std::vformat(fmt, std::make_format_args(CPP2_FORWARD(value)));
-}
-#else
-inline auto to_string(auto&& value, std::string_view) -> std::string
-{
- // This Cpp1 implementation does not support <format>-ted string interpolation
- // so the best we can do is ignore the formatting request (degraded operation
- // seems better than a dynamic error message string or a hard error)
- return to_string(CPP2_FORWARD(value));
-}
-#endif
-
-
-//-----------------------------------------------------------------------
-//
-// is and as
-//
-//-----------------------------------------------------------------------
-//
-
-//-------------------------------------------------------------------------------------------------------------
-// Built-in is
-//
-
-// For designating "holds no value" -- used only with is, not as
-// TODO: Does this really warrant a new synonym? Perhaps "is void" is enough
-using empty = void;
-
-
-// Templates
-//
-template <template <typename...> class C, typename... Ts>
-constexpr auto is(C< Ts...> const& ) -> bool {
- return true;
-}
-
-#if defined(_MSC_VER)
- template <template <typename, typename...> class C, typename T>
- constexpr auto is( T const& ) -> bool {
- return false;
- }
-#else
- template <template <typename...> class C, typename T>
- constexpr auto is( T const& ) -> bool {
- return false;
- }
-#endif
-
-template <template <typename,auto> class C, typename T, auto V>
-constexpr auto is( C<T, V> const& ) -> bool {
- return true;
-}
-
-template <template <typename,auto> class C, typename T>
-constexpr auto is( T const& ) -> bool {
- return false;
-}
-
-// Types
-//
-template< typename C, typename X >
-auto is( X const& ) -> bool {
- return false;
-}
-
-template< typename C, typename X >
- requires std::is_same_v<C, X>
-auto is( X const& ) -> bool {
- return true;
-}
-
-template< typename C, typename X >
- requires (std::is_base_of_v<C, X> && !std::is_same_v<C,X>)
-auto is( X const& ) -> bool {
- return true;
-}
-
-template< typename C, typename X >
- requires (
- ( std::is_base_of_v<X, C> ||
- ( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
- ) && !std::is_same_v<C,X>)
-auto is( X const& x ) -> bool {
- return Dynamic_cast<C const*>(&x) != nullptr;
-}
-
-template< typename C, typename X >
- requires (
- ( std::is_base_of_v<X, C> ||
- ( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
- ) && !std::is_same_v<C,X>)
-auto is( X const* x ) -> bool {
- return Dynamic_cast<C const*>(x) != nullptr;
-}
-
-template< typename C, typename X >
- requires (requires (X x) { *x; X(); } && std::is_same_v<C, empty>)
-auto is( X const& x ) -> bool {
- return x == X();
-}
-
-
-// Values
-//
-inline constexpr auto is( auto const& x, auto&& value ) -> bool
-{
- // Value with customized operator_is case
- if constexpr (requires{ x.op_is(value); }) {
- return x.op_is(value);
- }
-
- // Predicate case
- else if constexpr (requires{ bool{ value(x) }; }) {
- return value(x);
- }
- else if constexpr (std::is_function_v<decltype(value)> || requires{ &value.operator(); }) {
- return false;
- }
-
- // Value equality case
- else if constexpr (requires{ bool{x == value}; }) {
- return x == value;
- }
- return false;
-}
-
-
-//-------------------------------------------------------------------------------------------------------------
-// Built-in as
-//
-
-// The 'as' cast functions are <To, From> so use that order here
-// If it's confusing, we can switch this to <From, To>
-template< typename To, typename From >
-inline constexpr auto is_narrowing_v =
- // [dcl.init.list] 7.1
- (std::is_floating_point_v<From> && std::is_integral_v<To>) ||
- // [dcl.init.list] 7.2
- (std::is_floating_point_v<From> && std::is_floating_point_v<To> && sizeof(From) > sizeof(To)) ||
- // [dcl.init.list] 7.3
- (std::is_integral_v<From> && std::is_floating_point_v<To>) ||
- (std::is_enum_v<From> && std::is_floating_point_v<To>) ||
- // [dcl.init.list] 7.4
- (std::is_integral_v<From> && std::is_integral_v<To> && sizeof(From) > sizeof(To)) ||
- (std::is_enum_v<From> && std::is_integral_v<To> && sizeof(From) > sizeof(To)) ||
- // [dcl.init.list] 7.5
- (std::is_pointer_v<From> && std::is_same_v<To, bool>);
-
-template <typename... Ts>
-inline constexpr auto program_violates_type_safety_guarantee = sizeof...(Ts) < 0;
-
-// For literals we can check for safe 'narrowing' at a compile time (e.g., 1 as std::size_t)
-template< typename C, auto x >
-inline constexpr bool is_castable_v =
- std::is_integral_v<C> &&
- std::is_integral_v<CPP2_TYPEOF(x)> &&
- !(static_cast<CPP2_TYPEOF(x)>(static_cast<C>(x)) != x ||
- (
- (std::is_signed_v<C> != std::is_signed_v<CPP2_TYPEOF(x)>) &&
- ((static_cast<C>(x) < C{}) != (x < CPP2_TYPEOF(x){}))
- )
- );
-
-// As
-//
-
-template< typename C >
-auto as(auto const&) -> auto {
- return nonesuch;
-}
-
-template< typename C, auto x >
- requires (std::is_arithmetic_v<C> && std::is_arithmetic_v<CPP2_TYPEOF(x)>)
-inline constexpr auto as() -> auto
-{
- if constexpr ( is_castable_v<C, x> ) {
- return static_cast<C>(x);
- } else {
- return nonesuch;
- }
-}
-
-template< typename C >
-inline constexpr auto as(auto const& x) -> auto
- requires (
- std::is_floating_point_v<C> &&
- std::is_floating_point_v<CPP2_TYPEOF(x)> &&
- sizeof(CPP2_TYPEOF(x)) > sizeof(C)
- )
-{
- return nonesuch;
-}
-
-// Signed/unsigned conversions to a not-smaller type are handled as a precondition,
-// and trying to cast from a value that is in the half of the value space that isn't
-// representable in the target type C is flagged as a Type safety contract violation
-template< typename C >
-inline constexpr auto as(auto const& x CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> auto
- requires (
- std::is_integral_v<C> &&
- std::is_integral_v<CPP2_TYPEOF(x)> &&
- std::is_signed_v<CPP2_TYPEOF(x)> != std::is_signed_v<C> &&
- sizeof(CPP2_TYPEOF(x)) <= sizeof(C)
- )
-{
- const C c = static_cast<C>(x);
- Type.enforce( // precondition check: must be round-trippable => not lossy
- static_cast<CPP2_TYPEOF(x)>(c) == x && (c < C{}) == (x < CPP2_TYPEOF(x){}),
- "dynamic lossy narrowing conversion attempt detected" CPP2_SOURCE_LOCATION_ARG
- );
- return c;
-}
-
-template< typename C, typename X >
- requires std::is_same_v<C, X>
-auto as( X const& x ) -> decltype(auto) {
- return x;
-}
-
-template< typename C, typename X >
- requires std::is_same_v<C, X>
-auto as( X& x ) -> decltype(auto) {
- return x;
-}
-
-
-template< typename C, typename X >
-auto as(X const& x) -> C
- requires (std::is_same_v<C, std::string> && std::is_integral_v<X>)
-{
- return cpp2::to_string(x);
-}
-
-
-template< typename C, typename X >
-auto as( X const& x ) -> auto
- requires (!std::is_same_v<C, X> && !std::is_base_of_v<C, X> && requires { C{x}; }
- && !(std::is_same_v<C, std::string> && std::is_integral_v<X>) // exclude above case
- )
-{
- // Experiment: Recognize the nested `::value_type` pattern for some dynamic library types
- // like std::optional, and try to prevent accidental narrowing conversions even when
- // those types themselves don't defend against them
- if constexpr( requires { requires std::is_convertible_v<X, typename C::value_type>; } ) {
- if constexpr( is_narrowing_v<typename C::value_type, X>) {
- return nonesuch;
- }
- }
- return C{x};
-}
-
-template< typename C, typename X >
- requires (std::is_base_of_v<C, X> && !std::is_same_v<C, X>)
-auto as( X& x ) -> C& {
- return x;
-}
-
-template< typename C, typename X >
- requires (std::is_base_of_v<C, X> && !std::is_same_v<C, X>)
-auto as( X const& x ) -> C const& {
- return x;
-}
-
-template< typename C, typename X >
- requires (std::is_base_of_v<X, C> && !std::is_same_v<C,X>)
-auto as( X& x ) -> C& {
- return Dynamic_cast<C&>(x);
-}
-
-template< typename C, typename X >
- requires (std::is_base_of_v<X, C> && !std::is_same_v<C,X>)
-auto as( X const& x ) -> C const& {
- return Dynamic_cast<C const&>(x);
-}
-
-template< typename C, typename X >
- requires (
- std::is_pointer_v<C>
- && std::is_pointer_v<X>
- && std::is_base_of_v<CPP2_TYPEOF(*std::declval<X>()), CPP2_TYPEOF(*std::declval<C>())>
- && !std::is_same_v<C, X>
- )
-auto as( X x ) -> C {
- return Dynamic_cast<C>(x);
-}
-
-
-//-------------------------------------------------------------------------------------------------------------
-// std::variant is and as
-//
-
-// Common internal helper
-//
-template<std::size_t I, typename... Ts>
-constexpr auto operator_as( std::variant<Ts...> && x ) -> decltype(auto) {
- if constexpr (I < std::variant_size_v<std::variant<Ts...>>) {
- return std::get<I>( x );
- }
- else {
- return nonesuch;
- }
-}
-
-template<std::size_t I, typename... Ts>
-constexpr auto operator_as( std::variant<Ts...> & x ) -> decltype(auto) {
- if constexpr (I < std::variant_size_v<std::variant<Ts...>>) {
- return std::get<I>( x );
- }
- else {
- return nonesuch;
- }
-}
-
-template<std::size_t I, typename... Ts>
-constexpr auto operator_as( std::variant<Ts...> const& x ) -> decltype(auto) {
- if constexpr (I < std::variant_size_v<std::variant<Ts...>>) {
- return std::get<I>( x );
- }
- else {
- return nonesuch;
- }
-}
-
-
-// is Type
-//
-template<typename... Ts>
-constexpr auto operator_is( std::variant<Ts...> const& x ) {
- return x.index();
-}
-
-template<typename T, typename... Ts>
-auto is( std::variant<Ts...> const& x );
-
-
-// is Value
-//
-template<typename... Ts>
-constexpr auto is( std::variant<Ts...> const& x, auto&& value ) -> bool
-{
- // Predicate case
- if constexpr (requires{ bool{ value(operator_as< 0>(x)) }; }) { if (x.index() == 0) return value(operator_as< 0>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 1>(x)) }; }) { if (x.index() == 1) return value(operator_as< 1>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 2>(x)) }; }) { if (x.index() == 2) return value(operator_as< 2>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 3>(x)) }; }) { if (x.index() == 3) return value(operator_as< 3>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 4>(x)) }; }) { if (x.index() == 4) return value(operator_as< 4>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 5>(x)) }; }) { if (x.index() == 5) return value(operator_as< 5>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 6>(x)) }; }) { if (x.index() == 6) return value(operator_as< 6>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 7>(x)) }; }) { if (x.index() == 7) return value(operator_as< 7>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 8>(x)) }; }) { if (x.index() == 8) return value(operator_as< 8>(x)); }
- else if constexpr (requires{ bool{ value(operator_as< 9>(x)) }; }) { if (x.index() == 9) return value(operator_as< 9>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<10>(x)) }; }) { if (x.index() == 10) return value(operator_as<10>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<11>(x)) }; }) { if (x.index() == 11) return value(operator_as<11>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<12>(x)) }; }) { if (x.index() == 12) return value(operator_as<12>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<13>(x)) }; }) { if (x.index() == 13) return value(operator_as<13>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<14>(x)) }; }) { if (x.index() == 14) return value(operator_as<14>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<15>(x)) }; }) { if (x.index() == 15) return value(operator_as<15>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<16>(x)) }; }) { if (x.index() == 16) return value(operator_as<16>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<17>(x)) }; }) { if (x.index() == 17) return value(operator_as<17>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<18>(x)) }; }) { if (x.index() == 18) return value(operator_as<18>(x)); }
- else if constexpr (requires{ bool{ value(operator_as<19>(x)) }; }) { if (x.index() == 19) return value(operator_as<19>(x)); }
- else if constexpr (std::is_function_v<decltype(value)> || requires{ &value.operator(); }) {
- return false;
- }
-
- // Value case
- else {
- if constexpr (requires{ bool{ operator_as< 0>(x) == value }; }) { if (x.index() == 0) return operator_as< 0>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 1>(x) == value }; }) { if (x.index() == 1) return operator_as< 1>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 2>(x) == value }; }) { if (x.index() == 2) return operator_as< 2>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 3>(x) == value }; }) { if (x.index() == 3) return operator_as< 3>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 4>(x) == value }; }) { if (x.index() == 4) return operator_as< 4>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 5>(x) == value }; }) { if (x.index() == 5) return operator_as< 5>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 6>(x) == value }; }) { if (x.index() == 6) return operator_as< 6>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 7>(x) == value }; }) { if (x.index() == 7) return operator_as< 7>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 8>(x) == value }; }) { if (x.index() == 8) return operator_as< 8>(x) == value; }
- if constexpr (requires{ bool{ operator_as< 9>(x) == value }; }) { if (x.index() == 9) return operator_as< 9>(x) == value; }
- if constexpr (requires{ bool{ operator_as<10>(x) == value }; }) { if (x.index() == 10) return operator_as<10>(x) == value; }
- if constexpr (requires{ bool{ operator_as<11>(x) == value }; }) { if (x.index() == 11) return operator_as<11>(x) == value; }
- if constexpr (requires{ bool{ operator_as<12>(x) == value }; }) { if (x.index() == 12) return operator_as<12>(x) == value; }
- if constexpr (requires{ bool{ operator_as<13>(x) == value }; }) { if (x.index() == 13) return operator_as<13>(x) == value; }
- if constexpr (requires{ bool{ operator_as<14>(x) == value }; }) { if (x.index() == 14) return operator_as<14>(x) == value; }
- if constexpr (requires{ bool{ operator_as<15>(x) == value }; }) { if (x.index() == 15) return operator_as<15>(x) == value; }
- if constexpr (requires{ bool{ operator_as<16>(x) == value }; }) { if (x.index() == 16) return operator_as<16>(x) == value; }
- if constexpr (requires{ bool{ operator_as<17>(x) == value }; }) { if (x.index() == 17) return operator_as<17>(x) == value; }
- if constexpr (requires{ bool{ operator_as<18>(x) == value }; }) { if (x.index() == 18) return operator_as<18>(x) == value; }
- if constexpr (requires{ bool{ operator_as<19>(x) == value }; }) { if (x.index() == 19) return operator_as<19>(x) == value; }
- }
- return false;
-}
-
-
-// as
-//
-template<typename T, typename... Ts>
-auto is( std::variant<Ts...> const& x ) {
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 0>(x)), T >) { if (x.index() == 0) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 1>(x)), T >) { if (x.index() == 1) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 2>(x)), T >) { if (x.index() == 2) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 3>(x)), T >) { if (x.index() == 3) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 4>(x)), T >) { if (x.index() == 4) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 5>(x)), T >) { if (x.index() == 5) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 6>(x)), T >) { if (x.index() == 6) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 7>(x)), T >) { if (x.index() == 7) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 8>(x)), T >) { if (x.index() == 8) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 9>(x)), T >) { if (x.index() == 9) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<10>(x)), T >) { if (x.index() == 10) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<11>(x)), T >) { if (x.index() == 11) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<12>(x)), T >) { if (x.index() == 12) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<13>(x)), T >) { if (x.index() == 13) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<14>(x)), T >) { if (x.index() == 14) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<15>(x)), T >) { if (x.index() == 15) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<16>(x)), T >) { if (x.index() == 16) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<17>(x)), T >) { if (x.index() == 17) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<18>(x)), T >) { if (x.index() == 18) return true; }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<19>(x)), T >) { if (x.index() == 19) return true; }
- if constexpr (std::is_same_v< T, empty > ) {
- if (x.valueless_by_exception()) return true;
- // Need to guard this with is_any otherwise the get_if is illegal
- if constexpr (is_any<std::monostate, Ts...>) return std::get_if<std::monostate>(&x) != nullptr;
- }
- return false;
-}
-
-template<typename T, typename... Ts>
-auto as( std::variant<Ts...> && x ) -> decltype(auto) {
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 0>(x)), T >) { if (x.index() == 0) return operator_as<0>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 1>(x)), T >) { if (x.index() == 1) return operator_as<1>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 2>(x)), T >) { if (x.index() == 2) return operator_as<2>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 3>(x)), T >) { if (x.index() == 3) return operator_as<3>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 4>(x)), T >) { if (x.index() == 4) return operator_as<4>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 5>(x)), T >) { if (x.index() == 5) return operator_as<5>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 6>(x)), T >) { if (x.index() == 6) return operator_as<6>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 7>(x)), T >) { if (x.index() == 7) return operator_as<7>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 8>(x)), T >) { if (x.index() == 8) return operator_as<8>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 9>(x)), T >) { if (x.index() == 9) return operator_as<9>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<10>(x)), T >) { if (x.index() == 10) return operator_as<10>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<11>(x)), T >) { if (x.index() == 11) return operator_as<11>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<12>(x)), T >) { if (x.index() == 12) return operator_as<12>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<13>(x)), T >) { if (x.index() == 13) return operator_as<13>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<14>(x)), T >) { if (x.index() == 14) return operator_as<14>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<15>(x)), T >) { if (x.index() == 15) return operator_as<15>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<16>(x)), T >) { if (x.index() == 16) return operator_as<16>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<17>(x)), T >) { if (x.index() == 17) return operator_as<17>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<18>(x)), T >) { if (x.index() == 18) return operator_as<18>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<19>(x)), T >) { if (x.index() == 19) return operator_as<19>(x); }
- Throw( std::bad_variant_access(), "'as' cast failed for 'variant'");
-}
-
-template<typename T, typename... Ts>
-auto as( std::variant<Ts...> & x ) -> decltype(auto) {
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 0>(x)), T >) { if (x.index() == 0) return operator_as<0>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 1>(x)), T >) { if (x.index() == 1) return operator_as<1>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 2>(x)), T >) { if (x.index() == 2) return operator_as<2>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 3>(x)), T >) { if (x.index() == 3) return operator_as<3>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 4>(x)), T >) { if (x.index() == 4) return operator_as<4>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 5>(x)), T >) { if (x.index() == 5) return operator_as<5>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 6>(x)), T >) { if (x.index() == 6) return operator_as<6>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 7>(x)), T >) { if (x.index() == 7) return operator_as<7>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 8>(x)), T >) { if (x.index() == 8) return operator_as<8>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 9>(x)), T >) { if (x.index() == 9) return operator_as<9>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<10>(x)), T >) { if (x.index() == 10) return operator_as<10>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<11>(x)), T >) { if (x.index() == 11) return operator_as<11>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<12>(x)), T >) { if (x.index() == 12) return operator_as<12>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<13>(x)), T >) { if (x.index() == 13) return operator_as<13>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<14>(x)), T >) { if (x.index() == 14) return operator_as<14>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<15>(x)), T >) { if (x.index() == 15) return operator_as<15>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<16>(x)), T >) { if (x.index() == 16) return operator_as<16>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<17>(x)), T >) { if (x.index() == 17) return operator_as<17>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<18>(x)), T >) { if (x.index() == 18) return operator_as<18>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<19>(x)), T >) { if (x.index() == 19) return operator_as<19>(x); }
- Throw( std::bad_variant_access(), "'as' cast failed for 'variant'");
-}
-
-template<typename T, typename... Ts>
-auto as( std::variant<Ts...> const& x ) -> decltype(auto) {
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 0>(x)), T >) { if (x.index() == 0) return operator_as<0>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 1>(x)), T >) { if (x.index() == 1) return operator_as<1>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 2>(x)), T >) { if (x.index() == 2) return operator_as<2>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 3>(x)), T >) { if (x.index() == 3) return operator_as<3>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 4>(x)), T >) { if (x.index() == 4) return operator_as<4>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 5>(x)), T >) { if (x.index() == 5) return operator_as<5>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 6>(x)), T >) { if (x.index() == 6) return operator_as<6>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 7>(x)), T >) { if (x.index() == 7) return operator_as<7>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 8>(x)), T >) { if (x.index() == 8) return operator_as<8>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 9>(x)), T >) { if (x.index() == 9) return operator_as<9>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<10>(x)), T >) { if (x.index() == 10) return operator_as<10>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<11>(x)), T >) { if (x.index() == 11) return operator_as<11>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<12>(x)), T >) { if (x.index() == 12) return operator_as<12>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<13>(x)), T >) { if (x.index() == 13) return operator_as<13>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<14>(x)), T >) { if (x.index() == 14) return operator_as<14>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<15>(x)), T >) { if (x.index() == 15) return operator_as<15>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<16>(x)), T >) { if (x.index() == 16) return operator_as<16>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<17>(x)), T >) { if (x.index() == 17) return operator_as<17>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<18>(x)), T >) { if (x.index() == 18) return operator_as<18>(x); }
- if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<19>(x)), T >) { if (x.index() == 19) return operator_as<19>(x); }
- Throw( std::bad_variant_access(), "'as' cast failed for 'variant'");
-}
-
-
-//-------------------------------------------------------------------------------------------------------------
-// std::any is and as
-//
-
-// is Type
-//
-template<typename T, typename X>
- requires (std::is_same_v<X,std::any> && !std::is_same_v<T,std::any> && !std::is_same_v<T,empty>)
-constexpr auto is( X const& x ) -> bool
- { return x.type() == Typeid<T>(); }
-
-template<typename T, typename X>
- requires (std::is_same_v<X,std::any> && std::is_same_v<T,empty>)
-constexpr auto is( X const& x ) -> bool
- { return !x.has_value(); }
-
-
-// is Value
-//
-inline constexpr auto is( std::any const& x, auto&& value ) -> bool
-{
- // Predicate case
- if constexpr (requires{ bool{ value(x) }; }) {
- return value(x);
- }
- else if constexpr (std::is_function_v<decltype(value)> || requires{ &value.operator(); }) {
- return false;
- }
-
- // Value case
- else if constexpr (requires{ bool{ *std::any_cast<CPP2_TYPEOF(value)>(&x) == value }; }) {
- auto pvalue = std::any_cast<CPP2_TYPEOF(value)>(&x);
- return pvalue && *pvalue == value;
- }
- // else
- return false;
-}
-
-
-// as
-//
-template<typename T, typename X>
- requires (!std::is_reference_v<T> && std::is_same_v<X,std::any> && !std::is_same_v<T,std::any>)
-constexpr auto as( X const& x ) -> T
- { return std::any_cast<T>( x ); }
-
-
-//-------------------------------------------------------------------------------------------------------------
-// std::optional is and as
-//
-
-// is Type
-//
-template<typename T, typename X>
- requires std::is_same_v<X,std::optional<T>>
-constexpr auto is( X const& x ) -> bool
- { return x.has_value(); }
-
-template<typename T, typename U>
- requires std::is_same_v<T,empty>
-constexpr auto is( std::optional<U> const& x ) -> bool
- { return !x.has_value(); }
-
-
-// is Value
-//
-template<typename T>
-constexpr auto is( std::optional<T> const& x, auto&& value ) -> bool
-{
- // Predicate case
- if constexpr (requires{ bool{ value(x) }; }) {
- return value(x);
- }
- else if constexpr (std::is_function_v<decltype(value)> || requires{ &value.operator(); }) {
- return false;
- }
-
- // Value case
- else if constexpr (requires{ bool{ x.value() == value }; }) {
- return x.has_value() && x.value() == value;
- }
- return false;
-}
-
-
-// as
-//
-template<typename T, typename X>
- requires std::is_same_v<X,std::optional<T>>
-constexpr auto as( X const& x ) -> decltype(auto)
- { return x.value(); }
-
-
-//-----------------------------------------------------------------------
-//
-// A variation of GSL's final_action_success / finally
-//
-// finally ensures something is run at the end of a scope always
-//
-// finally_success ensures something is run at the end of a scope
-// if no exception is thrown
-//
-// finally_presuccess ensures a group of add'd operations are run
-// immediately before (not after) the return if no exception is
-// thrown - right now this is used only for postconditions, so
-// they can inspect named return values before they're moved from
-//
-//-----------------------------------------------------------------------
-//
-
-template <class F>
-class finally_success
-{
-public:
- explicit finally_success(const F& ff) noexcept : f{ff} { }
- explicit finally_success(F&& ff) noexcept : f{std::move(ff)} { }
-
- ~finally_success() noexcept
- {
- if (invoke && ecount == std::uncaught_exceptions()) {
- f();
- }
- }
-
- finally_success(finally_success&& that) noexcept
- : f(std::move(that.f)), invoke(std::exchange(that.invoke, false))
- { }
-
- finally_success(finally_success const&) = delete;
- void operator= (finally_success const&) = delete;
- void operator= (finally_success&&) = delete;
-
-private:
- F f;
- int ecount = std::uncaught_exceptions();
- bool invoke = true;
-};
-
-
-template <class F>
-class finally
-{
-public:
- explicit finally(const F& ff) noexcept : f{ff} { }
- explicit finally(F&& ff) noexcept : f{std::move(ff)} { }
-
- ~finally() noexcept { f(); }
-
- finally(finally&& that) noexcept
- : f(std::move(that.f)), invoke(std::exchange(that.invoke, false))
- { }
-
- finally (finally const&) = delete;
- void operator=(finally const&) = delete;
- void operator=(finally&&) = delete;
-
-private:
- F f;
- bool invoke = true;
-};
-
-
-class finally_presuccess
-{
-public:
- finally_presuccess() = default;
-
- auto add(const auto& f) { fs.push_back(f); }
-
- // In compiled Cpp2 code, this function will be called
- // immediately before 'return' (both explicit and implicit)
- auto run() {
- if (invoke && ecount == std::uncaught_exceptions()) {
- for (auto const& f : fs) {
- f();
- }
- }
- invoke = false;
- }
-
- ~finally_presuccess() noexcept {
- run();
- }
-
- finally_presuccess(finally_presuccess const&) = delete;
- void operator= (finally_presuccess const&) = delete;
- void operator= (finally_presuccess &&) = delete;
-
-private:
- std::vector<std::function<void()>> fs;
- int ecount = std::uncaught_exceptions();
- bool invoke = true;
-};
-
-
-//-----------------------------------------------------------------------
-//
-// args: see main() arguments as vector<string_view>
-//
-//-----------------------------------------------------------------------
-//
-struct args_t : std::vector<std::string_view>
-{
- args_t(int c, char** v) : vector{static_cast<std::size_t>(c)}, argc{c}, argv{v} {}
-
- mutable int argc = 0; // mutable for compatibility with frameworks that take 'int& argc'
- char** argv = nullptr;
-};
-
-inline auto make_args(int argc, char** argv) -> args_t
-{
- auto ret = args_t{argc, argv};
- auto args = std::span(argv, static_cast<std::size_t>(argc));
- std::copy( args.begin(), args.end(), ret.data());
- return ret;
-}
-
-
-//-----------------------------------------------------------------------
-//
-// alien_memory: memory typed as T but that is outside C++ and that the
-// compiler may not assume it knows anything at all about
-//
-//-----------------------------------------------------------------------
-//
-template<typename T>
-using alien_memory = T volatile;
-
-
-//-----------------------------------------------------------------------
-//
-// An implementation of GSL's narrow_cast with a clearly 'unsafe' name
-//
-//-----------------------------------------------------------------------
-//
-template <typename C, typename X>
-constexpr auto unsafe_narrow( X&& x ) noexcept -> decltype(auto)
-{
- return static_cast<C>(CPP2_FORWARD(x));
-}
-
-
-//-----------------------------------------------------------------------
-//
-// has_flags: query whether a flag_enum value has all flags in 'flags' set
-//
-// flags set of flags to check
-//
-// Returns a function object that takes a 'value' of the same type as
-// 'flags', and evaluates to true if and only if 'value' has set all of
-// the bits set in 'flags'
-//
-//-----------------------------------------------------------------------
-//
-template <typename T>
-auto has_flags(T flags)
-{
- return [=](T value) { return (value & flags) == flags; };
-}
-
-
-//-----------------------------------------------------------------------
-//
-// Speculative: RAII wrapping for the C standard library
-//
-// As part of embracing compatibility while also reducing what we have to
-// teach and learn about C++ (which includes the C standard library), I
-// was curious to see if we can improve use of the C standard library
-// from Cpp2 code... UFCS is a part of that, and then RAII destructors is
-// another that goes hand in hand with that, hence this section...
-// but see caveat note at the end.
-//
-//-----------------------------------------------------------------------
-//
-template<typename T, typename D>
-class c_raii {
- T t;
- D dtor;
-public:
- c_raii( T t_, D d )
- : t{ t_ }
- , dtor{ d }
- { }
-
- ~c_raii() { dtor(t); }
-
- operator T&() { return t; }
-
- c_raii(c_raii const&) = delete;
- auto operator=(c_raii const&) = delete;
-};
-
-inline auto fopen( const char* filename, const char* mode ) {
-
- // Suppress annoying deprecation warning about fopen
- #ifdef _MSC_VER
- #pragma warning( push )
- #pragma warning( disable : 4996 )
- #endif
-
- auto x = std::fopen(filename, mode);
-
- #ifdef _MSC_VER
- #pragma warning( pop )
- #endif
-
- if (!x) {
- Throw( std::make_error_condition(std::errc::no_such_file_or_directory), "'fopen' attempt failed");
- }
- return c_raii( x, &std::fclose );
-}
-
-// Caveat: There's little else in the C stdlib that allocates a resource...
-//
-// malloc is already wrapped like this via std::unique_ptr, which
-// typically uses malloc or gets memory from the same pool
-// thrd_create std::jthread is better
-//
-// ... is that it? I don't think it's useful to provide a c_raii just for fopen,
-// but perhaps c_raii may be useful for bringing forward third-party C code too,
-// with cpp2::fopen as a starting example.
-
-
-//-----------------------------------------------------------------------
-//
-// Signed/unsigned comparison checks
-//
-//-----------------------------------------------------------------------
-//
-template<typename T, typename U>
-CPP2_FORCE_INLINE constexpr auto cmp_mixed_signedness_check() -> void
-{
- if constexpr (
- std::is_same_v<T, bool> ||
- std::is_same_v<U, bool>
- )
- {
- static_assert(
- program_violates_type_safety_guarantee<T, U>,
- "comparing bool values using < <= >= > is unsafe and not allowed - are you missing parentheses?");
- }
- else if constexpr (
- std::is_integral_v<T> &&
- std::is_integral_v<U> &&
- std::is_signed_v<T> != std::is_signed_v<U>
- )
- {
- // Note: It's tempting here to "just call std::cmp_*() instead"
- // which does signed/unsigned relational comparison correctly
- // for negative values, and so silently "fix that for you." But
- // doing that has security pitfalls for the reasons described at
- // https://github.com/hsutter/cppfront/issues/220, so this
- // static_assert to reject the comparison is the right way to go.
- static_assert(
- program_violates_type_safety_guarantee<T, U>,
- "mixed signed/unsigned comparison is unsafe - prefer using .ssize() instead of .size(), consider using std::cmp_less instead, or consider explicitly casting one of the values to change signedness by using 'as' or 'cpp2::unsafe_narrow'"
- );
- }
-}
-
-
-CPP2_FORCE_INLINE constexpr auto cmp_less(auto&& t, auto&& u) -> decltype(auto)
- requires requires {CPP2_FORWARD(t) < CPP2_FORWARD(u);}
-{
- cmp_mixed_signedness_check<CPP2_TYPEOF(t), CPP2_TYPEOF(u)>();
- return CPP2_FORWARD(t) < CPP2_FORWARD(u);
-}
-
-CPP2_FORCE_INLINE constexpr auto cmp_less(auto&& t, auto&& u) -> decltype(auto)
-{
- static_assert(
- program_violates_type_safety_guarantee<decltype(t), decltype(u)>,
- "attempted to compare '<' for incompatible types"
- );
- return nonesuch;
-}
-
-
-CPP2_FORCE_INLINE constexpr auto cmp_less_eq(auto&& t, auto&& u) -> decltype(auto)
- requires requires {CPP2_FORWARD(t) <= CPP2_FORWARD(u);}
-{
- cmp_mixed_signedness_check<CPP2_TYPEOF(t), CPP2_TYPEOF(u)>();
- return CPP2_FORWARD(t) <= CPP2_FORWARD(u);
-}
-
-CPP2_FORCE_INLINE constexpr auto cmp_less_eq(auto&& t, auto&& u) -> decltype(auto)
-{
- static_assert(
- program_violates_type_safety_guarantee<decltype(t), decltype(u)>,
- "attempted to compare '<=' for incompatible types"
- );
- return nonesuch;
-}
-
-
-CPP2_FORCE_INLINE constexpr auto cmp_greater(auto&& t, auto&& u) -> decltype(auto)
- requires requires {CPP2_FORWARD(t) > CPP2_FORWARD(u);}
-{
- cmp_mixed_signedness_check<CPP2_TYPEOF(t), CPP2_TYPEOF(u)>();
- return CPP2_FORWARD(t) > CPP2_FORWARD(u);
-}
-
-CPP2_FORCE_INLINE constexpr auto cmp_greater(auto&& t, auto&& u) -> decltype(auto)
-{
- static_assert(
- program_violates_type_safety_guarantee<decltype(t), decltype(u)>,
- "attempted to compare '>' for incompatible types"
- );
- return nonesuch;
-}
-
-
-CPP2_FORCE_INLINE constexpr auto cmp_greater_eq(auto&& t, auto&& u) -> decltype(auto)
- requires requires {CPP2_FORWARD(t) >= CPP2_FORWARD(u);}
-{
- cmp_mixed_signedness_check<CPP2_TYPEOF(t), CPP2_TYPEOF(u)>();
- return CPP2_FORWARD(t) >= CPP2_FORWARD(u);
-}
-
-CPP2_FORCE_INLINE constexpr auto cmp_greater_eq(auto&& t, auto&& u) -> decltype(auto)
-{
- static_assert(
- program_violates_type_safety_guarantee<decltype(t), decltype(u)>,
- "attempted to compare '>=' for incompatible types"
- );
- return nonesuch;
-}
-
-
-
-//-----------------------------------------------------------------------
-//
-// A static-asserting "as" for better diagnostics than raw 'nonesuch'
-//
-// Note for the future: This needs go after all 'as', which is fine for
-// the ones in this file but will have problems with further user-
-// defined 'as' customizations. One solution would be to make the main
-// 'as' be a class template, and have all customizations be actual
-// specializations... that way name lookup should find the primary
-// template first and then see later specializations. Or we could just
-// remove this and live with the 'nonesuch' error messages. Either way,
-// we don't need anything more right now, this solution is fine to
-// unblock general progress
-//
-//-----------------------------------------------------------------------
-//
-template< typename C >
-inline constexpr auto as_( auto&& x ) -> decltype(auto)
-{
- if constexpr (is_narrowing_v<C, CPP2_TYPEOF(x)>) {
- static_assert(
- program_violates_type_safety_guarantee<C, CPP2_TYPEOF(x)>,
- "'as' does not allow unsafe narrowing conversions - if you're sure you want this, use `unsafe_narrow<T>()` to force the conversion"
- );
- }
- else if constexpr( std::is_same_v< CPP2_TYPEOF(as<C>(CPP2_FORWARD(x))), nonesuch_ > ) {
- static_assert(
- program_violates_type_safety_guarantee<C, CPP2_TYPEOF(x)>,
- "No safe 'as' cast available - please check your cast"
- );
- }
- // else
- return as<C>(CPP2_FORWARD(x));
-}
-
-template< typename C, auto x >
-inline constexpr auto as_() -> decltype(auto)
-{
- if constexpr (requires { as<C, x>(); }) {
- if constexpr( std::is_same_v< CPP2_TYPEOF((as<C, x>())), nonesuch_ > ) {
- static_assert(
- program_violates_type_safety_guarantee<C, CPP2_TYPEOF(x)>,
- "Literal cannot be narrowed using 'as' - if you're sure you want this, use 'unsafe_narrow<T>()' to force the conversion"
- );
- }
- }
- else {
- static_assert(
- program_violates_type_safety_guarantee<C, CPP2_TYPEOF(x)>,
- "No safe 'as' cast available - please check your cast"
- );
- }
- // else
- return as<C,x>();
-}
-
-
-}
-
-
-using cpp2::cpp2_new;
-
-
-// Stabilize line numbers for "compatibility" static assertions that we know
-// will fire for some compilers, to keep regression test outputs cleaner
-#line 9999
-
-// GCC 10 doesn't support 'requires' in forward declarations in some cases
-// Workaround: Disable the requires clause where that gets reasonable behavior
-// Diagnostic: static_assert the other cases that can't be worked around
-#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ == 10
- #define CPP2_REQUIRES(...) /* empty */
- #define CPP2_REQUIRES_(...) static_assert(false, "GCC 11 or higher is required to support variables and type-scope functions that have a 'requires' clause. This includes a type-scope 'forward' parameter of non-wildcard type, such as 'func: (this, forward s: std::string)', which relies on being able to add a 'requires' clause - in that case, use 'forward s: _' instead if you need the result to compile with GCC 10.")
-#else
- #define CPP2_REQUIRES(...) requires (__VA_ARGS__)
- #define CPP2_REQUIRES_(...) requires (__VA_ARGS__)
-#endif
-
-#endif