diff --git a/3rdparty/cppzmq/LICENSE b/3rdparty/cppzmq/LICENSE new file mode 100644 index 000000000..ae98bd859 --- /dev/null +++ b/3rdparty/cppzmq/LICENSE @@ -0,0 +1,17 @@ + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + 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. diff --git a/3rdparty/cppzmq/README.md b/3rdparty/cppzmq/README.md new file mode 100644 index 000000000..e2bea0b63 --- /dev/null +++ b/3rdparty/cppzmq/README.md @@ -0,0 +1,196 @@ +[![CI](https://github.com/zeromq/cppzmq/actions/workflows/ci.yml/badge.svg)](https://github.com/zeromq/cppzmq/actions) +[![Coverage Status](https://coveralls.io/repos/github/zeromq/cppzmq/badge.svg?branch=master)](https://coveralls.io/github/zeromq/cppzmq?branch=master) +[![License](https://img.shields.io/github/license/zeromq/cppzmq.svg)](https://github.com/zeromq/cppzmq/blob/master/LICENSE) + +Introduction & Design Goals +=========================== + +cppzmq is a C++ binding for libzmq. It has the following design goals: + - cppzmq maps the libzmq C API to C++ concepts. In particular: + - it is type-safe (the libzmq C API exposes various class-like concepts as void*) + - it provides exception-based error handling (the libzmq C API provides errno-based error handling) + - it provides RAII-style classes that automate resource management (the libzmq C API requires the user to take care to free resources explicitly) + - cppzmq is a light-weight, header-only binding. You only need to include the header file zmq.hpp (and maybe zmq_addon.hpp) to use it. + - zmq.hpp is meant to contain direct mappings of the abstractions provided by the libzmq C API, while zmq_addon.hpp provides additional higher-level abstractions. + +There are other C++ bindings for ZeroMQ with different design goals. In particular, none of the following bindings are header-only: + - [zmqpp](https://github.com/zeromq/zmqpp) is a high-level binding to libzmq. + - [czmqpp](https://github.com/zeromq/czmqpp) is a binding based on the high-level czmq API. + - [fbzmq](https://github.com/facebook/fbzmq) is a binding that integrates with Apache Thrift and provides higher-level abstractions in addition. It requires C++14. + +Supported platforms +=================== + + - Only a subset of the platforms that are supported by libzmq itself are supported. Some features already require a compiler supporting C++11. In the future, probably all features will require C++11. To build and run the tests, CMake and Catch are required. + - Any libzmq 4.x version is expected to work. DRAFT features may only work for the most recent tested version. Currently explicitly tested libzmq versions are + - 4.2.0 (without DRAFT API) + - 4.3.4 (with and without DRAFT API) + - Platforms with full support (i.e. CI executing build and tests) + - Ubuntu 18.04 x64 (with gcc 4.8.5, 5.5.0, 7.5.0) + - Ubuntu 20.04 x64 (with gcc 9.3.0, 10.3.0 and clang 12) + - Visual Studio 2017 x64 + - Visual Studio 2019 x64 + - macOS 10.15 (with clang 12, without DRAFT API) + - Additional platforms that are known to work: + - We have no current reports on additional platforms that are known to work yet. Please add your platform here. If CI can be provided for them with a cloud-based CI service working with GitHub, you are invited to add CI, and make it possible to be included in the list above. + - Additional platforms that probably work: + - Any platform supported by libzmq that provides a sufficiently recent gcc (4.8.1 or newer) or clang (3.4.1 or newer) + - Visual Studio 2012+ x86/x64 + +Examples +======== +These examples require at least C++11. +```c++ +#include + +int main() +{ + zmq::context_t ctx; + zmq::socket_t sock(ctx, zmq::socket_type::push); + sock.bind("inproc://test"); + sock.send(zmq::str_buffer("Hello, world"), zmq::send_flags::dontwait); +} +``` +This a more complex example where we send and receive multi-part messages over TCP with a wildcard port. +```c++ +#include +#include + +int main() +{ + zmq::context_t ctx; + zmq::socket_t sock1(ctx, zmq::socket_type::push); + zmq::socket_t sock2(ctx, zmq::socket_type::pull); + sock1.bind("tcp://127.0.0.1:*"); + const std::string last_endpoint = + sock1.get(zmq::sockopt::last_endpoint); + std::cout << "Connecting to " + << last_endpoint << std::endl; + sock2.connect(last_endpoint); + + std::array send_msgs = { + zmq::str_buffer("foo"), + zmq::str_buffer("bar!") + }; + if (!zmq::send_multipart(sock1, send_msgs)) + return 1; + + std::vector recv_msgs; + const auto ret = zmq::recv_multipart( + sock2, std::back_inserter(recv_msgs)); + if (!ret) + return 1; + std::cout << "Got " << *ret + << " messages" << std::endl; + return 0; +} +``` + +See the `examples` directory for more examples. When the project is compiled with tests enabled, each example gets compiled to an executable. + + +API Overview +============ + +For an extensive overview of the `zmq.hpp` API in use, see this [Tour of CPPZMQ by @brettviren](https://brettviren.github.io/cppzmq-tour/index.html). + +Bindings for libzmq in `zmq.hpp`: + +Types: +* class `zmq::context_t` +* enum `zmq::ctxopt` +* class `zmq::socket_t` +* class `zmq::socket_ref` +* enum `zmq::socket_type` +* enum `zmq::sockopt` +* enum `zmq::send_flags` +* enum `zmq::recv_flags` +* class `zmq::message_t` +* class `zmq::const_buffer` +* class `zmq::mutable_buffer` +* struct `zmq::recv_buffer_size` +* alias `zmq::send_result_t` +* alias `zmq::recv_result_t` +* alias `zmq::recv_buffer_result_t` +* class `zmq::error_t` +* class `zmq::monitor_t` +* struct `zmq_event_t`, +* alias `zmq::free_fn`, +* alias `zmq::pollitem_t`, +* alias `zmq::fd_t` +* class `zmq::poller_t` DRAFT +* enum `zmq::event_flags` DRAFT +* enum `zmq::poller_event` DRAFT + +Functions: +* `zmq::version` +* `zmq::poll` +* `zmq::proxy` +* `zmq::proxy_steerable` +* `zmq::buffer` +* `zmq::str_buffer` + +Extra high-level types and functions `zmq_addon.hpp`: + +Types: +* class `zmq::multipart_t` +* class `zmq::active_poller_t` DRAFT + +Functions: +* `zmq::recv_multipart` +* `zmq::send_multipart` +* `zmq::send_multipart_n` +* `zmq::encode` +* `zmq::decode` + +Compatibility Guidelines +======================== + +The users of cppzmq are expected to follow the guidelines below to ensure not to break when upgrading cppzmq to newer versions (non-exhaustive list): + +* Do not depend on any macros defined in cppzmq unless explicitly declared public here. + +The following macros may be used by consumers of cppzmq: `CPPZMQ_VERSION`, `CPPZMQ_VERSION_MAJOR`, `CPPZMQ_VERSION_MINOR`, `CPPZMQ_VERSION_PATCH`. + +Contribution policy +=================== + +The contribution policy is at: http://rfc.zeromq.org/spec:22 + +Build instructions +================== + +Build steps: + +1. Build [libzmq](https://github.com/zeromq/libzmq) via cmake. This does an out of source build and installs the build files + - download and unzip the lib, cd to directory + - mkdir build + - cd build + - cmake .. + - sudo make -j4 install + +2. Build cppzmq via cmake. This does an out of source build and installs the build files + - download and unzip the lib, cd to directory + - mkdir build + - cd build + - cmake .. + - sudo make -j4 install + +3. Build cppzmq via [vcpkg](https://github.com/Microsoft/vcpkg/). This does an out of source build and installs the build files + - git clone https://github.com/Microsoft/vcpkg.git + - cd vcpkg + - ./bootstrap-vcpkg.sh # bootstrap-vcpkg.bat for Powershell + - ./vcpkg integrate install + - ./vcpkg install cppzmq + +Using this: + +A cmake find package scripts is provided for you to easily include this library. +Add these lines in your CMakeLists.txt to include the headers and library files of +cpp zmq (which will also include libzmq for you). + +``` +#find cppzmq wrapper, installed by make of cppzmq +find_package(cppzmq) +target_link_libraries(*Your Project Name* cppzmq) +``` diff --git a/3rdparty/cppzmq/zmq.hpp b/3rdparty/cppzmq/zmq.hpp index 979ac9a79..3fa484c6c 100644 --- a/3rdparty/cppzmq/zmq.hpp +++ b/3rdparty/cppzmq/zmq.hpp @@ -147,7 +147,7 @@ /* Version macros for compile-time API version detection */ #define CPPZMQ_VERSION_MAJOR 4 -#define CPPZMQ_VERSION_MINOR 9 +#define CPPZMQ_VERSION_MINOR 10 #define CPPZMQ_VERSION_PATCH 0 #define CPPZMQ_VERSION \ @@ -538,6 +538,11 @@ class message_t throw error_t(); memcpy(data(), data_, size_); } + + void rebuild(const std::string &str) + { + rebuild(str.data(), str.size()); + } void rebuild(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR) { @@ -1477,6 +1482,9 @@ ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CURVE_SERVER, curve_server, int); #ifdef ZMQ_CURVE_SERVERKEY ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SERVERKEY, curve_serverkey); #endif +#ifdef ZMQ_DISCONNECT_MSG +ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_DISCONNECT_MSG, disconnect_msg); +#endif #ifdef ZMQ_EVENTS ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_EVENTS, events, int); #endif @@ -1517,6 +1525,9 @@ ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TIMEOUT, heartbeat_timeout, int); #ifdef ZMQ_HEARTBEAT_TTL ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TTL, heartbeat_ttl, int); #endif +#ifdef ZMQ_HELLO_MSG +ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_HELLO_MSG, hello_msg); +#endif #ifdef ZMQ_IMMEDIATE ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IMMEDIATE, immediate, int); #endif @@ -1562,6 +1573,9 @@ ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_PASSWORD, plain_password); #ifdef ZMQ_PLAIN_USERNAME ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_USERNAME, plain_username); #endif +#ifdef ZMQ_PRIORITY +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_PRIORITY, priority, int); +#endif #ifdef ZMQ_USE_FD ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_USE_FD, use_fd, int); #endif @@ -1589,6 +1603,9 @@ ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL, reconnect_ivl, int); #ifdef ZMQ_RECONNECT_IVL_MAX ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL_MAX, reconnect_ivl_max, int); #endif +#ifdef ZMQ_RECONNECT_STOP +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_STOP, reconnect_stop, int); +#endif #ifdef ZMQ_RECOVERY_IVL ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECOVERY_IVL, recovery_ivl, int); #endif @@ -1619,9 +1636,15 @@ ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDHWM, sndhwm, int); #ifdef ZMQ_SNDTIMEO ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDTIMEO, sndtimeo, int); #endif +#ifdef ZMQ_SOCKS_PASSWORD +ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PASSWORD, socks_password); +#endif #ifdef ZMQ_SOCKS_PROXY ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PROXY, socks_proxy); #endif +#ifdef ZMQ_SOCKS_USERNAME +ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_USERNAME, socks_username); +#endif #ifdef ZMQ_STREAM_NOTIFY ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_STREAM_NOTIFY, stream_notify, int); #endif @@ -1679,6 +1702,9 @@ ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSER, xpub_verboser, int); #ifdef ZMQ_XPUB_MANUAL ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL, xpub_manual, int); #endif +#ifdef ZMQ_XPUB_MANUAL_LAST_VALUE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL_LAST_VALUE, xpub_manual_last_value, int); +#endif #ifdef ZMQ_XPUB_NODROP ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_NODROP, xpub_nodrop, int); #endif @@ -2637,6 +2663,17 @@ template class poller_t add_impl(socket, events, nullptr); } + template< + typename Dummy = void, + typename = + typename std::enable_if::value, Dummy>::type> + void add(fd_t fd, event_flags events, T *user_data) + { + add_impl(fd, events, user_data); + } + + void add(fd_t fd, event_flags events) { add_impl(fd, events, nullptr); } + void remove(zmq::socket_ref socket) { if (0 != zmq_poller_remove(poller_ptr.get(), socket.handle())) { @@ -2703,6 +2740,15 @@ template class poller_t throw error_t(); } } + + void add_impl(fd_t fd, event_flags events, T *user_data) + { + if (0 + != zmq_poller_add_fd(poller_ptr.get(), fd, user_data, + static_cast(events))) { + throw error_t(); + } + } }; #endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) diff --git a/3rdparty/cppzmq/zmq_addon.hpp b/3rdparty/cppzmq/zmq_addon.hpp index 147abe145..958eec56d 100644 --- a/3rdparty/cppzmq/zmq_addon.hpp +++ b/3rdparty/cppzmq/zmq_addon.hpp @@ -77,7 +77,7 @@ inline bool is_little_endian() inline void write_network_order(unsigned char *buf, const uint32_t value) { if (is_little_endian()) { - ZMQ_CONSTEXPR_VAR uint32_t mask = std::numeric_limits::max(); + ZMQ_CONSTEXPR_VAR uint32_t mask = (std::numeric_limits::max)(); *buf++ = static_cast((value >> 24) & mask); *buf++ = static_cast((value >> 16) & mask); *buf++ = static_cast((value >> 8) & mask); @@ -224,12 +224,12 @@ message_t encode(const Range &parts) // First pass check sizes for (const auto &part : parts) { const size_t part_size = part.size(); - if (part_size > std::numeric_limits::max()) { + if (part_size > (std::numeric_limits::max)()) { // Size value must fit into uint32_t. throw std::range_error("Invalid size, message part too large"); } const size_t count_size = - part_size < std::numeric_limits::max() ? 1 : 5; + part_size < (std::numeric_limits::max)() ? 1 : 5; mmsg_size += part_size + count_size; } @@ -240,12 +240,12 @@ message_t encode(const Range &parts) const unsigned char *part_data = static_cast(part.data()); - if (part_size < std::numeric_limits::max()) { + if (part_size < (std::numeric_limits::max)()) { // small part *buf++ = (unsigned char) part_size; } else { // big part - *buf++ = std::numeric_limits::max(); + *buf++ = (std::numeric_limits::max)(); detail::write_network_order(buf, part_size); buf += sizeof(part_size); } @@ -279,7 +279,7 @@ template OutputIt decode(const message_t &encoded, OutputIt out) while (source < limit) { size_t part_size = *source++; - if (part_size == std::numeric_limits::max()) { + if (part_size == (std::numeric_limits::max)()) { if (static_cast(limit - source) < sizeof(uint32_t)) { throw std::out_of_range( "Malformed encoding, overflow in reading size"); @@ -343,10 +343,10 @@ class multipart_t multipart_t(message_t &&message) { add(std::move(message)); } // Move constructor - multipart_t(multipart_t &&other) { m_parts = std::move(other.m_parts); } + multipart_t(multipart_t &&other) ZMQ_NOTHROW { m_parts = std::move(other.m_parts); } // Move assignment operator - multipart_t &operator=(multipart_t &&other) + multipart_t &operator=(multipart_t &&other) ZMQ_NOTHROW { m_parts = std::move(other.m_parts); return *this; diff --git a/include/behaviortree_cpp/flatbuffers/base.h b/3rdparty/flatbuffers/base.h similarity index 76% rename from include/behaviortree_cpp/flatbuffers/base.h rename to 3rdparty/flatbuffers/base.h index 54a51aacb..1c19dde98 100644 --- a/include/behaviortree_cpp/flatbuffers/base.h +++ b/3rdparty/flatbuffers/base.h @@ -32,7 +32,7 @@ #include #include -#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H) +#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H) && defined(__AVR__) #include #else #include @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -50,10 +51,6 @@ #include #endif -#ifdef _STLPORT_VERSION - #define FLATBUFFERS_CPP98_STL -#endif - #ifdef __ANDROID__ #include #endif @@ -142,9 +139,9 @@ #endif #endif // !defined(FLATBUFFERS_LITTLEENDIAN) -#define FLATBUFFERS_VERSION_MAJOR 1 -#define FLATBUFFERS_VERSION_MINOR 12 -#define FLATBUFFERS_VERSION_REVISION 0 +#define FLATBUFFERS_VERSION_MAJOR 24 +#define FLATBUFFERS_VERSION_MINOR 3 +#define FLATBUFFERS_VERSION_REVISION 25 #define FLATBUFFERS_STRING_EXPAND(X) #X #define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X) namespace flatbuffers { @@ -158,7 +155,7 @@ namespace flatbuffers { #define FLATBUFFERS_FINAL_CLASS final #define FLATBUFFERS_OVERRIDE override #define FLATBUFFERS_EXPLICIT_CPP11 explicit - #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t + #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : ::flatbuffers::voffset_t #else #define FLATBUFFERS_FINAL_CLASS #define FLATBUFFERS_OVERRIDE @@ -237,16 +234,26 @@ namespace flatbuffers { } #define FLATBUFFERS_HAS_STRING_VIEW 1 // Check for absl::string_view - #elif __has_include("absl/strings/string_view.h") - #include "absl/strings/string_view.h" - namespace flatbuffers { - typedef absl::string_view string_view; - } - #define FLATBUFFERS_HAS_STRING_VIEW 1 + #elif __has_include("absl/strings/string_view.h") && \ + __has_include("absl/base/config.h") && \ + (__cplusplus >= 201411) + #include "absl/base/config.h" + #if !defined(ABSL_USES_STD_STRING_VIEW) + #include "absl/strings/string_view.h" + namespace flatbuffers { + typedef absl::string_view string_view; + } + #define FLATBUFFERS_HAS_STRING_VIEW 1 + #endif #endif #endif // __has_include #endif // !FLATBUFFERS_HAS_STRING_VIEW +#ifndef FLATBUFFERS_GENERAL_HEAP_ALLOC_OK + // Allow heap allocations to be used + #define FLATBUFFERS_GENERAL_HEAP_ALLOC_OK 1 +#endif // !FLATBUFFERS_GENERAL_HEAP_ALLOC_OK + #ifndef FLATBUFFERS_HAS_NEW_STRTOD // Modern (C++11) strtod and strtof functions are available for use. // 1) nan/inf strings as argument of strtod; @@ -259,9 +266,12 @@ namespace flatbuffers { #endif // !FLATBUFFERS_HAS_NEW_STRTOD #ifndef FLATBUFFERS_LOCALE_INDEPENDENT - // Enable locale independent functions {strtof_l, strtod_l,strtoll_l, strtoull_l}. - #if ((defined(_MSC_VER) && _MSC_VER >= 1800) || \ - (defined(_XOPEN_VERSION) && (_XOPEN_VERSION>=700)) && (!defined(__ANDROID_API__) || (defined(__ANDROID_API__) && (__ANDROID_API__>=21)))) + // Enable locale independent functions {strtof_l, strtod_l,strtoll_l, + // strtoull_l}. + #if (defined(_MSC_VER) && _MSC_VER >= 1800) || \ + (defined(__ANDROID_API__) && __ANDROID_API__>= 21) || \ + (defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)) && \ + (!defined(__Fuchsia__) && !defined(__ANDROID_API__)) #define FLATBUFFERS_LOCALE_INDEPENDENT 1 #else #define FLATBUFFERS_LOCALE_INDEPENDENT 0 @@ -269,27 +279,29 @@ namespace flatbuffers { #endif // !FLATBUFFERS_LOCALE_INDEPENDENT // Suppress Undefined Behavior Sanitizer (recoverable only). Usage: -// - __supress_ubsan__("undefined") -// - __supress_ubsan__("signed-integer-overflow") +// - FLATBUFFERS_SUPPRESS_UBSAN("undefined") +// - FLATBUFFERS_SUPPRESS_UBSAN("signed-integer-overflow") #if defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >=7)) - #define __supress_ubsan__(type) __attribute__((no_sanitize(type))) + #define FLATBUFFERS_SUPPRESS_UBSAN(type) __attribute__((no_sanitize(type))) #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409) - #define __supress_ubsan__(type) __attribute__((no_sanitize_undefined)) + #define FLATBUFFERS_SUPPRESS_UBSAN(type) __attribute__((no_sanitize_undefined)) #else - #define __supress_ubsan__(type) + #define FLATBUFFERS_SUPPRESS_UBSAN(type) #endif -// This is constexpr function used for checking compile-time constants. -// Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`. -template FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) { - return !!t; +namespace flatbuffers { + // This is constexpr function used for checking compile-time constants. + // Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`. + template FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) { + return !!t; + } } // Enable C++ attribute [[]] if std:c++17 or higher. #if ((__cplusplus >= 201703L) \ || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))) // All attributes unknown to an implementation are ignored without causing an error. - #define FLATBUFFERS_ATTRIBUTE(attr) [[attr]] + #define FLATBUFFERS_ATTRIBUTE(attr) attr #define FLATBUFFERS_FALLTHROUGH() [[fallthrough]] #else @@ -314,9 +326,11 @@ namespace flatbuffers { // Also, using a consistent offset type maintains compatibility of serialized // offset values between 32bit and 64bit systems. typedef uint32_t uoffset_t; +typedef uint64_t uoffset64_t; // Signed offsets for references that can go in both directions. typedef int32_t soffset_t; +typedef int64_t soffset64_t; // Offset/index used in v-tables, can be changed to uint8_t in // format forks to save a bit of space if desired. @@ -325,10 +339,23 @@ typedef uint16_t voffset_t; typedef uintmax_t largest_scalar_t; // In 32bits, this evaluates to 2GB - 1 -#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(::flatbuffers::soffset_t) * 8 - 1)) - 1) +#define FLATBUFFERS_MAX_BUFFER_SIZE std::numeric_limits<::flatbuffers::soffset_t>::max() +#define FLATBUFFERS_MAX_64_BUFFER_SIZE std::numeric_limits<::flatbuffers::soffset64_t>::max() + +// The minimum size buffer that can be a valid flatbuffer. +// Includes the offset to the root table (uoffset_t), the offset to the vtable +// of the root table (soffset_t), the size of the vtable (uint16_t), and the +// size of the referring table (uint16_t). +#define FLATBUFFERS_MIN_BUFFER_SIZE sizeof(uoffset_t) + sizeof(soffset_t) + \ + sizeof(uint16_t) + sizeof(uint16_t) // We support aligning the contents of buffers up to this size. -#define FLATBUFFERS_MAX_ALIGNMENT 16 +#ifndef FLATBUFFERS_MAX_ALIGNMENT + #define FLATBUFFERS_MAX_ALIGNMENT 32 +#endif + +/// @brief The length of a FlatBuffer file header. +static const size_t kFileIdentifierLength = 4; inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) { return (min_align <= align) && (align <= (FLATBUFFERS_MAX_ALIGNMENT)) && @@ -336,7 +363,6 @@ inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) { } #if defined(_MSC_VER) - #pragma warning(disable: 4351) // C4351: new behavior: elements of array ... will be default initialized #pragma warning(push) #pragma warning(disable: 4127) // C4127: conditional expression is constant #endif @@ -397,7 +423,7 @@ template T EndianScalar(T t) { template // UBSAN: C++ aliasing type rules, see std::bit_cast<> for details. -__supress_ubsan__("alignment") +FLATBUFFERS_SUPPRESS_UBSAN("alignment") T ReadScalar(const void *p) { return EndianScalar(*reinterpret_cast(p)); } @@ -411,13 +437,13 @@ T ReadScalar(const void *p) { template // UBSAN: C++ aliasing type rules, see std::bit_cast<> for details. -__supress_ubsan__("alignment") +FLATBUFFERS_SUPPRESS_UBSAN("alignment") void WriteScalar(void *p, T t) { *reinterpret_cast(p) = EndianScalar(t); } template struct Offset; -template __supress_ubsan__("alignment") void WriteScalar(void *p, Offset t) { +template FLATBUFFERS_SUPPRESS_UBSAN("alignment") void WriteScalar(void *p, Offset t) { *reinterpret_cast(p) = EndianScalar(t.o); } @@ -428,10 +454,43 @@ template __supress_ubsan__("alignment") void WriteScalar(void *p, Of // Computes how many bytes you'd have to pad to be able to write an // "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in // memory). -__supress_ubsan__("unsigned-integer-overflow") +FLATBUFFERS_SUPPRESS_UBSAN("unsigned-integer-overflow") inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) { return ((~buf_size) + 1) & (scalar_size - 1); } +// Generic 'operator==' with conditional specialisations. +// T e - new value of a scalar field. +// T def - default of scalar (is known at compile-time). +template inline bool IsTheSameAs(T e, T def) { return e == def; } + +#if defined(FLATBUFFERS_NAN_DEFAULTS) && \ + defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) +// Like `operator==(e, def)` with weak NaN if T=(float|double). +template inline bool IsFloatTheSameAs(T e, T def) { + return (e == def) || ((def != def) && (e != e)); +} +template<> inline bool IsTheSameAs(float e, float def) { + return IsFloatTheSameAs(e, def); +} +template<> inline bool IsTheSameAs(double e, double def) { + return IsFloatTheSameAs(e, def); +} +#endif + +// Check 'v' is out of closed range [low; high]. +// Workaround for GCC warning [-Werror=type-limits]: +// comparison is always true due to limited range of data type. +template +inline bool IsOutRange(const T &v, const T &low, const T &high) { + return (v < low) || (high < v); +} + +// Check 'v' is in closed range [low; high]. +template +inline bool IsInRange(const T &v, const T &low, const T &high) { + return !IsOutRange(v, low, high); +} + } // namespace flatbuffers #endif // FLATBUFFERS_BASE_H_ diff --git a/3rdparty/lexy/CMakeLists.txt b/3rdparty/lexy/CMakeLists.txt index 1d8cf7964..a76693a9e 100644 --- a/3rdparty/lexy/CMakeLists.txt +++ b/3rdparty/lexy/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +# Copyright (C) 2020-2024 Jonathan Müller and lexy contributors # SPDX-License-Identifier: BSL-1.0 cmake_minimum_required(VERSION 3.8) @@ -9,6 +9,42 @@ option(LEXY_FORCE_CPP17 "Whether or not lexy should use C++17 even if compil add_subdirectory(src) +option(LEXY_ENABLE_INSTALL "whether or not to enable the install rule" ON) +if(LEXY_ENABLE_INSTALL) + include(CMakePackageConfigHelpers) + include(GNUInstallDirs) + + install(TARGETS lexy lexy_core lexy_file lexy_unicode lexy_ext _lexy_base lexy_dev + EXPORT ${PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + install(EXPORT ${PROJECT_NAME}Targets + NAMESPACE foonathan:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + + configure_package_config_file( + cmake/lexyConfig.cmake.in + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + + # YYYY.MM.N1 is compatible with YYYY.MM.N2. + write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + COMPATIBILITY SameMinorVersion) + + install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + + install(DIRECTORY include/lexy include/lexy_ext + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING + PATTERN "*.hpp") +endif() + if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) cmake_minimum_required(VERSION 3.18) option(LEXY_BUILD_BENCHMARKS "whether or not benchmarks should be built" OFF) @@ -16,7 +52,6 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) option(LEXY_BUILD_TESTS "whether or not tests should be built" ON) option(LEXY_BUILD_DOCS "whether or not docs should be built" OFF) option(LEXY_BUILD_PACKAGE "whether or not the package should be built" ON) - option(LEXY_ENABLE_INSTALL "whether or not to enable the install rule" ON) if(LEXY_BUILD_PACKAGE) set(package_files include/ src/ cmake/ CMakeLists.txt LICENSE) @@ -41,39 +76,4 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) if(LEXY_BUILD_DOCS) add_subdirectory(docs EXCLUDE_FROM_ALL) endif() - - if(LEXY_ENABLE_INSTALL) - include(CMakePackageConfigHelpers) - include(GNUInstallDirs) - - install(TARGETS lexy lexy_core lexy_file lexy_unicode lexy_ext _lexy_base lexy_dev - EXPORT ${PROJECT_NAME}Targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - install(EXPORT ${PROJECT_NAME}Targets - NAMESPACE foonathan:: - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") - - configure_package_config_file( - cmake/lexyConfig.cmake.in - "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") - install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") - - # YYYY.MM.N1 is compatible with YYYY.MM.N2. - write_basic_package_version_file( - "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - COMPATIBILITY SameMinorVersion) - - install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") - - install(DIRECTORY include/lexy include/lexy_ext - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING - PATTERN "*.hpp") - endif() endif() diff --git a/3rdparty/lexy/README.adoc b/3rdparty/lexy/README.adoc index 069ab5216..6bc88487f 100644 --- a/3rdparty/lexy/README.adoc +++ b/3rdparty/lexy/README.adoc @@ -113,8 +113,9 @@ Why should I use lexy over XYZ?:: http://boost-spirit.com/home/[Boost.Spirit]::: The main difference: it is not a Boost library. - Otherwise, it is just a different implementation with a different flavor. - Use lexy if you like lexy more. + In addition, Boost.Spirit is quite old and doesn't support e.g. non-common ranges as input. + Boost.Spirit also eagerly creates attributes from the rules, which can lead to nested tuples/variants while lexy uses callbacks which enables zero-copy parsing directly into your own data structure. + However, lexy's grammar is more verbose and designed to parser bigger grammars instead of the small one-off rules that Boost.Spirit is good at. https://github.com/taocpp/PEGTL[PEGTL]::: PEGTL is very similar and was a big inspiration. The biggest difference is that lexy uses an operator based DSL instead of inheriting from templated classes as PEGTL does; diff --git a/3rdparty/lexy/cmake/lexyConfig.cmake.in b/3rdparty/lexy/cmake/lexyConfig.cmake.in index a10ef13fc..e6dc89d30 100644 --- a/3rdparty/lexy/cmake/lexyConfig.cmake.in +++ b/3rdparty/lexy/cmake/lexyConfig.cmake.in @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +# Copyright (C) 2020-2024 Jonathan Müller and lexy contributors # SPDX-License-Identifier: BSL-1.0 # lexy CMake configuration file. diff --git a/3rdparty/lexy/include/lexy/_detail/any_ref.hpp b/3rdparty/lexy/include/lexy/_detail/any_ref.hpp index 11e9c0d31..9eca714b2 100644 --- a/3rdparty/lexy/include/lexy/_detail/any_ref.hpp +++ b/3rdparty/lexy/include/lexy/_detail/any_ref.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_ANY_REF_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/assert.hpp b/3rdparty/lexy/include/lexy/_detail/assert.hpp index 01ccbf6ce..52aa115de 100644 --- a/3rdparty/lexy/include/lexy/_detail/assert.hpp +++ b/3rdparty/lexy/include/lexy/_detail/assert.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_ASSERT_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/buffer_builder.hpp b/3rdparty/lexy/include/lexy/_detail/buffer_builder.hpp index ede3bd324..94ba1fd27 100644 --- a/3rdparty/lexy/include/lexy/_detail/buffer_builder.hpp +++ b/3rdparty/lexy/include/lexy/_detail/buffer_builder.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_BUFFER_BUILDER_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/code_point.hpp b/3rdparty/lexy/include/lexy/_detail/code_point.hpp index 969fba5d3..bc805b11e 100644 --- a/3rdparty/lexy/include/lexy/_detail/code_point.hpp +++ b/3rdparty/lexy/include/lexy/_detail/code_point.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_CODE_POINT_HPP_INCLUDED @@ -133,9 +133,9 @@ enum class cp_error template struct cp_result { - char32_t cp; - cp_error error; - typename Reader::iterator end; + char32_t cp; + cp_error error; + typename Reader::marker end; }; template @@ -144,16 +144,16 @@ constexpr cp_result parse_code_point(Reader reader) if constexpr (std::is_same_v) { if (reader.peek() == Reader::encoding::eof()) - return {{}, cp_error::eof, reader.position()}; + return {{}, cp_error::eof, reader.current()}; auto cur = reader.peek(); reader.bump(); auto cp = static_cast(cur); if (cp <= 0x7F) - return {cp, cp_error::success, reader.position()}; + return {cp, cp_error::success, reader.current()}; else - return {cp, cp_error::out_of_range, reader.position()}; + return {cp, cp_error::out_of_range, reader.current()}; } else if constexpr (std::is_same_v // || std::is_same_v) @@ -176,11 +176,11 @@ constexpr cp_result parse_code_point(Reader reader) { // ASCII character. reader.bump(); - return {first, cp_error::success, reader.position()}; + return {first, cp_error::success, reader.current()}; } else if ((first & ~payload_cont) == pattern_cont) { - return {{}, cp_error::leads_with_trailing, reader.position()}; + return {{}, cp_error::leads_with_trailing, reader.current()}; } else if ((first & ~payload_lead2) == pattern_lead2) { @@ -188,7 +188,7 @@ constexpr cp_result parse_code_point(Reader reader) auto second = uchar_t(reader.peek()); if ((second & ~payload_cont) != pattern_cont) - return {{}, cp_error::missing_trailing, reader.position()}; + return {{}, cp_error::missing_trailing, reader.current()}; reader.bump(); auto result = char32_t(first & payload_lead2); @@ -197,9 +197,9 @@ constexpr cp_result parse_code_point(Reader reader) // C0 and C1 are overlong ASCII. if (first == 0xC0 || first == 0xC1) - return {result, cp_error::overlong_sequence, reader.position()}; + return {result, cp_error::overlong_sequence, reader.current()}; else - return {result, cp_error::success, reader.position()}; + return {result, cp_error::success, reader.current()}; } else if ((first & ~payload_lead3) == pattern_lead3) { @@ -207,12 +207,12 @@ constexpr cp_result parse_code_point(Reader reader) auto second = uchar_t(reader.peek()); if ((second & ~payload_cont) != pattern_cont) - return {{}, cp_error::missing_trailing, reader.position()}; + return {{}, cp_error::missing_trailing, reader.current()}; reader.bump(); auto third = uchar_t(reader.peek()); if ((third & ~payload_cont) != pattern_cont) - return {{}, cp_error::missing_trailing, reader.position()}; + return {{}, cp_error::missing_trailing, reader.current()}; reader.bump(); auto result = char32_t(first & payload_lead3); @@ -223,11 +223,11 @@ constexpr cp_result parse_code_point(Reader reader) auto cp = result; if (0xD800 <= cp && cp <= 0xDFFF) - return {cp, cp_error::surrogate, reader.position()}; + return {cp, cp_error::surrogate, reader.current()}; else if (first == 0xE0 && second < 0xA0) - return {cp, cp_error::overlong_sequence, reader.position()}; + return {cp, cp_error::overlong_sequence, reader.current()}; else - return {cp, cp_error::success, reader.position()}; + return {cp, cp_error::success, reader.current()}; } else if ((first & ~payload_lead4) == pattern_lead4) { @@ -235,17 +235,17 @@ constexpr cp_result parse_code_point(Reader reader) auto second = uchar_t(reader.peek()); if ((second & ~payload_cont) != pattern_cont) - return {{}, cp_error::missing_trailing, reader.position()}; + return {{}, cp_error::missing_trailing, reader.current()}; reader.bump(); auto third = uchar_t(reader.peek()); if ((third & ~payload_cont) != pattern_cont) - return {{}, cp_error::missing_trailing, reader.position()}; + return {{}, cp_error::missing_trailing, reader.current()}; reader.bump(); auto fourth = uchar_t(reader.peek()); if ((fourth & ~payload_cont) != pattern_cont) - return {{}, cp_error::missing_trailing, reader.position()}; + return {{}, cp_error::missing_trailing, reader.current()}; reader.bump(); auto result = char32_t(first & payload_lead4); @@ -258,15 +258,15 @@ constexpr cp_result parse_code_point(Reader reader) auto cp = result; if (cp > 0x10'FFFF) - return {cp, cp_error::out_of_range, reader.position()}; + return {cp, cp_error::out_of_range, reader.current()}; else if (first == 0xF0 && second < 0x90) - return {cp, cp_error::overlong_sequence, reader.position()}; + return {cp, cp_error::overlong_sequence, reader.current()}; else - return {cp, cp_error::success, reader.position()}; + return {cp, cp_error::success, reader.current()}; } else // FE or FF { - return {{}, cp_error::eof, reader.position()}; + return {{}, cp_error::eof, reader.current()}; } } else if constexpr (std::is_same_v) @@ -278,18 +278,18 @@ constexpr cp_result parse_code_point(Reader reader) constexpr auto pattern2 = 0b110111 << 10; if (reader.peek() == Reader::encoding::eof()) - return {{}, cp_error::eof, reader.position()}; + return {{}, cp_error::eof, reader.current()}; auto first = char16_t(reader.peek()); if ((first & ~payload1) == pattern1) { reader.bump(); if (reader.peek() == Reader::encoding::eof()) - return {{}, cp_error::missing_trailing, reader.position()}; + return {{}, cp_error::missing_trailing, reader.current()}; auto second = char16_t(reader.peek()); if ((second & ~payload2) != pattern2) - return {{}, cp_error::missing_trailing, reader.position()}; + return {{}, cp_error::missing_trailing, reader.current()}; reader.bump(); // We've got a valid code point. @@ -297,34 +297,34 @@ constexpr cp_result parse_code_point(Reader reader) result <<= 10; result |= char32_t(second & payload2); result |= 0x10000; - return {result, cp_error::success, reader.position()}; + return {result, cp_error::success, reader.current()}; } else if ((first & ~payload2) == pattern2) { - return {{}, cp_error::leads_with_trailing, reader.position()}; + return {{}, cp_error::leads_with_trailing, reader.current()}; } else { // Single code unit code point; always valid. reader.bump(); - return {first, cp_error::success, reader.position()}; + return {first, cp_error::success, reader.current()}; } } else if constexpr (std::is_same_v) { if (reader.peek() == Reader::encoding::eof()) - return {{}, cp_error::eof, reader.position()}; + return {{}, cp_error::eof, reader.current()}; auto cur = reader.peek(); reader.bump(); auto cp = cur; if (cp > 0x10'FFFF) - return {cp, cp_error::out_of_range, reader.position()}; + return {cp, cp_error::out_of_range, reader.current()}; else if (0xD800 <= cp && cp <= 0xDFFF) - return {cp, cp_error::surrogate, reader.position()}; + return {cp, cp_error::surrogate, reader.current()}; else - return {cp, cp_error::success, reader.position()}; + return {cp, cp_error::success, reader.current()}; } else { @@ -341,7 +341,7 @@ constexpr void recover_code_point(Reader& reader, cp_result result) { case cp_error::success: // Consume the entire code point. - reader.set_position(result.end); + reader.reset(result.end); break; case cp_error::eof: // We don't need to do anything to "recover" from EOF. @@ -349,7 +349,7 @@ constexpr void recover_code_point(Reader& reader, cp_result result) case cp_error::leads_with_trailing: // Invalid code unit, consume to recover. - LEXY_PRECONDITION(result.end == reader.position()); + LEXY_PRECONDITION(result.end.position() == reader.position()); reader.bump(); break; @@ -358,7 +358,7 @@ constexpr void recover_code_point(Reader& reader, cp_result result) case cp_error::out_of_range: case cp_error::overlong_sequence: // Consume all the invalid code units to recover. - reader.set_position(result.end); + reader.reset(result.end); break; } } diff --git a/3rdparty/lexy/include/lexy/_detail/config.hpp b/3rdparty/lexy/include/lexy/_detail/config.hpp index 0b57dfc5a..4aa40135b 100644 --- a/3rdparty/lexy/include/lexy/_detail/config.hpp +++ b/3rdparty/lexy/include/lexy/_detail/config.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_CONFIG_HPP_INCLUDED @@ -17,6 +17,14 @@ # endif #endif +#ifndef LEXY_HAS_UNICODE_DATABASE +# define LEXY_HAS_UNICODE_DATABASE 0 +#endif + +#ifndef LEXY_EXPERIMENTAL +# define LEXY_EXPERIMENTAL 0 +#endif + //=== utility traits===// #define LEXY_MOV(...) static_cast&&>(__VA_ARGS__) #define LEXY_FWD(...) static_cast(__VA_ARGS__) @@ -90,6 +98,21 @@ using type_or = std::conditional_t, Fallback, T>; # define LEXY_CONSTEVAL constexpr #endif +//=== constexpr ===// +#ifndef LEXY_HAS_CONSTEXPR_DTOR +# if __cpp_constexpr_dynamic_alloc +# define LEXY_HAS_CONSTEXPR_DTOR 1 +# else +# define LEXY_HAS_CONSTEXPR_DTOR 0 +# endif +#endif + +#if LEXY_HAS_CONSTEXPR_DTOR +# define LEXY_CONSTEXPR_DTOR constexpr +#else +# define LEXY_CONSTEXPR_DTOR +#endif + //=== char8_t ===// #ifndef LEXY_HAS_CHAR8_T # if __cpp_char8_t diff --git a/3rdparty/lexy/include/lexy/_detail/detect.hpp b/3rdparty/lexy/include/lexy/_detail/detect.hpp index 8174805c4..7534c44c4 100644 --- a/3rdparty/lexy/include/lexy/_detail/detect.hpp +++ b/3rdparty/lexy/include/lexy/_detail/detect.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_DETECT_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/integer_sequence.hpp b/3rdparty/lexy/include/lexy/_detail/integer_sequence.hpp index bc8cba6e1..36e3cb08c 100644 --- a/3rdparty/lexy/include/lexy/_detail/integer_sequence.hpp +++ b/3rdparty/lexy/include/lexy/_detail/integer_sequence.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_INTEGER_SEQUENCE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/invoke.hpp b/3rdparty/lexy/include/lexy/_detail/invoke.hpp index bc683c9bc..8604e582e 100644 --- a/3rdparty/lexy/include/lexy/_detail/invoke.hpp +++ b/3rdparty/lexy/include/lexy/_detail/invoke.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_INVOKE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/iterator.hpp b/3rdparty/lexy/include/lexy/_detail/iterator.hpp index 9d3f46dd9..42ec995a4 100644 --- a/3rdparty/lexy/include/lexy/_detail/iterator.hpp +++ b/3rdparty/lexy/include/lexy/_detail/iterator.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_ITERATOR_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/lazy_init.hpp b/3rdparty/lexy/include/lexy/_detail/lazy_init.hpp index 0a08ebcbb..29fcfa308 100644 --- a/3rdparty/lexy/include/lexy/_detail/lazy_init.hpp +++ b/3rdparty/lexy/include/lexy/_detail/lazy_init.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_LAZY_INIT_HPP_INCLUDED @@ -6,6 +6,7 @@ #include #include +#include namespace lexy::_detail { @@ -25,6 +26,12 @@ struct _lazy_init_storage_trivial constexpr _lazy_init_storage_trivial(int, Args&&... args) : _init(true), _value(LEXY_FWD(args)...) {} + + template + constexpr void _construct(Args&&... args) + { + *this = _lazy_init_storage_trivial(0, LEXY_FWD(args)...); + } }; template @@ -40,24 +47,29 @@ struct _lazy_init_storage_non_trivial constexpr _lazy_init_storage_non_trivial() noexcept : _init(false), _empty() {} template - constexpr _lazy_init_storage_non_trivial(int, Args&&... args) - : _init(true), _value(LEXY_FWD(args)...) - {} + LEXY_CONSTEXPR_DTOR void _construct(Args&&... args) + { + _detail::construct_at(&_value, LEXY_FWD(args)...); + _init = true; + } - ~_lazy_init_storage_non_trivial() noexcept + // Cannot add noexcept due to https://github.com/llvm/llvm-project/issues/59854. + LEXY_CONSTEXPR_DTOR ~_lazy_init_storage_non_trivial() /* noexcept */ { if (_init) _value.~T(); } - _lazy_init_storage_non_trivial(_lazy_init_storage_non_trivial&& other) noexcept + LEXY_CONSTEXPR_DTOR _lazy_init_storage_non_trivial( + _lazy_init_storage_non_trivial&& other) noexcept : _init(other._init), _empty() { if (_init) - ::new (static_cast(&_value)) T(LEXY_MOV(other._value)); + _detail::construct_at(&_value, LEXY_MOV(other._value)); } - _lazy_init_storage_non_trivial& operator=(_lazy_init_storage_non_trivial&& other) noexcept + LEXY_CONSTEXPR_DTOR _lazy_init_storage_non_trivial& operator=( + _lazy_init_storage_non_trivial&& other) noexcept { if (_init && other._init) _value = LEXY_MOV(other._value); @@ -68,7 +80,7 @@ struct _lazy_init_storage_non_trivial } else if (!_init && other._init) { - ::new (static_cast(&_value)) T(LEXY_MOV(other._value)); + _detail::construct_at(&_value, LEXY_MOV(other._value)); _init = true; } else @@ -104,9 +116,11 @@ class lazy_init : _lazy_init_storage template constexpr T& emplace(Args&&... args) { - LEXY_PRECONDITION(!*this); + if (*this) + this->_value = T(LEXY_FWD(args)...); + else + this->_construct(LEXY_FWD(args)...); - *this = lazy_init(0, LEXY_FWD(args)...); return this->_value; } @@ -169,7 +183,6 @@ class lazy_init constexpr T& emplace(T& ref) { - LEXY_PRECONDITION(!*this); _ptr = &ref; return ref; } @@ -210,7 +223,6 @@ class lazy_init constexpr void emplace() { - LEXY_PRECONDITION(!*this); _init = true; } template diff --git a/3rdparty/lexy/include/lexy/_detail/memory_resource.hpp b/3rdparty/lexy/include/lexy/_detail/memory_resource.hpp index bc651d208..324a96c84 100644 --- a/3rdparty/lexy/include/lexy/_detail/memory_resource.hpp +++ b/3rdparty/lexy/include/lexy/_detail/memory_resource.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_MEMORY_RESOURCE_HPP_INCLUDED @@ -29,7 +29,7 @@ class default_memory_resource static void* allocate(std::size_t bytes, std::size_t alignment) { if (alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) - return ::operator new (bytes, std::align_val_t{alignment}); + return ::operator new(bytes, std::align_val_t{alignment}); else return ::operator new(bytes); } @@ -47,14 +47,14 @@ class default_memory_resource #ifdef __cpp_sized_deallocation if (alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) - ::operator delete (ptr, bytes, std::align_val_t{alignment}); + ::operator delete(ptr, bytes, std::align_val_t{alignment}); else ::operator delete(ptr, bytes); #else (void)bytes; if (alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) - ::operator delete (ptr, std::align_val_t{alignment}); + ::operator delete(ptr, std::align_val_t{alignment}); else ::operator delete(ptr); #endif @@ -140,9 +140,8 @@ using memory_resource_ptr _memory_resource_ptr>>; // clang-format on -template || std::is_empty_v>> +template + || std::is_empty_v>> constexpr MemoryResource* get_memory_resource() { return nullptr; diff --git a/3rdparty/lexy/include/lexy/_detail/nttp_string.hpp b/3rdparty/lexy/include/lexy/_detail/nttp_string.hpp index 5ef586cd2..7301914a8 100644 --- a/3rdparty/lexy/include/lexy/_detail/nttp_string.hpp +++ b/3rdparty/lexy/include/lexy/_detail/nttp_string.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_NTTP_STRING_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/stateless_lambda.hpp b/3rdparty/lexy/include/lexy/_detail/stateless_lambda.hpp index 75ac77fe1..63c8dc7e5 100644 --- a/3rdparty/lexy/include/lexy/_detail/stateless_lambda.hpp +++ b/3rdparty/lexy/include/lexy/_detail/stateless_lambda.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_STATELESS_LAMBDA_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/std.hpp b/3rdparty/lexy/include/lexy/_detail/std.hpp index f6525bd0b..bb3381f08 100644 --- a/3rdparty/lexy/include/lexy/_detail/std.hpp +++ b/3rdparty/lexy/include/lexy/_detail/std.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_STD_HPP_INCLUDED @@ -6,6 +6,7 @@ #include +//=== iterator tags ===// #if defined(__GLIBCXX__) namespace std @@ -35,5 +36,63 @@ struct bidirectional_iterator_tag; #endif +//=== (constexpr) construct_at ===// +#if !LEXY_HAS_CONSTEXPR_DTOR + +namespace lexy::_detail +{ +// We don't have constexpr dtor's, so this is just a regular function. +template +T* construct_at(T* ptr, Args&&... args) +{ + return ::new ((void*)ptr) T(LEXY_FWD(args)...); +} +} // namespace lexy::_detail + +#elif defined(_MSC_VER) + +namespace lexy::_detail +{ +// MSVC can make it constexpr if marked with an attribute given by a macro. +template +constexpr T* construct_at(T* ptr, Args&&... args) +{ +# if defined(_MSVC_CONSTEXPR) + _MSVC_CONSTEXPR +# endif + return ::new ((void*)ptr) T(LEXY_FWD(args)...); +} +} // namespace lexy::_detail + +#else + +namespace lexy::_detail +{ +struct _construct_at_tag +{}; +} // namespace lexy::_detail + +namespace std +{ +// GCC only allows constexpr placement new inside a function called `std::construct_at`. +// So we write our own. +template +constexpr T* construct_at(lexy::_detail::_construct_at_tag, T* ptr, Args&&... args) +{ + return ::new ((void*)ptr) T(LEXY_FWD(args)...); +} +} // namespace std + +namespace lexy::_detail +{ +template +constexpr T* construct_at(T* ptr, Args&&... args) +{ + return std::construct_at(lexy::_detail::_construct_at_tag{}, ptr, LEXY_FWD(args)...); +} +} // namespace lexy::_detail + +#endif + #endif // LEXY_DETAIL_STD_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/string_view.hpp b/3rdparty/lexy/include/lexy/_detail/string_view.hpp index 1ee3fa015..41d42bc42 100644 --- a/3rdparty/lexy/include/lexy/_detail/string_view.hpp +++ b/3rdparty/lexy/include/lexy/_detail/string_view.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_STRING_VIEW_HPP_INCLUDED @@ -136,10 +136,18 @@ class basic_string_view } } - constexpr bool starts_with(basic_string_view prefix) const + constexpr bool starts_with(basic_string_view prefix) const noexcept { return substr(0, prefix.size()) == prefix; } + constexpr bool try_remove_prefix(basic_string_view prefix) noexcept + { + if (!starts_with(prefix)) + return false; + + remove_prefix(prefix.length()); + return true; + } constexpr std::size_t find(basic_string_view str, std::size_t pos = 0) const noexcept { diff --git a/3rdparty/lexy/include/lexy/_detail/swar.hpp b/3rdparty/lexy/include/lexy/_detail/swar.hpp index 6d8b5e6d6..d7734d0f4 100644 --- a/3rdparty/lexy/include/lexy/_detail/swar.hpp +++ b/3rdparty/lexy/include/lexy/_detail/swar.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_SWAR_HPP_INCLUDED @@ -222,13 +222,13 @@ class swar_reader_base : _swar_base { auto ptr = static_cast(*this).position(); ptr += swar_length; - static_cast(*this).set_position(ptr); + static_cast(*this).reset({ptr}); } void bump_swar(std::size_t char_count) { auto ptr = static_cast(*this).position(); ptr += char_count; - static_cast(*this).set_position(ptr); + static_cast(*this).reset({ptr}); } }; diff --git a/3rdparty/lexy/include/lexy/_detail/tuple.hpp b/3rdparty/lexy/include/lexy/_detail/tuple.hpp index bb8eb86d2..b9c7ebf55 100644 --- a/3rdparty/lexy/include/lexy/_detail/tuple.hpp +++ b/3rdparty/lexy/include/lexy/_detail/tuple.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_TUPLE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/_detail/type_name.hpp b/3rdparty/lexy/include/lexy/_detail/type_name.hpp index 0dd6f652c..8e7ffe250 100644 --- a/3rdparty/lexy/include/lexy/_detail/type_name.hpp +++ b/3rdparty/lexy/include/lexy/_detail/type_name.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DETAIL_TYPE_NAME_HPP_INCLUDED @@ -29,6 +29,7 @@ constexpr auto _full_type_name() auto function = string_view(__PRETTY_FUNCTION__); function.remove_prefix(prefix.length()); function.remove_suffix(suffix.length()); + function.try_remove_prefix("(anonymous namespace)::"); return function; #elif defined(__GNUC__) @@ -46,6 +47,7 @@ constexpr auto _full_type_name() auto function = string_view(__PRETTY_FUNCTION__); function.remove_prefix(prefix.length()); function.remove_suffix(suffix.length()); + function.try_remove_prefix("{anonymous}::"); return function; #elif defined(_MSC_VER) @@ -58,12 +60,8 @@ constexpr auto _full_type_name() auto function = string_view(__FUNCSIG__); function.remove_prefix(prefix.length()); function.remove_suffix(suffix.length()); - - if (auto s = string_view("struct "); function.starts_with(s)) - function.remove_prefix(s.length()); - else if (auto c = string_view("class "); function.starts_with(c)) - function.remove_prefix(c.length()); - + function.try_remove_prefix("struct ") || function.try_remove_prefix("class "); + function.try_remove_prefix("`anonymous-namespace'::"); return function; #else diff --git a/3rdparty/lexy/include/lexy/action/base.hpp b/3rdparty/lexy/include/lexy/action/base.hpp index b74f9e1ce..84cc15f2d 100644 --- a/3rdparty/lexy/include/lexy/action/base.hpp +++ b/3rdparty/lexy/include/lexy/action/base.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_ACTION_BASE_HPP_INCLUDED @@ -200,6 +200,7 @@ constexpr void* no_parse_state = nullptr; template constexpr auto _do_action(_pc& context, Reader& reader) { + context.on(parse_events::grammar_start{}, reader.position()); context.on(parse_events::production_start{}, reader.position()); // We parse whitespace, theen the rule, then finish. @@ -209,9 +210,15 @@ constexpr auto _do_action(_pc& context, Reader& read auto rule_result = parser::parse(context, reader); if (rule_result) + { context.on(parse_events::production_finish{}, reader.position()); + context.on(parse_events::grammar_finish{}, reader); + } else + { context.on(parse_events::production_cancel{}, reader.position()); + context.on(parse_events::grammar_cancel{}, reader); + } return rule_result; } diff --git a/3rdparty/lexy/include/lexy/action/match.hpp b/3rdparty/lexy/include/lexy/action/match.hpp index ca885848b..dade7042c 100644 --- a/3rdparty/lexy/include/lexy/action/match.hpp +++ b/3rdparty/lexy/include/lexy/action/match.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_ACTION_MATCH_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/action/parse.hpp b/3rdparty/lexy/include/lexy/action/parse.hpp index a5cd9a2ac..ec4241590 100644 --- a/3rdparty/lexy/include/lexy/action/parse.hpp +++ b/3rdparty/lexy/include/lexy/action/parse.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_ACTION_PARSE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/action/parse_as_tree.hpp b/3rdparty/lexy/include/lexy/action/parse_as_tree.hpp index dbf865330..b2f54d2c0 100644 --- a/3rdparty/lexy/include/lexy/action/parse_as_tree.hpp +++ b/3rdparty/lexy/include/lexy/action/parse_as_tree.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_ACTION_PARSE_AS_TREE_HPP_INCLUDED @@ -18,7 +18,7 @@ class _pth template explicit _pth(Tree& tree, const _detail::any_holder& input, _detail::any_holder& sink) - : _tree(&tree), _depth(0), _validate(input, sink), _reader(input.get()->reader()) + : _tree(&tree), _depth(0), _validate(input, sink) {} class event_handler @@ -28,40 +28,53 @@ class _pth public: event_handler(production_info info) : _validate(info) {} + void on(_pth& handler, parse_events::grammar_start, iterator) + { + LEXY_PRECONDITION(handler._depth == 0); + + handler._builder.emplace(LEXY_MOV(*handler._tree), _validate.get_info()); + } + void on(_pth& handler, parse_events::grammar_finish, Reader& reader) + { + LEXY_PRECONDITION(handler._depth == 0); + + auto begin = reader.position(); + lexy::try_match_token(dsl::any, reader); + auto end = reader.position(); + + *handler._tree = LEXY_MOV(*handler._builder).finish({begin, end}); + } + void on(_pth& handler, parse_events::grammar_cancel, Reader&) + { + LEXY_PRECONDITION(handler._depth == 0); + + handler._tree->clear(); + } + void on(_pth& handler, parse_events::production_start ev, iterator pos) { - if (handler._depth++ == 0) - handler._builder.emplace(LEXY_MOV(*handler._tree), _validate.get_info()); - else + if (handler._depth++ > 0) _marker = handler._builder->start_production(_validate.get_info()); _validate.on(handler._validate, ev, pos); } - void on(_pth& handler, parse_events::production_finish, iterator pos) + void on(_pth& handler, parse_events::production_finish ev, iterator pos) { - if (--handler._depth == 0) - { - auto reader = handler._reader; - reader.set_position(pos); - lexy::try_match_token(dsl::any, reader); - auto end = reader.position(); - - *handler._tree = LEXY_MOV(*handler._builder).finish({pos, end}); - } - else + if (--handler._depth > 0) { + if (handler._builder->current_child_count() == 0) + handler._builder->token(lexy::position_token_kind, _validate.production_begin(), + _validate.production_begin()); handler._builder->finish_production(LEXY_MOV(_marker)); } + + _validate.on(handler._validate, ev, pos); } - void on(_pth& handler, parse_events::production_cancel, iterator pos) + void on(_pth& handler, parse_events::production_cancel ev, iterator pos) { - if (--handler._depth == 0) - { - handler._tree->clear(); - } - else + if (--handler._depth > 0) { // Cancelling the production removes all nodes from the tree. // To ensure that the parse tree remains lossless, we add everything consumed by it @@ -69,6 +82,8 @@ class _pth handler._builder->cancel_production(LEXY_MOV(_marker)); handler._builder->token(lexy::error_token_kind, _validate.production_begin(), pos); } + + _validate.on(handler._validate, ev, pos); } auto on(_pth& handler, lexy::parse_events::operation_chain_start, iterator) @@ -130,7 +145,6 @@ class _pth int _depth; _vh _validate; - Reader _reader; }; template _input; - _detail::any_holder<_error_sink_t> _sink; - _detail::parse_context_control_block<_handler> _cb; - _pc<_handler, State, _production> _context; + _detail::any_holder _input; + _detail::any_holder<_error_sink_t> _sink; + _detail::parse_context_control_block<_handler, State> _cb; + _pc<_handler, State, _production> _context; friend _impl; }; diff --git a/3rdparty/lexy/include/lexy/action/trace.hpp b/3rdparty/lexy/include/lexy/action/trace.hpp index 84417d854..1a38fac64 100644 --- a/3rdparty/lexy/include/lexy/action/trace.hpp +++ b/3rdparty/lexy/include/lexy/action/trace.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_ACTION_TRACE_HPP_INCLUDED @@ -319,6 +319,10 @@ class _th public: constexpr event_handler(production_info info) : _info(info) {} + void on(_th&, parse_events::grammar_start, iterator) {} + void on(_th&, parse_events::grammar_finish, lexy::input_reader&) {} + void on(_th&, parse_events::grammar_cancel, lexy::input_reader&) {} + void on(_th& handler, parse_events::production_start, iterator pos) { auto loc = handler.get_location(pos); diff --git a/3rdparty/lexy/include/lexy/action/validate.hpp b/3rdparty/lexy/include/lexy/action/validate.hpp index f3644fa30..ac6b48f0e 100644 --- a/3rdparty/lexy/include/lexy/action/validate.hpp +++ b/3rdparty/lexy/include/lexy/action/validate.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_ACTION_VALIDATE_HPP_INCLUDED @@ -196,27 +196,31 @@ class _vh handler._top = _prev; } - template - constexpr void on(_vh& handler, parse_events::error, const error& error) + template + constexpr void on(_vh& handler, parse_events::error, const error& error) { handler._cb.generic(handler._cb.sink, get_info(), handler._cb.input, _begin, error); } - constexpr void on(_vh& handler, parse_events::error, const error& error) + template + constexpr void on(_vh& handler, parse_events::error, const error& error) { handler._cb.generic(handler._cb.sink, get_info(), handler._cb.input, _begin, error); } - constexpr void on(_vh& handler, parse_events::error, - const error& error) + template + constexpr void on(_vh& handler, parse_events::error, + const error& error) { handler._cb.literal(handler._cb.sink, get_info(), handler._cb.input, _begin, error); } - constexpr void on(_vh& handler, parse_events::error, - const error& error) + template + constexpr void on(_vh& handler, parse_events::error, + const error& error) { handler._cb.keyword(handler._cb.sink, get_info(), handler._cb.input, _begin, error); } - constexpr void on(_vh& handler, parse_events::error, - const error& error) + template + constexpr void on(_vh& handler, parse_events::error, + const error& error) { handler._cb.char_class(handler._cb.sink, get_info(), handler._cb.input, _begin, error); } diff --git a/3rdparty/lexy/include/lexy/callback.hpp b/3rdparty/lexy/include/lexy/callback.hpp index 237ebe316..fa65f3ebb 100644 --- a/3rdparty/lexy/include/lexy/callback.hpp +++ b/3rdparty/lexy/include/lexy/callback.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/adapter.hpp b/3rdparty/lexy/include/lexy/callback/adapter.hpp index 29b2750d6..b212fd2ab 100644 --- a/3rdparty/lexy/include/lexy/callback/adapter.hpp +++ b/3rdparty/lexy/include/lexy/callback/adapter.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_ADAPTER_HPP_INCLUDED @@ -16,6 +16,33 @@ struct _callback : _overloaded constexpr explicit _callback(Fns... fns) : _overloaded(LEXY_MOV(fns)...) {} }; +template +struct _callback_with_state : _overloaded +{ + using return_type = ReturnType; + + template + struct _with_state + { + const _callback_with_state& _cb; + State& _state; + + template + constexpr return_type operator()(Args&&... args) const&& + { + return _cb(_state, LEXY_FWD(args)...); + } + }; + + constexpr explicit _callback_with_state(Fns... fns) : _overloaded(LEXY_MOV(fns)...) {} + + template + constexpr auto operator[](State& state) const + { + return _with_state{*this, state}; + } +}; + /// Creates a callback. template constexpr auto callback(Fns&&... fns) @@ -26,14 +53,28 @@ constexpr auto callback(Fns&&... fns) else return _callback...>(LEXY_FWD(fns)...); } - -/// Creates a callback. template constexpr auto callback(Fns&&... fns) { return _callback...>(LEXY_FWD(fns)...); } +/// Creates a callback that also receives the parse state. +template +constexpr auto callback_with_state(Fns&&... fns) +{ + if constexpr ((lexy::is_callback> && ...)) + return _callback_with_state::return_type...>, + std::decay_t...>(LEXY_FWD(fns)...); + else + return _callback_with_state...>(LEXY_FWD(fns)...); +} +template +constexpr auto callback_with_state(Fns&&... fns) +{ + return _callback_with_state...>(LEXY_FWD(fns)...); +} + template struct _cb_from_sink { diff --git a/3rdparty/lexy/include/lexy/callback/aggregate.hpp b/3rdparty/lexy/include/lexy/callback/aggregate.hpp index fbb04688d..97420f146 100644 --- a/3rdparty/lexy/include/lexy/callback/aggregate.hpp +++ b/3rdparty/lexy/include/lexy/callback/aggregate.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_AGGREGATE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/base.hpp b/3rdparty/lexy/include/lexy/callback/base.hpp index 8edaa86a5..915afdd7d 100644 --- a/3rdparty/lexy/include/lexy/callback/base.hpp +++ b/3rdparty/lexy/include/lexy/callback/base.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_BASE_HPP_INCLUDED @@ -27,6 +27,13 @@ template constexpr bool is_callback_state = _detail::is_detected<_detect_callback_state, T, std::decay_t>; +template +using _detect_callback_with_state_for + = decltype(LEXY_DECLVAL(const T)[LEXY_DECLVAL(State&)](LEXY_DECLVAL(Args)...)); +template +constexpr bool is_callback_with_state_for + = _detail::is_detected<_detect_callback_with_state_for, std::decay_t, State, Args...>; + /// Returns the type of the `.sink()` function. template using sink_callback = decltype(LEXY_DECLVAL(Sink).sink(LEXY_DECLVAL(Args)...)); @@ -82,4 +89,3 @@ constexpr auto _make_overloaded(Op&&... op) } // namespace lexy #endif // LEXY_CALLBACK_BASE_HPP_INCLUDED - diff --git a/3rdparty/lexy/include/lexy/callback/bind.hpp b/3rdparty/lexy/include/lexy/callback/bind.hpp index 520e62853..a73851ad4 100644 --- a/3rdparty/lexy/include/lexy/callback/bind.hpp +++ b/3rdparty/lexy/include/lexy/callback/bind.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_BIND_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/bit_cast.hpp b/3rdparty/lexy/include/lexy/callback/bit_cast.hpp index dbb488f01..9401c00f5 100644 --- a/3rdparty/lexy/include/lexy/callback/bit_cast.hpp +++ b/3rdparty/lexy/include/lexy/callback/bit_cast.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_BIT_CAST_HPP_INCLUDED @@ -16,7 +16,7 @@ #ifndef LEXY_HAS_BITCAST # if defined(__has_include) -# if __has_include() +# if __has_include() && __cplusplus >= 202002L # include # ifdef __cpp_lib_bit_cast # define LEXY_HAS_BITCAST 1 diff --git a/3rdparty/lexy/include/lexy/callback/composition.hpp b/3rdparty/lexy/include/lexy/callback/composition.hpp index b072b4dd6..0936c541b 100644 --- a/3rdparty/lexy/include/lexy/callback/composition.hpp +++ b/3rdparty/lexy/include/lexy/callback/composition.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_COMPOSITION_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/constant.hpp b/3rdparty/lexy/include/lexy/callback/constant.hpp index 0421edc78..4ffbd61ca 100644 --- a/3rdparty/lexy/include/lexy/callback/constant.hpp +++ b/3rdparty/lexy/include/lexy/callback/constant.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_CONSTANT_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/container.hpp b/3rdparty/lexy/include/lexy/callback/container.hpp index d35dbf32c..a96c64bab 100644 --- a/3rdparty/lexy/include/lexy/callback/container.hpp +++ b/3rdparty/lexy/include/lexy/callback/container.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_CONTAINER_HPP_INCLUDED @@ -16,7 +16,7 @@ template constexpr auto _has_reserve = _detail::is_detected<_detect_reserve, Container>; template -using _detect_append = decltype(LEXY_DECLVAL(Container&).append(LEXY_DECLVAL(Container &&))); +using _detect_append = decltype(LEXY_DECLVAL(Container&).append(LEXY_DECLVAL(Container&&))); template constexpr auto _has_append = _detail::is_detected<_detect_append, Container>; } // namespace lexy @@ -32,18 +32,19 @@ struct _list_sink using return_type = Container; template - auto operator()(U&& obj) -> decltype(LEXY_DECLVAL(C&).push_back(LEXY_FWD(obj))) + constexpr auto operator()(U&& obj) -> decltype(LEXY_DECLVAL(C&).push_back(LEXY_FWD(obj))) { return _result.push_back(LEXY_FWD(obj)); } template - auto operator()(Args&&... args) -> decltype(LEXY_DECLVAL(C&).emplace_back(LEXY_FWD(args)...)) + constexpr auto operator()(Args&&... args) + -> decltype(LEXY_DECLVAL(C&).emplace_back(LEXY_FWD(args)...)) { return _result.emplace_back(LEXY_FWD(args)...); } - Container&& finish() && + constexpr Container&& finish() && { return LEXY_MOV(_result); } @@ -171,18 +172,19 @@ struct _collection_sink using return_type = Container; template - auto operator()(U&& obj) -> decltype(LEXY_DECLVAL(C&).insert(LEXY_FWD(obj))) + constexpr auto operator()(U&& obj) -> decltype(LEXY_DECLVAL(C&).insert(LEXY_FWD(obj))) { return _result.insert(LEXY_FWD(obj)); } template - auto operator()(Args&&... args) -> decltype(LEXY_DECLVAL(C&).emplace(LEXY_FWD(args)...)) + constexpr auto operator()(Args&&... args) + -> decltype(LEXY_DECLVAL(C&).emplace(LEXY_FWD(args)...)) { return _result.emplace(LEXY_FWD(args)...); } - Container&& finish() && + constexpr Container&& finish() && { return LEXY_MOV(_result); } @@ -355,7 +357,7 @@ struct _concat using return_type = Container; - void operator()(Container&& container) + constexpr void operator()(Container&& container) { if (_result.empty()) { @@ -389,7 +391,7 @@ struct _concat } } - Container&& finish() && + constexpr Container&& finish() && { return LEXY_MOV(_result); } diff --git a/3rdparty/lexy/include/lexy/callback/fold.hpp b/3rdparty/lexy/include/lexy/callback/fold.hpp index 478bc5482..b58e80dc7 100644 --- a/3rdparty/lexy/include/lexy/callback/fold.hpp +++ b/3rdparty/lexy/include/lexy/callback/fold.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_FOLD_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/forward.hpp b/3rdparty/lexy/include/lexy/callback/forward.hpp index f4342816c..2655af45b 100644 --- a/3rdparty/lexy/include/lexy/callback/forward.hpp +++ b/3rdparty/lexy/include/lexy/callback/forward.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_FORWARD_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/integer.hpp b/3rdparty/lexy/include/lexy/callback/integer.hpp index de2f94cdc..ab7500210 100644 --- a/3rdparty/lexy/include/lexy/callback/integer.hpp +++ b/3rdparty/lexy/include/lexy/callback/integer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_INTEGER_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/noop.hpp b/3rdparty/lexy/include/lexy/callback/noop.hpp index 03485d9e3..a36e0dc30 100644 --- a/3rdparty/lexy/include/lexy/callback/noop.hpp +++ b/3rdparty/lexy/include/lexy/callback/noop.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_NOOP_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/object.hpp b/3rdparty/lexy/include/lexy/callback/object.hpp index a99dfbf3f..eb87e841d 100644 --- a/3rdparty/lexy/include/lexy/callback/object.hpp +++ b/3rdparty/lexy/include/lexy/callback/object.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_OBJECT_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/callback/string.hpp b/3rdparty/lexy/include/lexy/callback/string.hpp index 954c56e14..984f1e1ba 100644 --- a/3rdparty/lexy/include/lexy/callback/string.hpp +++ b/3rdparty/lexy/include/lexy/callback/string.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CALLBACK_STRING_HPP_INCLUDED @@ -149,39 +149,39 @@ struct _as_string using return_type = String; template - void operator()(CharT c) + constexpr void operator()(CharT c) { _result.push_back(c); } - void operator()(String&& str) + constexpr void operator()(String&& str) { _result.append(LEXY_MOV(str)); } template - auto operator()(Iterator begin, Iterator end) + constexpr auto operator()(Iterator begin, Iterator end) -> decltype(void(LEXY_DECLVAL(Str).append(begin, end))) { _result.append(begin, end); } template - void operator()(lexeme lex) + constexpr void operator()(lexeme lex) { static_assert(lexy::char_type_compatible_with_reader, "cannot convert lexeme to this string type"); _result.append(lex.begin(), lex.end()); } - void operator()(code_point cp) + constexpr void operator()(code_point cp) { typename Encoding::char_type buffer[4] = {}; auto size = _detail::encode_code_point(cp.value(), buffer, 4); _result.append(buffer, buffer + size); } - String&& finish() && + constexpr String&& finish() && { return _case_folding(LEXY_MOV(_result)); } diff --git a/3rdparty/lexy/include/lexy/code_point.hpp b/3rdparty/lexy/include/lexy/code_point.hpp index d77d73fbd..a67b3bdbe 100644 --- a/3rdparty/lexy/include/lexy/code_point.hpp +++ b/3rdparty/lexy/include/lexy/code_point.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_CODE_POINT_HPP_INCLUDED @@ -8,10 +8,6 @@ #include #include -#ifndef LEXY_HAS_UNICODE_DATABASE -# define LEXY_HAS_UNICODE_DATABASE 0 -#endif - #if LEXY_HAS_UNICODE_DATABASE # define LEXY_UNICODE_CONSTEXPR constexpr #else @@ -89,7 +85,7 @@ class code_point LEXY_UNICODE_CATEGORY(Lo, other_letter), LEXY_UNICODE_CATEGORY(Mn, nonspacing_mark), - LEXY_UNICODE_CATEGORY(Mc, spaing_mark), + LEXY_UNICODE_CATEGORY(Mc, spacing_mark), LEXY_UNICODE_CATEGORY(Me, enclosing_mark), LEXY_UNICODE_CATEGORY(Nd, decimal_number), diff --git a/3rdparty/lexy/include/lexy/dsl.hpp b/3rdparty/lexy/include/lexy/dsl.hpp index 2cc8a21cc..b41eeceb1 100644 --- a/3rdparty/lexy/include/lexy/dsl.hpp +++ b/3rdparty/lexy/include/lexy/dsl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_HPP_INCLUDED @@ -60,5 +60,9 @@ #include #include +#if LEXY_EXPERIMENTAL +# include +#endif + #endif // LEXY_DSL_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/any.hpp b/3rdparty/lexy/include/lexy/dsl/any.hpp index 734ec611c..2b30e39ef 100644 --- a/3rdparty/lexy/include/lexy/dsl/any.hpp +++ b/3rdparty/lexy/include/lexy/dsl/any.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_ANY_HPP_INCLUDED @@ -15,9 +15,9 @@ struct _any : token_base<_any, unconditional_branch_base> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr std::true_type try_parse(Reader reader) { @@ -32,7 +32,7 @@ struct _any : token_base<_any, unconditional_branch_base> while (reader.peek() != encoding::eof()) reader.bump(); - end = reader.position(); + end = reader.current(); return {}; } }; diff --git a/3rdparty/lexy/include/lexy/dsl/ascii.hpp b/3rdparty/lexy/include/lexy/dsl/ascii.hpp index 16613f8db..7bc237034 100644 --- a/3rdparty/lexy/include/lexy/dsl/ascii.hpp +++ b/3rdparty/lexy/include/lexy/dsl/ascii.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_ASCII_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/base.hpp b/3rdparty/lexy/include/lexy/dsl/base.hpp index 918e447a8..ea965b0b6 100644 --- a/3rdparty/lexy/include/lexy/dsl/base.hpp +++ b/3rdparty/lexy/include/lexy/dsl/base.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_BASE_HPP_INCLUDED @@ -12,6 +12,19 @@ //=== parse_events ===// namespace lexy::parse_events { +/// Parsing started. +/// Arguments: position +struct grammar_start +{}; +/// Parsing finished succesfully. +/// Arguments: the reader at the final parse position. +struct grammar_finish +{}; +/// Parsing finished unsuccesfully. +/// Arguments: the reader at the final parse position. +struct grammar_cancel +{}; + /// Start of the current production. /// Arguments: position struct production_start @@ -237,7 +250,7 @@ LEXY_FORCE_INLINE constexpr auto try_match_token(TokenRule, Reader& reader) if constexpr (std::is_same_v) { parser.try_parse(reader); - reader.set_position(parser.end); + reader.reset(parser.end); return std::true_type{}; } else if constexpr (std::is_same_v) @@ -250,7 +263,7 @@ LEXY_FORCE_INLINE constexpr auto try_match_token(TokenRule, Reader& reader) if (!parser.try_parse(reader)) return false; - reader.set_position(parser.end); + reader.reset(parser.end); return true; } } diff --git a/3rdparty/lexy/include/lexy/dsl/bits.hpp b/3rdparty/lexy/include/lexy/dsl/bits.hpp index adce85bf4..ab6d484c0 100644 --- a/3rdparty/lexy/include/lexy/dsl/bits.hpp +++ b/3rdparty/lexy/include/lexy/dsl/bits.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_BITS_HPP_INCLUDED @@ -104,13 +104,13 @@ struct _bits : token_base<_bits> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { - static_assert(std::is_same_v); + static_assert(lexy::is_byte_encoding); auto byte = reader.peek(); if (byte == Reader::encoding::eof() @@ -118,14 +118,14 @@ struct _bits : token_base<_bits> return false; reader.bump(); - end = reader.position(); + end = reader.current(); return true; } template constexpr void report_error(Context& context, const Reader&) { - auto err = lexy::error(end, "bits"); + auto err = lexy::error(end.position(), "bits"); context.on(_ev::error{}, err); } }; diff --git a/3rdparty/lexy/include/lexy/dsl/bom.hpp b/3rdparty/lexy/include/lexy/dsl/bom.hpp index e19fa7e55..a3010cc37 100644 --- a/3rdparty/lexy/include/lexy/dsl/bom.hpp +++ b/3rdparty/lexy/include/lexy/dsl/bom.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_BOM_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/brackets.hpp b/3rdparty/lexy/include/lexy/dsl/brackets.hpp index cde68ffee..7e461c929 100644 --- a/3rdparty/lexy/include/lexy/dsl/brackets.hpp +++ b/3rdparty/lexy/include/lexy/dsl/brackets.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_BRACKETS_HPP_INCLUDED @@ -100,7 +100,8 @@ struct _brackets template constexpr auto brackets(Open, Close) { - static_assert(lexy::is_branch_rule && lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Open, "brackets()"); + LEXY_REQUIRE_BRANCH_RULE(Close, "brackets()"); return _brackets{}; } diff --git a/3rdparty/lexy/include/lexy/dsl/branch.hpp b/3rdparty/lexy/include/lexy/dsl/branch.hpp index 2156c9d75..1bbd7fd18 100644 --- a/3rdparty/lexy/include/lexy/dsl/branch.hpp +++ b/3rdparty/lexy/include/lexy/dsl/branch.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_BRANCH_HPP_INCLUDED @@ -31,19 +31,19 @@ struct _br : _copy_base template constexpr auto operator>>(Condition, Then) { - static_assert(lexy::is_branch_rule, "condition must be a branch"); + LEXY_REQUIRE_BRANCH_RULE(Condition, "Left-hand-side of >>"); return _br{}; } template constexpr auto operator>>(Condition, _seq) { - static_assert(lexy::is_branch_rule, "condition must be a branch"); + LEXY_REQUIRE_BRANCH_RULE(Condition, "Left-hand-side of >>"); return _br{}; } template constexpr auto operator>>(Condition, _br) { - static_assert(lexy::is_branch_rule, "condition must be a branch"); + LEXY_REQUIRE_BRANCH_RULE(Condition, "Left-hand-side of >>"); return _br{}; } diff --git a/3rdparty/lexy/include/lexy/dsl/byte.hpp b/3rdparty/lexy/include/lexy/dsl/byte.hpp index 804dba1be..32df8597b 100644 --- a/3rdparty/lexy/include/lexy/dsl/byte.hpp +++ b/3rdparty/lexy/include/lexy/dsl/byte.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_BYTE_HPP_INCLUDED @@ -7,58 +7,140 @@ #include #include #include +#include #include //=== byte ===// namespace lexyd { -template -struct _b : token_base<_b> +template +struct _b : token_base<_b> { static_assert(N > 0); + static constexpr bool _match(lexy::byte_encoding::int_type cur) + { + if (cur == lexy::byte_encoding::eof()) + return false; + + if constexpr (!std::is_void_v) + { + constexpr auto predicate = Predicate{}; + return predicate(static_cast(cur)); + } + else + { + return true; + } + } + template > struct tp; + template struct tp> { - typename Reader::iterator end; + static_assert(lexy::is_byte_encoding); + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { - static_assert(std::is_same_v); - // Bump N times. - auto result = ((reader.peek() == Reader::encoding::eof() ? ((void)Idx, false) - : (reader.bump(), true)) - && ...); - end = reader.position(); + auto result + = ((_match(reader.peek()) ? (reader.bump(), true) : ((void)Idx, false)) && ...); + end = reader.current(); return result; } template constexpr void report_error(Context& context, const Reader&) { - auto err = lexy::error(end, "byte"); + constexpr auto name + = std::is_void_v ? "byte" : lexy::_detail::type_name(); + auto err = lexy::error(end.position(), name); context.on(_ev::error{}, err); } }; + + //=== dsl ===// + template + constexpr auto if_() const + { + static_assert(std::is_void_v); + return _b{}; + } + + template + constexpr auto range() const + { + struct predicate + { + static LEXY_CONSTEVAL auto name() + { + return "byte.range"; + } + + constexpr bool operator()(unsigned char byte) const + { + return Low <= byte && byte <= High; + } + }; + + return if_(); + } + + template + constexpr auto set() const + { + struct predicate + { + static LEXY_CONSTEVAL auto name() + { + return "byte.set"; + } + + constexpr bool operator()(unsigned char byte) const + { + return ((byte == Bytes) || ...); + } + }; + + return if_(); + } + + constexpr auto ascii() const + { + struct predicate + { + static LEXY_CONSTEVAL auto name() + { + return "byte.ASCII"; + } + + constexpr bool operator()(unsigned char byte) const + { + return byte <= 0x7F; + } + }; + + return if_(); + } }; /// Matches an arbitrary byte. -constexpr auto byte = _b<1>{}; +constexpr auto byte = _b<1, void>{}; /// Matches N arbitrary bytes. template -constexpr auto bytes = _b{}; +constexpr auto bytes = _b{}; } // namespace lexyd namespace lexy { template -constexpr auto token_kind_of> = lexy::any_token_kind; +constexpr auto token_kind_of> = lexy::any_token_kind; } // namespace lexy //=== padding bytes ===// @@ -84,13 +166,14 @@ struct _pb : branch_base template struct bp { - typename Reader::iterator end; + static_assert(lexy::is_byte_encoding); + typename Reader::marker end; constexpr auto try_parse(const void*, const Reader& reader) { - lexy::token_parser_for<_b, Reader> parser(reader); - auto result = parser.try_parse(reader); - end = parser.end; + lexy::token_parser_for<_b, Reader> parser(reader); + auto result = parser.try_parse(reader); + end = parser.end; return result; } @@ -102,10 +185,10 @@ struct _pb : branch_base LEXY_PARSER_FUNC auto finish(Context& context, Reader& reader, Args&&... args) { auto begin = reader.position(); - context.on(_ev::token{}, lexy::any_token_kind, begin, end); - reader.set_position(end); + context.on(_ev::token{}, lexy::any_token_kind, begin, end.position()); + reader.reset(end); - _validate(context, reader, begin, end); + _validate(context, reader, begin, end.position()); return lexy::whitespace_parser::parse(context, reader, LEXY_FWD(args)...); } @@ -117,8 +200,9 @@ struct _pb : branch_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { + static_assert(lexy::is_byte_encoding); auto begin = reader.position(); - if (!_b::token_parse(context, reader)) + if (!_b::token_parse(context, reader)) return false; auto end = reader.position(); @@ -167,6 +251,7 @@ auto _bint() return 0; } } + template using bint = decltype(_bint()); } // namespace lexy::_detail @@ -187,10 +272,11 @@ namespace lexyd template struct _bint : branch_base { - using _rule = lexy::_detail::type_or>; + using _rule = lexy::_detail::type_or>; template > struct _pc; + template struct _pc> { @@ -238,7 +324,8 @@ struct _bint : branch_base template struct bp { - typename Reader::iterator end; + static_assert(lexy::is_byte_encoding); + typename Reader::marker end; constexpr auto try_parse(const void*, const Reader& reader) { @@ -256,10 +343,11 @@ struct _bint : branch_base LEXY_PARSER_FUNC auto finish(Context& context, Reader& reader, Args&&... args) { auto begin = reader.position(); - context.on(_ev::token{}, _rule{}, begin, end); - reader.set_position(end); + context.on(_ev::token{}, _rule{}, begin, end.position()); + reader.reset(end); - return _pc::parse(context, reader, begin, end, LEXY_FWD(args)...); + return _pc::parse(context, reader, begin, end.position(), + LEXY_FWD(args)...); } }; @@ -269,6 +357,7 @@ struct _bint : branch_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { + static_assert(lexy::is_byte_encoding); auto begin = reader.position(); if (!_rule::token_parse(context, reader)) return false; @@ -308,4 +397,3 @@ inline constexpr auto big_bint64 = _bint<8, lexy::_detail::bint_big>{}; } // namespace lexyd #endif // LEXY_DSL_BYTE_HPP_INCLUDED - diff --git a/3rdparty/lexy/include/lexy/dsl/capture.hpp b/3rdparty/lexy/include/lexy/dsl/capture.hpp index e6fa59520..92d4d8de2 100644 --- a/3rdparty/lexy/include/lexy/dsl/capture.hpp +++ b/3rdparty/lexy/include/lexy/dsl/capture.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_CAPTURE_HPP_INCLUDED @@ -16,7 +16,7 @@ struct _cap : _copy_base template struct bp { - typename Reader::iterator end; + typename Reader::marker end; constexpr auto try_parse(const void*, const Reader& reader) { @@ -35,12 +35,12 @@ struct _cap : _copy_base { auto begin = reader.position(); - context.on(_ev::token{}, Token{}, begin, end); - reader.set_position(end); + context.on(_ev::token{}, Token{}, begin, end.position()); + reader.reset(end); using continuation = lexy::whitespace_parser; return continuation::parse(context, reader, LEXY_FWD(args)..., - lexy::lexeme(begin, end)); + lexy::lexeme(begin, end.position())); } }; diff --git a/3rdparty/lexy/include/lexy/dsl/case_folding.hpp b/3rdparty/lexy/include/lexy/dsl/case_folding.hpp index d51647a62..c4beb55dd 100644 --- a/3rdparty/lexy/include/lexy/dsl/case_folding.hpp +++ b/3rdparty/lexy/include/lexy/dsl/case_folding.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_CASE_FOLDING_HPP_INCLUDED @@ -45,10 +45,10 @@ struct _cfl : token_base<_cfl>, _lit_base struct tp { lexy::token_parser_for> impl; - typename Reader::iterator end; + typename Reader::marker end; constexpr explicit tp(const Reader& reader) - : impl(CaseFolding{reader}), end(reader.position()) + : impl(CaseFolding{reader}), end(reader.current()) {} constexpr bool try_parse(Reader _reader) @@ -84,6 +84,7 @@ struct _acfr // ascii case folding reader using encoding = typename Reader::encoding; using iterator = typename Reader::iterator; + using marker = typename Reader::marker; constexpr auto peek() const -> typename encoding::int_type { @@ -104,9 +105,13 @@ struct _acfr // ascii case folding reader return _impl.position(); } - constexpr void set_position(iterator new_pos) + constexpr marker current() const noexcept { - _impl.set_position(new_pos); + return _impl.current(); + } + constexpr void reset(marker m) noexcept + { + _impl.reset(m); } }; } // namespace lexy @@ -146,6 +151,7 @@ struct _sucfr32 // simple unicode case folding reader, UTF-32 using encoding = typename Reader::encoding; using iterator = typename Reader::iterator; + using marker = typename Reader::marker; constexpr auto peek() const -> typename encoding::int_type { @@ -163,9 +169,13 @@ struct _sucfr32 // simple unicode case folding reader, UTF-32 return _impl.position(); } - constexpr void set_position(iterator new_pos) + constexpr marker current() const noexcept { - _impl.set_position(new_pos); + return _impl.current(); + } + constexpr void reset(marker m) noexcept + { + _impl.reset(m); } }; @@ -174,22 +184,23 @@ struct _sucfrm // simple unicode case folding reader, UTF-8 and UTF-16 { using encoding = typename Reader::encoding; using iterator = typename Reader::iterator; + using marker = typename Reader::marker; Reader _impl; - typename Reader::iterator _cur_pos; + typename Reader::marker _cur_pos; typename encoding::char_type _buffer[4]; unsigned char _buffer_size; unsigned char _buffer_cur; constexpr explicit _sucfrm(Reader impl) - : _impl(impl), _cur_pos(_impl.position()), _buffer{}, _buffer_size(0), _buffer_cur(0) + : _impl(impl), _cur_pos(_impl.current()), _buffer{}, _buffer_size(0), _buffer_cur(0) { _fill(); } constexpr void _fill() { - _cur_pos = _impl.position(); + _cur_pos = _impl.current(); // We need to read the next code point at this point. auto result = lexy::_detail::parse_code_point(_impl); @@ -200,13 +211,13 @@ struct _sucfrm // simple unicode case folding reader, UTF-8 and UTF-16 _buffer_size = static_cast( lexy::_detail::encode_code_point(folded.value(), _buffer, 4)); _buffer_cur = 0; - _impl.set_position(result.end); + _impl.reset(result.end); } else { // Fill the buffer with the partial code point. _buffer_cur = _buffer_size = 0; - while (_impl.position() != result.end) + while (_impl.position() != result.end.position()) { _buffer[_buffer_size] = static_cast(_impl.peek()); ++_buffer_size; @@ -233,22 +244,23 @@ struct _sucfrm // simple unicode case folding reader, UTF-8 and UTF-16 constexpr iterator position() const { - // We only report the position at a code point boundary. + return current().position(); + } + + constexpr marker current() const noexcept + { + // We only report a marker at a code point boundary. // This has two consequences: // 1. If we don't match a rule, the error token does not include any common start code - // units. - // That's actually nice, and makes it unnecessary to handle that situation in the error - // reporting. The only relevant difference is in the error token. + // units. That's actually nice, and makes it unnecessary to handle that situation in the + // error reporting. The only relevant difference is in the error token. // 2. If the user wants to match partial code unit sequences, the behavior can become buggy. // However, that's not really something we should worry about. return _cur_pos; } - - constexpr void set_position(iterator new_pos) + constexpr void reset(marker m) noexcept { - // It's a code point boundary, so reset. - _impl.set_position(new_pos); - _fill(); + _impl.reset(m); } }; diff --git a/3rdparty/lexy/include/lexy/dsl/char_class.hpp b/3rdparty/lexy/include/lexy/dsl/char_class.hpp index c8e7516f7..cc09ab31e 100644 --- a/3rdparty/lexy/include/lexy/dsl/char_class.hpp +++ b/3rdparty/lexy/include/lexy/dsl/char_class.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_CHAR_CLASS_HPP_INCLUDED @@ -204,17 +204,19 @@ struct char_class_base : token_base, _char_class_base template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { + static_assert(lexy::is_char_encoding); + using matcher = lexy::_detail::ascii_set_matcher<_cas>; if (matcher::template match(reader.peek())) { reader.bump(); - end = reader.position(); + end = reader.current(); return true; } @@ -223,38 +225,37 @@ struct char_class_base : token_base, _char_class_base { return false; } - else if constexpr (std::is_same_v // - || std::is_same_v) + else if constexpr (lexy::is_unicode_encoding) { - static_assert(!Derived::char_class_unicode(), - "cannot use this character class with default/byte_encoding"); + static_assert(Derived::char_class_unicode(), + "cannot use this character class with Unicode encoding"); - if (reader.peek() == Reader::encoding::eof()) + // Parse one code point. + auto result = lexy::_detail::parse_code_point(reader); + if (result.error != lexy::_detail::cp_error::success) return false; - auto cp = static_cast(reader.peek()); - reader.bump(); - - if (!Derived::char_class_match_cp(cp)) + if (!Derived::char_class_match_cp(result.cp)) return false; - end = reader.position(); + end = result.end; return true; } else { - static_assert(Derived::char_class_unicode(), - "cannot use this character class with Unicode encoding"); + static_assert(!Derived::char_class_unicode(), + "cannot use this character class with non-Unicode char encodings"); - // Parse one code point. - auto result = lexy::_detail::parse_code_point(reader); - if (result.error != lexy::_detail::cp_error::success) + if (reader.peek() == Reader::encoding::eof()) return false; - if (!Derived::char_class_match_cp(result.cp)) + auto cp = static_cast(reader.peek()); + reader.bump(); + + if (!Derived::char_class_match_cp(cp)) return false; - end = result.end; + end = reader.current(); return true; } } @@ -361,8 +362,8 @@ constexpr auto _make_char_class(C c) return c; } template || std::is_same_v>> + typename = std::enable_if_t + || std::is_same_v>> constexpr auto _make_char_class(_lit) { if constexpr (std::is_same_v) @@ -411,8 +412,8 @@ struct _calt : char_class_base<_calt> static constexpr auto char_class_match_cp(char32_t cp) { - if constexpr ((std::is_same_v && ...)) + if constexpr ((std::is_same_v + && ...)) return std::false_type{}; else return (Cs::char_class_match_cp(cp) || ...); @@ -572,8 +573,8 @@ struct _cand : char_class_base<_cand> static constexpr auto char_class_match_cp(char32_t cp) { - if constexpr ((std::is_same_v && ...)) + if constexpr ((std::is_same_v + && ...)) return std::false_type{}; else return (Cs::char_class_match_cp(cp) && ...); diff --git a/3rdparty/lexy/include/lexy/dsl/choice.hpp b/3rdparty/lexy/include/lexy/dsl/choice.hpp index 22672147a..ed0fbd952 100644 --- a/3rdparty/lexy/include/lexy/dsl/choice.hpp +++ b/3rdparty/lexy/include/lexy/dsl/choice.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_CHOICE_HPP_INCLUDED @@ -134,20 +134,20 @@ struct _chc template constexpr auto operator|(R, S) { - static_assert(lexy::is_branch_rule, "choice requires a branch condition"); - static_assert(lexy::is_branch_rule, "choice requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(R, "choice"); + LEXY_REQUIRE_BRANCH_RULE(S, "choice"); return _chc{}; } template constexpr auto operator|(_chc, S) { - static_assert(lexy::is_branch_rule, "choice requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(S, "choice"); return _chc{}; } template constexpr auto operator|(R, _chc) { - static_assert(lexy::is_branch_rule, "choice requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(R, "choice"); return _chc{}; } template diff --git a/3rdparty/lexy/include/lexy/dsl/code_point.hpp b/3rdparty/lexy/include/lexy/dsl/code_point.hpp index 2658be22a..bc09666aa 100644 --- a/3rdparty/lexy/include/lexy/dsl/code_point.hpp +++ b/3rdparty/lexy/include/lexy/dsl/code_point.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_CODE_POINT_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/combination.hpp b/3rdparty/lexy/include/lexy/dsl/combination.hpp index 0d6b96c71..73db67b97 100644 --- a/3rdparty/lexy/include/lexy/dsl/combination.hpp +++ b/3rdparty/lexy/include/lexy/dsl/combination.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_COMBINATION_HPP_INCLUDED @@ -130,7 +130,7 @@ struct _comb : rule_base template constexpr auto combination(R...) { - static_assert((lexy::is_branch_rule && ...), "combination() requires a branch rule"); + LEXY_REQUIRE_BRANCH_RULE(R..., "combination()"); static_assert((!lexy::is_unconditional_branch_rule && ...), "combination() does not support unconditional branches"); return _comb{}; @@ -141,7 +141,7 @@ constexpr auto combination(R...) template constexpr auto partial_combination(R...) { - static_assert((lexy::is_branch_rule && ...), "partial_combination() requires a branch rule"); + LEXY_REQUIRE_BRANCH_RULE(R..., "partial_combination()"); static_assert((!lexy::is_unconditional_branch_rule && ...), "partial_combination() does not support unconditional branches"); // If the choice no longer matches, we just break. diff --git a/3rdparty/lexy/include/lexy/dsl/context_counter.hpp b/3rdparty/lexy/include/lexy/dsl/context_counter.hpp index 5efe371bc..411ca1ad9 100644 --- a/3rdparty/lexy/include/lexy/dsl/context_counter.hpp +++ b/3rdparty/lexy/include/lexy/dsl/context_counter.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_CONTEXT_COUNTER_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/context_flag.hpp b/3rdparty/lexy/include/lexy/dsl/context_flag.hpp index 20d0e6307..6782c5322 100644 --- a/3rdparty/lexy/include/lexy/dsl/context_flag.hpp +++ b/3rdparty/lexy/include/lexy/dsl/context_flag.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_CONTEXT_FLAG_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/context_identifier.hpp b/3rdparty/lexy/include/lexy/dsl/context_identifier.hpp index b797c0293..6850904f9 100644 --- a/3rdparty/lexy/include/lexy/dsl/context_identifier.hpp +++ b/3rdparty/lexy/include/lexy/dsl/context_identifier.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_CONTEXT_IDENTIFIER_HPP_INCLUDED @@ -73,7 +73,7 @@ struct _ctx_irem : branch_base template struct bp { - typename Reader::iterator end; + typename Reader::marker end; template constexpr bool try_parse(const ControlBlock* cb, const Reader& reader) @@ -85,7 +85,7 @@ struct _ctx_irem : branch_base end = parser.end; // The two lexemes need to be equal. - auto lexeme = lexy::lexeme(reader.position(), end); + auto lexeme = lexy::lexeme(reader.position(), end.position()); return lexy::_detail::equal_lexemes(_ctx_id::get(cb), lexeme); } @@ -97,8 +97,9 @@ struct _ctx_irem : branch_base LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { // Finish parsing the token. - context.on(_ev::token{}, lexy::identifier_token_kind, reader.position(), end); - reader.set_position(end); + context.on(_ev::token{}, lexy::identifier_token_kind, reader.position(), + end.position()); + reader.reset(end); return lexy::whitespace_parser::parse(context, reader, LEXY_FWD(args)...); } diff --git a/3rdparty/lexy/include/lexy/dsl/delimited.hpp b/3rdparty/lexy/include/lexy/dsl/delimited.hpp index d72dc502f..0b6684d94 100644 --- a/3rdparty/lexy/include/lexy/dsl/delimited.hpp +++ b/3rdparty/lexy/include/lexy/dsl/delimited.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_DELIMITED_HPP_INCLUDED @@ -110,12 +110,33 @@ struct _del_chars else if constexpr (!std::is_same_v) { - // Try to match any code point in default_encoding or byte_encoding. - if constexpr (std::is_same_v // - || std::is_same_v) + if constexpr (lexy::is_unicode_encoding) + { + static_assert(CharClass::char_class_unicode(), + "cannot use this character class with Unicode encoding"); + + auto result = lexy::_detail::parse_code_point(reader); + if (result.error == lexy::_detail::cp_error::success + && CharClass::char_class_match_cp(result.cp)) + { + reader.reset(result.end); + } + else + { + finish(context, sink, reader.position()); + + auto recover_begin = reader.position(); + if (recover_begin == result.end.position()) + reader.bump(); + else + reader.reset(result.end); + _recover(context, recover_begin, reader.position()); + } + } + else { static_assert(!CharClass::char_class_unicode(), - "cannot use this character class with default/byte_encoding"); + "cannot use this character class with non-Unicode char encoding"); LEXY_ASSERT(reader.peek() != encoding::eof(), "EOF should be checked before calling this"); @@ -129,25 +150,6 @@ struct _del_chars _recover(context, recover_begin, reader.position()); } } - // Otherwise, try to match Unicode characters. - else - { - static_assert(CharClass::char_class_unicode(), - "cannot use this character class with Unicode encoding"); - - auto result = lexy::_detail::parse_code_point(reader); - if (result.error == lexy::_detail::cp_error::success - && CharClass::char_class_match_cp(result.cp)) - { - reader.set_position(result.end); - } - else - { - finish(context, sink, reader.position()); - _recover(context, reader.position(), result.end); - reader.set_position(result.end); - } - } } // It doesn't match Unicode characters. else @@ -253,6 +255,7 @@ struct _del : rule_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { + static_assert(lexy::is_char_encoding); auto sink = context.value_callback().sink(); // Parse characters until we have the closing delimiter. @@ -325,7 +328,8 @@ struct _delim_dsl template constexpr auto delimited(Open, Close) { - static_assert(lexy::is_branch_rule && lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Open, "delimited()"); + LEXY_REQUIRE_BRANCH_RULE(Close, "delimited()"); return _delim_dsl{}; } @@ -333,7 +337,7 @@ constexpr auto delimited(Open, Close) template constexpr auto delimited(Delim) { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Delim, "delimited()"); return _delim_dsl{}; } @@ -424,7 +428,7 @@ struct _escape : _escape_base template constexpr auto rule(Branch) const { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Branch, "escape()"); return _escape{}; } @@ -432,7 +436,7 @@ struct _escape : _escape_base template constexpr auto capture(Branch branch) const { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Branch, "escape()"); return this->rule(lexy::dsl::capture(branch)); } diff --git a/3rdparty/lexy/include/lexy/dsl/digit.hpp b/3rdparty/lexy/include/lexy/dsl/digit.hpp index 33232cfc2..a3f1dc61d 100644 --- a/3rdparty/lexy/include/lexy/dsl/digit.hpp +++ b/3rdparty/lexy/include/lexy/dsl/digit.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_DIGIT_HPP_INCLUDED @@ -310,7 +310,8 @@ constexpr bool _match_digits(Reader& reader) // ... then manually to get any trailing digits. while (lexy::try_match_token(digit, reader)) - {} + { + } return true; } @@ -355,24 +356,27 @@ struct _digits_st : token_base<_digits_st> template struct tp { - typename Reader::iterator end; - bool forbidden_leading_zero; + typename Reader::marker end; + bool forbidden_leading_zero; constexpr explicit tp(const Reader& reader) - : end(reader.position()), forbidden_leading_zero(false) + : end(reader.current()), forbidden_leading_zero(false) {} constexpr bool try_parse(Reader reader) { using char_type = typename Reader::encoding::char_type; - auto begin = reader.position(); + auto begin = reader.current(); auto result = _match_digits_sep(reader); - end = reader.position(); + end = reader.current(); - if (result && lexy::_detail::next(begin) != end - && *begin == lexy::_detail::transcode_char('0')) + if (result && lexy::_detail::next(begin.position()) != end.position() + && *begin.position() == lexy::_detail::transcode_char('0')) { - end = lexy::_detail::next(begin); + reader.reset(begin); + reader.bump(); + end = reader.current(); + forbidden_leading_zero = true; return false; } @@ -385,14 +389,14 @@ struct _digits_st : token_base<_digits_st> { if (forbidden_leading_zero) { - auto err - = lexy::error(reader.position(), end); + auto err = lexy::error(reader.position(), + end.position()); context.on(_ev::error{}, err); } else { - auto err - = lexy::error(end, Base::char_class_name()); + auto err = lexy::error(end.position(), + Base::char_class_name()); context.on(_ev::error{}, err); } } @@ -405,21 +409,22 @@ struct _digits_s : token_base<_digits_s> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { auto result = _match_digits_sep(reader); - end = reader.position(); + end = reader.current(); return result; } template constexpr void report_error(Context& context, const Reader&) { - auto err = lexy::error(end, Base::char_class_name()); + auto err = lexy::error(end.position(), + Base::char_class_name()); context.on(_ev::error{}, err); } }; @@ -436,24 +441,27 @@ struct _digits_t : token_base<_digits_t> template struct tp { - typename Reader::iterator end; - bool forbidden_leading_zero; + typename Reader::marker end; + bool forbidden_leading_zero; constexpr explicit tp(const Reader& reader) - : end(reader.position()), forbidden_leading_zero(false) + : end(reader.current()), forbidden_leading_zero(false) {} constexpr bool try_parse(Reader reader) { using char_type = typename Reader::encoding::char_type; - auto begin = reader.position(); + auto begin = reader.current(); auto result = _match_digits(reader); - end = reader.position(); + end = reader.current(); - if (result && lexy::_detail::next(begin) != end - && *begin == lexy::_detail::transcode_char('0')) + if (result && lexy::_detail::next(begin.position()) != end.position() + && *begin.position() == lexy::_detail::transcode_char('0')) { - end = lexy::_detail::next(begin); + reader.reset(begin); + reader.bump(); + end = reader.current(); + forbidden_leading_zero = true; return false; } @@ -467,7 +475,7 @@ struct _digits_t : token_base<_digits_t> if (forbidden_leading_zero) { auto err = lexy::error(reader.position(), - this->end); + end.position()); context.on(_ev::error{}, err); } else @@ -493,14 +501,14 @@ struct _digits : token_base<_digits> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { auto result = _match_digits(reader); - end = reader.position(); + end = reader.current(); return result; } @@ -557,16 +565,16 @@ struct _ndigits_s : token_base<_ndigits_s> template struct tp> { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { // Match the Base one time. if (!lexy::try_match_token(digit, reader)) { - end = reader.position(); + end = reader.current(); return false; } @@ -574,14 +582,15 @@ struct _ndigits_s : token_base<_ndigits_s> auto success = (((void)Idx, lexy::try_match_token(Sep{}, reader), lexy::try_match_token(digit, reader)) && ...); - end = reader.position(); + end = reader.current(); return success; } template constexpr void report_error(Context& context, const Reader&) { - auto err = lexy::error(end, Base::char_class_name()); + auto err = lexy::error(end.position(), + Base::char_class_name()); context.on(_ev::error{}, err); } }; @@ -597,22 +606,23 @@ struct _ndigits : token_base<_ndigits> template struct tp> { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { // Match the Base N times. auto success = (((void)Idx, lexy::try_match_token(digit, reader)) && ...); - end = reader.position(); + end = reader.current(); return success; } template constexpr void report_error(Context& context, const Reader&) { - auto err = lexy::error(end, Base::char_class_name()); + auto err = lexy::error(end.position(), + Base::char_class_name()); context.on(_ev::error{}, err); } }; diff --git a/3rdparty/lexy/include/lexy/dsl/eof.hpp b/3rdparty/lexy/include/lexy/dsl/eof.hpp index 3c934357e..beb96cb97 100644 --- a/3rdparty/lexy/include/lexy/dsl/eof.hpp +++ b/3rdparty/lexy/include/lexy/dsl/eof.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_EOF_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/error.hpp b/3rdparty/lexy/include/lexy/dsl/error.hpp index 341e26f7d..7be4fac65 100644 --- a/3rdparty/lexy/include/lexy/dsl/error.hpp +++ b/3rdparty/lexy/include/lexy/dsl/error.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_ERROR_HPP_INCLUDED @@ -10,6 +10,14 @@ namespace lexyd { +template +struct _err_production +{ + static constexpr auto name = ""; + static constexpr auto max_recursion_depth = 0; + static constexpr auto rule = Rule{}; +}; + template struct _err : unconditional_branch_base { @@ -23,9 +31,17 @@ struct _err : unconditional_branch_base auto end = reader.position(); if constexpr (!std::is_same_v) { - lexy::token_parser_for parser(reader); - parser.try_parse(reader); - end = parser.end; + auto backtrack = reader.current(); + + // We match a dummy production that only consists of the rule. + lexy::do_action< + _err_production, + lexy::match_action::template result_type>(lexy::_mh(), + context.control_block + ->parse_state, + reader); + end = reader.position(); + reader.reset(LEXY_MOV(backtrack)); } auto err = lexy::error(begin, end); @@ -102,7 +118,7 @@ struct _must_dsl template constexpr auto must(Branch) { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Branch, "must()"); static_assert(!lexy::is_unconditional_branch_rule); return _must_dsl{}; } diff --git a/3rdparty/lexy/include/lexy/dsl/expression.hpp b/3rdparty/lexy/include/lexy/dsl/expression.hpp index 0b8fe505e..a7d4f94fa 100644 --- a/3rdparty/lexy/include/lexy/dsl/expression.hpp +++ b/3rdparty/lexy/include/lexy/dsl/expression.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_EXPRESSION_HPP_INCLUDED @@ -197,7 +197,7 @@ struct operation_list (void)((cur_idx <= op.idx && op.idx < cur_idx + op_of::op_literals::size ? (result = Continuation::parse(context, reader, - parsed_operator{op.pos, + parsed_operator{op.cur, op.idx - cur_idx}, LEXY_FWD(args)...), true) @@ -309,7 +309,7 @@ struct _expr : rule_base if (op.idx >= op_rule::op_literals::size) { // The list ends at this point. - reader.set_position(op.pos); + reader.reset(op.cur); break; } @@ -381,10 +381,11 @@ struct _expr : rule_base if (op.idx < op_rule::op_literals::size) { using tag = typename Context::production::operator_chain_error; - auto err = lexy::error(op.pos, reader.position()); + auto err + = lexy::error(op.cur.position(), reader.position()); context.on(_ev::error{}, err); } - reader.set_position(op.pos); + reader.reset(op.cur); } } else if constexpr (binding_power.is_postfix()) @@ -416,11 +417,11 @@ struct _expr : rule_base if (state.cur_nesting_level++ >= production::max_operator_nesting) { using tag = typename production::operator_nesting_error; - auto err = lexy::error(op.pos, reader.position()); + auto err = lexy::error(op.cur.position(), reader.position()); context.on(_ev::error{}, err); // We do not recover, to prevent stack overflow. - reader.set_position(op.pos); + reader.reset(op.cur); return false; } @@ -437,7 +438,7 @@ struct _expr : rule_base { // Operators can't be grouped. using tag = typename production::operator_group_error; - auto err = lexy::error(op.pos, reader.position()); + auto err = lexy::error(op.cur.position(), reader.position()); context.on(_ev::error{}, err); // Trivially recover, but don't update group: // let the first one stick. @@ -470,11 +471,11 @@ struct _expr : rule_base if (op.idx >= op_list::ops::size) { // We don't have a prefix operator, so it must be an atom. - reader.set_position(op.pos); + reader.reset(op.cur); return atom_parser::parse(context, reader); } - auto start_event = context.on(_ev::operation_chain_start{}, op.pos); + auto start_event = context.on(_ev::operation_chain_start{}, op.cur.position()); auto result = op_list::template apply<_continuation>(context, reader, op, state); context.on(_ev::operation_chain_finish{}, LEXY_MOV(start_event), reader.position()); return result; @@ -507,7 +508,7 @@ struct _expr : rule_base auto op = parse_operator(reader); if (op.idx >= op_list::ops::size) { - reader.set_position(op.pos); + reader.reset(op.cur); break; } diff --git a/3rdparty/lexy/include/lexy/dsl/flags.hpp b/3rdparty/lexy/include/lexy/dsl/flags.hpp index a86f7410a..51cd1f948 100644 --- a/3rdparty/lexy/include/lexy/dsl/flags.hpp +++ b/3rdparty/lexy/include/lexy/dsl/flags.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_FLAGS_HPP_INCLUDED @@ -126,9 +126,15 @@ struct _flag : rule_base template constexpr auto flag(Rule) { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Rule, "flag()"); return _flag{}; } + +template +constexpr auto flag(Rule rule) +{ + return flag(rule); +} } // namespace lexyd #endif // LEXY_DSL_FLAGS_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/follow.hpp b/3rdparty/lexy/include/lexy/dsl/follow.hpp index 38abd3539..9d47e09dd 100644 --- a/3rdparty/lexy/include/lexy/dsl/follow.hpp +++ b/3rdparty/lexy/include/lexy/dsl/follow.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_FOLLOW_HPP_INCLUDED @@ -49,11 +49,11 @@ struct _nf : token_base<_nf>, _lit_base struct tp { lexy::token_parser_for impl; - typename Reader::iterator end; + typename Reader::marker end; bool literal_success; constexpr explicit tp(const Reader& reader) - : impl(reader), end(reader.position()), literal_success(false) + : impl(reader), end(reader.current()), literal_success(false) {} constexpr bool try_parse(Reader reader) @@ -67,7 +67,7 @@ struct _nf : token_base<_nf>, _lit_base literal_success = true; // To match, we must not match the char class now. - reader.set_position(end); + reader.reset(end); if constexpr (std::is_void_v) { return !lexy::try_match_token(CharClass{}, reader); @@ -88,7 +88,8 @@ struct _nf : token_base<_nf>, _lit_base } else { - auto err = lexy::error(end, end); + auto err + = lexy::error(end.position(), end.position()); context.on(_ev::error{}, err); } } diff --git a/3rdparty/lexy/include/lexy/dsl/identifier.hpp b/3rdparty/lexy/include/lexy/dsl/identifier.hpp index b388a7bc3..1b780f00f 100644 --- a/3rdparty/lexy/include/lexy/dsl/identifier.hpp +++ b/3rdparty/lexy/include/lexy/dsl/identifier.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_IDENTIFIER_HPP_INCLUDED @@ -36,12 +36,14 @@ struct _idp : token_base<_idp> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { + static_assert(lexy::is_char_encoding); + // Need to match Leading character. if (!lexy::try_match_token(Leading{}, reader)) return false; @@ -61,7 +63,7 @@ struct _idp : token_base<_idp> break; } - end = reader.position(); + end = reader.current(); return true; } @@ -170,7 +172,7 @@ struct _id : branch_base template struct bp { - typename Reader::iterator end; + typename Reader::marker end; constexpr bool try_parse(const void*, const Reader& reader) { @@ -181,7 +183,8 @@ struct _id : branch_base end = parser.end; // We only succeed if it's not a reserved identifier. - [[maybe_unused]] auto input = lexy::partial_input(reader, reader.position(), end); + [[maybe_unused]] auto input + = lexy::partial_input(reader, reader.position(), end.position()); return !(ReservedPredicate::is_reserved(input) || ...); } @@ -194,12 +197,12 @@ struct _id : branch_base { auto begin = reader.position(); - context.on(_ev::token{}, lexy::identifier_token_kind, begin, end); - reader.set_position(end); + context.on(_ev::token{}, lexy::identifier_token_kind, begin, end.position()); + reader.reset(end); using continuation = lexy::whitespace_parser; return continuation::parse(context, reader, LEXY_FWD(args)..., - lexy::lexeme(begin, end)); + lexy::lexeme(begin, end.position())); } }; @@ -341,16 +344,16 @@ struct _kw : token_base<_kw>, _lit_base template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { // Need to match the literal. if (!lexy::_detail::match_literal<0, CharT, C...>(reader)) return false; - end = reader.position(); + end = reader.current(); // To qualify as a keyword, and not just the prefix of an identifier, // we must not have a trailing identifier character. diff --git a/3rdparty/lexy/include/lexy/dsl/if.hpp b/3rdparty/lexy/include/lexy/dsl/if.hpp index 48889a679..ff4f1d4a0 100644 --- a/3rdparty/lexy/include/lexy/dsl/if.hpp +++ b/3rdparty/lexy/include/lexy/dsl/if.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_IF_HPP_INCLUDED @@ -36,7 +36,7 @@ struct _if : rule_base template constexpr auto if_(Branch) { - static_assert(lexy::is_branch_rule, "if_() requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(Branch, "if()"); if constexpr (lexy::is_unconditional_branch_rule) // Branch is always taken, so don't wrap in if_(). return Branch{}; diff --git a/3rdparty/lexy/include/lexy/dsl/integer.hpp b/3rdparty/lexy/include/lexy/dsl/integer.hpp index 435f2adec..95475fa0c 100644 --- a/3rdparty/lexy/include/lexy/dsl/integer.hpp +++ b/3rdparty/lexy/include/lexy/dsl/integer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_INTEGER_HPP_INCLUDED @@ -414,7 +414,7 @@ struct _int : _copy_base template struct bp { - typename Reader::iterator end; + typename Reader::marker end; constexpr auto try_parse(const void*, const Reader& reader) { @@ -432,10 +432,11 @@ struct _int : _copy_base LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { auto begin = reader.position(); - context.on(_ev::token{}, Token{}, begin, end); - reader.set_position(end); + context.on(_ev::token{}, Token{}, begin, end.position()); + reader.reset(end); - return _pc::parse(context, reader, begin, end, LEXY_FWD(args)...); + return _pc::parse(context, reader, begin, end.position(), + LEXY_FWD(args)...); } }; @@ -448,17 +449,19 @@ struct _int : _copy_base auto begin = reader.position(); if (lexy::token_parser_for parser(reader); parser.try_parse(reader)) { - context.on(_ev::token{}, typename Token::token_type{}, begin, parser.end); - reader.set_position(parser.end); + context.on(_ev::token{}, typename Token::token_type{}, begin, + parser.end.position()); + reader.reset(parser.end); } else { parser.report_error(context, reader); - reader.set_position(parser.end); + reader.reset(parser.end); // To recover we try and skip additional digits. while (lexy::try_match_token(digit, reader)) - {} + { + } auto recovery_end = reader.position(); if (begin == recovery_end) diff --git a/3rdparty/lexy/include/lexy/dsl/list.hpp b/3rdparty/lexy/include/lexy/dsl/list.hpp index 861d93177..25b85076d 100644 --- a/3rdparty/lexy/include/lexy/dsl/list.hpp +++ b/3rdparty/lexy/include/lexy/dsl/list.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_LIST_HPP_INCLUDED @@ -132,8 +132,7 @@ struct _lst : _copy_base template constexpr auto list(Item) { - static_assert(lexy::is_branch_rule, - "list() without a separator requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(Item, "list() without a separator"); return _lst{}; } @@ -148,8 +147,7 @@ constexpr auto list(Item, _sep) template constexpr auto list(Item, _tsep) { - static_assert(lexy::is_branch_rule, - "list() without a trailing separator requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(Item, "list() with a trailing separator"); return _lst>{}; } diff --git a/3rdparty/lexy/include/lexy/dsl/literal.hpp b/3rdparty/lexy/include/lexy/dsl/literal.hpp index 4fc1b6066..adc2cf599 100644 --- a/3rdparty/lexy/include/lexy/dsl/literal.hpp +++ b/3rdparty/lexy/include/lexy/dsl/literal.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_LITERAL_HPP_INCLUDED @@ -18,6 +18,7 @@ namespace lexy::_detail template constexpr auto match_literal(Reader& reader) { + static_assert(lexy::is_char_encoding); using char_type = typename Reader::encoding::char_type; if constexpr (CurCharIndex >= sizeof...(Cs)) { @@ -184,11 +185,11 @@ struct _merge_case_folding typename H::lit_case_folding, CurrentCaseFolding>, T...> { - static_assert( - std::is_same_v // - || std::is_void_v || std::is_void_v, - "cannot mix literals with different case foldings in a literal_set"); + static_assert(std::is_same_v // + || std::is_void_v + || std::is_void_v, + "cannot mix literals with different case foldings in a literal_set"); }; template @@ -272,7 +273,7 @@ struct lit_trie_matcher if constexpr (sizeof...(Idx) > 0) { - auto cur_pos = reader.position(); + auto cur = reader.current(); auto cur_char = reader.peek(); auto next_value = Trie.node_no_match; @@ -283,7 +284,7 @@ struct lit_trie_matcher return next_value; // We haven't found a longer match, return our match. - reader.set_position(cur_pos); + reader.reset(cur); } // But first, we might need to check that we don't match that nodes char class. @@ -305,6 +306,7 @@ struct lit_trie_matcher template LEXY_FORCE_INLINE static constexpr std::size_t try_match(Reader& _reader) { + static_assert(lexy::is_char_encoding); if constexpr (std::is_same_v, Reader>) { return _impl<>::try_match(_reader); @@ -313,7 +315,7 @@ struct lit_trie_matcher { CaseFolding reader{_reader}; auto result = _impl<>::try_match(reader); - _reader.set_position(reader.position()); + _reader.reset(reader.current()); return result; } } @@ -350,14 +352,14 @@ struct _lit template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr auto try_parse(Reader reader) { auto result = lexy::_detail::match_literal<0, CharT, C...>(reader); - end = reader.position(); + end = reader.current(); return result; } @@ -368,7 +370,7 @@ struct _lit constexpr auto str = lexy::_detail::type_string::template c_str; auto begin = reader.position(); - auto index = lexy::_detail::range_size(begin, this->end); + auto index = lexy::_detail::range_size(begin, end.position()); auto err = lexy::error(begin, str, index, sizeof...(C)); context.on(_ev::error{}, err); } @@ -445,9 +447,9 @@ struct _lcp : token_base<_lcp>, _lit_base template struct tp> { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { @@ -455,7 +457,7 @@ struct _lcp : token_base<_lcp>, _lit_base auto result = lexy::_detail::match_literal<0, typename encoding::char_type, _string.data[Idx]...>(reader); - end = reader.position(); + end = reader.current(); return result; } @@ -465,7 +467,7 @@ struct _lcp : token_base<_lcp>, _lit_base using encoding = typename Reader::encoding; auto begin = reader.position(); - auto index = lexy::_detail::range_size(begin, end); + auto index = lexy::_detail::range_size(begin, end.position()); auto err = lexy::error(begin, _string.data, index, _string.length); context.on(_ev::error{}, err); @@ -537,9 +539,9 @@ struct _lset : token_base<_lset>, _lset_base template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { @@ -547,7 +549,7 @@ struct _lset : token_base<_lset>, _lset_base using matcher = lexy::_detail::lit_trie_matcher<_t, 0>; auto result = matcher::try_match(reader); - end = reader.position(); + end = reader.current(); return result != _t.node_no_match; } diff --git a/3rdparty/lexy/include/lexy/dsl/lookahead.hpp b/3rdparty/lexy/include/lexy/dsl/lookahead.hpp index 37c69d611..3ee995a18 100644 --- a/3rdparty/lexy/include/lexy/dsl/lookahead.hpp +++ b/3rdparty/lexy/include/lexy/dsl/lookahead.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_LOOKAHEAD_HPP_INCLUDED @@ -50,6 +50,8 @@ struct _look : branch_base template struct bp { + static_assert(lexy::is_char_encoding); + typename Reader::iterator begin; typename Reader::iterator end; @@ -102,6 +104,7 @@ struct _look : branch_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { + static_assert(lexy::is_char_encoding); bp impl{}; if (!impl.try_parse(context.control_block, reader)) { diff --git a/3rdparty/lexy/include/lexy/dsl/loop.hpp b/3rdparty/lexy/include/lexy/dsl/loop.hpp index 68a433ff2..e7988d270 100644 --- a/3rdparty/lexy/include/lexy/dsl/loop.hpp +++ b/3rdparty/lexy/include/lexy/dsl/loop.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_LOOP_HPP_INCLUDED @@ -94,7 +94,7 @@ struct _whl : rule_base template constexpr auto while_(Rule) { - static_assert(lexy::is_branch_rule, "while() requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(Rule, "while()"); return _whl{}; } } // namespace lexyd @@ -105,7 +105,7 @@ namespace lexyd template constexpr auto while_one(Rule rule) { - static_assert(lexy::is_branch_rule, "while_one() requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(Rule, "while_one()"); return rule >> while_(rule); } } // namespace lexyd diff --git a/3rdparty/lexy/include/lexy/dsl/member.hpp b/3rdparty/lexy/include/lexy/dsl/member.hpp index afc6bf3e5..a478ef2dd 100644 --- a/3rdparty/lexy/include/lexy/dsl/member.hpp +++ b/3rdparty/lexy/include/lexy/dsl/member.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_MEMBER_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/newline.hpp b/3rdparty/lexy/include/lexy/dsl/newline.hpp index fc34556c7..24078f032 100644 --- a/3rdparty/lexy/include/lexy/dsl/newline.hpp +++ b/3rdparty/lexy/include/lexy/dsl/newline.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_NEWLINE_HPP_INCLUDED @@ -36,6 +36,8 @@ struct _eol : branch_base template struct bp { + static_assert(lexy::is_char_encoding); + constexpr bool try_parse(const void*, Reader reader) { return reader.peek() == Reader::encoding::eof() @@ -70,6 +72,7 @@ struct _eol : branch_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { + static_assert(lexy::is_char_encoding); return bp{}.template finish(context, reader, LEXY_FWD(args)...); } }; diff --git a/3rdparty/lexy/include/lexy/dsl/operator.hpp b/3rdparty/lexy/include/lexy/dsl/operator.hpp index b992e31df..188ebf19a 100644 --- a/3rdparty/lexy/include/lexy/dsl/operator.hpp +++ b/3rdparty/lexy/include/lexy/dsl/operator.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_OPERATOR_HPP_INCLUDED @@ -75,8 +75,8 @@ struct op_lit_list template struct parsed_operator { - typename Reader::iterator pos; - std::size_t idx; + typename Reader::marker cur; + std::size_t idx; }; template @@ -85,7 +85,7 @@ constexpr auto parse_operator(Reader& reader) using encoding = typename Reader::encoding; using op_matcher = lexy::_detail::lit_trie_matcher, 0>; - auto begin = reader.position(); + auto begin = reader.current(); auto op = op_matcher::try_match(reader); return parsed_operator{begin, op}; } @@ -96,6 +96,11 @@ namespace lexyd template using _detect_op_tag_ctor = decltype(Tag(LEXY_DECLVAL(Reader).position())); +template +using _detect_op_tag_ctor_with_state + = decltype(Tag(*LEXY_DECLVAL(Context).control_block->parse_state, + LEXY_DECLVAL(Reader).position())); + template struct _op : branch_base { @@ -107,15 +112,20 @@ struct _op : branch_base lexy::_detail::parsed_operator op, Args&&... args) { - context.on(_ev::token{}, typename Literal::token_type{}, op.pos, reader.position()); + context.on(_ev::token{}, typename Literal::token_type{}, op.cur.position(), + reader.position()); using continuation = lexy::whitespace_parser, NextParser>>; if constexpr (std::is_void_v) return continuation::parse(context, reader, LEXY_FWD(args)...); + else if constexpr (lexy::_detail::is_detected<_detect_op_tag_ctor_with_state, op_tag_type, + Reader, Context>) + return continuation::parse(context, reader, LEXY_FWD(args)..., + op_tag_type(*context.control_block->parse_state, op.pos)); else if constexpr (lexy::_detail::is_detected<_detect_op_tag_ctor, op_tag_type, Reader>) return continuation::parse(context, reader, LEXY_FWD(args)..., - op_tag_type(reader.position())); + op_tag_type(op.cur.position())); else return continuation::parse(context, reader, LEXY_FWD(args)..., op_tag_type{}); } @@ -144,6 +154,12 @@ struct _op : branch_base if constexpr (std::is_void_v) return impl.template finish(context, reader, LEXY_FWD(args)...); + else if constexpr (lexy::_detail::is_detected<_detect_op_tag_ctor_with_state, + op_tag_type, Reader, Context>) + return impl + .template finish(context, reader, LEXY_FWD(args)..., + op_tag_type(*context.control_block->parse_state, + reader.position())); else if constexpr (lexy::_detail::is_detected<_detect_op_tag_ctor, op_tag_type, Reader>) return impl.template finish(context, reader, LEXY_FWD(args)..., op_tag_type(reader.position())); @@ -165,6 +181,10 @@ struct _op : branch_base = lexy::parser_for, NextParser>>; if constexpr (std::is_void_v) return continuation::parse(context, reader, LEXY_FWD(args)...); + else if constexpr (lexy::_detail::is_detected<_detect_op_tag_ctor_with_state, + op_tag_type, Reader, Context>) + return continuation::parse(context, reader, LEXY_FWD(args)..., + op_tag_type(*context.control_block->parse_state, pos)); else if constexpr (lexy::_detail::is_detected<_detect_op_tag_ctor, op_tag_type, Reader>) return continuation::parse(context, reader, LEXY_FWD(args)..., op_tag_type(pos)); else @@ -246,12 +266,12 @@ struct _opc : branch_base struct bp { lexy::_detail::parsed_operator op; - typename Reader::iterator end; + typename Reader::marker end; constexpr auto try_parse(const void*, Reader reader) { op = lexy::_detail::parse_operator(reader); - end = reader.position(); + end = reader.current(); return op.idx < op_literals::size; } @@ -262,7 +282,7 @@ struct _opc : branch_base template LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { - reader.set_position(end); + reader.reset(end); return op_finish(context, reader, op, LEXY_FWD(args)...); } }; @@ -276,7 +296,7 @@ struct _opc : branch_base bp impl{}; if (!impl.try_parse(context.control_block, reader)) { - auto err = lexy::error(impl.op.pos); + auto err = lexy::error(impl.op.cur.position()); context.on(_ev::error{}, err); return false; } @@ -311,4 +331,3 @@ constexpr auto operator/(_opc, _opc) } // namespace lexyd #endif // LEXY_DSL_OPERATOR_HPP_INCLUDED - diff --git a/3rdparty/lexy/include/lexy/dsl/option.hpp b/3rdparty/lexy/include/lexy/dsl/option.hpp index 9ef1f7cc0..0ba0c7404 100644 --- a/3rdparty/lexy/include/lexy/dsl/option.hpp +++ b/3rdparty/lexy/include/lexy/dsl/option.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_OPTION_HPP_INCLUDED @@ -80,7 +80,7 @@ struct _opt : rule_base template constexpr auto opt(Rule) { - static_assert(lexy::is_branch_rule, "opt() requires a branch condition"); + LEXY_REQUIRE_BRANCH_RULE(Rule, "opt()"); if constexpr (lexy::is_unconditional_branch_rule) // Branch is always taken, so don't wrap in opt(). return Rule{}; diff --git a/3rdparty/lexy/include/lexy/dsl/parse_as.hpp b/3rdparty/lexy/include/lexy/dsl/parse_as.hpp index 27e8e161a..4efdde15a 100644 --- a/3rdparty/lexy/include/lexy/dsl/parse_as.hpp +++ b/3rdparty/lexy/include/lexy/dsl/parse_as.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_PARSE_AS_HPP_INCLUDED @@ -11,7 +11,7 @@ namespace lexyd { // Custom handler that forwards events but overrides the value callback. -template +template struct _pas_handler { Handler& _handler; @@ -26,31 +26,38 @@ struct _pas_handler return static_cast(_handler); } - // For child productions, use ::value to get a value. + // We use ::value to get a value. + // We can't use it unconditionally, as the initial production that contains the parse_as might + // not have one. So we silently fallback if that's the case - this might cause worse errors if + // the value is missing. template - struct value_callback : lexy::production_value_callback - { - using lexy::production_value_callback::production_value_callback; - }; - // For the production that contains parse_as, use lexy::construct. - template - struct value_callback : lexy::_construct + using value_callback + = std::conditional_t, + lexy::production_value_callback, + lexy::_detail::void_value_callback>; +}; + +struct _pas_final_parser +{ + template + LEXY_PARSER_FUNC static bool parse(Context&, Reader&, lexy::_detail::lazy_init& value, + Args&&... args) { - constexpr value_callback() = default; - constexpr value_callback(State*) {} - }; + value.emplace_result(lexy::construct, LEXY_FWD(args)...); + return true; + } }; -template +template constexpr auto _make_pas_handler(Handler& handler) { - return _pas_handler{handler}; + return _pas_handler{handler}; } // Prevent infinite nesting when parse_as itself is recursive. -template -constexpr auto _make_pas_handler(_pas_handler& handler) +template +constexpr auto _make_pas_handler(_pas_handler& handler) { - return _pas_handler{handler._handler}; + return handler; } template @@ -77,18 +84,20 @@ struct _pas : _copy_base template LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { - auto handler = _make_pas_handler( - context.control_block->parse_handler); + auto handler = _make_pas_handler(context.control_block->parse_handler); lexy::_detail::parse_context_control_block cb(LEXY_MOV(handler), context.control_block); using context_type = lexy::_pc; context_type sub_context(&cb); + sub_context.handler = LEXY_MOV(context).handler; - auto result - = rule_parser.template finish(sub_context, reader); + lexy::_detail::lazy_init value; + auto result + = rule_parser.template finish<_pas_final_parser>(sub_context, reader, value); context.control_block->copy_vars_from(&cb); + context.handler = LEXY_MOV(sub_context).handler; if (!result) return false; @@ -96,11 +105,9 @@ struct _pas : _copy_base // NOLINTNEXTLINE: clang-tidy wrongly thinks the branch is repeated. return NextParser::parse(context, reader, LEXY_FWD(args)...); else if constexpr (Front) - return NextParser::parse(context, reader, *LEXY_MOV(sub_context.value), - LEXY_FWD(args)...); + return NextParser::parse(context, reader, *LEXY_MOV(value), LEXY_FWD(args)...); else - return NextParser::parse(context, reader, LEXY_FWD(args)..., - *LEXY_MOV(sub_context.value)); + return NextParser::parse(context, reader, LEXY_FWD(args)..., *LEXY_MOV(value)); } }; @@ -110,18 +117,20 @@ struct _pas : _copy_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { - auto handler = _make_pas_handler( - context.control_block->parse_handler); + auto handler = _make_pas_handler(context.control_block->parse_handler); lexy::_detail::parse_context_control_block cb(LEXY_MOV(handler), context.control_block); using context_type = lexy::_pc; context_type sub_context(&cb); + sub_context.handler = LEXY_MOV(context).handler; - auto result - = lexy::parser_for::parse(sub_context, reader); + lexy::_detail::lazy_init value; + auto result + = lexy::parser_for::parse(sub_context, reader, value); context.control_block->copy_vars_from(&cb); + context.handler = LEXY_MOV(sub_context).handler; if (!result) return false; @@ -129,11 +138,9 @@ struct _pas : _copy_base // NOLINTNEXTLINE: clang-tidy wrongly thinks the branch is repeated. return NextParser::parse(context, reader, LEXY_FWD(args)...); else if constexpr (Front) - return NextParser::parse(context, reader, *LEXY_MOV(sub_context.value), - LEXY_FWD(args)...); + return NextParser::parse(context, reader, *LEXY_MOV(value), LEXY_FWD(args)...); else - return NextParser::parse(context, reader, LEXY_FWD(args)..., - *LEXY_MOV(sub_context.value)); + return NextParser::parse(context, reader, LEXY_FWD(args)..., *LEXY_MOV(value)); } }; }; diff --git a/3rdparty/lexy/include/lexy/dsl/parse_tree_node.hpp b/3rdparty/lexy/include/lexy/dsl/parse_tree_node.hpp new file mode 100644 index 000000000..c8aff2505 --- /dev/null +++ b/3rdparty/lexy/include/lexy/dsl/parse_tree_node.hpp @@ -0,0 +1,251 @@ +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors +// SPDX-License-Identifier: BSL-1.0 + +#ifndef LEXY_DSL_PARSE_TREE_NODE_HPP_INCLUDED +#define LEXY_DSL_PARSE_TREE_NODE_HPP_INCLUDED + +#include +#include + +#if !LEXY_EXPERIMENTAL +# error "lexy::dsl::tnode/pnode are experimental" +#endif + +//=== impl ===// +namespace lexyd +{ +template +struct _n; + +template +struct _nr : branch_base +{ + template + struct _cont + { + template + LEXY_PARSER_FUNC static bool parse(Context& context, ChildReader& child_reader, + bool& rule_succeded, Reader& reader, Args&&... args) + { + rule_succeded = true; + + if (child_reader.peek() != ChildReader::encoding::eof()) + { + auto begin = child_reader.position(); + auto end = reader.position(); + context.on(_ev::token{}, lexy::error_token_kind, begin, end); + + auto err = lexy::error(begin, end); + context.on(_ev::error{}, err); + } + + return lexy::whitespace_parser::parse(context, reader, + LEXY_FWD(args)...); + } + }; + + template + LEXY_PARSER_FUNC static bool _parse_rule(Context& context, Reader& reader, + typename Reader::marker end, Args&&... args) + { + auto child_reader = Derived::node_child_reader(reader); + reader.reset(end); + + using rule_parser + = lexy::whitespace_parser>>; + if (auto rule_succeded = false; + rule_parser::parse(context, child_reader, rule_succeded, reader, LEXY_FWD(args)...)) + { + return true; + } + else + { + if (!rule_succeded) + // Report an error token for the child span that wasn't able to be parsed. + context.on(_ev::token{}, lexy::error_token_kind, child_reader.position(), + end.position()); + return false; + } + } + + template + struct bp + { + typename Reader::marker end; + + constexpr bool try_parse(const void*, const Reader& reader) + { + lexy::token_parser_for<_n, Reader> parser(reader); + auto result = parser.try_parse(reader); + end = parser.end; + return result; + } + + template + constexpr void cancel(Context&) + {} + + template + LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) + { + return _parse_rule(context, reader, end, LEXY_FWD(args)...); + } + }; + + template + struct p + { + template + LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) + { + lexy::token_parser_for<_n, Reader> parser(reader); + if (!parser.try_parse(reader)) + { + LEXY_ASSERT(parser.end.position() == reader.position(), "impl should be LL(1)"); + parser.report_error(context, reader); + return false; + } + + return _parse_rule(context, reader, parser.end, LEXY_FWD(args)...); + } + }; +}; + +template +struct _n : token_base +{ + template + struct tp + { + typename Reader::marker end; + + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} + + constexpr auto try_parse(Reader reader) + { + if constexpr (lexy::is_node_encoding) + { + if (!Reader::encoding::match(reader.peek(), Derived::node_kind())) + return false; + + reader.bump(); + end = reader.current(); + return true; + } + else + { + // This happens when it is used as whitespace, which is inherited while parsing the + // token lexeme, we don't match anything in that case. + return std::false_type{}; + } + } + + template + constexpr void report_error(Context& context, Reader reader) + { + constexpr auto name = Derived::node_kind_name(); + + auto err = lexy::error(reader.position(), name); + context.on(_ev::error{}, err); + } + }; + + template + constexpr auto operator()(Rule) const + { + return _nr{}; + } +}; +} // namespace lexyd + +//=== dsl::tnode ===// +namespace lexy +{ +struct expected_token_end +{ + static LEXY_CONSTEVAL auto name() + { + return "expected token end"; + } +}; +} // namespace lexy + +namespace lexyd +{ +template +struct _tn : _n<_tn> +{ + static LEXY_CONSTEVAL auto node_kind() + { + return Kind; + } + + static LEXY_CONSTEVAL auto node_kind_name() + { + using lexy::token_kind_name; + return token_kind_name(Kind); + } + + using node_end_error = lexy::expected_token_end; + + template + static constexpr auto node_child_reader(Reader& reader) + { + return reader.lexeme_reader(); + } +}; + +template +constexpr auto tnode = _tn{}; +} // namespace lexyd + +namespace lexy +{ +template +constexpr auto token_kind_of> = Kind; +} // namespace lexy + +//=== dsl::pnode ===// +namespace lexy +{ +struct expected_production_end +{ + static LEXY_CONSTEVAL auto name() + { + return "expected production end"; + } +}; +} // namespace lexy + +namespace lexyd +{ +template +struct _pn : _n<_pn> +{ + static_assert(lexy::is_production); + + static LEXY_CONSTEVAL auto node_kind() + { + return Production{}; + } + + static LEXY_CONSTEVAL auto node_kind_name() + { + return lexy::production_name(); + } + + using node_end_error = lexy::expected_production_end; + + template + static constexpr auto node_child_reader(Reader& reader) + { + return reader.child_reader(); + } +}; + +template +constexpr auto pnode = _pn{}; +} // namespace lexyd + +#endif // LEXY_DSL_PARSE_TREE_NODE_HPP_INCLUDED + diff --git a/3rdparty/lexy/include/lexy/dsl/peek.hpp b/3rdparty/lexy/include/lexy/dsl/peek.hpp index 933521f8a..57b3576b8 100644 --- a/3rdparty/lexy/include/lexy/dsl/peek.hpp +++ b/3rdparty/lexy/include/lexy/dsl/peek.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_PEEK_HPP_INCLUDED @@ -37,7 +37,7 @@ struct _peek : branch_base struct bp { typename Reader::iterator begin; - typename Reader::iterator end; + typename Reader::marker end; constexpr bool try_parse(const void*, Reader reader) { @@ -54,13 +54,13 @@ struct _peek : branch_base template constexpr void cancel(Context& context) { - context.on(_ev::backtracked{}, begin, end); + context.on(_ev::backtracked{}, begin, end.position()); } template LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { - context.on(_ev::backtracked{}, begin, end); + context.on(_ev::backtracked{}, begin, end.position()); return NextParser::parse(context, reader, LEXY_FWD(args)...); } }; @@ -76,13 +76,13 @@ struct _peek : branch_base { // Report that we've failed. using tag = lexy::_detail::type_or; - auto err = lexy::error(impl.begin, impl.end); + auto err = lexy::error(impl.begin, impl.end.position()); context.on(_ev::error{}, err); // But recover immediately, as we wouldn't have consumed anything either way. } - context.on(_ev::backtracked{}, impl.begin, impl.end); + context.on(_ev::backtracked{}, impl.begin, impl.end.position()); return NextParser::parse(context, reader, LEXY_FWD(args)...); } }; @@ -98,7 +98,7 @@ struct _peekn : branch_base struct bp { typename Reader::iterator begin; - typename Reader::iterator end; + typename Reader::marker end; constexpr bool try_parse(const void*, Reader reader) { @@ -115,13 +115,13 @@ struct _peekn : branch_base template constexpr void cancel(Context& context) { - context.on(_ev::backtracked{}, begin, end); + context.on(_ev::backtracked{}, begin, end.position()); } template LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { - context.on(_ev::backtracked{}, begin, end); + context.on(_ev::backtracked{}, begin, end.position()); return NextParser::parse(context, reader, LEXY_FWD(args)...); } }; @@ -137,20 +137,20 @@ struct _peekn : branch_base { // Report that we've failed. using tag = lexy::_detail::type_or; - auto err = lexy::error(impl.begin, impl.end); + auto err = lexy::error(impl.begin, impl.end.position()); context.on(_ev::error{}, err); // And recover by consuming the input. context.on(_ev::recovery_start{}, impl.begin); - context.on(_ev::token{}, lexy::error_token_kind, impl.begin, impl.end); - context.on(_ev::recovery_finish{}, impl.end); + context.on(_ev::token{}, lexy::error_token_kind, impl.begin, impl.end.position()); + context.on(_ev::recovery_finish{}, impl.end.position()); - reader.set_position(impl.end); + reader.reset(impl.end); return NextParser::parse(context, reader, LEXY_FWD(args)...); } else { - context.on(_ev::backtracked{}, impl.begin, impl.end); + context.on(_ev::backtracked{}, impl.begin, impl.end.position()); return NextParser::parse(context, reader, LEXY_FWD(args)...); } } diff --git a/3rdparty/lexy/include/lexy/dsl/position.hpp b/3rdparty/lexy/include/lexy/dsl/position.hpp index b1ab70232..088187bf9 100644 --- a/3rdparty/lexy/include/lexy/dsl/position.hpp +++ b/3rdparty/lexy/include/lexy/dsl/position.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_POSITION_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/production.hpp b/3rdparty/lexy/include/lexy/dsl/production.hpp index 225b55bd2..ba74de2a7 100644 --- a/3rdparty/lexy/include/lexy/dsl/production.hpp +++ b/3rdparty/lexy/include/lexy/dsl/production.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_PRODUCTION_HPP_INCLUDED @@ -179,7 +179,7 @@ struct _recb : branch_base template struct bp { - static_assert(lexy::is_branch_rule>); + LEXY_REQUIRE_BRANCH_RULE(lexy::production_rule, "recurse_branch"); using impl = lexy::branch_parser_for<_prd, Reader>; impl _impl; diff --git a/3rdparty/lexy/include/lexy/dsl/punctuator.hpp b/3rdparty/lexy/include/lexy/dsl/punctuator.hpp index 9e1937a7c..e53f7b0f2 100644 --- a/3rdparty/lexy/include/lexy/dsl/punctuator.hpp +++ b/3rdparty/lexy/include/lexy/dsl/punctuator.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_PUNCTUATOR_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/recover.hpp b/3rdparty/lexy/include/lexy/dsl/recover.hpp index 0a31ae659..208d8c409 100644 --- a/3rdparty/lexy/include/lexy/dsl/recover.hpp +++ b/3rdparty/lexy/include/lexy/dsl/recover.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_RECOVER_HPP_INCLUDED @@ -38,17 +38,24 @@ struct _recovery_wrapper : _recovery_base LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { context.on(_ev::recovery_start{}, reader.position()); - auto recovery_finished = false; - auto result - = lexy::parser_for::parse(context, reader, recovery_finished, - LEXY_FWD(args)...); + + // As part of the recovery, we parse the rule and whitespace. + using parser = lexy::parser_for>; + auto result = parser::parse(context, reader, recovery_finished, LEXY_FWD(args)...); + if (!recovery_finished) context.on(_ev::recovery_cancel{}, reader.position()); return result; } }; }; + +struct _noop_recovery : rule_base +{ + template + using p = NextParser; +}; } // namespace lexyd namespace lexyd @@ -72,20 +79,20 @@ struct _find : _recovery_base context.on(_ev::recovery_start{}, begin); while (true) { - auto end = reader.position(); // *before* we've consumed Token/Limit + auto end = reader.current(); // *before* we've consumed Token/Limit auto result = matcher::try_match(reader); if (result == 0) { - context.on(_ev::token{}, lexy::error_token_kind, begin, end); - context.on(_ev::recovery_finish{}, end); - reader.set_position(end); // reset to before the token + context.on(_ev::token{}, lexy::error_token_kind, begin, end.position()); + context.on(_ev::recovery_finish{}, end.position()); + reader.reset(end); // reset to before the token return NextParser::parse(context, reader, LEXY_FWD(args)...); } else if (result == 1 || reader.peek() == Reader::encoding::eof()) { - context.on(_ev::token{}, lexy::error_token_kind, begin, end); - context.on(_ev::recovery_cancel{}, end); - reader.set_position(end); // reset to before the limit + context.on(_ev::token{}, lexy::error_token_kind, begin, end.position()); + context.on(_ev::recovery_cancel{}, end.position()); + reader.reset(end); // reset to before the limit return false; } else @@ -200,7 +207,7 @@ template constexpr auto recover(Branches...) { static_assert(sizeof...(Branches) > 0); - static_assert((lexy::is_branch_rule && ...)); + LEXY_REQUIRE_BRANCH_RULE(Branches..., "recover"); return _reco{}; } } // namespace lexyd @@ -231,13 +238,23 @@ struct _tryt : rule_base LEXY_PARSER_FUNC static bool recover(Context& context, Reader& reader, Args&&... args) { if constexpr (std::is_void_v) - return NextParser::parse(context, reader, LEXY_FWD(args)...); + { + using recovery_rule = _recovery_wrapper<_noop_recovery>; + return lexy::parser_for::parse(context, reader, + LEXY_FWD(args)...); + } else if constexpr (std::is_base_of_v<_recovery_base, Recover>) - return lexy::parser_for::parse(context, reader, - LEXY_FWD(args)...); + { + using recovery_rule = Recover; + return lexy::parser_for::parse(context, reader, + LEXY_FWD(args)...); + } else - return lexy::parser_for<_recovery_wrapper, - NextParser>::parse(context, reader, LEXY_FWD(args)...); + { + using recovery_rule = _recovery_wrapper; + return lexy::parser_for::parse(context, reader, + LEXY_FWD(args)...); + } } }; diff --git a/3rdparty/lexy/include/lexy/dsl/repeat.hpp b/3rdparty/lexy/include/lexy/dsl/repeat.hpp index 7321d54ad..bb41404b6 100644 --- a/3rdparty/lexy/include/lexy/dsl/repeat.hpp +++ b/3rdparty/lexy/include/lexy/dsl/repeat.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_REPEAT_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/return.hpp b/3rdparty/lexy/include/lexy/dsl/return.hpp index e3f7269ba..46477f6f0 100644 --- a/3rdparty/lexy/include/lexy/dsl/return.hpp +++ b/3rdparty/lexy/include/lexy/dsl/return.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_RETURN_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/scan.hpp b/3rdparty/lexy/include/lexy/dsl/scan.hpp index 313dd2d57..d630fd61c 100644 --- a/3rdparty/lexy/include/lexy/dsl/scan.hpp +++ b/3rdparty/lexy/include/lexy/dsl/scan.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_SCAN_HPP_INCLUDED @@ -18,7 +18,9 @@ struct _prd; template struct _peek; template -struct _capt; +struct _cap; +template +struct _capr; template struct _int_dsl; @@ -184,6 +186,10 @@ class scanner { return _reader.position(); } + constexpr auto current() const noexcept -> typename Reader::marker + { + return _reader.current(); + } constexpr auto remaining_input() const noexcept { @@ -228,7 +234,7 @@ class scanner template >> constexpr bool branch(scan_result& result, Rule) { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Rule, "branch"); if (_state == _state_failed) return false; @@ -323,6 +329,13 @@ class scanner context.on(parse_events::error{}, lexy::error(LEXY_FWD(args)...)); } + template + constexpr void error(const char* msg, Args&&... args) + { + auto& context = static_cast(*this).context(); + context.on(parse_events::error{}, lexy::error(LEXY_FWD(args)..., msg)); + } + template constexpr void fatal_error(Tag tag, Args&&... args) { @@ -330,6 +343,13 @@ class scanner _state = _state_failed; } + template + constexpr void fatal_error(const char* msg, Args&&... args) + { + error(msg, LEXY_FWD(args)...); + _state = _state_failed; + } + //=== convenience ===// template >> constexpr auto parse(Rule rule) @@ -361,25 +381,18 @@ class scanner return result; } - template - constexpr auto capture(Rule rule) -> scan_result> + template + constexpr auto capture(Token) { - static_assert(lexy::is_rule); - - auto begin = _reader.position(); - parse(rule); - auto end = _reader.position(); - - if (*this) - return lexeme(begin, end); - else - return scan_failed; + scan_result> result; + parse(result, lexyd::_cap{}); + return result; } - template - constexpr auto capture_token(Token) + template + constexpr auto capture(lexyd::_prd) { scan_result> result; - parse(result, lexyd::_capt{}); + parse(result, lexyd::_capr>{}); return result; } @@ -446,8 +459,9 @@ class rule_scanner : public _detail::scanner, Read namespace lexyd { -template -using _detect_scan_state = decltype(Context::production::scan(LEXY_DECLVAL(Scanner&), *StatePtr())); +template +using _detect_scan_state = decltype(Context::production::scan(LEXY_DECLVAL(Scanner&), *StatePtr(), + LEXY_DECLVAL(Args)...)); struct _scan : rule_base { @@ -458,16 +472,16 @@ struct _scan : rule_base LEXY_PARSER_FUNC static bool _parse(Scanner& scanner, Context& context, Reader& reader, Args&&... args) { - lexy::scan_result result = [&] { + typename Context::production::scan_result result = [&] { if constexpr (lexy::_detail::is_detected< _detect_scan_state, Context, decltype(scanner), - decltype(context.control_block->parse_state)>) + decltype(context.control_block->parse_state), Args&&...>) return Context::production::scan(scanner, *context.control_block->parse_state, LEXY_FWD(args)...); else return Context::production::scan(scanner, LEXY_FWD(args)...); }(); - reader.set_position(scanner.position()); + reader.reset(scanner.current()); if (!result) return false; diff --git a/3rdparty/lexy/include/lexy/dsl/separator.hpp b/3rdparty/lexy/include/lexy/dsl/separator.hpp index 175f7bf92..f50744d66 100644 --- a/3rdparty/lexy/include/lexy/dsl/separator.hpp +++ b/3rdparty/lexy/include/lexy/dsl/separator.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_SEPARATOR_HPP_INCLUDED @@ -90,7 +90,7 @@ struct _sep : _sep_base template constexpr auto sep(Branch) { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Branch, "sep"); return _sep{}; } @@ -110,7 +110,7 @@ struct _tsep : _sep_base template constexpr auto trailing_sep(Branch) { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Branch, "trailing_sep"); return _tsep{}; } diff --git a/3rdparty/lexy/include/lexy/dsl/sequence.hpp b/3rdparty/lexy/include/lexy/dsl/sequence.hpp index 02a098fa3..6715e7ae3 100644 --- a/3rdparty/lexy/include/lexy/dsl/sequence.hpp +++ b/3rdparty/lexy/include/lexy/dsl/sequence.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_SEQUENCE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/sign.hpp b/3rdparty/lexy/include/lexy/dsl/sign.hpp index c0178b275..5cf38de0d 100644 --- a/3rdparty/lexy/include/lexy/dsl/sign.hpp +++ b/3rdparty/lexy/include/lexy/dsl/sign.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_SIGN_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/subgrammar.hpp b/3rdparty/lexy/include/lexy/dsl/subgrammar.hpp index 9f4bbc97f..6a291dfc4 100644 --- a/3rdparty/lexy/include/lexy/dsl/subgrammar.hpp +++ b/3rdparty/lexy/include/lexy/dsl/subgrammar.hpp @@ -20,6 +20,9 @@ using _subgrammar_for = _subgrammar \ + constexpr auto production_has_value_callback = true; \ + \ template \ struct _subgrammar \ { \ @@ -104,4 +107,3 @@ constexpr auto subgrammar = _subg{}; } // namespace lexyd #endif // LEXY_DSL_SUBGRAMMAR_HPP_INCLUDED - diff --git a/3rdparty/lexy/include/lexy/dsl/symbol.hpp b/3rdparty/lexy/include/lexy/dsl/symbol.hpp index f8a58a9b1..f94511068 100644 --- a/3rdparty/lexy/include/lexy/dsl/symbol.hpp +++ b/3rdparty/lexy/include/lexy/dsl/symbol.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_SYMBOL_HPP_INCLUDED @@ -268,7 +268,8 @@ struct _sym : branch_base template struct bp { - typename Reader::iterator end; + static_assert(lexy::is_char_encoding); + typename Reader::marker end; typename LEXY_DECAY_DECLTYPE(Table)::key_index symbol; constexpr auto value() const @@ -286,7 +287,7 @@ struct _sym : branch_base end = parser.end; // Check whether this is a symbol. - auto content = lexy::partial_input(reader, end); + auto content = lexy::partial_input(reader, end.position()); symbol = Table.parse(content); // Only succeed if it is a symbol. @@ -301,8 +302,8 @@ struct _sym : branch_base LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { // We need to consume and report the token. - context.on(_ev::token{}, Token{}, reader.position(), end); - reader.set_position(end); + context.on(_ev::token{}, Token{}, reader.position(), end.position()); + reader.reset(end); // And continue parsing with the symbol value after whitespace skipping. using continuation = lexy::whitespace_parser; @@ -340,6 +341,7 @@ struct _sym : branch_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { + static_assert(lexy::is_char_encoding); // Capture the token and continue with special continuation. return lexy::parser_for<_cap, _cont>::parse(context, reader, LEXY_FWD(args)...); @@ -360,8 +362,9 @@ struct _sym, Tag> : branch_base template struct bp { + static_assert(lexy::is_char_encoding); typename LEXY_DECAY_DECLTYPE(Table)::key_index symbol; - typename Reader::iterator end; + typename Reader::marker end; constexpr auto value() const { @@ -374,7 +377,7 @@ struct _sym, Tag> : branch_base symbol = Table.try_parse(reader); if (!symbol) return false; - end = reader.position(); + end = reader.current(); // We had a symbol, but it must not be the prefix of a valid identifier. return !lexy::try_match_token(T{}, reader); @@ -388,8 +391,8 @@ struct _sym, Tag> : branch_base LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { // We need to consume and report the identifier pattern. - context.on(_ev::token{}, _idp{}, reader.position(), end); - reader.set_position(end); + context.on(_ev::token{}, _idp{}, reader.position(), end.position()); + reader.reset(end); // And continue parsing with the symbol value after whitespace skipping. using continuation = lexy::whitespace_parser; @@ -403,6 +406,7 @@ struct _sym, Tag> : branch_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { + static_assert(lexy::is_char_encoding); auto begin = reader.position(); // Try to parse a symbol that is not the prefix of an identifier. @@ -427,9 +431,9 @@ struct _sym, Tag> : branch_base else { // We need to consume and report the identifier pattern. - auto end = symbol_reader.position(); - context.on(_ev::token{}, _idp{}, begin, end); - reader.set_position(end); + auto end = symbol_reader.current(); + context.on(_ev::token{}, _idp{}, begin, end.position()); + reader.reset(end); // And continue parsing with the symbol value after whitespace skipping. using continuation = lexy::whitespace_parser; @@ -449,8 +453,9 @@ struct _sym : branch_base template struct bp { + static_assert(lexy::is_char_encoding); typename LEXY_DECAY_DECLTYPE(Table)::key_index symbol; - typename Reader::iterator end; + typename Reader::marker end; constexpr auto value() const { @@ -461,7 +466,7 @@ struct _sym : branch_base { // Try to parse a symbol. symbol = Table.try_parse(reader); - end = reader.position(); + end = reader.current(); // Only succeed if it is a symbol. return static_cast(symbol); @@ -475,8 +480,9 @@ struct _sym : branch_base LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { // We need to consume and report the token. - context.on(_ev::token{}, lexy::identifier_token_kind, reader.position(), end); - reader.set_position(end); + context.on(_ev::token{}, lexy::identifier_token_kind, reader.position(), + end.position()); + reader.reset(end); // And continue parsing with the symbol value after whitespace skipping. using continuation = lexy::whitespace_parser; @@ -490,6 +496,7 @@ struct _sym : branch_base template LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) { + static_assert(lexy::is_char_encoding); bp impl{}; if (impl.try_parse(context.control_block, reader)) return impl.template finish(context, reader, LEXY_FWD(args)...); diff --git a/3rdparty/lexy/include/lexy/dsl/terminator.hpp b/3rdparty/lexy/include/lexy/dsl/terminator.hpp index 9535d01d9..56a4e53df 100644 --- a/3rdparty/lexy/include/lexy/dsl/terminator.hpp +++ b/3rdparty/lexy/include/lexy/dsl/terminator.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_TERMINATOR_HPP_INCLUDED @@ -105,7 +105,7 @@ struct _term template constexpr auto terminator(Branch) { - static_assert(lexy::is_branch_rule); + LEXY_REQUIRE_BRANCH_RULE(Branch, "terminator"); return _term{}; } } // namespace lexyd diff --git a/3rdparty/lexy/include/lexy/dsl/times.hpp b/3rdparty/lexy/include/lexy/dsl/times.hpp index 9aa1e9c2c..7ebf327cd 100644 --- a/3rdparty/lexy/include/lexy/dsl/times.hpp +++ b/3rdparty/lexy/include/lexy/dsl/times.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_TIMES_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/token.hpp b/3rdparty/lexy/include/lexy/dsl/token.hpp index 809fb8684..95c812c1c 100644 --- a/3rdparty/lexy/include/lexy/dsl/token.hpp +++ b/3rdparty/lexy/include/lexy/dsl/token.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_TOKEN_HPP_INCLUDED @@ -46,7 +46,7 @@ struct token_base : _token_inherit template struct bp { - typename Reader::iterator end; + typename Reader::marker end; constexpr auto try_parse(const void*, const Reader& reader) { @@ -63,8 +63,8 @@ struct token_base : _token_inherit template LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args) { - context.on(_ev::token{}, Derived{}, reader.position(), end); - reader.set_position(end); + context.on(_ev::token{}, Derived{}, reader.position(), end.position()); + reader.reset(end); return lexy::whitespace_parser::parse(context, reader, LEXY_FWD(args)...); } @@ -85,16 +85,17 @@ struct token_base : _token_inherit { if (!parser.try_parse(reader)) { - context.on(_ev::token{}, lexy::error_token_kind, reader.position(), parser.end); + context.on(_ev::token{}, lexy::error_token_kind, reader.position(), + parser.end.position()); parser.report_error(context, reader); - reader.set_position(parser.end); + reader.reset(parser.end); return false; } } - context.on(_ev::token{}, typename Derived::token_type{}, begin, parser.end); - reader.set_position(parser.end); + context.on(_ev::token{}, typename Derived::token_type{}, begin, parser.end.position()); + reader.reset(parser.end); return true; } @@ -153,7 +154,7 @@ struct _toke : token_base<_toke, Token> constexpr void report_error(Context& context, const Reader& reader) { // Report a different error. - auto err = lexy::error(reader.position(), this->end); + auto err = lexy::error(reader.position(), this->end.position()); context.on(_ev::error{}, err); } }; @@ -184,9 +185,9 @@ struct _token : token_base<_token> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { @@ -196,14 +197,14 @@ struct _token : token_base<_token> lexy::match_action::template result_type>(lexy::_mh(), lexy::no_parse_state, reader); - end = reader.position(); + end = reader.current(); return success; } template constexpr void report_error(Context& context, const Reader& reader) { - auto err = lexy::error(reader.position(), end); + auto err = lexy::error(reader.position(), end.position()); context.on(_ev::error{}, err); } }; diff --git a/3rdparty/lexy/include/lexy/dsl/unicode.hpp b/3rdparty/lexy/include/lexy/dsl/unicode.hpp index 1737b06fd..e895ae3c8 100644 --- a/3rdparty/lexy/include/lexy/dsl/unicode.hpp +++ b/3rdparty/lexy/include/lexy/dsl/unicode.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_UNICODE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/dsl/until.hpp b/3rdparty/lexy/include/lexy/dsl/until.hpp index 6dc0b6346..626d0b4fd 100644 --- a/3rdparty/lexy/include/lexy/dsl/until.hpp +++ b/3rdparty/lexy/include/lexy/dsl/until.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_UNTIL_HPP_INCLUDED @@ -39,9 +39,9 @@ struct _until_eof : token_base<_until_eof, unconditional_branch_base> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr std::true_type try_parse(Reader reader) { @@ -64,7 +64,7 @@ struct _until_eof : token_base<_until_eof, unconditional_branch_base> reader.bump(); } - end = reader.position(); + end = reader.current(); return {}; } }; @@ -76,9 +76,9 @@ struct _until : token_base<_until> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr bool try_parse(Reader reader) { @@ -90,7 +90,7 @@ struct _until : token_base<_until> if (lexy::try_match_token(Condition{}, reader)) { // It did match, we're done at that end. - end = reader.position(); + end = reader.current(); return true; } @@ -100,7 +100,7 @@ struct _until : token_base<_until> if (reader.peek() == Reader::encoding::eof()) { // It did, so we did not succeed. - end = reader.position(); + end = reader.current(); return false; } @@ -117,7 +117,7 @@ struct _until : token_base<_until> // We need to trigger the error `Condition` would. // As such, we try parsing it, which will report an error. - reader.set_position(end); + reader.reset(end); LEXY_ASSERT(reader.peek() == Reader::encoding::eof(), "forgot to set end in try_parse()"); diff --git a/3rdparty/lexy/include/lexy/dsl/whitespace.hpp b/3rdparty/lexy/include/lexy/dsl/whitespace.hpp index 5ffb87dbb..f80b30dcf 100644 --- a/3rdparty/lexy/include/lexy/dsl/whitespace.hpp +++ b/3rdparty/lexy/include/lexy/dsl/whitespace.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_DSL_WHITESPACE_HPP_INCLUDED @@ -137,7 +137,8 @@ constexpr auto skip_whitespace(ws_handler&& handler, Reader& reader) { // Without SWAR, we just repeatedly skip the whitespace rule. while (lexy::try_match_token(WhitespaceRule{}, reader)) - {} + { + } } handler.real_on(lexy::parse_events::token{}, lexy::whitespace_token_kind, begin, diff --git a/3rdparty/lexy/include/lexy/encoding.hpp b/3rdparty/lexy/include/lexy/encoding.hpp index 6c154d069..4529e67a1 100644 --- a/3rdparty/lexy/include/lexy/encoding.hpp +++ b/3rdparty/lexy/include/lexy/encoding.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_ENCODING_HPP_INCLUDED @@ -253,13 +253,35 @@ struct _deduce_encoding }; } // namespace lexy +//=== encoding traits ===// +namespace lexy +{ +template +constexpr auto is_unicode_encoding + = std::is_same_v || std::is_same_v + || std::is_same_v || std::is_same_v + || std::is_same_v; + +template +constexpr auto is_text_encoding + = is_unicode_encoding || std::is_same_v; + +template +constexpr auto is_byte_encoding = std::is_same_v; + +template +constexpr auto is_char_encoding = is_text_encoding || is_byte_encoding; + +template +constexpr auto is_node_encoding = false; +} // namespace lexy + //=== impls ===// namespace lexy::_detail { template -constexpr bool is_compatible_char_type - = std::is_same_v || Encoding::template is_secondary_char_type(); +constexpr bool is_compatible_char_type = std::is_same_v + || Encoding::template is_secondary_char_type(); template using require_secondary_char_type diff --git a/3rdparty/lexy/include/lexy/error.hpp b/3rdparty/lexy/include/lexy/error.hpp index 0a7645c68..77a40937d 100644 --- a/3rdparty/lexy/include/lexy/error.hpp +++ b/3rdparty/lexy/include/lexy/error.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_ERROR_HPP_INCLUDED @@ -26,6 +26,13 @@ class error : _pos(begin), _end(end), _msg(msg) {} + template >> + constexpr operator error() const noexcept + { + return error(_pos, _end, _msg); + } + constexpr auto position() const noexcept { return _pos; @@ -68,6 +75,13 @@ class error : public error typename Reader::iterator end) noexcept : error(begin, end, _detail::type_name()) {} + + template >> + constexpr operator error() const noexcept + { + return error(this->begin(), this->end()); + } }; /// Expected the literal character sequence. @@ -83,6 +97,13 @@ class error : _pos(pos), _str(str), _idx(index), _length(length) {} + template >> + constexpr operator error() const noexcept + { + return error(_pos, _str, _idx, _length); + } + constexpr auto position() const noexcept { return _pos; @@ -127,6 +148,13 @@ class error : _begin(begin), _end(end), _str(str), _length(length) {} + template >> + constexpr operator error() const noexcept + { + return error(_begin, _end, _str, _length); + } + constexpr auto position() const noexcept { return _begin; @@ -169,6 +197,13 @@ class error : _pos(pos), _name(name) {} + template >> + constexpr operator error() const noexcept + { + return error(_pos, _name); + } + constexpr auto position() const noexcept { return _pos; diff --git a/3rdparty/lexy/include/lexy/grammar.hpp b/3rdparty/lexy/include/lexy/grammar.hpp index 4c03b0aa9..b1986594e 100644 --- a/3rdparty/lexy/include/lexy/grammar.hpp +++ b/3rdparty/lexy/include/lexy/grammar.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_GRAMMAR_HPP_INCLUDED @@ -65,8 +65,17 @@ constexpr auto is_separator = std::is_base_of_v; template constexpr auto is_operation = std::is_base_of_v; + +template +constexpr bool _require_branch_rule = (is_branch_rule && ...); } // namespace lexy +#define LEXY_REQUIRE_BRANCH_RULE(Rule, Name) \ + static_assert(lexy::_require_branch_rule, Name \ + " requires a branch condition." \ + " You may need to use `>>` to specify the condition that is used for dispatch." \ + " See https://lexy.foonathan.net/learn/branching/ for more information.") + //=== predefined_token_kind ===// namespace lexy { @@ -88,7 +97,12 @@ enum predefined_token_kind : std::uint_least16_t _smallest_predefined_token_kind = digits_token_kind, }; -constexpr const char* _kind_name(predefined_token_kind kind) noexcept +template +constexpr const char* token_kind_name(const T&) noexcept +{ + return "token"; +} +constexpr const char* token_kind_name(predefined_token_kind kind) noexcept { switch (kind) { @@ -244,6 +258,9 @@ using _detect_value_of = // qualify value_of() (it causes a hard error instead of going to ::value). typename decltype(LEXY_DECLVAL(ParseState&).value_of(Production{}))::return_type; +template +using _detect_value = decltype(Production::value); + template struct _sfinae_sink { @@ -270,6 +287,11 @@ struct _sfinae_sink } }; +template +constexpr bool production_has_value_callback + = lexy::_detail::is_detected<_detect_value_of, ParseState, Production> + || lexy::_detail::is_detected<_detect_value, Production>; + template class production_value_callback { @@ -323,12 +345,14 @@ class production_value_callback template constexpr return_type operator()(Args&&... args) const { - if constexpr (lexy::is_callback_for<_type, Args&&...>) + if constexpr (lexy::is_callback_with_state_for<_type, ParseState, Args&&...> + && !std::is_void_v) { - if constexpr (!std::is_void_v && lexy::is_callback_state<_type, ParseState>) - return _get_value(_state)[*_state](LEXY_FWD(args)...); - else - return _get_value(_state)(LEXY_FWD(args)...); + return _get_value(_state)[*_state](LEXY_FWD(args)...); + } + else if constexpr (lexy::is_callback_for<_type, Args&&...>) + { + return _get_value(_state)(LEXY_FWD(args)...); } else if constexpr ((lexy::is_sink<_type> // || lexy::is_sink<_type, std::add_lvalue_reference_t>) // @@ -355,4 +379,3 @@ class production_value_callback } // namespace lexy #endif // LEXY_GRAMMAR_HPP_INCLUDED - diff --git a/3rdparty/lexy/include/lexy/input/argv_input.hpp b/3rdparty/lexy/include/lexy/input/argv_input.hpp index f60ee4e8f..f4b4f1d70 100644 --- a/3rdparty/lexy/include/lexy/input/argv_input.hpp +++ b/3rdparty/lexy/include/lexy/input/argv_input.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_INPUT_ARGV_INPUT_HPP_INCLUDED @@ -121,9 +121,9 @@ class argv_input public: using encoding = Encoding; using char_type = typename encoding::char_type; - static_assert( - std::is_same_v || Encoding::template is_secondary_char_type(), - "invalid encoding for argv"); + static_assert(std::is_same_v + || Encoding::template is_secondary_char_type(), + "invalid encoding for argv"); //=== constructors ===// constexpr argv_input() = default; @@ -147,7 +147,7 @@ class argv_input argv_iterator _begin, _end; }; -argv_input(int argc, char* argv[])->argv_input<>; +argv_input(int argc, char* argv[]) -> argv_input<>; } // namespace lexy namespace lexy @@ -169,9 +169,9 @@ struct _argvsep : token_base<_argvsep> template struct tp { - typename Reader::iterator end; + typename Reader::marker end; - constexpr explicit tp(const Reader& reader) : end(reader.position()) {} + constexpr explicit tp(const Reader& reader) : end(reader.current()) {} constexpr auto try_parse([[maybe_unused]] Reader reader) { @@ -182,7 +182,7 @@ struct _argvsep : token_base<_argvsep> return false; reader.bump(); - end = reader.position(); + end = reader.current(); return true; } else diff --git a/3rdparty/lexy/include/lexy/input/base.hpp b/3rdparty/lexy/include/lexy/input/base.hpp index ebd35f319..2bc260e2f 100644 --- a/3rdparty/lexy/include/lexy/input/base.hpp +++ b/3rdparty/lexy/include/lexy/input/base.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_INPUT_BASE_HPP_INCLUDED @@ -18,6 +18,16 @@ class _rr using encoding = Encoding; using iterator = Iterator; + struct marker + { + iterator _it; + + constexpr iterator position() const noexcept + { + return _it; + } + }; + constexpr explicit _rr(Iterator begin, Sentinel end) noexcept : _cur(begin), _end(end) { LEXY_PRECONDITION(lexy::_detail::precedes(begin, end)); @@ -42,10 +52,14 @@ class _rr return _cur; } - constexpr void set_position(iterator new_pos) noexcept + constexpr marker current() const noexcept + { + return {_cur}; + } + constexpr void reset(marker m) noexcept { - LEXY_PRECONDITION(lexy::_detail::precedes(new_pos, _end)); - _cur = new_pos; + LEXY_PRECONDITION(lexy::_detail::precedes(m._it, _end)); + _cur = m._it; } private: diff --git a/3rdparty/lexy/include/lexy/input/buffer.hpp b/3rdparty/lexy/include/lexy/input/buffer.hpp index b6bfe758b..450ecf254 100644 --- a/3rdparty/lexy/include/lexy/input/buffer.hpp +++ b/3rdparty/lexy/include/lexy/input/buffer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_INPUT_BUFFER_HPP_INCLUDED @@ -21,6 +21,16 @@ class _br : public _detail::swar_reader_base<_br> using encoding = Encoding; using iterator = const typename Encoding::char_type*; + struct marker + { + iterator _it; + + constexpr iterator position() const noexcept + { + return _it; + } + }; + explicit _br(iterator begin) noexcept : _cur(begin) {} auto peek() const noexcept @@ -39,9 +49,13 @@ class _br : public _detail::swar_reader_base<_br> return _cur; } - void set_position(iterator new_pos) noexcept + marker current() const noexcept + { + return {_cur}; + } + void reset(marker m) noexcept { - _cur = new_pos; + _cur = m._it; } private: @@ -80,13 +94,14 @@ namespace lexy template class buffer { + static_assert(lexy::is_char_encoding); static constexpr auto _has_sentinel = std::is_same_v; public: using encoding = Encoding; using char_type = typename encoding::char_type; - static_assert(std::is_trivial_v); + static_assert(std::is_trivially_copyable_v); //=== constructors ===// /// Allows the creation of an uninitialized buffer that is then filled by the user. @@ -119,6 +134,17 @@ class buffer buffer _buffer; }; + static buffer adopt(const char_type* data, std::size_t size, + MemoryResource* resource = _detail::get_memory_resource()) + { + buffer result(resource); + // We can cast away the const-ness, since we require that `data` came from a buffer + // origionally, where it wasn't const. + result._data = const_cast(data); + result._size = size; + return result; + } + constexpr buffer() noexcept : buffer(_detail::get_memory_resource()) {} constexpr explicit buffer(MemoryResource* resource) noexcept @@ -227,6 +253,14 @@ class buffer return _size; } + const char_type* release() && noexcept + { + auto result = _data; + _data = nullptr; + _size = 0; + return result; + } + //=== input ===// auto reader() const& noexcept { diff --git a/3rdparty/lexy/include/lexy/input/file.hpp b/3rdparty/lexy/include/lexy/input/file.hpp index 9c47d2d6c..8c4a2d57d 100644 --- a/3rdparty/lexy/include/lexy/input/file.hpp +++ b/3rdparty/lexy/include/lexy/input/file.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_INPUT_FILE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/input/parse_tree_input.hpp b/3rdparty/lexy/include/lexy/input/parse_tree_input.hpp new file mode 100644 index 000000000..fdc7572f9 --- /dev/null +++ b/3rdparty/lexy/include/lexy/input/parse_tree_input.hpp @@ -0,0 +1,184 @@ +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors +// SPDX-License-Identifier: BSL-1.0 + +#ifndef LEXY_INPUT_PARSE_TREE_INPUT_HPP_INCLUDED +#define LEXY_INPUT_PARSE_TREE_INPUT_HPP_INCLUDED + +#include +#include +#include +#include + +#if !LEXY_EXPERIMENTAL +# error "lexy::parse_tree_input is experimental" +#endif + +namespace lexy +{ +template +struct parse_tree_input_traits; + +struct _parse_tree_eof // not real EOF, just no more siblings +{ + template + friend constexpr bool operator==(const Node& node, _parse_tree_eof) noexcept + { + return parse_tree_input_traits::is_null(node); + } + template + friend constexpr bool operator==(_parse_tree_eof, const Node& node) noexcept + { + return parse_tree_input_traits::is_null(node); + } + + template + friend constexpr bool operator!=(const Node& node, _parse_tree_eof) noexcept + { + return !parse_tree_input_traits::is_null(node); + } + template + friend constexpr bool operator!=(_parse_tree_eof, const Node& node) noexcept + { + return !parse_tree_input_traits::is_null(node); + } +}; + +template +class parse_tree_encoding +{ + using _traits = parse_tree_input_traits; + +public: + using char_encoding = typename _traits::char_encoding; + using char_type = typename char_encoding::char_type; + using value_type = Node; + + static LEXY_CONSTEVAL auto eof() + { + return _parse_tree_eof{}; + } + + template + static bool match(const Node& node, const NodeKind& node_kind) + { + return _traits::has_kind(node, node_kind); + } +}; +template +constexpr auto is_node_encoding> = true; + +template +class _ptr // parse tree reader +{ + using _traits = parse_tree_input_traits; + +public: + using encoding = parse_tree_encoding; + using iterator = typename _traits::iterator; + + struct marker + { + Node _parent = _traits::null(); + Node _cur = _traits::null(); + + constexpr iterator position() const noexcept + { + return _cur == _parse_tree_eof{} ? _traits::position_end(_parent) + : _traits::position_begin(_cur); + } + }; + + constexpr explicit _ptr(const Node& root) noexcept + : _parent(root), _cur(_traits::first_child(root)) + {} + + constexpr _ptr child_reader() const& noexcept + { + return _ptr(_cur); + } + constexpr auto lexeme_reader() const& noexcept + { + auto lexeme = _traits::lexeme(_cur); + return _range_reader(lexeme.begin(), lexeme.end()); + } + + constexpr const Node& peek() const noexcept + { + return _cur; + } + + constexpr void bump() noexcept + { + LEXY_PRECONDITION(_cur != _parse_tree_eof{}); + _cur = _traits::sibling(_cur); + } + + constexpr marker current() const noexcept + { + return {_parent, _cur}; + } + constexpr void reset(marker m) noexcept + { + _cur = m._cur; + } + + constexpr iterator position() const noexcept + { + return current().position(); + } + +private: + Node _parent; + Node _cur; +}; + +template +class parse_tree_input +{ +public: + using encoding = parse_tree_encoding; + using value_type = Node; + + //=== constructors ===// + constexpr parse_tree_input() noexcept : _root(nullptr) {} + + constexpr explicit parse_tree_input(Node root) noexcept : _root(LEXY_MOV(root)) {} + + template >> + constexpr explicit parse_tree_input(const ParseTree& tree) noexcept : _root(tree.root()) + {} + + //=== access ===// + constexpr const Node& root() const noexcept + { + return _root; + } + + //=== reader ===// + constexpr auto reader() const& noexcept + { + return _ptr(_root); + } + +private: + Node _root; +}; + +template +parse_tree_input(const ParseTree&) + -> parse_tree_input; + +//=== convenience typedefs ===// +template +using parse_tree_lexeme = lexeme_for>; + +template +using parse_tree_error = error_for, Tag>; + +template +using parse_tree_error_context = error_context>; +} // namespace lexy + +#endif // LEXY_INPUT_PARSE_TREE_INPUT_HPP_INCLUDED + diff --git a/3rdparty/lexy/include/lexy/input/range_input.hpp b/3rdparty/lexy/include/lexy/input/range_input.hpp index 3ad00f189..c32c0d3a7 100644 --- a/3rdparty/lexy/include/lexy/input/range_input.hpp +++ b/3rdparty/lexy/include/lexy/input/range_input.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_INPUT_RANGE_INPUT_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/input/string_input.hpp b/3rdparty/lexy/include/lexy/input/string_input.hpp index 72568a715..a59a387da 100644 --- a/3rdparty/lexy/include/lexy/input/string_input.hpp +++ b/3rdparty/lexy/include/lexy/input/string_input.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_INPUT_STRING_INPUT_HPP_INCLUDED @@ -17,6 +17,8 @@ using _string_view_char_type = LEXY_DECAY_DECLTYPE(*LEXY_DECLVAL(View).data()); template class string_input { + static_assert(lexy::is_char_encoding); + public: using encoding = Encoding; using char_type = typename encoding::char_type; diff --git a/3rdparty/lexy/include/lexy/input_location.hpp b/3rdparty/lexy/include/lexy/input_location.hpp index e6c14cf2d..983d2aa02 100644 --- a/3rdparty/lexy/include/lexy/input_location.hpp +++ b/3rdparty/lexy/include/lexy/input_location.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_INPUT_LOCATION_HPP_INCLUDED @@ -16,18 +16,18 @@ namespace lexy template struct input_location_anchor { - using iterator = typename lexy::input_reader::iterator; + using marker = typename lexy::input_reader::marker; constexpr explicit input_location_anchor(const Input& input) - : _line_begin(input.reader().position()), _line_nr(1) + : _line_begin(input.reader().current()), _line_nr(1) {} // implementation detail - constexpr explicit input_location_anchor(iterator line_begin, unsigned line_nr) + constexpr explicit input_location_anchor(marker line_begin, unsigned line_nr) : _line_begin(line_begin), _line_nr(line_nr) {} - iterator _line_begin; + marker _line_begin; unsigned _line_nr; }; } // namespace lexy @@ -42,12 +42,14 @@ class code_unit_location_counting template constexpr bool try_match_newline(Reader& reader) { + static_assert(lexy::is_char_encoding); return lexy::try_match_token(lexy::dsl::newline, reader); } template constexpr void match_column(Reader& reader) { + static_assert(lexy::is_char_encoding); reader.bump(); } }; @@ -59,12 +61,14 @@ class code_point_location_counting template constexpr bool try_match_newline(Reader& reader) { + static_assert(lexy::is_char_encoding); return lexy::try_match_token(lexy::dsl::newline, reader); } template constexpr void match_column(Reader& reader) { + static_assert(lexy::is_char_encoding); if (!lexy::try_match_token(lexy::dsl::code_point, reader)) reader.bump(); } @@ -78,6 +82,7 @@ class byte_location_counting template constexpr bool try_match_newline(Reader& reader) { + static_assert(lexy::is_byte_encoding); LEXY_PRECONDITION(_cur_index <= LineWidth - 1); if (_cur_index == LineWidth - 1) { @@ -98,7 +103,7 @@ class byte_location_counting template constexpr void match_column(Reader& reader) { - static_assert(std::is_same_v); + static_assert(lexy::is_byte_encoding); reader.bump(); ++_cur_index; @@ -109,9 +114,20 @@ class byte_location_counting }; template -using _default_location_counting = std::conditional_t< - std::is_same_v::encoding, lexy::byte_encoding>, - byte_location_counting<>, code_unit_location_counting>; +auto _compute_default_location_counting() +{ + using encoding = typename lexy::input_reader::encoding; + if constexpr (lexy::is_byte_encoding) + return byte_location_counting{}; + else if constexpr (lexy::is_char_encoding) + return code_unit_location_counting{}; + else + static_assert(_detail::error, + "input encoding does not have a default location counting policy"); +} + +template +using _default_location_counting = decltype(_compute_default_location_counting()); } // namespace lexy //=== input_location ===// @@ -122,10 +138,12 @@ template > class input_location { using iterator = typename lexy::input_reader::iterator; + using marker = typename lexy::input_reader::marker; public: constexpr explicit input_location(const Input& input) - : _line_begin(input.reader().position()), _column_begin(_line_begin), _line_nr(1), _column_nr(1) + : _line_begin(input.reader().current()), _column_begin(_line_begin.position()), _line_nr(1), + _column_nr(1) {} /// The closest previous anchor. @@ -162,7 +180,7 @@ class input_location { if (lhs._line_nr != rhs._line_nr) return lhs._line_nr < rhs._line_nr; - return lhs._column_nr < rhs._colum_nr; + return lhs._column_nr < rhs._column_nr; } friend constexpr bool operator<=(const input_location& lhs, const input_location& rhs) { @@ -178,12 +196,13 @@ class input_location } private: - constexpr input_location(iterator line_begin, unsigned line_nr, iterator column_begin, + constexpr input_location(marker line_begin, unsigned line_nr, iterator column_begin, unsigned column_nr) : _line_begin(line_begin), _column_begin(column_begin), _line_nr(line_nr), _column_nr(column_nr) {} - iterator _line_begin, _column_begin; + marker _line_begin; + iterator _column_begin; unsigned _line_nr, _column_nr; template @@ -201,7 +220,7 @@ constexpr auto get_input_location(const Input& i -> input_location { auto reader = input.reader(); - reader.set_position(anchor._line_begin); + reader.reset(anchor._line_begin); auto line_begin = anchor._line_begin; auto line_nr = anchor._line_nr; @@ -227,8 +246,10 @@ constexpr auto get_input_location(const Input& i else if (counting.try_match_newline(reader)) { // [column_begin, newline_end) covers the newline. - auto newline_end = reader.position(); - if (lexy::_detail::min_range_end(column_begin, newline_end, position) != newline_end) + auto newline_end = reader.current(); + if (lexy::_detail::min_range_end(column_begin.position(), newline_end.position(), + position) + != newline_end.position()) break; // Advance to the next line. @@ -242,8 +263,10 @@ constexpr auto get_input_location(const Input& i counting.match_column(reader); // [column_begin, column_end) covers the column. - auto column_end = reader.position(); - if (lexy::_detail::min_range_end(column_begin, column_end, position) != column_end) + auto column_end = reader.current(); + if (lexy::_detail::min_range_end(column_begin.position(), column_end.position(), + position) + != column_end.position()) break; // Advance to the next column. @@ -252,7 +275,7 @@ constexpr auto get_input_location(const Input& i } } - return {line_begin, line_nr, column_begin, column_nr}; + return {line_begin, line_nr, column_begin.position(), column_nr}; } template @@ -281,11 +304,11 @@ constexpr auto get_input_location(const Input& i namespace lexy::_detail { template -constexpr auto get_input_line(const Input& input, - typename lexy::input_reader::iterator line_begin) +constexpr auto get_input_line(const Input& input, + typename lexy::input_reader::marker line_begin) { auto reader = input.reader(); - reader.set_position(line_begin); + reader.reset(line_begin); auto line_end = reader.position(); for (Counting counting; @@ -301,7 +324,7 @@ constexpr auto get_input_line(const Input& input lexy::lexeme_for line; lexy::lexeme_for newline; }; - return result_t{{line_begin, line_end}, {line_end, newline_end}}; + return result_t{{line_begin.position(), line_end}, {line_end, newline_end}}; } // Advances the iterator to the beginning of the next code point. diff --git a/3rdparty/lexy/include/lexy/lexeme.hpp b/3rdparty/lexy/include/lexy/lexeme.hpp index 09d274a27..69d609854 100644 --- a/3rdparty/lexy/include/lexy/lexeme.hpp +++ b/3rdparty/lexy/include/lexy/lexeme.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_LEXEME_HPP_INCLUDED @@ -17,8 +17,8 @@ class lexeme { public: using encoding = typename Reader::encoding; - using char_type = typename encoding::char_type; using iterator = typename Reader::iterator; + using char_type = LEXY_DECAY_DECLTYPE(*LEXY_DECLVAL(iterator&)); constexpr lexeme() noexcept : _begin(), _end() {} constexpr lexeme(iterator begin, iterator end) noexcept : _begin(begin), _end(end) {} @@ -30,6 +30,13 @@ class lexeme : _begin(begin), _end(reader.position()) {} + template >> + constexpr operator lexeme() const noexcept + { + return lexeme(this->begin(), this->end()); + } + constexpr bool empty() const noexcept { return _begin == _end; diff --git a/3rdparty/lexy/include/lexy/parse_tree.hpp b/3rdparty/lexy/include/lexy/parse_tree.hpp index 403c6b4d0..b82efb1bd 100644 --- a/3rdparty/lexy/include/lexy/parse_tree.hpp +++ b/3rdparty/lexy/include/lexy/parse_tree.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_PARSE_TREE_HPP_INCLUDED @@ -11,6 +11,12 @@ #include #include +namespace lexy +{ +template +struct parse_tree_input_traits; +} + //=== internal: pt_node ===// namespace lexy::_detail { @@ -125,7 +131,8 @@ struct pt_node_token : pt_node { if constexpr (_optimize_end) { - static_assert(sizeof(pt_node_token) == 3 * sizeof(void*)); + static_assert(!std::is_pointer_v + || sizeof(pt_node_token) == 3 * sizeof(void*)); auto size = std::size_t(end - begin); LEXY_PRECONDITION(size <= UINT_LEAST32_MAX); @@ -133,7 +140,8 @@ struct pt_node_token : pt_node } else { - static_assert(sizeof(pt_node_token) <= 4 * sizeof(void*)); + static_assert(!std::is_pointer_v + || sizeof(pt_node_token) <= 4 * sizeof(void*)); end_impl = end; } @@ -327,9 +335,16 @@ class pt_buffer //=== parse_tree ===// namespace lexy { +template +class _pt_node_kind; +template +class _pt_node; + template class parse_tree { + static_assert(lexy::is_char_encoding); + public: //=== construction ===// class builder; @@ -363,8 +378,8 @@ class parse_tree } //=== node access ===// - class node; - class node_kind; + using node_kind = _pt_node_kind; + using node = _pt_node; node root() const noexcept { @@ -390,7 +405,11 @@ class parse_tree //=== remaining input ===// lexy::lexeme remaining_input() const noexcept { - return _remaining_input; + if (empty()) + return {}; + + auto token = _root->next_node()->as_token(); + return {token->begin, token->end()}; } private: @@ -398,7 +417,6 @@ class parse_tree _detail::pt_node_production* _root; std::size_t _size; std::size_t _depth; - lexy::lexeme _remaining_input; }; template @@ -542,12 +560,29 @@ class parse_tree::builder } explicit builder(production_info production) : builder(parse_tree(), production) {} - parse_tree&& finish(lexy::lexeme remaining_input = {}) && + [[deprecated("Pass the remaining input, or `input.end()` if there is none.")]] parse_tree&& + finish() && + { + return LEXY_MOV(*this).finish(lexy::lexeme()); + } + parse_tree&& finish(typename Reader::iterator end) && + { + return LEXY_MOV(*this).finish({end, end}); + } + parse_tree&& finish(lexy::lexeme remaining_input) && { LEXY_PRECONDITION(_cur.prod == _result._root); + _cur.insert_children_into(_cur.prod); _cur.update_size_depth(_result._size, _result._depth); - _result._remaining_input = remaining_input; + + _result._buffer.reserve(sizeof(_detail::pt_node_token)); + auto node = _result._buffer + .template allocate<_detail::pt_node_token>(lexy::eof_token_kind, + remaining_input.begin(), + remaining_input.end()); + _result._root->set_sibling(node); + return LEXY_MOV(_result); } @@ -712,13 +747,19 @@ class parse_tree::builder } } + //=== accessors ===// + std::size_t current_child_count() const noexcept + { + return _cur.child_count; + } + private: parse_tree _result; marker _cur; }; -template -class parse_tree::node_kind +template +class _pt_node_kind { public: bool is_token() const noexcept @@ -732,8 +773,10 @@ class parse_tree::node_kind bool is_root() const noexcept { - // Root node has no next node. - return _ptr->next_node() == nullptr; + // Root node has a next node (the remaining input node) which has no next node. + // We assume that _ptr is never the remaining input node, so we know that we have a next + // node. + return _ptr->next_node()->next_node() == nullptr; } bool is_token_production() const noexcept { @@ -753,65 +796,65 @@ class parse_tree::node_kind } } - friend bool operator==(node_kind lhs, node_kind rhs) + friend bool operator==(_pt_node_kind lhs, _pt_node_kind rhs) { if (lhs.is_token() && rhs.is_token()) return lhs._ptr->as_token()->kind == rhs._ptr->as_token()->kind; else return lhs._ptr->as_production()->id == rhs._ptr->as_production()->id; } - friend bool operator!=(node_kind lhs, node_kind rhs) + friend bool operator!=(_pt_node_kind lhs, _pt_node_kind rhs) { return !(lhs == rhs); } - friend bool operator==(node_kind nk, token_kind tk) + friend bool operator==(_pt_node_kind nk, token_kind tk) { if (auto token = nk._ptr->as_token()) return token_kind::from_raw(token->kind) == tk; else return false; } - friend bool operator==(token_kind tk, node_kind nk) + friend bool operator==(token_kind tk, _pt_node_kind nk) { return nk == tk; } - friend bool operator!=(node_kind nk, token_kind tk) + friend bool operator!=(_pt_node_kind nk, token_kind tk) { return !(nk == tk); } - friend bool operator!=(token_kind tk, node_kind nk) + friend bool operator!=(token_kind tk, _pt_node_kind nk) { return !(nk == tk); } - friend bool operator==(node_kind nk, production_info info) + friend bool operator==(_pt_node_kind nk, production_info info) { return nk.is_production() && nk._ptr->as_production()->id == info.id; } - friend bool operator==(production_info info, node_kind nk) + friend bool operator==(production_info info, _pt_node_kind nk) { return nk == info; } - friend bool operator!=(node_kind nk, production_info info) + friend bool operator!=(_pt_node_kind nk, production_info info) { return !(nk == info); } - friend bool operator!=(production_info info, node_kind nk) + friend bool operator!=(production_info info, _pt_node_kind nk) { return !(nk == info); } private: - explicit node_kind(_detail::pt_node* ptr) : _ptr(ptr) {} + explicit _pt_node_kind(_detail::pt_node* ptr) : _ptr(ptr) {} _detail::pt_node* _ptr; - friend parse_tree::node; + friend _pt_node; }; -template -class parse_tree::node +template +class _pt_node { public: void* address() const noexcept @@ -821,7 +864,7 @@ class parse_tree::node auto kind() const noexcept { - return node_kind(_ptr); + return _pt_node_kind(_ptr); } auto parent() const noexcept @@ -834,20 +877,20 @@ class parse_tree::node auto cur = _ptr; while (cur->next_role() == _detail::pt_node::role_sibling) cur = cur->next_node(); - return node(cur->next_node()); + return _pt_node(cur->next_node()); } class children_range { public: - class iterator : public _detail::forward_iterator_base + class iterator : public _detail::forward_iterator_base { public: iterator() noexcept : _cur(nullptr) {} - node deref() const noexcept + auto deref() const noexcept { - return node(_cur); + return _pt_node(_cur); } void increment() noexcept @@ -903,7 +946,7 @@ class parse_tree::node _detail::pt_node* _node; - friend node; + friend _pt_node; }; auto children() const noexcept @@ -914,14 +957,14 @@ class parse_tree::node class sibling_range { public: - class iterator : public _detail::forward_iterator_base + class iterator : public _detail::forward_iterator_base { public: iterator() noexcept : _cur() {} - node deref() const noexcept + auto deref() const noexcept { - return node(_cur); + return _pt_node(_cur); } void increment() noexcept @@ -969,7 +1012,7 @@ class parse_tree::node _detail::pt_node* _node; - friend node; + friend _pt_node; }; auto siblings() const noexcept @@ -983,6 +1026,19 @@ class parse_tree::node return _ptr->next_role() == _detail::pt_node::role_parent; } + auto position() const noexcept -> typename Reader::iterator + { + // Find the first descendant that is a token. + auto cur = _ptr; + while (cur->type() == _detail::pt_node::type_production) + { + cur = cur->as_production()->first_child(); + LEXY_PRECONDITION(cur); + } + + return cur->as_token()->begin; + } + auto lexeme() const noexcept { if (auto token = _ptr->as_token()) @@ -991,6 +1047,28 @@ class parse_tree::node return lexy::lexeme(); } + auto covering_lexeme() const noexcept + { + if (auto token = _ptr->as_token()) + return lexy::lexeme(token->begin, token->end()); + + auto begin = position(); + + auto sibling = _ptr; + while (true) + { + auto next_role = sibling->next_role(); + sibling = sibling->next_node(); + // If we went to parent, we need to continue finding siblings. + if (next_role == _detail::pt_node::role_sibling) + break; + } + auto end = _pt_node(sibling).position(); + + LEXY_PRECONDITION(begin == end || end != typename Reader::iterator()); + return lexy::lexeme(begin, end); + } + auto token() const noexcept { LEXY_PRECONDITION(kind().is_token()); @@ -1000,21 +1078,22 @@ class parse_tree::node return lexy::token(kind, token->begin, token->end()); } - friend bool operator==(node lhs, node rhs) noexcept + friend bool operator==(_pt_node lhs, _pt_node rhs) noexcept { return lhs._ptr == rhs._ptr; } - friend bool operator!=(node lhs, node rhs) noexcept + friend bool operator!=(_pt_node lhs, _pt_node rhs) noexcept { return lhs._ptr != rhs._ptr; } private: - explicit node(_detail::pt_node* ptr) noexcept : _ptr(ptr) {} + explicit _pt_node(_detail::pt_node* ptr) noexcept : _ptr(ptr) {} _detail::pt_node* _ptr; - friend parse_tree; + friend parse_tree; + friend parse_tree_input_traits<_pt_node>; }; enum class traverse_event @@ -1143,5 +1222,70 @@ class parse_tree::traverse_range }; } // namespace lexy +#if LEXY_EXPERIMENTAL +namespace lexy +{ +template +struct parse_tree_input_traits<_pt_node> +{ + using _node = _pt_node; + + using char_encoding = typename Reader::encoding; + + static bool is_null(_node cur) noexcept + { + return cur._ptr == nullptr; + } + + static _node null() noexcept + { + return _node(nullptr); + } + + static _node first_child(_node cur) noexcept + { + LEXY_PRECONDITION(!is_null(cur)); + if (auto prod = cur._ptr->as_production()) + return _node(prod->first_child()); + else + return _node(nullptr); + } + + static _node sibling(_node cur) noexcept + { + LEXY_PRECONDITION(!is_null(cur)); + return cur._ptr->next_role() == _detail::pt_node::role_sibling + ? _node(cur._ptr->next_node()) + : _node(nullptr); + } + + template + static bool has_kind(_node cur, const Kind& kind) noexcept + { + return !is_null(cur) && cur.kind() == kind; + } + + using iterator = typename Reader::iterator; + + static iterator position_begin(_node cur) noexcept + { + LEXY_PRECONDITION(!is_null(cur)); + return cur.position(); + } + static iterator position_end(_node cur) noexcept + { + LEXY_PRECONDITION(!is_null(cur)); + return cur.covering_lexeme().end(); + } + + static auto lexeme(_node cur) noexcept + { + LEXY_PRECONDITION(!is_null(cur)); + return cur.lexeme(); + } +}; +} // namespace lexy +#endif + #endif // LEXY_PARSE_TREE_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy/token.hpp b/3rdparty/lexy/include/lexy/token.hpp index 3ea1532b8..a7b1442e5 100644 --- a/3rdparty/lexy/include/lexy/token.hpp +++ b/3rdparty/lexy/include/lexy/token.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_TOKEN_HPP_INCLUDED @@ -88,9 +88,6 @@ inline constexpr auto token_kind_map_for = token_kind_map; namespace lexy { -template -using _detect_token_kind_name = decltype(token_kind_name(TokenKind{})); - template constexpr auto _has_special_token_kind = [] { using kind = LEXY_DECAY_DECLTYPE(lexy::token_kind_of); @@ -174,12 +171,13 @@ class token_kind constexpr const char* name() const noexcept { if (is_predefined()) - return _kind_name(static_cast(_value)); - else if constexpr (lexy::_detail::is_detected<_detect_token_kind_name, TokenKind>) - return token_kind_name(get()); // ADL + return token_kind_name(static_cast(_value)); else - // We only have a generic name. - return "token"; + return token_kind_name(get()); // ADL + } + friend constexpr const char* token_kind_name(token_kind kind) noexcept + { + return kind.name(); } constexpr _underlying_type get() const noexcept diff --git a/3rdparty/lexy/include/lexy/visualize.hpp b/3rdparty/lexy/include/lexy/visualize.hpp index 8b0b6f467..42b3fb0be 100644 --- a/3rdparty/lexy/include/lexy/visualize.hpp +++ b/3rdparty/lexy/include/lexy/visualize.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_VISUALIZE_HPP_INCLUDED @@ -363,32 +363,7 @@ OutputIt visualize_to(OutputIt out, lexy::lexeme lexeme, }; using encoding = typename Reader::encoding; - if constexpr (std::is_same_v // - || std::is_same_v) - { - auto count = 0u; - for (char c : lexeme) - { - // If the character is in fact ASCII, visualize the code point. - // Otherwise, visualize as byte. - if (lexy::_detail::is_ascii(c)) - out = visualize_to(out, lexy::code_point(static_cast(c)), opts); - else - out = write_escaped_byte(out, static_cast(c)); - - ++count; - if (count == opts.max_lexeme_width) - { - out = _detail::write_ellipsis(out, opts); - break; - } - } - return out; - } - else if constexpr (std::is_same_v // - || std::is_same_v // - || std::is_same_v // - || std::is_same_v) + if constexpr (lexy::is_unicode_encoding) { // Parse the individual code points, and write them out. lexy::range_input input(lexeme.begin(), lexeme.end()); @@ -406,7 +381,7 @@ OutputIt visualize_to(OutputIt out, lexy::lexeme lexeme, else if (result.error == lexy::_detail::cp_error::success) { // Consume and visualize. - reader.set_position(result.end); + reader.reset(result.end); out = visualize_to(out, lexy::code_point(result.cp), opts); } else @@ -461,7 +436,28 @@ OutputIt visualize_to(OutputIt out, lexy::lexeme lexeme, } return out; } - else if constexpr (std::is_same_v) + else if constexpr (lexy::is_text_encoding) + { + auto count = 0u; + for (char c : lexeme) + { + // If the character is in fact ASCII, visualize the code point. + // Otherwise, visualize as byte. + if (lexy::_detail::is_ascii(c)) + out = visualize_to(out, lexy::code_point(static_cast(c)), opts); + else + out = write_escaped_byte(out, static_cast(c)); + + ++count; + if (count == opts.max_lexeme_width) + { + out = _detail::write_ellipsis(out, opts); + break; + } + } + return out; + } + else if constexpr (lexy::is_byte_encoding) { auto count = 0u; for (auto iter = lexeme.begin(); iter != lexeme.end(); ++iter) @@ -480,6 +476,13 @@ OutputIt visualize_to(OutputIt out, lexy::lexeme lexeme, } return out; } + else if constexpr (lexy::is_node_encoding) + { + // Visualize as an iterator range of characters. + lexy::range_input + input(lexeme.begin(), lexeme.end()); + return visualize_to(out, lexy::lexeme_for(input.begin(), input.end())); + } else { static_assert(lexy::_detail::error, "unknown encoding"); @@ -622,6 +625,41 @@ struct cfile_output_iterator } }; +struct stderr_output_iterator +{ + auto operator*() const noexcept + { + return *this; + } + auto operator++(int) const noexcept + { + return *this; + } + + stderr_output_iterator& operator=(char c) + { + std::fputc(c, stderr); + return *this; + } +}; +struct stdout_output_iterator +{ + auto operator*() const noexcept + { + return *this; + } + auto operator++(int) const noexcept + { + return *this; + } + + stdout_output_iterator& operator=(char c) + { + std::fputc(c, stdout); + return *this; + } +}; + /// Writes the visualization to the FILE. template void visualize(std::FILE* file, const T& obj, visualization_options opts = {}) diff --git a/3rdparty/lexy/include/lexy_ext/compiler_explorer.hpp b/3rdparty/lexy/include/lexy_ext/compiler_explorer.hpp index 588a456ea..220adf4ab 100644 --- a/3rdparty/lexy/include/lexy_ext/compiler_explorer.hpp +++ b/3rdparty/lexy/include/lexy_ext/compiler_explorer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_EXT_COMPILER_EXPLORER_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy_ext/parse_tree_algorithm.hpp b/3rdparty/lexy/include/lexy_ext/parse_tree_algorithm.hpp index 9009ee08e..f8242fab6 100644 --- a/3rdparty/lexy/include/lexy_ext/parse_tree_algorithm.hpp +++ b/3rdparty/lexy/include/lexy_ext/parse_tree_algorithm.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_EXT_PARSE_TREE_ALGORITHM_HPP_INCLUDED @@ -216,7 +216,7 @@ class _filtered_node_range template _filtered_node_range(Predicate&& pred, Iterator begin, Sentinel end) noexcept - ->_filtered_node_range, Iterator, Sentinel>; + -> _filtered_node_range, Iterator, Sentinel>; /// Returns the children that of node that match the predicate. /// diff --git a/3rdparty/lexy/include/lexy_ext/parse_tree_doctest.hpp b/3rdparty/lexy/include/lexy_ext/parse_tree_doctest.hpp index 51c1d1f29..18b12dead 100644 --- a/3rdparty/lexy/include/lexy_ext/parse_tree_doctest.hpp +++ b/3rdparty/lexy/include/lexy_ext/parse_tree_doctest.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_EXT_PARSE_TREE_DOCTEST_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy_ext/report_error.hpp b/3rdparty/lexy/include/lexy_ext/report_error.hpp index fc04e10cf..0ee6c32a2 100644 --- a/3rdparty/lexy/include/lexy_ext/report_error.hpp +++ b/3rdparty/lexy/include/lexy_ext/report_error.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_EXT_REPORT_ERROR_HPP_INCLUDED @@ -317,7 +317,7 @@ OutputIt write_error(OutputIt out, const lexy::error_context& context, namespace lexy_ext { -template +template struct _report_error { OutputIterator _iter; @@ -337,18 +337,14 @@ struct _report_error void operator()(const lexy::error_context& context, const lexy::error& error) { - if constexpr (std::is_same_v) - _detail::write_error(lexy::cfile_output_iterator{stderr}, context, error, _opts, - _path); - else - _iter = _detail::write_error(_iter, context, error, _opts, _path); + _iter = _detail::write_error(_iter, context, error, _opts, _path); ++_count; } std::size_t finish() && { if (_count != 0) - std::fputs("\n", stderr); + *_iter++ = '\n'; return _count; } }; @@ -378,7 +374,7 @@ struct _report_error }; /// An error callback that uses diagnostic_writer to print to stderr (by default). -constexpr auto report_error = _report_error<>{}; +constexpr auto report_error = _report_error{}; } // namespace lexy_ext #endif // LEXY_EXT_REPORT_ERROR_HPP_INCLUDED diff --git a/3rdparty/lexy/include/lexy_ext/shell.hpp b/3rdparty/lexy/include/lexy_ext/shell.hpp index 6fe81ee01..66865bbda 100644 --- a/3rdparty/lexy/include/lexy_ext/shell.hpp +++ b/3rdparty/lexy/include/lexy_ext/shell.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 #ifndef LEXY_EXT_SHELL_HPP_INCLUDED @@ -168,6 +168,16 @@ class shell using encoding = typename Prompt::encoding; using iterator = typename lexy::_detail::buffer_builder::stable_iterator; + struct marker + { + iterator _it; + + constexpr iterator position() const noexcept + { + return _it; + } + }; + auto reader() const& { return *this; @@ -191,9 +201,13 @@ class shell return iterator(_shell->_buffer, _idx); } - void set_position(iterator new_pos) noexcept + marker current() const noexcept + { + return {position()}; + } + void reset(marker m) noexcept { - _idx = new_pos.index(); + _idx = m._it.index(); } private: diff --git a/3rdparty/lexy/src/CMakeLists.txt b/3rdparty/lexy/src/CMakeLists.txt index 6f07f43db..709cc831f 100644 --- a/3rdparty/lexy/src/CMakeLists.txt +++ b/3rdparty/lexy/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +# Copyright (C) 2020-2024 Jonathan Müller and lexy contributors # SPDX-License-Identifier: BSL-1.0 get_filename_component(include_dir ${CMAKE_CURRENT_SOURCE_DIR}/../include/lexy ABSOLUTE) @@ -80,6 +80,7 @@ set(header_files ${include_dir}/dsl/option.hpp ${include_dir}/dsl/operator.hpp ${include_dir}/dsl/parse_as.hpp + ${include_dir}/dsl/parse_tree_node.hpp ${include_dir}/dsl/peek.hpp ${include_dir}/dsl/position.hpp ${include_dir}/dsl/production.hpp @@ -105,6 +106,7 @@ set(header_files ${include_dir}/input/buffer.hpp ${include_dir}/input/file.hpp ${include_dir}/input/lexeme_input.hpp + ${include_dir}/input/parse_tree_input.hpp ${include_dir}/input/range_input.hpp ${include_dir}/input/string_input.hpp @@ -191,7 +193,7 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") # GCC's arry bounds, maybe uninitialized, and restrict warning seems to have false positives. target_compile_options(lexy_dev INTERFACE -Wno-array-bounds -Wno-maybe-uninitialized -Wno-restrict) elseif(MSVC) - target_compile_options(lexy_dev INTERFACE /WX /W3 /D _CRT_SECURE_NO_WARNINGS /wd5105) + target_compile_options(lexy_dev INTERFACE /WX /W3 /D _CRT_SECURE_NO_WARNINGS /wd5105 /utf-8) endif() # Link to have FILE I/O. @@ -214,3 +216,9 @@ target_sources(lexy_ext INTERFACE ${ext_headers_files}) add_library(lexy INTERFACE) add_alias(lexy lexy) target_link_libraries(lexy INTERFACE foonathan::lexy::core foonathan::lexy::file foonathan::lexy::unicode foonathan::lexy::ext) + +# Link to enable experimental features. +add_library(lexy_experimental INTERFACE) +add_alias(lexy::experimental lexy_experimental) +target_compile_definitions(lexy_experimental INTERFACE LEXY_EXPERIMENTAL=1) + diff --git a/3rdparty/lexy/src/input/file.cpp b/3rdparty/lexy/src/input/file.cpp index 655473ebc..028fb6de3 100644 --- a/3rdparty/lexy/src/input/file.cpp +++ b/3rdparty/lexy/src/input/file.cpp @@ -1,6 +1,7 @@ -// Copyright (C) 2020-2023 Jonathan Müller and lexy contributors +// Copyright (C) 2020-2024 Jonathan Müller and lexy contributors // SPDX-License-Identifier: BSL-1.0 +#include #include #include @@ -56,8 +57,8 @@ lexy::file_error get_file_error() noexcept } } -constexpr std::size_t small_file_size = 4 * 1024; -constexpr std::size_t medium_file_size = 32 * 1024; +constexpr std::size_t small_file_size = std::size_t(4) * 1024; +constexpr std::size_t medium_file_size = std::size_t(32) * 1024; } // namespace lexy::file_error lexy::_detail::read_file(const char* path, file_callback cb, void* user_data) diff --git a/3rdparty/tinyxml2/tinyxml2.cpp b/3rdparty/tinyxml2/tinyxml2.cpp index 31925d964..c5c487010 100755 --- a/3rdparty/tinyxml2/tinyxml2.cpp +++ b/3rdparty/tinyxml2/tinyxml2.cpp @@ -103,12 +103,17 @@ distribution. #if defined(_WIN64) #define TIXML_FSEEK _fseeki64 #define TIXML_FTELL _ftelli64 -#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__ANDROID__) +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__) #define TIXML_FSEEK fseeko #define TIXML_FTELL ftello -#elif defined(__unix__) && defined(__x86_64__) - #define TIXML_FSEEK fseeko64 - #define TIXML_FTELL ftello64 +#elif defined(__ANDROID__) + #if __ANDROID_API__ > 24 + #define TIXML_FSEEK fseeko64 + #define TIXML_FTELL ftello64 + #else + #define TIXML_FSEEK fseeko + #define TIXML_FTELL ftello + #endif #else #define TIXML_FSEEK fseek #define TIXML_FTELL ftell @@ -707,7 +712,7 @@ bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { } -char* XMLDocument::Identify( char* p, XMLNode** node ) +char* XMLDocument::Identify( char* p, XMLNode** node, bool first ) { TIXMLASSERT( node ); TIXMLASSERT( p ); @@ -759,9 +764,19 @@ char* XMLDocument::Identify( char* p, XMLNode** node ) p += dtdHeaderLen; } else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { - returnNode = CreateUnlinkedNode( _elementPool ); - returnNode->_parseLineNum = _parseCurLineNum; - p += elementHeaderLen; + + // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag + if (WhitespaceMode() == PEDANTIC_WHITESPACE && first && p != start && *(p + elementHeaderLen) == '/') { + returnNode = CreateUnlinkedNode(_textPool); + returnNode->_parseLineNum = startLine; + p = start; // Back it up, all the text counts. + _parseCurLineNum = startLine; + } + else { + returnNode = CreateUnlinkedNode(_elementPool); + returnNode->_parseLineNum = _parseCurLineNum; + p += elementHeaderLen; + } } else { returnNode = CreateUnlinkedNode( _textPool ); @@ -814,6 +829,34 @@ XMLNode::~XMLNode() } } +// ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. + +int XMLNode::ChildElementCount(const char *value) const { + int count = 0; + + const XMLElement *e = FirstChildElement(value); + + while (e) { + e = e->NextSiblingElement(value); + count++; + } + + return count; +} + +int XMLNode::ChildElementCount() const { + int count = 0; + + const XMLElement *e = FirstChildElement(); + + while (e) { + e = e->NextSiblingElement(); + count++; + } + + return count; +} + const char* XMLNode::Value() const { // Edge case: XMLDocuments don't have a Value. Return null. @@ -1062,21 +1105,23 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) if (_document->Error()) return 0; + bool first = true; while( p && *p ) { XMLNode* node = 0; - p = _document->Identify( p, &node ); + p = _document->Identify( p, &node, first ); TIXMLASSERT( p ); if ( node == 0 ) { break; } + first = false; const int initialLineNum = node->_parseLineNum; StrPair endTag; p = node->ParseDeep( p, &endTag, curLineNumPtr ); if ( !p ) { - DeleteNode( node ); + _document->DeleteNode( node ); if ( !_document->Error() ) { _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); } @@ -1109,7 +1154,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) } if ( !wellLocated ) { _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); - DeleteNode( node ); + _document->DeleteNode( node ); break; } } @@ -1144,7 +1189,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) } if ( mismatch ) { _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); - DeleteNode( node ); + _document->DeleteNode( node ); break; } } @@ -1776,11 +1821,11 @@ XMLError XMLElement::QueryInt64Text(int64_t* ival) const } -XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const +XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const { if(FirstChild() && FirstChild()->ToText()) { const char* t = FirstChild()->Value(); - if(XMLUtil::ToUnsigned64(t, ival)) { + if(XMLUtil::ToUnsigned64(t, uval)) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; @@ -2412,21 +2457,21 @@ XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) } -XMLError XMLDocument::Parse( const char* p, size_t len ) +XMLError XMLDocument::Parse( const char* xml, size_t nBytes ) { Clear(); - if ( len == 0 || !p || !*p ) { + if ( nBytes == 0 || !xml || !*xml ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } - if ( len == static_cast(-1) ) { - len = strlen( p ); + if ( nBytes == static_cast(-1) ) { + nBytes = strlen( xml ); } TIXMLASSERT( _charBuffer == 0 ); - _charBuffer = new char[ len+1 ]; - memcpy( _charBuffer, p, len ); - _charBuffer[len] = 0; + _charBuffer = new char[ nBytes+1 ]; + memcpy( _charBuffer, xml, nBytes ); + _charBuffer[nBytes] = 0; Parse(); if ( Error() ) { diff --git a/3rdparty/tinyxml2/tinyxml2.h b/3rdparty/tinyxml2/tinyxml2.h index 452ae95bb..7586f7b8d 100755 --- a/3rdparty/tinyxml2/tinyxml2.h +++ b/3rdparty/tinyxml2/tinyxml2.h @@ -42,9 +42,6 @@ distribution. #endif #include -/* - TODO: intern strings instead of allocation. -*/ /* gcc: g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe @@ -64,7 +61,7 @@ distribution. # pragma warning(disable: 4251) #endif -#ifdef _WIN32 +#ifdef _MSC_VER # ifdef TINYXML2_EXPORT # define TINYXML2_LIB __declspec(dllexport) # elif defined(TINYXML2_IMPORT) @@ -83,27 +80,27 @@ distribution. #if defined(TINYXML2_DEBUG) # if defined(_MSC_VER) # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like -# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# define TIXMLASSERT( x ) do { if ( !((void)0,(x))) { __debugbreak(); } } while(false) # elif defined (ANDROID_NDK) # include -# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# define TIXMLASSERT( x ) do { if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } } while(false) # else # include # define TIXMLASSERT assert # endif #else -# define TIXMLASSERT( x ) {} +# define TIXMLASSERT( x ) do {} while(false) #endif #endif /* Versioning, past 1.0.14: http://semver.org/ */ -static const int TIXML2_MAJOR_VERSION = 9; +static const int TIXML2_MAJOR_VERSION = 10; static const int TIXML2_MINOR_VERSION = 0; static const int TIXML2_PATCH_VERSION = 0; -#define TINYXML2_MAJOR_VERSION 9 +#define TINYXML2_MAJOR_VERSION 10 #define TINYXML2_MINOR_VERSION 0 #define TINYXML2_PATCH_VERSION 0 @@ -112,7 +109,7 @@ static const int TIXML2_PATCH_VERSION = 0; // system, and the capacity of the stack. On the other hand, it's a trivial // attack that can result from ill, malicious, or even correctly formed XML, // so there needs to be a limit in place. -static const int TINYXML2_MAX_ELEMENT_DEPTH = 100; +static const int TINYXML2_MAX_ELEMENT_DEPTH = 500; namespace tinyxml2 { @@ -305,9 +302,9 @@ class DynArray if ( cap > _allocated ) { TIXMLASSERT( cap <= INT_MAX / 2 ); const int newAllocated = cap * 2; - T* newMem = new T[newAllocated]; + T* newMem = new T[static_cast(newAllocated)]; TIXMLASSERT( newAllocated >= _size ); - memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + memcpy( newMem, _mem, sizeof(T)*static_cast(_size) ); // warning: not using constructors, only works for PODs if ( _mem != _pool ) { delete [] _mem; } @@ -317,7 +314,7 @@ class DynArray } T* _mem; - T _pool[INITIAL_SIZE]; + T _pool[static_cast(INITIAL_SIZE)]; int _allocated; // objects allocated int _size; // number objects in use }; @@ -365,17 +362,17 @@ class MemPoolT : public MemPool _nUntracked = 0; } - virtual int ItemSize() const { + virtual int ItemSize() const override{ return ITEM_SIZE; } int CurrentAllocs() const { return _currentAllocs; } - virtual void* Alloc() { + virtual void* Alloc() override{ if ( !_root ) { // Need a new block. - Block* block = new Block(); + Block* block = new Block; _blockPtrs.Push( block ); Item* blockItems = block->items; @@ -398,7 +395,7 @@ class MemPoolT : public MemPool return result; } - virtual void Free( void* mem ) { + virtual void Free( void* mem ) override { if ( !mem ) { return; } @@ -416,7 +413,7 @@ class MemPoolT : public MemPool ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); } - void SetTracked() { + void SetTracked() override { --_nUntracked; } @@ -443,7 +440,7 @@ class MemPoolT : public MemPool union Item { Item* next; - char itemData[ITEM_SIZE]; + char itemData[static_cast(ITEM_SIZE)]; }; struct Block { Item items[ITEMS_PER_BLOCK]; @@ -603,7 +600,7 @@ class TINYXML2_LIB XMLUtil TIXMLASSERT( p ); TIXMLASSERT( q ); TIXMLASSERT( nChar >= 0 ); - return strncmp( p, q, nChar ) == 0; + return strncmp( p, q, static_cast(nChar) ) == 0; } inline static bool IsUTF8Continuation( const char p ) { @@ -732,6 +729,12 @@ class TINYXML2_LIB XMLNode return 0; } + // ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. + + int ChildElementCount(const char *value) const; + + int ChildElementCount() const; + /** The meaning of 'value' changes for the specific type. @verbatim Document: empty (NULL is returned, not an empty string) @@ -992,12 +995,12 @@ class TINYXML2_LIB XMLText : public XMLNode { friend class XMLDocument; public: - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; - virtual XMLText* ToText() { + virtual XMLText* ToText() override { return this; } - virtual const XMLText* ToText() const { + virtual const XMLText* ToText() const override { return this; } @@ -1010,14 +1013,14 @@ class TINYXML2_LIB XMLText : public XMLNode return _isCData; } - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} virtual ~XMLText() {} - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: bool _isCData; @@ -1032,23 +1035,23 @@ class TINYXML2_LIB XMLComment : public XMLNode { friend class XMLDocument; public: - virtual XMLComment* ToComment() { + virtual XMLComment* ToComment() override { return this; } - virtual const XMLComment* ToComment() const { + virtual const XMLComment* ToComment() const override { return this; } - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLComment( XMLDocument* doc ); virtual ~XMLComment(); - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr) override; private: XMLComment( const XMLComment& ); // not supported @@ -1071,23 +1074,23 @@ class TINYXML2_LIB XMLDeclaration : public XMLNode { friend class XMLDocument; public: - virtual XMLDeclaration* ToDeclaration() { + virtual XMLDeclaration* ToDeclaration() override { return this; } - virtual const XMLDeclaration* ToDeclaration() const { + virtual const XMLDeclaration* ToDeclaration() const override { return this; } - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLDeclaration( XMLDocument* doc ); virtual ~XMLDeclaration(); - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLDeclaration( const XMLDeclaration& ); // not supported @@ -1106,23 +1109,23 @@ class TINYXML2_LIB XMLUnknown : public XMLNode { friend class XMLDocument; public: - virtual XMLUnknown* ToUnknown() { + virtual XMLUnknown* ToUnknown() override { return this; } - virtual const XMLUnknown* ToUnknown() const { + virtual const XMLUnknown* ToUnknown() const override { return this; } - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLUnknown( XMLDocument* doc ); virtual ~XMLUnknown(); - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLUnknown( const XMLUnknown& ); // not supported @@ -1274,13 +1277,13 @@ class TINYXML2_LIB XMLElement : public XMLNode SetValue( str, staticMem ); } - virtual XMLElement* ToElement() { + virtual XMLElement* ToElement() override { return this; } - virtual const XMLElement* ToElement() const { + virtual const XMLElement* ToElement() const override { return this; } - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none @@ -1676,11 +1679,11 @@ class TINYXML2_LIB XMLElement : public XMLNode ElementClosingType ClosingType() const { return _closingType; } - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLElement( XMLDocument* doc ); @@ -1704,7 +1707,8 @@ class TINYXML2_LIB XMLElement : public XMLNode enum Whitespace { PRESERVE_WHITESPACE, - COLLAPSE_WHITESPACE + COLLAPSE_WHITESPACE, + PEDANTIC_WHITESPACE }; @@ -1728,11 +1732,11 @@ class TINYXML2_LIB XMLDocument : public XMLNode XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); ~XMLDocument(); - virtual XMLDocument* ToDocument() { + virtual XMLDocument* ToDocument() override { TIXMLASSERT( this == _document ); return this; } - virtual const XMLDocument* ToDocument() const { + virtual const XMLDocument* ToDocument() const override { TIXMLASSERT( this == _document ); return this; } @@ -1829,7 +1833,7 @@ class TINYXML2_LIB XMLDocument : public XMLNode @endverbatim */ void Print( XMLPrinter* streamer=0 ) const; - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; /** Create a new Element associated with @@ -1915,15 +1919,15 @@ class TINYXML2_LIB XMLDocument : public XMLNode void DeepCopy(XMLDocument* target) const; // internal - char* Identify( char* p, XMLNode** node ); + char* Identify( char* p, XMLNode** node, bool first ); // internal void MarkInUse(const XMLNode* const); - virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const override{ return 0; } - virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const override{ return false; } @@ -2286,18 +2290,18 @@ class TINYXML2_LIB XMLPrinter : public XMLVisitor void PushDeclaration( const char* value ); void PushUnknown( const char* value ); - virtual bool VisitEnter( const XMLDocument& /*doc*/ ); - virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) override; + virtual bool VisitExit( const XMLDocument& /*doc*/ ) override { return true; } - virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); - virtual bool VisitExit( const XMLElement& element ); + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) override; + virtual bool VisitExit( const XMLElement& element ) override; - virtual bool Visit( const XMLText& text ); - virtual bool Visit( const XMLComment& comment ); - virtual bool Visit( const XMLDeclaration& declaration ); - virtual bool Visit( const XMLUnknown& unknown ); + virtual bool Visit( const XMLText& text ) override; + virtual bool Visit( const XMLComment& comment ) override; + virtual bool Visit( const XMLDeclaration& declaration ) override; + virtual bool Visit( const XMLUnknown& unknown ) override; /** If in print to memory mode, return a pointer to diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3abc9b986..49aa120c2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,29 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +4.6.2 (2024-06-26) +------------------ +* Initialize template variable `T out` (`#839 `_) +* Building with a recent compiler fails due incompatible expected library (`#833 `_) + * nonstd::expected updated to 0.8 +* fix issue `#829 `_: support again custom JSON converters +* fix issue `#834 `_: enable minitrace +* allow multiple instances of the loggers +* fix issue `#827 `_ : verify name +* add TickMonitorCallback +* Fix typo in FallbackNode constructor parameter name (`#830 `_) +* fix segfault and throw instead when manifest is nullptr +* Add in call to ament_export_targets. (`#826 `_) +* Contributors: Davide Faconti, S. Messerschmidt, Sharmin Ramli, avikus-seonghyeon.kwon + +4.6.1 (2024-05-20) +------------------ +* remove flatbuffers from public API and old file_logger +* fix issue `#824 `_: use global in Blackboard::set +* Add test for setting a global blackboard entry using a node's output port `#823 `_ +* examples renamed +* Contributors: Davide Faconti, Robin Müller + 4.6.0 (2024-04-28) ------------------ * add tutorial 19 about the global blackboard diff --git a/CMakeLists.txt b/CMakeLists.txt index 69ec49fab..788c0d0cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16.3) # version on Ubuntu Focal -project(behaviortree_cpp VERSION 4.6.0 LANGUAGES C CXX) +project(behaviortree_cpp VERSION 4.6.2 LANGUAGES C CXX) set(CMAKE_CONFIG_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CONFIG_PATH}") @@ -74,12 +74,15 @@ else() include(cmake/conan_build.cmake) endif() - ############################################################# # LIBRARY add_subdirectory(3rdparty/lexy) +add_library(minitrace STATIC 3rdparty/minitrace/minitrace.cpp) +target_compile_definitions(minitrace PRIVATE MTR_ENABLED=True) +set_property(TARGET minitrace PROPERTY POSITION_INDEPENDENT_CODE ON) + list(APPEND BT_SOURCE src/action_node.cpp src/interaction_node.cpp @@ -126,7 +129,6 @@ list(APPEND BT_SOURCE src/loggers/bt_observer.cpp 3rdparty/tinyxml2/tinyxml2.cpp - 3rdparty/minitrace/minitrace.cpp ) @@ -166,6 +168,7 @@ target_link_libraries(${BTCPP_LIBRARY} Threads::Threads ${CMAKE_DL_LIBS} $ + $ PUBLIC ${BTCPP_EXTRA_LIBRARIES} ) @@ -186,6 +189,7 @@ target_compile_definitions(${BTCPP_LIBRARY} PUBLIC BTCPP_LIBRARY_VERSION="${CMAK target_compile_features(${BTCPP_LIBRARY} PUBLIC cxx_std_17) if(MSVC) + target_compile_options(${BTCPP_LIBRARY} PRIVATE "/source-charset:utf-8") else() target_compile_options(${BTCPP_LIBRARY} PRIVATE -Wall -Wextra) endif() @@ -197,7 +201,9 @@ message( STATUS "BTCPP_LIB_DESTINATION: ${BTCPP_LIB_DESTINATION} " ) message( STATUS "BTCPP_INCLUDE_DESTINATION: ${BTCPP_INCLUDE_DESTINATION} " ) message( STATUS "BTCPP_UNIT_TESTS: ${BTCPP_UNIT_TESTS} " ) +if (BTCPP_UNIT_TESTS OR BTCPP_EXAMPLES) add_subdirectory(sample_nodes) +endif() ###################################################### @@ -217,7 +223,7 @@ endif() # INSTALL INSTALL(TARGETS ${BTCPP_LIBRARY} - EXPORT ${PROJECT_NAME}Targets + EXPORT ${BTCPP_LIBRARY}Targets ARCHIVE DESTINATION ${BTCPP_LIB_DESTINATION} LIBRARY DESTINATION ${BTCPP_LIB_DESTINATION} RUNTIME DESTINATION ${BTCPP_BIN_DESTINATION} diff --git a/cmake/ament_build.cmake b/cmake/ament_build.cmake index 9de2fd099..55c3011b2 100644 --- a/cmake/ament_build.cmake +++ b/cmake/ament_build.cmake @@ -33,5 +33,6 @@ mark_as_advanced( macro(export_btcpp_package) ament_export_include_directories(include) ament_export_libraries(${BTCPP_LIBRARY}) + ament_export_targets(${BTCPP_LIBRARY}Targets) ament_package() endmacro() diff --git a/examples/t11_groot_howto.cpp b/examples/t11_groot_howto.cpp index 4b3d824e8..da974947c 100644 --- a/examples/t11_groot_howto.cpp +++ b/examples/t11_groot_howto.cpp @@ -4,6 +4,7 @@ #include "behaviortree_cpp/loggers/groot2_publisher.h" #include "behaviortree_cpp/xml_parsing.h" #include "behaviortree_cpp/json_export.h" +#include "behaviortree_cpp/loggers/bt_minitrace_logger.h" /** We are using the same example in Tutorial 5, * But this time we also show how to connect @@ -120,6 +121,7 @@ int main() // Logging with lightweight serialization BT::FileLogger2 logger2(tree, "t12_logger2.btlog"); + BT::MinitraceLogger minilog(tree, "minitrace.json"); while(1) { diff --git a/include/behaviortree_cpp/blackboard.h b/include/behaviortree_cpp/blackboard.h index afb650368..c6ae40904 100644 --- a/include/behaviortree_cpp/blackboard.h +++ b/include/behaviortree_cpp/blackboard.h @@ -136,6 +136,11 @@ class Blackboard Blackboard::Ptr parent(); + // recursively look for parent Blackboard, until you find the root + Blackboard* rootBlackboard(); + + const Blackboard* rootBlackboard() const; + private: mutable std::mutex mutex_; mutable std::recursive_mutex entry_mutex_; @@ -198,6 +203,11 @@ inline void Blackboard::unset(const std::string& key) template inline void Blackboard::set(const std::string& key, const T& value) { + if(StartWith(key, '@')) + { + rootBlackboard()->set(key.substr(1, key.size() - 1), value); + return; + } std::unique_lock lock(mutex_); // check local storage diff --git a/include/behaviortree_cpp/contrib/expected.hpp b/include/behaviortree_cpp/contrib/expected.hpp index adf375bb5..305f3abad 100644 --- a/include/behaviortree_cpp/contrib/expected.hpp +++ b/include/behaviortree_cpp/contrib/expected.hpp @@ -1,2537 +1,3555 @@ -// This version targets C++11 and later. -// -// Copyright (C) 2016-2020 Martin Moene. -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// expected lite is based on: -// A proposal to add a utility class to represent expected monad -// by Vicente J. Botet Escriba and Pierre Talbot. http:://wg21.link/p0323 - -#ifndef NONSTD_EXPECTED_LITE_HPP -#define NONSTD_EXPECTED_LITE_HPP - -#define expected_lite_MAJOR 0 -#define expected_lite_MINOR 6 -#define expected_lite_PATCH 3 - -#define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH) - -#define expected_STRINGIFY( x ) expected_STRINGIFY_( x ) -#define expected_STRINGIFY_( x ) #x - -// expected-lite configuration: - -#define nsel_EXPECTED_DEFAULT 0 -#define nsel_EXPECTED_NONSTD 1 -#define nsel_EXPECTED_STD 2 - -// tweak header support: - -#ifdef __has_include -# if __has_include() -# include -# endif -#define expected_HAVE_TWEAK_HEADER 1 -#else -#define expected_HAVE_TWEAK_HEADER 0 -//# pragma message("expected.hpp: Note: Tweak header not supported.") -#endif - -// expected selection and configuration: - -#if !defined( nsel_CONFIG_SELECT_EXPECTED ) -# define nsel_CONFIG_SELECT_EXPECTED ( nsel_HAVE_STD_EXPECTED ? nsel_EXPECTED_STD : nsel_EXPECTED_NONSTD ) -#endif - -// Proposal revisions: -// -// DXXXXR0: -- -// N4015 : -2 (2014-05-26) -// N4109 : -1 (2014-06-29) -// P0323R0: 0 (2016-05-28) -// P0323R1: 1 (2016-10-12) -// -------: -// P0323R2: 2 (2017-06-15) -// P0323R3: 3 (2017-10-15) -// P0323R4: 4 (2017-11-26) -// P0323R5: 5 (2018-02-08) -// P0323R6: 6 (2018-04-02) -// P0323R7: 7 (2018-06-22) * -// -// expected-lite uses 2 and higher - -#ifndef nsel_P0323R -# define nsel_P0323R 7 -#endif - -// Control presence of C++ exception handling (try and auto discover): - -#ifndef nsel_CONFIG_NO_EXCEPTIONS -# if defined(_MSC_VER) -# include // for _HAS_EXCEPTIONS -# endif -# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) -# define nsel_CONFIG_NO_EXCEPTIONS 0 -# else -# define nsel_CONFIG_NO_EXCEPTIONS 1 -# endif -#endif - -// at default use SEH with MSVC for no C++ exceptions - -#ifndef nsel_CONFIG_NO_EXCEPTIONS_SEH -# define nsel_CONFIG_NO_EXCEPTIONS_SEH ( nsel_CONFIG_NO_EXCEPTIONS && _MSC_VER ) -#endif - -// C++ language version detection (C++23 is speculative): -// Note: VC14.0/1900 (VS2015) lacks too much from C++14. - -#ifndef nsel_CPLUSPLUS -# if defined(_MSVC_LANG ) && !defined(__clang__) -# define nsel_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) -# else -# define nsel_CPLUSPLUS __cplusplus -# endif -#endif - -#define nsel_CPP98_OR_GREATER ( nsel_CPLUSPLUS >= 199711L ) -#define nsel_CPP11_OR_GREATER ( nsel_CPLUSPLUS >= 201103L ) -#define nsel_CPP14_OR_GREATER ( nsel_CPLUSPLUS >= 201402L ) -#define nsel_CPP17_OR_GREATER ( nsel_CPLUSPLUS >= 201703L ) -#define nsel_CPP20_OR_GREATER ( nsel_CPLUSPLUS >= 202002L ) -#define nsel_CPP23_OR_GREATER ( nsel_CPLUSPLUS >= 202300L ) - -// Use C++23 std::expected if available and requested: - -#if nsel_CPP23_OR_GREATER && defined(__has_include ) -# if __has_include( ) -# define nsel_HAVE_STD_EXPECTED 1 -# else -# define nsel_HAVE_STD_EXPECTED 0 -# endif -#else -# define nsel_HAVE_STD_EXPECTED 0 -#endif - -#define nsel_USES_STD_EXPECTED ( (nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) || ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && nsel_HAVE_STD_EXPECTED) ) - -// -// in_place: code duplicated in any-lite, expected-lite, expected-lite, value-ptr-lite, variant-lite: -// - -#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES -#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 - -// C++17 std::in_place in : - -#if nsel_CPP17_OR_GREATER - -#include - -namespace nonstd { - -using std::in_place; -using std::in_place_type; -using std::in_place_index; -using std::in_place_t; -using std::in_place_type_t; -using std::in_place_index_t; - -#define nonstd_lite_in_place_t( T) std::in_place_t -#define nonstd_lite_in_place_type_t( T) std::in_place_type_t -#define nonstd_lite_in_place_index_t(K) std::in_place_index_t - -#define nonstd_lite_in_place( T) std::in_place_t{} -#define nonstd_lite_in_place_type( T) std::in_place_type_t{} -#define nonstd_lite_in_place_index(K) std::in_place_index_t{} - -} // namespace nonstd - -#else // nsel_CPP17_OR_GREATER - -#include - -namespace nonstd { -namespace detail { - -template< class T > -struct in_place_type_tag {}; - -template< std::size_t K > -struct in_place_index_tag {}; - -} // namespace detail - -struct in_place_t {}; - -template< class T > -inline in_place_t in_place( detail::in_place_type_tag = detail::in_place_type_tag() ) -{ - return in_place_t(); -} - -template< std::size_t K > -inline in_place_t in_place( detail::in_place_index_tag = detail::in_place_index_tag() ) -{ - return in_place_t(); -} - -template< class T > -inline in_place_t in_place_type( detail::in_place_type_tag = detail::in_place_type_tag() ) -{ - return in_place_t(); -} - -template< std::size_t K > -inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_place_index_tag() ) -{ - return in_place_t(); -} - -// mimic templated typedef: - -#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) -#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) -#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) - -#define nonstd_lite_in_place( T) nonstd::in_place_type -#define nonstd_lite_in_place_type( T) nonstd::in_place_type -#define nonstd_lite_in_place_index(K) nonstd::in_place_index - -} // namespace nonstd - -#endif // nsel_CPP17_OR_GREATER -#endif // nonstd_lite_HAVE_IN_PLACE_TYPES - -// -// Using std::expected: -// - -#if nsel_USES_STD_EXPECTED - -#include - -namespace nonstd { - - using std::expected; -// ... -} - -#else // nsel_USES_STD_EXPECTED - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// additional includes: - -#if nsel_CONFIG_NO_EXCEPTIONS -# if nsel_CONFIG_NO_EXCEPTIONS_SEH -# include // for ExceptionCodes -# else -// already included: -# endif -#else -# include -#endif - -// C++ feature usage: - -#if nsel_CPP11_OR_GREATER -# define nsel_constexpr constexpr -#else -# define nsel_constexpr /*constexpr*/ -#endif - -#if nsel_CPP14_OR_GREATER -# define nsel_constexpr14 constexpr -#else -# define nsel_constexpr14 /*constexpr*/ -#endif - -#if nsel_CPP17_OR_GREATER -# define nsel_inline17 inline -#else -# define nsel_inline17 /*inline*/ -#endif - -// Compiler versions: -// -// MSVC++ 6.0 _MSC_VER == 1200 nsel_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) -// MSVC++ 7.0 _MSC_VER == 1300 nsel_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) -// MSVC++ 7.1 _MSC_VER == 1310 nsel_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) -// MSVC++ 8.0 _MSC_VER == 1400 nsel_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) -// MSVC++ 9.0 _MSC_VER == 1500 nsel_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) -// MSVC++ 10.0 _MSC_VER == 1600 nsel_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) -// MSVC++ 11.0 _MSC_VER == 1700 nsel_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) -// MSVC++ 12.0 _MSC_VER == 1800 nsel_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) -// MSVC++ 14.0 _MSC_VER == 1900 nsel_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) -// MSVC++ 14.1 _MSC_VER >= 1910 nsel_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) -// MSVC++ 14.2 _MSC_VER >= 1920 nsel_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) - -#if defined(_MSC_VER) && !defined(__clang__) -# define nsel_COMPILER_MSVC_VER (_MSC_VER ) -# define nsel_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) ) -#else -# define nsel_COMPILER_MSVC_VER 0 -# define nsel_COMPILER_MSVC_VERSION 0 -#endif - -#define nsel_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) - -#if defined(__clang__) -# define nsel_COMPILER_CLANG_VERSION nsel_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) -#else -# define nsel_COMPILER_CLANG_VERSION 0 -#endif - -#if defined(__GNUC__) && !defined(__clang__) -# define nsel_COMPILER_GNUC_VERSION nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#else -# define nsel_COMPILER_GNUC_VERSION 0 -#endif - -// half-open range [lo..hi): -//#define nsel_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) - -// Method enabling - -#define nsel_REQUIRES_0(...) \ - template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > - -#define nsel_REQUIRES_T(...) \ - , typename std::enable_if< (__VA_ARGS__), int >::type = 0 - -#define nsel_REQUIRES_R(R, ...) \ - typename std::enable_if< (__VA_ARGS__), R>::type - -#define nsel_REQUIRES_A(...) \ - , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr - -// Presence of language and library features: - -#ifdef _HAS_CPP0X -# define nsel_HAS_CPP0X _HAS_CPP0X -#else -# define nsel_HAS_CPP0X 0 -#endif - -//#define nsel_CPP11_140 (nsel_CPP11_OR_GREATER || nsel_COMPILER_MSVC_VER >= 1900) - -// Clang, GNUC, MSVC warning suppression macros: - -#ifdef __clang__ -# pragma clang diagnostic push -#elif defined __GNUC__ -# pragma GCC diagnostic push -#endif // __clang__ - -#if nsel_COMPILER_MSVC_VERSION >= 140 -# pragma warning( push ) -# define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(disable: codes) ) -#else -# define nsel_DISABLE_MSVC_WARNINGS(codes) -#endif - -#ifdef __clang__ -# define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") -#elif defined __GNUC__ -# define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") -#elif nsel_COMPILER_MSVC_VERSION >= 140 -# define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) ) -#else -# define nsel_RESTORE_WARNINGS() -#endif - -// Suppress the following MSVC (GSL) warnings: -// - C26409: Avoid calling new and delete explicitly, use std::make_unique instead (r.11) - -nsel_DISABLE_MSVC_WARNINGS( 26409 ) - -// -// expected: -// - -namespace nonstd { namespace expected_lite { - -// type traits C++17: - -namespace std17 { - -#if nsel_CPP17_OR_GREATER - -using std::conjunction; -using std::is_swappable; -using std::is_nothrow_swappable; - -#else // nsel_CPP17_OR_GREATER - -namespace detail { - -using std::swap; - -struct is_swappable -{ - template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > - static std::true_type test( int /* unused */); - - template< typename > - static std::false_type test(...); -}; - -struct is_nothrow_swappable -{ - // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): - - template< typename T > - static constexpr bool satisfies() - { - return noexcept( swap( std::declval(), std::declval() ) ); - } - - template< typename T > - static auto test( int ) -> std::integral_constant()>{} - - template< typename > - static auto test(...) -> std::false_type; -}; -} // namespace detail - -// is [nothrow] swappable: - -template< typename T > -struct is_swappable : decltype( detail::is_swappable::test(0) ){}; - -template< typename T > -struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; - -// conjunction: - -template< typename... > struct conjunction : std::true_type{}; -template< typename B1 > struct conjunction : B1{}; - -template< typename B1, typename... Bn > -struct conjunction : std::conditional, B1>::type{}; - -#endif // nsel_CPP17_OR_GREATER - -} // namespace std17 - -// type traits C++20: - -namespace std20 { - -#if defined(__cpp_lib_remove_cvref) - -using std::remove_cvref; - -#else - -template< typename T > -struct remove_cvref -{ - typedef typename std::remove_cv< typename std::remove_reference::type >::type type; -}; - -#endif - -} // namespace std20 - -// forward declaration: - -template< typename T, typename E > -class expected; - -namespace detail { - -/// discriminated union to hold value or 'error'. - -template< typename T, typename E > -class storage_t_impl -{ - template< typename, typename > friend class nonstd::expected_lite::expected; - -public: - using value_type = T; - using error_type = E; - - // no-op construction - storage_t_impl() {} - ~storage_t_impl() {} - - explicit storage_t_impl( bool has_value ) - : m_has_value( has_value ) - {} - - void construct_value( value_type const & e ) - { - new( &m_value ) value_type( e ); - } - - void construct_value( value_type && e ) - { - new( &m_value ) value_type( std::move( e ) ); - } - - template< class... Args > - void emplace_value( Args&&... args ) - { - new( &m_value ) value_type( std::forward(args)...); - } - - template< class U, class... Args > - void emplace_value( std::initializer_list il, Args&&... args ) - { - new( &m_value ) value_type( il, std::forward(args)... ); - } - - void destruct_value() - { - m_value.~value_type(); - } - - void construct_error( error_type const & e ) - { - new( &m_error ) error_type( e ); - } - - void construct_error( error_type && e ) - { - new( &m_error ) error_type( std::move( e ) ); - } - - template< class... Args > - void emplace_error( Args&&... args ) - { - new( &m_error ) error_type( std::forward(args)...); - } - - template< class U, class... Args > - void emplace_error( std::initializer_list il, Args&&... args ) - { - new( &m_error ) error_type( il, std::forward(args)... ); - } - - void destruct_error() - { - m_error.~error_type(); - } - - constexpr value_type const & value() const & - { - return m_value; - } - - value_type & value() & - { - return m_value; - } - - constexpr value_type const && value() const && - { - return std::move( m_value ); - } - - nsel_constexpr14 value_type && value() && - { - return std::move( m_value ); - } - - value_type const * value_ptr() const - { - return &m_value; - } - - value_type * value_ptr() - { - return &m_value; - } - - error_type const & error() const & - { - return m_error; - } - - error_type & error() & - { - return m_error; - } - - constexpr error_type const && error() const && - { - return std::move( m_error ); - } - - nsel_constexpr14 error_type && error() && - { - return std::move( m_error ); - } - - bool has_value() const - { - return m_has_value; - } - - void set_has_value( bool v ) - { - m_has_value = v; - } - -private: - union - { - value_type m_value; - error_type m_error; - }; - - bool m_has_value = false; -}; - -/// discriminated union to hold only 'error'. - -template< typename E > -struct storage_t_impl -{ - template< typename, typename > friend class nonstd::expected_lite::expected; - -public: - using value_type = void; - using error_type = E; - - // no-op construction - storage_t_impl() {} - ~storage_t_impl() {} - - explicit storage_t_impl( bool has_value ) - : m_has_value( has_value ) - {} - - void construct_error( error_type const & e ) - { - new( &m_error ) error_type( e ); - } - - void construct_error( error_type && e ) - { - new( &m_error ) error_type( std::move( e ) ); - } - - template< class... Args > - void emplace_error( Args&&... args ) - { - new( &m_error ) error_type( std::forward(args)...); - } - - template< class U, class... Args > - void emplace_error( std::initializer_list il, Args&&... args ) - { - new( &m_error ) error_type( il, std::forward(args)... ); - } - - void destruct_error() - { - m_error.~error_type(); - } - - error_type const & error() const & - { - return m_error; - } - - error_type & error() & - { - return m_error; - } - - constexpr error_type const && error() const && - { - return std::move( m_error ); - } - - nsel_constexpr14 error_type && error() && - { - return std::move( m_error ); - } - - bool has_value() const - { - return m_has_value; - } - - void set_has_value( bool v ) - { - m_has_value = v; - } - -private: - union - { - char m_dummy; - error_type m_error; - }; - - bool m_has_value = false; -}; - -template< typename T, typename E, bool isConstructable, bool isMoveable > -class storage_t -{ -public: - storage_t() = default; - ~storage_t() = default; - - explicit storage_t( bool has_value ) - : storage_t_impl( has_value ) - {} - - storage_t( storage_t const & other ) = delete; - storage_t( storage_t && other ) = delete; -}; - -template< typename T, typename E > -class storage_t : public storage_t_impl -{ -public: - storage_t() = default; - ~storage_t() = default; - - explicit storage_t( bool has_value ) - : storage_t_impl( has_value ) - {} - - storage_t( storage_t const & other ) - : storage_t_impl( other.has_value() ) - { - if ( this->has_value() ) this->construct_value( other.value() ); - else this->construct_error( other.error() ); - } - - storage_t(storage_t && other ) - : storage_t_impl( other.has_value() ) - { - if ( this->has_value() ) this->construct_value( std::move( other.value() ) ); - else this->construct_error( std::move( other.error() ) ); - } -}; - -template< typename E > -class storage_t : public storage_t_impl -{ -public: - storage_t() = default; - ~storage_t() = default; - - explicit storage_t( bool has_value ) - : storage_t_impl( has_value ) - {} - - storage_t( storage_t const & other ) - : storage_t_impl( other.has_value() ) - { - if ( this->has_value() ) ; - else this->construct_error( other.error() ); - } - - storage_t(storage_t && other ) - : storage_t_impl( other.has_value() ) - { - if ( this->has_value() ) ; - else this->construct_error( std::move( other.error() ) ); - } -}; - -template< typename T, typename E > -class storage_t : public storage_t_impl -{ -public: - storage_t() = default; - ~storage_t() = default; - - explicit storage_t( bool has_value ) - : storage_t_impl( has_value ) - {} - - storage_t( storage_t const & other ) - : storage_t_impl(other.has_value()) - { - if ( this->has_value() ) this->construct_value( other.value() ); - else this->construct_error( other.error() ); - } - - storage_t( storage_t && other ) = delete; -}; - -template< typename E > -class storage_t : public storage_t_impl -{ -public: - storage_t() = default; - ~storage_t() = default; - - explicit storage_t( bool has_value ) - : storage_t_impl( has_value ) - {} - - storage_t( storage_t const & other ) - : storage_t_impl(other.has_value()) - { - if ( this->has_value() ) ; - else this->construct_error( other.error() ); - } - - storage_t( storage_t && other ) = delete; -}; - -template< typename T, typename E > -class storage_t : public storage_t_impl -{ -public: - storage_t() = default; - ~storage_t() = default; - - explicit storage_t( bool has_value ) - : storage_t_impl( has_value ) - {} - - storage_t( storage_t const & other ) = delete; - - storage_t( storage_t && other ) - : storage_t_impl( other.has_value() ) - { - if ( this->has_value() ) this->construct_value( std::move( other.value() ) ); - else this->construct_error( std::move( other.error() ) ); - } -}; - -template< typename E > -class storage_t : public storage_t_impl -{ -public: - storage_t() = default; - ~storage_t() = default; - - explicit storage_t( bool has_value ) - : storage_t_impl( has_value ) - {} - - storage_t( storage_t const & other ) = delete; - - storage_t( storage_t && other ) - : storage_t_impl( other.has_value() ) - { - if ( this->has_value() ) ; - else this->construct_error( std::move( other.error() ) ); - } -}; - -} // namespace detail - -/// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected. - -#if nsel_P0323R <= 2 -template< typename E = std::exception_ptr > -class unexpected_type -#else -template< typename E > -class unexpected_type -#endif // nsel_P0323R -{ -public: - using error_type = E; - - // x.x.5.2.1 Constructors - -// unexpected_type() = delete; - - constexpr unexpected_type( unexpected_type const & ) = default; - constexpr unexpected_type( unexpected_type && ) = default; - - template< typename... Args - nsel_REQUIRES_T( - std::is_constructible::value - ) - > - constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), Args &&... args ) - : m_error( std::forward( args )...) - {} - - template< typename U, typename... Args - nsel_REQUIRES_T( - std::is_constructible, Args&&...>::value - ) - > - constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), std::initializer_list il, Args &&... args ) - : m_error( il, std::forward( args )...) - {} - - template< typename E2 - nsel_REQUIRES_T( - std::is_constructible::value - && !std::is_same< typename std20::remove_cvref::type, nonstd_lite_in_place_t(E2) >::value - && !std::is_same< typename std20::remove_cvref::type, unexpected_type >::value - ) - > - constexpr explicit unexpected_type( E2 && error ) - : m_error( std::forward( error ) ) - {} - - template< typename E2 - nsel_REQUIRES_T( - std::is_constructible< E, E2>::value - && !std::is_constructible & >::value - && !std::is_constructible >::value - && !std::is_constructible const & >::value - && !std::is_constructible const >::value - && !std::is_convertible< unexpected_type &, E>::value - && !std::is_convertible< unexpected_type , E>::value - && !std::is_convertible< unexpected_type const &, E>::value - && !std::is_convertible< unexpected_type const , E>::value - && !std::is_convertible< E2 const &, E>::value /*=> explicit */ - ) - > - constexpr explicit unexpected_type( unexpected_type const & error ) - : m_error( E{ error.value() } ) - {} - - template< typename E2 - nsel_REQUIRES_T( - std::is_constructible< E, E2>::value - && !std::is_constructible & >::value - && !std::is_constructible >::value - && !std::is_constructible const & >::value - && !std::is_constructible const >::value - && !std::is_convertible< unexpected_type &, E>::value - && !std::is_convertible< unexpected_type , E>::value - && !std::is_convertible< unexpected_type const &, E>::value - && !std::is_convertible< unexpected_type const , E>::value - && std::is_convertible< E2 const &, E>::value /*=> explicit */ - ) - > - constexpr /*non-explicit*/ unexpected_type( unexpected_type const & error ) - : m_error( error.value() ) - {} - - template< typename E2 - nsel_REQUIRES_T( - std::is_constructible< E, E2>::value - && !std::is_constructible & >::value - && !std::is_constructible >::value - && !std::is_constructible const & >::value - && !std::is_constructible const >::value - && !std::is_convertible< unexpected_type &, E>::value - && !std::is_convertible< unexpected_type , E>::value - && !std::is_convertible< unexpected_type const &, E>::value - && !std::is_convertible< unexpected_type const , E>::value - && !std::is_convertible< E2 const &, E>::value /*=> explicit */ - ) - > - constexpr explicit unexpected_type( unexpected_type && error ) - : m_error( E{ std::move( error.value() ) } ) - {} - - template< typename E2 - nsel_REQUIRES_T( - std::is_constructible< E, E2>::value - && !std::is_constructible & >::value - && !std::is_constructible >::value - && !std::is_constructible const & >::value - && !std::is_constructible const >::value - && !std::is_convertible< unexpected_type &, E>::value - && !std::is_convertible< unexpected_type , E>::value - && !std::is_convertible< unexpected_type const &, E>::value - && !std::is_convertible< unexpected_type const , E>::value - && std::is_convertible< E2 const &, E>::value /*=> non-explicit */ - ) - > - constexpr /*non-explicit*/ unexpected_type( unexpected_type && error ) - : m_error( std::move( error.value() ) ) - {} - - // x.x.5.2.2 Assignment - - nsel_constexpr14 unexpected_type& operator=( unexpected_type const & ) = default; - nsel_constexpr14 unexpected_type& operator=( unexpected_type && ) = default; - - template< typename E2 = E > - nsel_constexpr14 unexpected_type & operator=( unexpected_type const & other ) - { - unexpected_type{ other.value() }.swap( *this ); - return *this; - } - - template< typename E2 = E > - nsel_constexpr14 unexpected_type & operator=( unexpected_type && other ) - { - unexpected_type{ std::move( other.value() ) }.swap( *this ); - return *this; - } - - // x.x.5.2.3 Observers - - nsel_constexpr14 E & value() & noexcept - { - return m_error; - } - - constexpr E const & value() const & noexcept - { - return m_error; - } - -#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - - nsel_constexpr14 E && value() && noexcept - { - return std::move( m_error ); - } - - constexpr E const && value() const && noexcept - { - return std::move( m_error ); - } - -#endif - - // x.x.5.2.4 Swap - - template< typename U=E > - nsel_REQUIRES_R( void, - std17::is_swappable::value - ) - swap( unexpected_type & other ) noexcept ( - std17::is_nothrow_swappable::value - ) - { - using std::swap; - swap( m_error, other.m_error ); - } - - // TODO: ??? unexpected_type: in-class friend operator==, != - -private: - error_type m_error; -}; - -#if nsel_CPP17_OR_GREATER - -/// template deduction guide: - -template< typename E > -unexpected_type( E ) -> unexpected_type< E >; - -#endif - -/// class unexpected_type, std::exception_ptr specialization (P0323R2) - -#if !nsel_CONFIG_NO_EXCEPTIONS -#if nsel_P0323R <= 2 - -// TODO: Should expected be specialized for particular E types such as exception_ptr and how? -// See p0323r7 2.1. Ergonomics, http://wg21.link/p0323 -template<> -class unexpected_type< std::exception_ptr > -{ -public: - using error_type = std::exception_ptr; - - unexpected_type() = delete; - - ~unexpected_type(){} - - explicit unexpected_type( std::exception_ptr const & error ) - : m_error( error ) - {} - - explicit unexpected_type(std::exception_ptr && error ) - : m_error( std::move( error ) ) - {} - - template< typename E > - explicit unexpected_type( E error ) - : m_error( std::make_exception_ptr( error ) ) - {} - - std::exception_ptr const & value() const - { - return m_error; - } - - std::exception_ptr & value() - { - return m_error; - } - -private: - std::exception_ptr m_error; -}; - -#endif // nsel_P0323R -#endif // !nsel_CONFIG_NO_EXCEPTIONS - -/// x.x.4, Unexpected equality operators - -template< typename E1, typename E2 > -constexpr bool operator==( unexpected_type const & x, unexpected_type const & y ) -{ - return x.value() == y.value(); -} - -template< typename E1, typename E2 > -constexpr bool operator!=( unexpected_type const & x, unexpected_type const & y ) -{ - return ! ( x == y ); -} - -#if nsel_P0323R <= 2 - -template< typename E > -constexpr bool operator<( unexpected_type const & x, unexpected_type const & y ) -{ - return x.value() < y.value(); -} - -template< typename E > -constexpr bool operator>( unexpected_type const & x, unexpected_type const & y ) -{ - return ( y < x ); -} - -template< typename E > -constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) -{ - return ! ( y < x ); -} - -template< typename E > -constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) -{ - return ! ( x < y ); -} - -#endif // nsel_P0323R - -/// x.x.5 Specialized algorithms - -template< typename E - nsel_REQUIRES_T( - std17::is_swappable::value - ) -> -void swap( unexpected_type & x, unexpected_type & y) noexcept ( noexcept ( x.swap(y) ) ) -{ - x.swap( y ); -} - -#if nsel_P0323R <= 2 - -// unexpected: relational operators for std::exception_ptr: - -inline constexpr bool operator<( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) -{ - return false; -} - -inline constexpr bool operator>( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) -{ - return false; -} - -inline constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) -{ - return ( x == y ); -} - -inline constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) -{ - return ( x == y ); -} - -#endif // nsel_P0323R - -// unexpected: traits - -#if nsel_P0323R <= 3 - -template< typename E> -struct is_unexpected : std::false_type {}; - -template< typename E> -struct is_unexpected< unexpected_type > : std::true_type {}; - -#endif // nsel_P0323R - -// unexpected: factory - -// keep make_unexpected() removed in p0323r2 for pre-C++17: - -template< typename E> -nsel_constexpr14 auto -make_unexpected( E && value ) -> unexpected_type< typename std::decay::type > -{ - return unexpected_type< typename std::decay::type >( std::forward(value) ); -} - -#if nsel_P0323R <= 3 - -/*nsel_constexpr14*/ auto inline -make_unexpected_from_current_exception() -> unexpected_type< std::exception_ptr > -{ - return unexpected_type< std::exception_ptr >( std::current_exception() ); -} - -#endif // nsel_P0323R - -/// x.x.6, x.x.7 expected access error - -template< typename E > -class bad_expected_access; - -/// x.x.7 bad_expected_access: expected access error - -template <> -class bad_expected_access< void > : public std::exception -{ -public: - explicit bad_expected_access() - : std::exception() - {} -}; - -/// x.x.6 bad_expected_access: expected access error - -#if !nsel_CONFIG_NO_EXCEPTIONS - -template< typename E > -class bad_expected_access : public bad_expected_access< void > -{ -public: - using error_type = E; - - explicit bad_expected_access( error_type error ) - : m_error( error ) - {} - - virtual char const * what() const noexcept override - { - return "bad_expected_access"; - } - - nsel_constexpr14 error_type & error() & - { - return m_error; - } - - constexpr error_type const & error() const & - { - return m_error; - } - -#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - - nsel_constexpr14 error_type && error() && - { - return std::move( m_error ); - } - - constexpr error_type const && error() const && - { - return std::move( m_error ); - } - -#endif - -private: - error_type m_error; -}; - -#endif // nsel_CONFIG_NO_EXCEPTIONS - -/// x.x.8 unexpect tag, in_place_unexpected tag: construct an error - -struct unexpect_t{}; -using in_place_unexpected_t = unexpect_t; - -nsel_inline17 constexpr unexpect_t unexpect{}; -nsel_inline17 constexpr unexpect_t in_place_unexpected{}; - -/// class error_traits - -#if nsel_CONFIG_NO_EXCEPTIONS - -namespace detail { - inline bool text( char const * /*text*/ ) { return true; } -} - -template< typename Error > -struct error_traits -{ - static void rethrow( Error const & /*e*/ ) - { -#if nsel_CONFIG_NO_EXCEPTIONS_SEH - RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); -#else - assert( false && detail::text("throw bad_expected_access{ e };") ); -#endif - } -}; - -template<> -struct error_traits< std::exception_ptr > -{ - static void rethrow( std::exception_ptr const & /*e*/ ) - { -#if nsel_CONFIG_NO_EXCEPTIONS_SEH - RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); -#else - assert( false && detail::text("throw bad_expected_access{ e };") ); -#endif - } -}; - -template<> -struct error_traits< std::error_code > -{ - static void rethrow( std::error_code const & /*e*/ ) - { -#if nsel_CONFIG_NO_EXCEPTIONS_SEH - RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); -#else - assert( false && detail::text("throw std::system_error( e );") ); -#endif - } -}; - -#else // nsel_CONFIG_NO_EXCEPTIONS - -template< typename Error > -struct error_traits -{ - static void rethrow( Error const & e ) - { - throw bad_expected_access{ e }; - } -}; - -template<> -struct error_traits< std::exception_ptr > -{ - static void rethrow( std::exception_ptr const & e ) - { - std::rethrow_exception( e ); - } -}; - -template<> -struct error_traits< std::error_code > -{ - static void rethrow( std::error_code const & e ) - { - throw std::system_error( e ); - } -}; - -#endif // nsel_CONFIG_NO_EXCEPTIONS - -} // namespace expected_lite - -// provide nonstd::unexpected_type: - -using expected_lite::unexpected_type; - -namespace expected_lite { - -/// class expected - -#if nsel_P0323R <= 2 -template< typename T, typename E = std::exception_ptr > -class expected -#else -template< typename T, typename E > -class expected -#endif // nsel_P0323R -{ -private: - template< typename, typename > friend class expected; - -public: - using value_type = T; - using error_type = E; - using unexpected_type = nonstd::unexpected_type; - - template< typename U > - struct rebind - { - using type = expected; - }; - - // x.x.4.1 constructors - - nsel_REQUIRES_0( - std::is_default_constructible::value - ) - nsel_constexpr14 expected() - : contained( true ) - { - contained.construct_value( value_type() ); - } - - nsel_constexpr14 expected( expected const & ) = default; - nsel_constexpr14 expected( expected && ) = default; - - template< typename U, typename G - nsel_REQUIRES_T( - std::is_constructible< T, U const &>::value - && std::is_constructible::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< expected & , T>::value - && !std::is_convertible< expected &&, T>::value - && !std::is_convertible< expected const & , T>::value - && !std::is_convertible< expected const &&, T>::value - && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ - ) - > - nsel_constexpr14 explicit expected( expected const & other ) - : contained( other.has_value() ) - { - if ( has_value() ) contained.construct_value( T{ other.contained.value() } ); - else contained.construct_error( E{ other.contained.error() } ); - } - - template< typename U, typename G - nsel_REQUIRES_T( - std::is_constructible< T, U const &>::value - && std::is_constructible::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< expected & , T>::value - && !std::is_convertible< expected &&, T>::value - && !std::is_convertible< expected const &, T>::value - && !std::is_convertible< expected const &&, T>::value - && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ - ) - > - nsel_constexpr14 /*non-explicit*/ expected( expected const & other ) - : contained( other.has_value() ) - { - if ( has_value() ) contained.construct_value( other.contained.value() ); - else contained.construct_error( other.contained.error() ); - } - - template< typename U, typename G - nsel_REQUIRES_T( - std::is_constructible< T, U>::value - && std::is_constructible::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< expected & , T>::value - && !std::is_convertible< expected &&, T>::value - && !std::is_convertible< expected const & , T>::value - && !std::is_convertible< expected const &&, T>::value - && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ - ) - > - nsel_constexpr14 explicit expected( expected && other ) - : contained( other.has_value() ) - { - if ( has_value() ) contained.construct_value( T{ std::move( other.contained.value() ) } ); - else contained.construct_error( E{ std::move( other.contained.error() ) } ); - } - - template< typename U, typename G - nsel_REQUIRES_T( - std::is_constructible< T, U>::value - && std::is_constructible::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< expected & , T>::value - && !std::is_convertible< expected &&, T>::value - && !std::is_convertible< expected const & , T>::value - && !std::is_convertible< expected const &&, T>::value - && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ - ) - > - nsel_constexpr14 /*non-explicit*/ expected( expected && other ) - : contained( other.has_value() ) - { - if ( has_value() ) contained.construct_value( std::move( other.contained.value() ) ); - else contained.construct_error( std::move( other.contained.error() ) ); - } - - template< typename U = T - nsel_REQUIRES_T( - std::is_copy_constructible::value - ) - > - nsel_constexpr14 expected( value_type const & value ) - : contained( true ) - { - contained.construct_value( value ); - } - - template< typename U = T - nsel_REQUIRES_T( - std::is_constructible::value - && !std::is_same::type, nonstd_lite_in_place_t(U)>::value - && !std::is_same< expected , typename std20::remove_cvref::type>::value - && !std::is_same, typename std20::remove_cvref::type>::value - && !std::is_convertible::value /*=> explicit */ - ) - > - nsel_constexpr14 explicit expected( U && value ) noexcept - ( - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value - ) - : contained( true ) - { - contained.construct_value( T{ std::forward( value ) } ); - } - - template< typename U = T - nsel_REQUIRES_T( - std::is_constructible::value - && !std::is_same::type, nonstd_lite_in_place_t(U)>::value - && !std::is_same< expected , typename std20::remove_cvref::type>::value - && !std::is_same, typename std20::remove_cvref::type>::value - && std::is_convertible::value /*=> non-explicit */ - ) - > - nsel_constexpr14 /*non-explicit*/ expected( U && value ) noexcept - ( - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value - ) - : contained( true ) - { - contained.construct_value( std::forward( value ) ); - } - - // construct error: - - template< typename G = E - nsel_REQUIRES_T( - std::is_constructible::value - && !std::is_convertible< G const &, E>::value /*=> explicit */ - ) - > - nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) - : contained( false ) - { - contained.construct_error( E{ error.value() } ); - } - - template< typename G = E - nsel_REQUIRES_T( - std::is_constructible::value - && std::is_convertible< G const &, E>::value /*=> non-explicit */ - ) - > - nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) - : contained( false ) - { - contained.construct_error( error.value() ); - } - - template< typename G = E - nsel_REQUIRES_T( - std::is_constructible::value - && !std::is_convertible< G&&, E>::value /*=> explicit */ - ) - > - nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) - : contained( false ) - { - contained.construct_error( E{ std::move( error.value() ) } ); - } - - template< typename G = E - nsel_REQUIRES_T( - std::is_constructible::value - && std::is_convertible< G&&, E>::value /*=> non-explicit */ - ) - > - nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) - : contained( false ) - { - contained.construct_error( std::move( error.value() ) ); - } - - // in-place construction, value - - template< typename... Args - nsel_REQUIRES_T( - std::is_constructible::value - ) - > - nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), Args&&... args ) - : contained( true ) - { - contained.emplace_value( std::forward( args )... ); - } - - template< typename U, typename... Args - nsel_REQUIRES_T( - std::is_constructible, Args&&...>::value - ) - > - nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) - : contained( true ) - { - contained.emplace_value( il, std::forward( args )... ); - } - - // in-place construction, error - - template< typename... Args - nsel_REQUIRES_T( - std::is_constructible::value - ) - > - nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) - : contained( false ) - { - contained.emplace_error( std::forward( args )... ); - } - - template< typename U, typename... Args - nsel_REQUIRES_T( - std::is_constructible, Args&&...>::value - ) - > - nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) - : contained( false ) - { - contained.emplace_error( il, std::forward( args )... ); - } - - // x.x.4.2 destructor - - // TODO: ~expected: triviality - // Effects: If T is not cv void and is_trivially_destructible_v is false and bool(*this), calls val.~T(). If is_trivially_destructible_v is false and !bool(*this), calls unexpect.~unexpected(). - // Remarks: If either T is cv void or is_trivially_destructible_v is true, and is_trivially_destructible_v is true, then this destructor shall be a trivial destructor. - - ~expected() - { - if ( has_value() ) contained.destruct_value(); - else contained.destruct_error(); - } - - // x.x.4.3 assignment - - expected & operator=( expected const & other ) - { - expected( other ).swap( *this ); - return *this; - } - - expected & operator=( expected && other ) noexcept - ( - std::is_nothrow_move_constructible< T>::value - && std::is_nothrow_move_assignable< T>::value - && std::is_nothrow_move_constructible::value // added for missing - && std::is_nothrow_move_assignable< E>::value ) // nothrow above - { - expected( std::move( other ) ).swap( *this ); - return *this; - } - - template< typename U - nsel_REQUIRES_T( - !std::is_same, typename std20::remove_cvref::type>::value - && std17::conjunction, std::is_same> >::value - && std::is_constructible::value - && std::is_assignable< T&,U>::value - && std::is_nothrow_move_constructible::value ) - > - expected & operator=( U && value ) - { - expected( std::forward( value ) ).swap( *this ); - return *this; - } - - template< typename G = E - nsel_REQUIRES_T( - std::is_constructible::value && - std::is_copy_constructible::value // TODO: std::is_nothrow_copy_constructible - && std::is_copy_assignable::value - ) - > - expected & operator=( nonstd::unexpected_type const & error ) - { - expected( unexpect, error.value() ).swap( *this ); - return *this; - } - - template< typename G = E - nsel_REQUIRES_T( - std::is_constructible::value && - std::is_move_constructible::value // TODO: std::is_nothrow_move_constructible - && std::is_move_assignable::value - ) - > - expected & operator=( nonstd::unexpected_type && error ) - { - expected( unexpect, std::move( error.value() ) ).swap( *this ); - return *this; - } - - template< typename... Args - nsel_REQUIRES_T( - std::is_nothrow_constructible::value - ) - > - value_type & emplace( Args &&... args ) - { - expected( nonstd_lite_in_place(T), std::forward(args)... ).swap( *this ); - return value(); - } - - template< typename U, typename... Args - nsel_REQUIRES_T( - std::is_nothrow_constructible&, Args&&...>::value - ) - > - value_type & emplace( std::initializer_list il, Args &&... args ) - { - expected( nonstd_lite_in_place(T), il, std::forward(args)... ).swap( *this ); - return value(); - } - - // x.x.4.4 swap - - template< typename U=T, typename G=E > - nsel_REQUIRES_R( void, - std17::is_swappable< U>::value - && std17::is_swappable::value - && ( std::is_move_constructible::value || std::is_move_constructible::value ) - ) - swap( expected & other ) noexcept - ( - std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && - std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value - ) - { - using std::swap; - - if ( bool(*this) && bool(other) ) { swap( contained.value(), other.contained.value() ); } - else if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); } - else if ( bool(*this) && ! bool(other) ) { error_type t( std::move( other.error() ) ); - other.contained.destruct_error(); - other.contained.construct_value( std::move( contained.value() ) ); - contained.destruct_value(); - contained.construct_error( std::move( t ) ); - bool has_value = contained.has_value(); - bool other_has_value = other.has_value(); - other.contained.set_has_value(has_value); - contained.set_has_value(other_has_value); - } - else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); } - } - - // x.x.4.5 observers - - constexpr value_type const * operator ->() const - { - return assert( has_value() ), contained.value_ptr(); - } - - value_type * operator ->() - { - return assert( has_value() ), contained.value_ptr(); - } - - constexpr value_type const & operator *() const & - { - return assert( has_value() ), contained.value(); - } - - value_type & operator *() & - { - return assert( has_value() ), contained.value(); - } - -#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - - constexpr value_type const && operator *() const && - { - return std::move( ( assert( has_value() ), contained.value() ) ); - } - - nsel_constexpr14 value_type && operator *() && - { - return std::move( ( assert( has_value() ), contained.value() ) ); - } - -#endif - - constexpr explicit operator bool() const noexcept - { - return has_value(); - } - - constexpr bool has_value() const noexcept - { - return contained.has_value(); - } - - constexpr value_type const & value() const & - { - return has_value() - ? ( contained.value() ) - : ( error_traits::rethrow( contained.error() ), contained.value() ); - } - - value_type & value() & - { - return has_value() - ? ( contained.value() ) - : ( error_traits::rethrow( contained.error() ), contained.value() ); - } - -#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - - constexpr value_type const && value() const && - { - return std::move( has_value() - ? ( contained.value() ) - : ( error_traits::rethrow( contained.error() ), contained.value() ) ); - } - - nsel_constexpr14 value_type && value() && - { - return std::move( has_value() - ? ( contained.value() ) - : ( error_traits::rethrow( contained.error() ), contained.value() ) ); - } - -#endif - - constexpr error_type const & error() const & - { - return assert( ! has_value() ), contained.error(); - } - - error_type & error() & - { - return assert( ! has_value() ), contained.error(); - } - -#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - - constexpr error_type const && error() const && - { - return std::move( ( assert( ! has_value() ), contained.error() ) ); - } - - error_type && error() && - { - return std::move( ( assert( ! has_value() ), contained.error() ) ); - } - -#endif - - constexpr unexpected_type get_unexpected() const - { - return make_unexpected( contained.error() ); - } - - template< typename Ex > - bool has_exception() const - { - using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; - return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; - } - - template< typename U - nsel_REQUIRES_T( - std::is_copy_constructible< T>::value - && std::is_convertible::value - ) - > - value_type value_or( U && v ) const & - { - return has_value() - ? contained.value() - : static_cast( std::forward( v ) ); - } - - template< typename U - nsel_REQUIRES_T( - std::is_move_constructible< T>::value - && std::is_convertible::value - ) - > - value_type value_or( U && v ) && - { - return has_value() - ? std::move( contained.value() ) - : static_cast( std::forward( v ) ); - } - - // unwrap() - -// template -// constexpr expected expected,E>::unwrap() const&; - -// template -// constexpr expected expected::unwrap() const&; - -// template -// expected expected, E>::unwrap() &&; - -// template -// template expected expected::unwrap() &&; - - // factories - -// template< typename Ex, typename F> -// expected catch_exception(F&& f); - -// template< typename F> -// expected())),E> map(F&& func) ; - -// template< typename F> -// 'see below' bind(F&& func); - -// template< typename F> -// expected catch_error(F&& f); - -// template< typename F> -// 'see below' then(F&& func); - -private: - detail::storage_t - < - T - ,E - , std::is_copy_constructible::value && std::is_copy_constructible::value - , std::is_move_constructible::value && std::is_move_constructible::value - > - contained; -}; - -/// class expected, void specialization - -template< typename E > -class expected -{ -private: - template< typename, typename > friend class expected; - -public: - using value_type = void; - using error_type = E; - using unexpected_type = nonstd::unexpected_type; - - // x.x.4.1 constructors - - constexpr expected() noexcept - : contained( true ) - {} - - nsel_constexpr14 expected( expected const & other ) = default; - nsel_constexpr14 expected( expected && other ) = default; - - constexpr explicit expected( nonstd_lite_in_place_t(void) ) - : contained( true ) - {} - - template< typename G = E - nsel_REQUIRES_T( - !std::is_convertible::value /*=> explicit */ - ) - > - nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) - : contained( false ) - { - contained.construct_error( E{ error.value() } ); - } - - template< typename G = E - nsel_REQUIRES_T( - std::is_convertible::value /*=> non-explicit */ - ) - > - nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) - : contained( false ) - { - contained.construct_error( error.value() ); - } - - template< typename G = E - nsel_REQUIRES_T( - !std::is_convertible::value /*=> explicit */ - ) - > - nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) - : contained( false ) - { - contained.construct_error( E{ std::move( error.value() ) } ); - } - - template< typename G = E - nsel_REQUIRES_T( - std::is_convertible::value /*=> non-explicit */ - ) - > - nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) - : contained( false ) - { - contained.construct_error( std::move( error.value() ) ); - } - - template< typename... Args - nsel_REQUIRES_T( - std::is_constructible::value - ) - > - nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) - : contained( false ) - { - contained.emplace_error( std::forward( args )... ); - } - - template< typename U, typename... Args - nsel_REQUIRES_T( - std::is_constructible, Args&&...>::value - ) - > - nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) - : contained( false ) - { - contained.emplace_error( il, std::forward( args )... ); - } - - // destructor - - ~expected() - { - if ( ! has_value() ) - { - contained.destruct_error(); - } - } - - // x.x.4.3 assignment - - expected & operator=( expected const & other ) - { - expected( other ).swap( *this ); - return *this; - } - - expected & operator=( expected && other ) noexcept - ( - std::is_nothrow_move_assignable::value && - std::is_nothrow_move_constructible::value ) - { - expected( std::move( other ) ).swap( *this ); - return *this; - } - - void emplace() - { - expected().swap( *this ); - } - - // x.x.4.4 swap - - template< typename G = E > - nsel_REQUIRES_R( void, - std17::is_swappable::value - && std::is_move_constructible::value - ) - swap( expected & other ) noexcept - ( - std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value - ) - { - using std::swap; - - if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); } - else if ( bool(*this) && ! bool(other) ) { contained.construct_error( std::move( other.error() ) ); - bool has_value = contained.has_value(); - bool other_has_value = other.has_value(); - other.contained.set_has_value(has_value); - contained.set_has_value(other_has_value); - } - else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); } - } - - // x.x.4.5 observers - - constexpr explicit operator bool() const noexcept - { - return has_value(); - } - - constexpr bool has_value() const noexcept - { - return contained.has_value(); - } - - void value() const - { - if ( ! has_value() ) - { - error_traits::rethrow( contained.error() ); - } - } - - constexpr error_type const & error() const & - { - return assert( ! has_value() ), contained.error(); - } - - error_type & error() & - { - return assert( ! has_value() ), contained.error(); - } - -#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - - constexpr error_type const && error() const && - { - return std::move( ( assert( ! has_value() ), contained.error() ) ); - } - - error_type && error() && - { - return std::move( ( assert( ! has_value() ), contained.error() ) ); - } - -#endif - - constexpr unexpected_type get_unexpected() const - { - return make_unexpected( contained.error() ); - } - - template< typename Ex > - bool has_exception() const - { - using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; - return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; - } - -// template constexpr 'see below' unwrap() const&; -// -// template 'see below' unwrap() &&; - - // factories - -// template< typename Ex, typename F> -// expected catch_exception(F&& f); -// -// template< typename F> -// expected map(F&& func) ; -// -// template< typename F> -// 'see below' bind(F&& func) ; -// -// template< typename F> -// expected catch_error(F&& f); -// -// template< typename F> -// 'see below' then(F&& func); - -private: - detail::storage_t - < - void - , E - , std::is_copy_constructible::value - , std::is_move_constructible::value - > - contained; -}; - -// x.x.4.6 expected<>: comparison operators - -template< typename T1, typename E1, typename T2, typename E2 - nsel_REQUIRES_T( - !std::is_void::value && !std::is_void::value - ) -> -constexpr bool operator==( expected const & x, expected const & y ) -{ - return bool(x) != bool(y) ? false : bool(x) ? *x == *y : x.error() == y.error(); -} - -template< typename T1, typename E1, typename T2, typename E2 - nsel_REQUIRES_T( - std::is_void::value && std::is_void::value - ) -> -constexpr bool operator==( expected const & x, expected const & y ) -{ - return bool(x) != bool(y) ? false : bool(x) || static_cast( x.error() == y.error() ); -} - -template< typename T1, typename E1, typename T2, typename E2 > -constexpr bool operator!=( expected const & x, expected const & y ) -{ - return !(x == y); -} - -#if nsel_P0323R <= 2 - -template< typename T, typename E > -constexpr bool operator<( expected const & x, expected const & y ) -{ - return (!y) ? false : (!x) ? true : *x < *y; -} - -template< typename T, typename E > -constexpr bool operator>( expected const & x, expected const & y ) -{ - return (y < x); -} - -template< typename T, typename E > -constexpr bool operator<=( expected const & x, expected const & y ) -{ - return !(y < x); -} - -template< typename T, typename E > -constexpr bool operator>=( expected const & x, expected const & y ) -{ - return !(x < y); -} - -#endif - -// x.x.4.7 expected: comparison with T - -template< typename T1, typename E1, typename T2 - nsel_REQUIRES_T( - !std::is_void::value - ) -> -constexpr bool operator==( expected const & x, T2 const & v ) -{ - return bool(x) ? *x == v : false; -} - -template< typename T1, typename E1, typename T2 - nsel_REQUIRES_T( - !std::is_void::value - ) -> -constexpr bool operator==(T2 const & v, expected const & x ) -{ - return bool(x) ? v == *x : false; -} - -template< typename T1, typename E1, typename T2 > -constexpr bool operator!=( expected const & x, T2 const & v ) -{ - return bool(x) ? *x != v : true; -} - -template< typename T1, typename E1, typename T2 > -constexpr bool operator!=( T2 const & v, expected const & x ) -{ - return bool(x) ? v != *x : true; -} - -#if nsel_P0323R <= 2 - -template< typename T, typename E > -constexpr bool operator<( expected const & x, T const & v ) -{ - return bool(x) ? *x < v : true; -} - -template< typename T, typename E > -constexpr bool operator<( T const & v, expected const & x ) -{ - return bool(x) ? v < *x : false; -} - -template< typename T, typename E > -constexpr bool operator>( T const & v, expected const & x ) -{ - return bool(x) ? *x < v : false; -} - -template< typename T, typename E > -constexpr bool operator>( expected const & x, T const & v ) -{ - return bool(x) ? v < *x : false; -} - -template< typename T, typename E > -constexpr bool operator<=( T const & v, expected const & x ) -{ - return bool(x) ? ! ( *x < v ) : false; -} - -template< typename T, typename E > -constexpr bool operator<=( expected const & x, T const & v ) -{ - return bool(x) ? ! ( v < *x ) : true; -} - -template< typename T, typename E > -constexpr bool operator>=( expected const & x, T const & v ) -{ - return bool(x) ? ! ( *x < v ) : false; -} - -template< typename T, typename E > -constexpr bool operator>=( T const & v, expected const & x ) -{ - return bool(x) ? ! ( v < *x ) : true; -} - -#endif // nsel_P0323R - -// x.x.4.8 expected: comparison with unexpected_type - -template< typename T1, typename E1 , typename E2 > -constexpr bool operator==( expected const & x, unexpected_type const & u ) -{ - return (!x) ? x.get_unexpected() == u : false; -} - -template< typename T1, typename E1 , typename E2 > -constexpr bool operator==( unexpected_type const & u, expected const & x ) -{ - return ( x == u ); -} - -template< typename T1, typename E1 , typename E2 > -constexpr bool operator!=( expected const & x, unexpected_type const & u ) -{ - return ! ( x == u ); -} - -template< typename T1, typename E1 , typename E2 > -constexpr bool operator!=( unexpected_type const & u, expected const & x ) -{ - return ! ( x == u ); -} - -#if nsel_P0323R <= 2 - -template< typename T, typename E > -constexpr bool operator<( expected const & x, unexpected_type const & u ) -{ - return (!x) ? ( x.get_unexpected() < u ) : false; -} - -template< typename T, typename E > -constexpr bool operator<( unexpected_type const & u, expected const & x ) -{ - return (!x) ? ( u < x.get_unexpected() ) : true ; -} - -template< typename T, typename E > -constexpr bool operator>( expected const & x, unexpected_type const & u ) -{ - return ( u < x ); -} - -template< typename T, typename E > -constexpr bool operator>( unexpected_type const & u, expected const & x ) -{ - return ( x < u ); -} - -template< typename T, typename E > -constexpr bool operator<=( expected const & x, unexpected_type const & u ) -{ - return ! ( u < x ); -} - -template< typename T, typename E > -constexpr bool operator<=( unexpected_type const & u, expected const & x) -{ - return ! ( x < u ); -} - -template< typename T, typename E > -constexpr bool operator>=( expected const & x, unexpected_type const & u ) -{ - return ! ( u > x ); -} - -template< typename T, typename E > -constexpr bool operator>=( unexpected_type const & u, expected const & x ) -{ - return ! ( x > u ); -} - -#endif // nsel_P0323R - -/// x.x.x Specialized algorithms - -template< typename T, typename E - nsel_REQUIRES_T( - ( std::is_void::value || std::is_move_constructible::value ) - && std::is_move_constructible::value - && std17::is_swappable::value - && std17::is_swappable::value ) -> -void swap( expected & x, expected & y ) noexcept ( noexcept ( x.swap(y) ) ) -{ - x.swap( y ); -} - -#if nsel_P0323R <= 3 - -template< typename T > -constexpr auto make_expected( T && v ) -> expected< typename std::decay::type > -{ - return expected< typename std::decay::type >( std::forward( v ) ); -} - -// expected specialization: - -auto inline make_expected() -> expected -{ - return expected( in_place ); -} - -template< typename T > -constexpr auto make_expected_from_current_exception() -> expected -{ - return expected( make_unexpected_from_current_exception() ); -} - -template< typename T > -auto make_expected_from_exception( std::exception_ptr v ) -> expected -{ - return expected( unexpected_type( std::forward( v ) ) ); -} - -template< typename T, typename E > -constexpr auto make_expected_from_error( E e ) -> expected::type> -{ - return expected::type>( make_unexpected( e ) ); -} - -template< typename F - nsel_REQUIRES_T( ! std::is_same::type, void>::value ) -> -/*nsel_constexpr14*/ -auto make_expected_from_call( F f ) -> expected< typename std::result_of::type > -{ - try - { - return make_expected( f() ); - } - catch (...) - { - return make_unexpected_from_current_exception(); - } -} - -template< typename F - nsel_REQUIRES_T( std::is_same::type, void>::value ) -> -/*nsel_constexpr14*/ -auto make_expected_from_call( F f ) -> expected -{ - try - { - f(); - return make_expected(); - } - catch (...) - { - return make_unexpected_from_current_exception(); - } -} - -#endif // nsel_P0323R - -} // namespace expected_lite - -using namespace expected_lite; - -// using expected_lite::expected; -// using ... - -} // namespace nonstd - -namespace std { - -// expected: hash support - -template< typename T, typename E > -struct hash< nonstd::expected > -{ - using result_type = std::size_t; - using argument_type = nonstd::expected; - - constexpr result_type operator()(argument_type const & arg) const - { - return arg ? std::hash{}(*arg) : result_type{}; - } -}; - -// TBD - ?? remove? see spec. -template< typename T, typename E > -struct hash< nonstd::expected > -{ - using result_type = std::size_t; - using argument_type = nonstd::expected; - - constexpr result_type operator()(argument_type const & arg) const - { - return arg ? std::hash{}(*arg) : result_type{}; - } -}; - -// TBD - implement -// bool(e), hash>()(e) shall evaluate to the hashing true; -// otherwise it evaluates to an unspecified value if E is exception_ptr or -// a combination of hashing false and hash()(e.error()). - -template< typename E > -struct hash< nonstd::expected > -{ -}; - -} // namespace std - -namespace nonstd { - -// void unexpected() is deprecated && removed in C++17 - -#if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141 -template< typename E > -using unexpected = unexpected_type; -#endif - -} // namespace nonstd - -#undef nsel_REQUIRES -#undef nsel_REQUIRES_0 -#undef nsel_REQUIRES_T - -nsel_RESTORE_WARNINGS() - -#endif // nsel_USES_STD_EXPECTED - -#endif // NONSTD_EXPECTED_LITE_HPP +// This version targets C++11 and later. +// +// Copyright (C) 2016-2020 Martin Moene. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// expected lite is based on: +// A proposal to add a utility class to represent expected monad +// by Vicente J. Botet Escriba and Pierre Talbot. http:://wg21.link/p0323 + +#ifndef NONSTD_EXPECTED_LITE_HPP +#define NONSTD_EXPECTED_LITE_HPP + +#define expected_lite_MAJOR 0 +#define expected_lite_MINOR 8 +#define expected_lite_PATCH 0 + +#define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH) + +#define expected_STRINGIFY( x ) expected_STRINGIFY_( x ) +#define expected_STRINGIFY_( x ) #x + +// expected-lite configuration: + +#define nsel_EXPECTED_DEFAULT 0 +#define nsel_EXPECTED_NONSTD 1 +#define nsel_EXPECTED_STD 2 + +// tweak header support: + +#ifdef __has_include +# if __has_include() +# include +# endif +#define expected_HAVE_TWEAK_HEADER 1 +#else +#define expected_HAVE_TWEAK_HEADER 0 +//# pragma message("expected.hpp: Note: Tweak header not supported.") +#endif + +// expected selection and configuration: + +#if !defined( nsel_CONFIG_SELECT_EXPECTED ) +# define nsel_CONFIG_SELECT_EXPECTED ( nsel_HAVE_STD_EXPECTED ? nsel_EXPECTED_STD : nsel_EXPECTED_NONSTD ) +#endif + +// Proposal revisions: +// +// DXXXXR0: -- +// N4015 : -2 (2014-05-26) +// N4109 : -1 (2014-06-29) +// P0323R0: 0 (2016-05-28) +// P0323R1: 1 (2016-10-12) +// -------: +// P0323R2: 2 (2017-06-15) +// P0323R3: 3 (2017-10-15) +// P0323R4: 4 (2017-11-26) +// P0323R5: 5 (2018-02-08) +// P0323R6: 6 (2018-04-02) +// P0323R7: 7 (2018-06-22) * +// +// expected-lite uses 2 and higher + +#ifndef nsel_P0323R +# define nsel_P0323R 7 +#endif + +// Monadic operations proposal revisions: +// +// P2505R0: 0 (2021-12-12) +// P2505R1: 1 (2022-02-10) +// P2505R2: 2 (2022-04-15) +// P2505R3: 3 (2022-06-05) +// P2505R4: 4 (2022-06-15) +// P2505R5: 5 (2022-09-20) * +// +// expected-lite uses 5 + +#ifndef nsel_P2505R +# define nsel_P2505R 5 +#endif + +// Control presence of C++ exception handling (try and auto discover): + +#ifndef nsel_CONFIG_NO_EXCEPTIONS +# if defined(_MSC_VER) +# include // for _HAS_EXCEPTIONS +# endif +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) +# define nsel_CONFIG_NO_EXCEPTIONS 0 +# else +# define nsel_CONFIG_NO_EXCEPTIONS 1 +# endif +#endif + +// at default use SEH with MSVC for no C++ exceptions + +#ifndef nsel_CONFIG_NO_EXCEPTIONS_SEH +# define nsel_CONFIG_NO_EXCEPTIONS_SEH ( nsel_CONFIG_NO_EXCEPTIONS && _MSC_VER ) +#endif + +// C++ language version detection (C++23 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef nsel_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define nsel_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define nsel_CPLUSPLUS __cplusplus +# endif +#endif + +#define nsel_CPP98_OR_GREATER ( nsel_CPLUSPLUS >= 199711L ) +#define nsel_CPP11_OR_GREATER ( nsel_CPLUSPLUS >= 201103L ) +#define nsel_CPP14_OR_GREATER ( nsel_CPLUSPLUS >= 201402L ) +#define nsel_CPP17_OR_GREATER ( nsel_CPLUSPLUS >= 201703L ) +#define nsel_CPP20_OR_GREATER ( nsel_CPLUSPLUS >= 202002L ) +#define nsel_CPP23_OR_GREATER ( nsel_CPLUSPLUS >= 202300L ) + +// Use C++23 std::expected if available and requested: + +#if nsel_CPP23_OR_GREATER && defined(__has_include ) +# if __has_include( ) +# define nsel_HAVE_STD_EXPECTED 1 +# else +# define nsel_HAVE_STD_EXPECTED 0 +# endif +#else +# define nsel_HAVE_STD_EXPECTED 0 +#endif + +#define nsel_USES_STD_EXPECTED ( (nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) || ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && nsel_HAVE_STD_EXPECTED) ) + +// +// in_place: code duplicated in any-lite, expected-lite, expected-lite, value-ptr-lite, variant-lite: +// + +#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES +#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 + +// C++17 std::in_place in : + +#if nsel_CPP17_OR_GREATER + +#include + +namespace nonstd { + +using std::in_place; +using std::in_place_type; +using std::in_place_index; +using std::in_place_t; +using std::in_place_type_t; +using std::in_place_index_t; + +#define nonstd_lite_in_place_t( T) std::in_place_t +#define nonstd_lite_in_place_type_t( T) std::in_place_type_t +#define nonstd_lite_in_place_index_t(K) std::in_place_index_t + +#define nonstd_lite_in_place( T) std::in_place_t{} +#define nonstd_lite_in_place_type( T) std::in_place_type_t{} +#define nonstd_lite_in_place_index(K) std::in_place_index_t{} + +} // namespace nonstd + +#else // nsel_CPP17_OR_GREATER + +#include + +namespace nonstd { +namespace detail { + +template< class T > +struct in_place_type_tag {}; + +template< std::size_t K > +struct in_place_index_tag {}; + +} // namespace detail + +struct in_place_t {}; + +template< class T > +inline in_place_t in_place( detail::in_place_type_tag = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place( detail::in_place_index_tag = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +template< class T > +inline in_place_t in_place_type( detail::in_place_type_tag = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +// mimic templated typedef: + +#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) + +#define nonstd_lite_in_place( T) nonstd::in_place_type +#define nonstd_lite_in_place_type( T) nonstd::in_place_type +#define nonstd_lite_in_place_index(K) nonstd::in_place_index + +} // namespace nonstd + +#endif // nsel_CPP17_OR_GREATER +#endif // nonstd_lite_HAVE_IN_PLACE_TYPES + +// +// Using std::expected: +// + +#if nsel_USES_STD_EXPECTED + +#include + +namespace nonstd { + + using std::expected; + using std::unexpected; + using std::bad_expected_access; + using std::unexpect_t; + using std::unexpect; + + //[[deprecated("replace unexpected_type with unexpected")]] + + template< typename E > + using unexpected_type = unexpected; + + // Unconditionally provide make_unexpected(): + + template< typename E> + constexpr auto make_unexpected( E && value ) -> unexpected< typename std::decay::type > + { + return unexpected< typename std::decay::type >( std::forward(value) ); + } +} // namespace nonstd + +#else // nsel_USES_STD_EXPECTED + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// additional includes: + +#if nsel_CONFIG_NO_EXCEPTIONS +# if nsel_CONFIG_NO_EXCEPTIONS_SEH +# include // for ExceptionCodes +# else +// already included: +# endif +#else +# include +#endif + +// C++ feature usage: + +#if nsel_CPP11_OR_GREATER +# define nsel_constexpr constexpr +#else +# define nsel_constexpr /*constexpr*/ +#endif + +#if nsel_CPP14_OR_GREATER +# define nsel_constexpr14 constexpr +#else +# define nsel_constexpr14 /*constexpr*/ +#endif + +#if nsel_CPP17_OR_GREATER +# define nsel_inline17 inline +#else +# define nsel_inline17 /*inline*/ +#endif + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 nsel_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 nsel_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 nsel_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 nsel_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 nsel_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 nsel_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 nsel_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 nsel_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 nsel_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 nsel_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 nsel_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) + +#if defined(_MSC_VER) && !defined(__clang__) +# define nsel_COMPILER_MSVC_VER (_MSC_VER ) +# define nsel_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) ) +#else +# define nsel_COMPILER_MSVC_VER 0 +# define nsel_COMPILER_MSVC_VERSION 0 +#endif + +#define nsel_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) + +#if defined(__clang__) +# define nsel_COMPILER_CLANG_VERSION nsel_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +# define nsel_COMPILER_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define nsel_COMPILER_GNUC_VERSION nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +# define nsel_COMPILER_GNUC_VERSION 0 +#endif + +// half-open range [lo..hi): +//#define nsel_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Method enabling + +#define nsel_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > + +#define nsel_REQUIRES_T(...) \ + , typename std::enable_if< (__VA_ARGS__), int >::type = 0 + +#define nsel_REQUIRES_R(R, ...) \ + typename std::enable_if< (__VA_ARGS__), R>::type + +#define nsel_REQUIRES_A(...) \ + , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr + +// Clang, GNUC, MSVC warning suppression macros: + +#ifdef __clang__ +# pragma clang diagnostic push +#elif defined __GNUC__ +# pragma GCC diagnostic push +#endif // __clang__ + +#if nsel_COMPILER_MSVC_VERSION >= 140 +# define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(push) ) __pragma( warning(disable: codes) ) +#else +# define nsel_DISABLE_MSVC_WARNINGS(codes) +#endif + +#ifdef __clang__ +# define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") +# define nsel_RESTORE_MSVC_WARNINGS() +#elif defined __GNUC__ +# define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") +# define nsel_RESTORE_MSVC_WARNINGS() +#elif nsel_COMPILER_MSVC_VERSION >= 140 +# define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) ) +# define nsel_RESTORE_MSVC_WARNINGS() nsel_RESTORE_WARNINGS() +#else +# define nsel_RESTORE_WARNINGS() +# define nsel_RESTORE_MSVC_WARNINGS() +#endif + +// Suppress the following MSVC (GSL) warnings: +// - C26409: Avoid calling new and delete explicitly, use std::make_unique instead (r.11) + +nsel_DISABLE_MSVC_WARNINGS( 26409 ) + +// Presence of language and library features: + +#ifdef _HAS_CPP0X +# define nsel_HAS_CPP0X _HAS_CPP0X +#else +# define nsel_HAS_CPP0X 0 +#endif + +// Presence of language and library features: + +#define nsel_CPP17_000 (nsel_CPP17_OR_GREATER) + +// Presence of C++17 language features: + +#define nsel_HAVE_DEPRECATED nsel_CPP17_000 + +// C++ feature usage: + +#if nsel_HAVE_DEPRECATED +# define nsel_deprecated(msg) [[deprecated(msg)]] +#else +# define nsel_deprecated(msg) /*[[deprecated]]*/ +#endif + +// +// expected: +// + +namespace nonstd { namespace expected_lite { + +// type traits C++17: + +namespace std17 { + +#if nsel_CPP17_OR_GREATER + +using std::conjunction; +using std::is_swappable; +using std::is_nothrow_swappable; + +#else // nsel_CPP17_OR_GREATER + +namespace detail { + +using std::swap; + +struct is_swappable +{ + template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > + static std::true_type test( int /* unused */); + + template< typename > + static std::false_type test(...); +}; + +struct is_nothrow_swappable +{ + // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): + + template< typename T > + static constexpr bool satisfies() + { + return noexcept( swap( std::declval(), std::declval() ) ); + } + + template< typename T > + static auto test( int ) -> std::integral_constant()>{} + + template< typename > + static auto test(...) -> std::false_type; +}; +} // namespace detail + +// is [nothrow] swappable: + +template< typename T > +struct is_swappable : decltype( detail::is_swappable::test(0) ){}; + +template< typename T > +struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; + +// conjunction: + +template< typename... > struct conjunction : std::true_type{}; +template< typename B1 > struct conjunction : B1{}; + +template< typename B1, typename... Bn > +struct conjunction : std::conditional, B1>::type{}; + +#endif // nsel_CPP17_OR_GREATER + +} // namespace std17 + +// type traits C++20: + +namespace std20 { + +#if defined(__cpp_lib_remove_cvref) + +using std::remove_cvref; + +#else + +template< typename T > +struct remove_cvref +{ + typedef typename std::remove_cv< typename std::remove_reference::type >::type type; +}; + +#endif + +} // namespace std20 + +// forward declaration: + +template< typename T, typename E > +class expected; + +namespace detail { + +#if nsel_P2505R >= 3 +template< typename T > +struct is_expected : std::false_type {}; + +template< typename T, typename E > +struct is_expected< expected< T, E > > : std::true_type {}; +#endif // nsel_P2505R >= 3 + +/// discriminated union to hold value or 'error'. + +template< typename T, typename E > +class storage_t_noncopy_nonmove_impl +{ + template< typename, typename > friend class nonstd::expected_lite::expected; + +public: + using value_type = T; + using error_type = E; + + // no-op construction + storage_t_noncopy_nonmove_impl() {} + ~storage_t_noncopy_nonmove_impl() {} + + explicit storage_t_noncopy_nonmove_impl( bool has_value ) + : m_has_value( has_value ) + {} + + void construct_value() + { + new( &m_value ) value_type(); + } + + // void construct_value( value_type const & e ) + // { + // new( &m_value ) value_type( e ); + // } + + // void construct_value( value_type && e ) + // { + // new( &m_value ) value_type( std::move( e ) ); + // } + + template< class... Args > + void emplace_value( Args&&... args ) + { + new( &m_value ) value_type( std::forward(args)...); + } + + template< class U, class... Args > + void emplace_value( std::initializer_list il, Args&&... args ) + { + new( &m_value ) value_type( il, std::forward(args)... ); + } + + void destruct_value() + { + m_value.~value_type(); + } + + // void construct_error( error_type const & e ) + // { + // // new( &m_error ) error_type( e ); + // } + + // void construct_error( error_type && e ) + // { + // // new( &m_error ) error_type( std::move( e ) ); + // } + + template< class... Args > + void emplace_error( Args&&... args ) + { + new( &m_error ) error_type( std::forward(args)...); + } + + template< class U, class... Args > + void emplace_error( std::initializer_list il, Args&&... args ) + { + new( &m_error ) error_type( il, std::forward(args)... ); + } + + void destruct_error() + { + m_error.~error_type(); + } + + constexpr value_type const & value() const & + { + return m_value; + } + + value_type & value() & + { + return m_value; + } + + constexpr value_type const && value() const && + { + return std::move( m_value ); + } + + nsel_constexpr14 value_type && value() && + { + return std::move( m_value ); + } + + value_type const * value_ptr() const + { + return &m_value; + } + + value_type * value_ptr() + { + return &m_value; + } + + error_type const & error() const & + { + return m_error; + } + + error_type & error() & + { + return m_error; + } + + constexpr error_type const && error() const && + { + return std::move( m_error ); + } + + nsel_constexpr14 error_type && error() && + { + return std::move( m_error ); + } + + bool has_value() const + { + return m_has_value; + } + + void set_has_value( bool v ) + { + m_has_value = v; + } + +private: + union + { + value_type m_value; + error_type m_error; + }; + + bool m_has_value = false; +}; + +template< typename T, typename E > +class storage_t_impl +{ + template< typename, typename > friend class nonstd::expected_lite::expected; + +public: + using value_type = T; + using error_type = E; + + // no-op construction + storage_t_impl() {} + ~storage_t_impl() {} + + explicit storage_t_impl( bool has_value ) + : m_has_value( has_value ) + {} + + void construct_value() + { + new( &m_value ) value_type(); + } + + void construct_value( value_type const & e ) + { + new( &m_value ) value_type( e ); + } + + void construct_value( value_type && e ) + { + new( &m_value ) value_type( std::move( e ) ); + } + + template< class... Args > + void emplace_value( Args&&... args ) + { + new( &m_value ) value_type( std::forward(args)...); + } + + template< class U, class... Args > + void emplace_value( std::initializer_list il, Args&&... args ) + { + new( &m_value ) value_type( il, std::forward(args)... ); + } + + void destruct_value() + { + m_value.~value_type(); + } + + void construct_error( error_type const & e ) + { + new( &m_error ) error_type( e ); + } + + void construct_error( error_type && e ) + { + new( &m_error ) error_type( std::move( e ) ); + } + + template< class... Args > + void emplace_error( Args&&... args ) + { + new( &m_error ) error_type( std::forward(args)...); + } + + template< class U, class... Args > + void emplace_error( std::initializer_list il, Args&&... args ) + { + new( &m_error ) error_type( il, std::forward(args)... ); + } + + void destruct_error() + { + m_error.~error_type(); + } + + constexpr value_type const & value() const & + { + return m_value; + } + + value_type & value() & + { + return m_value; + } + + constexpr value_type const && value() const && + { + return std::move( m_value ); + } + + nsel_constexpr14 value_type && value() && + { + return std::move( m_value ); + } + + value_type const * value_ptr() const + { + return &m_value; + } + + value_type * value_ptr() + { + return &m_value; + } + + error_type const & error() const & + { + return m_error; + } + + error_type & error() & + { + return m_error; + } + + constexpr error_type const && error() const && + { + return std::move( m_error ); + } + + nsel_constexpr14 error_type && error() && + { + return std::move( m_error ); + } + + bool has_value() const + { + return m_has_value; + } + + void set_has_value( bool v ) + { + m_has_value = v; + } + +private: + union + { + value_type m_value; + error_type m_error; + }; + + bool m_has_value = false; +}; + +/// discriminated union to hold only 'error'. + +template< typename E > +struct storage_t_impl +{ + template< typename, typename > friend class nonstd::expected_lite::expected; + +public: + using value_type = void; + using error_type = E; + + // no-op construction + storage_t_impl() {} + ~storage_t_impl() {} + + explicit storage_t_impl( bool has_value ) + : m_has_value( has_value ) + {} + + void construct_error( error_type const & e ) + { + new( &m_error ) error_type( e ); + } + + void construct_error( error_type && e ) + { + new( &m_error ) error_type( std::move( e ) ); + } + + template< class... Args > + void emplace_error( Args&&... args ) + { + new( &m_error ) error_type( std::forward(args)...); + } + + template< class U, class... Args > + void emplace_error( std::initializer_list il, Args&&... args ) + { + new( &m_error ) error_type( il, std::forward(args)... ); + } + + void destruct_error() + { + m_error.~error_type(); + } + + error_type const & error() const & + { + return m_error; + } + + error_type & error() & + { + return m_error; + } + + constexpr error_type const && error() const && + { + return std::move( m_error ); + } + + nsel_constexpr14 error_type && error() && + { + return std::move( m_error ); + } + + bool has_value() const + { + return m_has_value; + } + + void set_has_value( bool v ) + { + m_has_value = v; + } + +private: + union + { + char m_dummy; + error_type m_error; + }; + + bool m_has_value = false; +}; + +template< typename T, typename E, bool isConstructable, bool isMoveable > +class storage_t +{ +public: +}; + +template< typename T, typename E > +class storage_t : public storage_t_noncopy_nonmove_impl +{ +public: + storage_t() = default; + ~storage_t() = default; + + explicit storage_t( bool has_value ) + : storage_t_noncopy_nonmove_impl( has_value ) + {} + + storage_t( storage_t const & other ) = delete; + storage_t( storage_t && other ) = delete; + +}; + +template< typename T, typename E > +class storage_t : public storage_t_impl +{ +public: + storage_t() = default; + ~storage_t() = default; + + explicit storage_t( bool has_value ) + : storage_t_impl( has_value ) + {} + + storage_t( storage_t const & other ) + : storage_t_impl( other.has_value() ) + { + if ( this->has_value() ) this->construct_value( other.value() ); + else this->construct_error( other.error() ); + } + + storage_t(storage_t && other ) + : storage_t_impl( other.has_value() ) + { + if ( this->has_value() ) this->construct_value( std::move( other.value() ) ); + else this->construct_error( std::move( other.error() ) ); + } +}; + +template< typename E > +class storage_t : public storage_t_impl +{ +public: + storage_t() = default; + ~storage_t() = default; + + explicit storage_t( bool has_value ) + : storage_t_impl( has_value ) + {} + + storage_t( storage_t const & other ) + : storage_t_impl( other.has_value() ) + { + if ( this->has_value() ) ; + else this->construct_error( other.error() ); + } + + storage_t(storage_t && other ) + : storage_t_impl( other.has_value() ) + { + if ( this->has_value() ) ; + else this->construct_error( std::move( other.error() ) ); + } +}; + +template< typename T, typename E > +class storage_t : public storage_t_impl +{ +public: + storage_t() = default; + ~storage_t() = default; + + explicit storage_t( bool has_value ) + : storage_t_impl( has_value ) + {} + + storage_t( storage_t const & other ) + : storage_t_impl(other.has_value()) + { + if ( this->has_value() ) this->construct_value( other.value() ); + else this->construct_error( other.error() ); + } + + storage_t( storage_t && other ) = delete; +}; + +template< typename E > +class storage_t : public storage_t_impl +{ +public: + storage_t() = default; + ~storage_t() = default; + + explicit storage_t( bool has_value ) + : storage_t_impl( has_value ) + {} + + storage_t( storage_t const & other ) + : storage_t_impl(other.has_value()) + { + if ( this->has_value() ) ; + else this->construct_error( other.error() ); + } + + storage_t( storage_t && other ) = delete; +}; + +template< typename T, typename E > +class storage_t : public storage_t_impl +{ +public: + storage_t() = default; + ~storage_t() = default; + + explicit storage_t( bool has_value ) + : storage_t_impl( has_value ) + {} + + storage_t( storage_t const & other ) = delete; + + storage_t( storage_t && other ) + : storage_t_impl( other.has_value() ) + { + if ( this->has_value() ) this->construct_value( std::move( other.value() ) ); + else this->construct_error( std::move( other.error() ) ); + } +}; + +template< typename E > +class storage_t : public storage_t_impl +{ +public: + storage_t() = default; + ~storage_t() = default; + + explicit storage_t( bool has_value ) + : storage_t_impl( has_value ) + {} + + storage_t( storage_t const & other ) = delete; + + storage_t( storage_t && other ) + : storage_t_impl( other.has_value() ) + { + if ( this->has_value() ) ; + else this->construct_error( std::move( other.error() ) ); + } +}; + +#if nsel_P2505R >= 3 +// C++11 invoke implementation +template< typename > +struct is_reference_wrapper : std::false_type {}; +template< typename T > +struct is_reference_wrapper< std::reference_wrapper< T > > : std::true_type {}; + +template< typename FnT, typename ClassT, typename ObjectT, typename... Args + nsel_REQUIRES_T( + std::is_function::value + && ( std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value ) + ) +> +nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) + noexcept( noexcept( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ) ) ) + -> decltype( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )...) ) +{ + return (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ); +} + +template< typename FnT, typename ClassT, typename ObjectT, typename... Args + nsel_REQUIRES_T( + std::is_function::value + && is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) + noexcept( noexcept( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) ) + -> decltype( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) +{ + return (obj.get().*memfnptr)( std::forward< Args >( args ) ... ); +} + +template< typename FnT, typename ClassT, typename ObjectT, typename... Args + nsel_REQUIRES_T( + std::is_function::value + && !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) + noexcept( noexcept( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) ) + -> decltype( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) +{ + return ((*std::forward(obj)).*memfnptr)( std::forward< Args >( args ) ... ); +} + +template< typename MemberT, typename ClassT, typename ObjectT + nsel_REQUIRES_T( + std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) + noexcept( noexcept( std::forward< ObjectT >( obj ).*memobjptr ) ) + -> decltype( std::forward< ObjectT >( obj ).*memobjptr ) +{ + return std::forward< ObjectT >( obj ).*memobjptr; +} + +template< typename MemberT, typename ClassT, typename ObjectT + nsel_REQUIRES_T( + is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) + noexcept( noexcept( obj.get().*memobjptr ) ) + -> decltype( obj.get().*memobjptr ) +{ + return obj.get().*memobjptr; +} + +template< typename MemberT, typename ClassT, typename ObjectT + nsel_REQUIRES_T( + !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) + noexcept( noexcept( (*std::forward< ObjectT >( obj )).*memobjptr ) ) + -> decltype( (*std::forward< ObjectT >( obj )).*memobjptr ) +{ + return (*std::forward< ObjectT >( obj )).*memobjptr; +} + +template< typename F, typename... Args + nsel_REQUIRES_T( + std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value + ) +> +nsel_constexpr auto invoke( F && f, Args && ... args ) + noexcept( noexcept( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) ) + -> decltype( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) +{ + return invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ); +} + +template< typename F, typename... Args + nsel_REQUIRES_T( + std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value + ) +> +nsel_constexpr auto invoke( F && f, Args && ... args ) + noexcept( noexcept( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) ) + -> decltype( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) +{ + return invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ); +} + +template< typename F, typename... Args + nsel_REQUIRES_T( + !std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value + && !std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value + ) +> +nsel_constexpr auto invoke( F && f, Args && ... args ) + noexcept( noexcept( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) ) + -> decltype( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) +{ + return std::forward< F >( f )( std::forward< Args >( args ) ... ); +} + +template< typename F, typename ... Args > +using invoke_result_nocvref_t = typename std20::remove_cvref< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type; + +#if nsel_P2505R >= 5 +template< typename F, typename ... Args > +using transform_invoke_result_t = typename std::remove_cv< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type; +#else +template< typename F, typename ... Args > +using transform_invoke_result_t = invoke_result_nocvref_t +#endif // nsel_P2505R >= 5 + +template< typename T > +struct valid_expected_value_type : std::integral_constant< bool, std::is_destructible< T >::value && !std::is_reference< T >::value && !std::is_array< T >::value > {}; + +#endif // nsel_P2505R >= 3 +} // namespace detail + +/// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected. + +#if nsel_P0323R <= 2 +template< typename E = std::exception_ptr > +class unexpected_type +#else +template< typename E > +class unexpected_type +#endif // nsel_P0323R +{ +public: + using error_type = E; + + // x.x.5.2.1 Constructors + +// unexpected_type() = delete; + + constexpr unexpected_type( unexpected_type const & ) = default; + constexpr unexpected_type( unexpected_type && ) = default; + + template< typename... Args + nsel_REQUIRES_T( + std::is_constructible::value + ) + > + constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), Args &&... args ) + : m_error( std::forward( args )...) + {} + + template< typename U, typename... Args + nsel_REQUIRES_T( + std::is_constructible, Args&&...>::value + ) + > + constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), std::initializer_list il, Args &&... args ) + : m_error( il, std::forward( args )...) + {} + + template< typename E2 + nsel_REQUIRES_T( + std::is_constructible::value + && !std::is_same< typename std20::remove_cvref::type, nonstd_lite_in_place_t(E2) >::value + && !std::is_same< typename std20::remove_cvref::type, unexpected_type >::value + ) + > + constexpr explicit unexpected_type( E2 && error ) + : m_error( std::forward( error ) ) + {} + + template< typename E2 + nsel_REQUIRES_T( + std::is_constructible< E, E2>::value + && !std::is_constructible & >::value + && !std::is_constructible >::value + && !std::is_constructible const & >::value + && !std::is_constructible const >::value + && !std::is_convertible< unexpected_type &, E>::value + && !std::is_convertible< unexpected_type , E>::value + && !std::is_convertible< unexpected_type const &, E>::value + && !std::is_convertible< unexpected_type const , E>::value + && !std::is_convertible< E2 const &, E>::value /*=> explicit */ + ) + > + constexpr explicit unexpected_type( unexpected_type const & error ) + : m_error( E{ error.error() } ) + {} + + template< typename E2 + nsel_REQUIRES_T( + std::is_constructible< E, E2>::value + && !std::is_constructible & >::value + && !std::is_constructible >::value + && !std::is_constructible const & >::value + && !std::is_constructible const >::value + && !std::is_convertible< unexpected_type &, E>::value + && !std::is_convertible< unexpected_type , E>::value + && !std::is_convertible< unexpected_type const &, E>::value + && !std::is_convertible< unexpected_type const , E>::value + && std::is_convertible< E2 const &, E>::value /*=> explicit */ + ) + > + constexpr /*non-explicit*/ unexpected_type( unexpected_type const & error ) + : m_error( error.error() ) + {} + + template< typename E2 + nsel_REQUIRES_T( + std::is_constructible< E, E2>::value + && !std::is_constructible & >::value + && !std::is_constructible >::value + && !std::is_constructible const & >::value + && !std::is_constructible const >::value + && !std::is_convertible< unexpected_type &, E>::value + && !std::is_convertible< unexpected_type , E>::value + && !std::is_convertible< unexpected_type const &, E>::value + && !std::is_convertible< unexpected_type const , E>::value + && !std::is_convertible< E2 const &, E>::value /*=> explicit */ + ) + > + constexpr explicit unexpected_type( unexpected_type && error ) + : m_error( E{ std::move( error.error() ) } ) + {} + + template< typename E2 + nsel_REQUIRES_T( + std::is_constructible< E, E2>::value + && !std::is_constructible & >::value + && !std::is_constructible >::value + && !std::is_constructible const & >::value + && !std::is_constructible const >::value + && !std::is_convertible< unexpected_type &, E>::value + && !std::is_convertible< unexpected_type , E>::value + && !std::is_convertible< unexpected_type const &, E>::value + && !std::is_convertible< unexpected_type const , E>::value + && std::is_convertible< E2 const &, E>::value /*=> non-explicit */ + ) + > + constexpr /*non-explicit*/ unexpected_type( unexpected_type && error ) + : m_error( std::move( error.error() ) ) + {} + + // x.x.5.2.2 Assignment + + nsel_constexpr14 unexpected_type& operator=( unexpected_type const & ) = default; + nsel_constexpr14 unexpected_type& operator=( unexpected_type && ) = default; + + template< typename E2 = E > + nsel_constexpr14 unexpected_type & operator=( unexpected_type const & other ) + { + unexpected_type{ other.error() }.swap( *this ); + return *this; + } + + template< typename E2 = E > + nsel_constexpr14 unexpected_type & operator=( unexpected_type && other ) + { + unexpected_type{ std::move( other.error() ) }.swap( *this ); + return *this; + } + + // x.x.5.2.3 Observers + + nsel_constexpr14 E & error() & noexcept + { + return m_error; + } + + constexpr E const & error() const & noexcept + { + return m_error; + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + + nsel_constexpr14 E && error() && noexcept + { + return std::move( m_error ); + } + + constexpr E const && error() const && noexcept + { + return std::move( m_error ); + } + +#endif + + // x.x.5.2.3 Observers - deprecated + + nsel_deprecated("replace value() with error()") + + nsel_constexpr14 E & value() & noexcept + { + return m_error; + } + + nsel_deprecated("replace value() with error()") + + constexpr E const & value() const & noexcept + { + return m_error; + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + + nsel_deprecated("replace value() with error()") + + nsel_constexpr14 E && value() && noexcept + { + return std::move( m_error ); + } + + nsel_deprecated("replace value() with error()") + + constexpr E const && value() const && noexcept + { + return std::move( m_error ); + } + +#endif + + // x.x.5.2.4 Swap + + template< typename U=E > + nsel_REQUIRES_R( void, + std17::is_swappable::value + ) + swap( unexpected_type & other ) noexcept ( + std17::is_nothrow_swappable::value + ) + { + using std::swap; + swap( m_error, other.m_error ); + } + + // TODO: ??? unexpected_type: in-class friend operator==, != + +private: + error_type m_error; +}; + +#if nsel_CPP17_OR_GREATER + +/// template deduction guide: + +template< typename E > +unexpected_type( E ) -> unexpected_type< E >; + +#endif + +/// class unexpected_type, std::exception_ptr specialization (P0323R2) + +#if !nsel_CONFIG_NO_EXCEPTIONS +#if nsel_P0323R <= 2 + +// TODO: Should expected be specialized for particular E types such as exception_ptr and how? +// See p0323r7 2.1. Ergonomics, http://wg21.link/p0323 +template<> +class unexpected_type< std::exception_ptr > +{ +public: + using error_type = std::exception_ptr; + + unexpected_type() = delete; + + ~unexpected_type(){} + + explicit unexpected_type( std::exception_ptr const & error ) + : m_error( error ) + {} + + explicit unexpected_type(std::exception_ptr && error ) + : m_error( std::move( error ) ) + {} + + template< typename E > + explicit unexpected_type( E error ) + : m_error( std::make_exception_ptr( error ) ) + {} + + std::exception_ptr const & value() const + { + return m_error; + } + + std::exception_ptr & value() + { + return m_error; + } + +private: + std::exception_ptr m_error; +}; + +#endif // nsel_P0323R +#endif // !nsel_CONFIG_NO_EXCEPTIONS + +/// x.x.4, Unexpected equality operators + +template< typename E1, typename E2 > +constexpr bool operator==( unexpected_type const & x, unexpected_type const & y ) +{ + return x.error() == y.error(); +} + +template< typename E1, typename E2 > +constexpr bool operator!=( unexpected_type const & x, unexpected_type const & y ) +{ + return ! ( x == y ); +} + +#if nsel_P0323R <= 2 + +template< typename E > +constexpr bool operator<( unexpected_type const & x, unexpected_type const & y ) +{ + return x.error() < y.error(); +} + +template< typename E > +constexpr bool operator>( unexpected_type const & x, unexpected_type const & y ) +{ + return ( y < x ); +} + +template< typename E > +constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) +{ + return ! ( y < x ); +} + +template< typename E > +constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) +{ + return ! ( x < y ); +} + +#endif // nsel_P0323R + +/// x.x.5 Specialized algorithms + +template< typename E + nsel_REQUIRES_T( + std17::is_swappable::value + ) +> +void swap( unexpected_type & x, unexpected_type & y) noexcept ( noexcept ( x.swap(y) ) ) +{ + x.swap( y ); +} + +#if nsel_P0323R <= 2 + +// unexpected: relational operators for std::exception_ptr: + +inline constexpr bool operator<( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) +{ + return false; +} + +inline constexpr bool operator>( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) +{ + return false; +} + +inline constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) +{ + return ( x == y ); +} + +inline constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) +{ + return ( x == y ); +} + +#endif // nsel_P0323R + +// unexpected: traits + +#if nsel_P0323R <= 3 + +template< typename E> +struct is_unexpected : std::false_type {}; + +template< typename E> +struct is_unexpected< unexpected_type > : std::true_type {}; + +#endif // nsel_P0323R + +// unexpected: factory + +// keep make_unexpected() removed in p0323r2 for pre-C++17: + +template< typename E> +nsel_constexpr14 auto +make_unexpected( E && value ) -> unexpected_type< typename std::decay::type > +{ + return unexpected_type< typename std::decay::type >( std::forward(value) ); +} + +#if nsel_P0323R <= 3 + +/*nsel_constexpr14*/ auto inline +make_unexpected_from_current_exception() -> unexpected_type< std::exception_ptr > +{ + return unexpected_type< std::exception_ptr >( std::current_exception() ); +} + +#endif // nsel_P0323R + +/// x.x.6, x.x.7 expected access error + +template< typename E > +class bad_expected_access; + +/// x.x.7 bad_expected_access: expected access error + +template <> +class bad_expected_access< void > : public std::exception +{ +public: + explicit bad_expected_access() + : std::exception() + {} +}; + +/// x.x.6 bad_expected_access: expected access error + +#if !nsel_CONFIG_NO_EXCEPTIONS + +template< typename E > +class bad_expected_access : public bad_expected_access< void > +{ +public: + using error_type = E; + + explicit bad_expected_access( error_type error ) + : m_error( error ) + {} + + virtual char const * what() const noexcept override + { + return "bad_expected_access"; + } + + nsel_constexpr14 error_type & error() & + { + return m_error; + } + + constexpr error_type const & error() const & + { + return m_error; + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + + nsel_constexpr14 error_type && error() && + { + return std::move( m_error ); + } + + constexpr error_type const && error() const && + { + return std::move( m_error ); + } + +#endif + +private: + error_type m_error; +}; + +#endif // nsel_CONFIG_NO_EXCEPTIONS + +/// x.x.8 unexpect tag, in_place_unexpected tag: construct an error + +struct unexpect_t{}; +using in_place_unexpected_t = unexpect_t; + +nsel_inline17 constexpr unexpect_t unexpect{}; +nsel_inline17 constexpr unexpect_t in_place_unexpected{}; + +/// class error_traits + +#if nsel_CONFIG_NO_EXCEPTIONS + +namespace detail { + inline bool text( char const * /*text*/ ) { return true; } +} + +template< typename Error > +struct error_traits +{ + static void rethrow( Error const & /*e*/ ) + { +#if nsel_CONFIG_NO_EXCEPTIONS_SEH + RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); +#else + assert( false && detail::text("throw bad_expected_access{ e };") ); +#endif + } +}; + +template<> +struct error_traits< std::exception_ptr > +{ + static void rethrow( std::exception_ptr const & /*e*/ ) + { +#if nsel_CONFIG_NO_EXCEPTIONS_SEH + RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); +#else + assert( false && detail::text("throw bad_expected_access{ e };") ); +#endif + } +}; + +template<> +struct error_traits< std::error_code > +{ + static void rethrow( std::error_code const & /*e*/ ) + { +#if nsel_CONFIG_NO_EXCEPTIONS_SEH + RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); +#else + assert( false && detail::text("throw std::system_error( e );") ); +#endif + } +}; + +#else // nsel_CONFIG_NO_EXCEPTIONS + +template< typename Error > +struct error_traits +{ + static void rethrow( Error const & e ) + { + throw bad_expected_access{ e }; + } +}; + +template<> +struct error_traits< std::exception_ptr > +{ + static void rethrow( std::exception_ptr const & e ) + { + std::rethrow_exception( e ); + } +}; + +template<> +struct error_traits< std::error_code > +{ + static void rethrow( std::error_code const & e ) + { + throw std::system_error( e ); + } +}; + +#endif // nsel_CONFIG_NO_EXCEPTIONS + +#if nsel_P2505R >= 3 +namespace detail { + +// from https://en.cppreference.com/w/cpp/utility/expected/unexpected: +// "the type of the unexpected value. The type must not be an array type, a non-object type, a specialization of std::unexpected, or a cv-qualified type." +template< typename T > +struct valid_unexpected_type : std::integral_constant< bool, + std::is_same< T, typename std20::remove_cvref< T >::type >::value + && std::is_object< T >::value + && !std::is_array< T >::value +> {}; + +template< typename T > +struct valid_unexpected_type< unexpected_type< T > > : std::false_type {}; + +} // namespace detail +#endif // nsel_P2505R >= 3 + +} // namespace expected_lite + +// provide nonstd::unexpected_type: + +using expected_lite::unexpected_type; + +namespace expected_lite { + +/// class expected + +#if nsel_P0323R <= 2 +template< typename T, typename E = std::exception_ptr > +class expected +#else +template< typename T, typename E > +class expected +#endif // nsel_P0323R +{ +private: + template< typename, typename > friend class expected; + +public: + using value_type = T; + using error_type = E; + using unexpected_type = nonstd::unexpected_type; + + template< typename U > + struct rebind + { + using type = expected; + }; + + // x.x.4.1 constructors + + nsel_REQUIRES_0( + std::is_default_constructible::value + ) + nsel_constexpr14 expected() + : contained( true ) + { + contained.construct_value(); + } + + nsel_constexpr14 expected( expected const & ) = default; + nsel_constexpr14 expected( expected && ) = default; + + template< typename U, typename G + nsel_REQUIRES_T( + std::is_constructible< T, U const &>::value + && std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< expected & , T>::value + && !std::is_convertible< expected &&, T>::value + && !std::is_convertible< expected const & , T>::value + && !std::is_convertible< expected const &&, T>::value + && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ + ) + > + nsel_constexpr14 explicit expected( expected const & other ) + : contained( other.has_value() ) + { + if ( has_value() ) contained.construct_value( T{ other.contained.value() } ); + else contained.construct_error( E{ other.contained.error() } ); + } + + template< typename U, typename G + nsel_REQUIRES_T( + std::is_constructible< T, U const &>::value + && std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< expected & , T>::value + && !std::is_convertible< expected &&, T>::value + && !std::is_convertible< expected const &, T>::value + && !std::is_convertible< expected const &&, T>::value + && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ + ) + > + nsel_constexpr14 /*non-explicit*/ expected( expected const & other ) + : contained( other.has_value() ) + { + if ( has_value() ) contained.construct_value( other.contained.value() ); + else contained.construct_error( other.contained.error() ); + } + + template< typename U, typename G + nsel_REQUIRES_T( + std::is_constructible< T, U>::value + && std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< expected & , T>::value + && !std::is_convertible< expected &&, T>::value + && !std::is_convertible< expected const & , T>::value + && !std::is_convertible< expected const &&, T>::value + && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ + ) + > + nsel_constexpr14 explicit expected( expected && other ) + : contained( other.has_value() ) + { + if ( has_value() ) contained.construct_value( T{ std::move( other.contained.value() ) } ); + else contained.construct_error( E{ std::move( other.contained.error() ) } ); + } + + template< typename U, typename G + nsel_REQUIRES_T( + std::is_constructible< T, U>::value + && std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< expected & , T>::value + && !std::is_convertible< expected &&, T>::value + && !std::is_convertible< expected const & , T>::value + && !std::is_convertible< expected const &&, T>::value + && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ + ) + > + nsel_constexpr14 /*non-explicit*/ expected( expected && other ) + : contained( other.has_value() ) + { + if ( has_value() ) contained.construct_value( std::move( other.contained.value() ) ); + else contained.construct_error( std::move( other.contained.error() ) ); + } + + template< typename U = T + nsel_REQUIRES_T( + std::is_copy_constructible::value + ) + > + nsel_constexpr14 expected( value_type const & value ) + : contained( true ) + { + contained.construct_value( value ); + } + + template< typename U = T + nsel_REQUIRES_T( + std::is_constructible::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same< expected , typename std20::remove_cvref::type>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && !std::is_convertible::value /*=> explicit */ + ) + > + nsel_constexpr14 explicit expected( U && value ) noexcept + ( + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value + ) + : contained( true ) + { + contained.construct_value( T{ std::forward( value ) } ); + } + + template< typename U = T + nsel_REQUIRES_T( + std::is_constructible::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same< expected , typename std20::remove_cvref::type>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && std::is_convertible::value /*=> non-explicit */ + ) + > + nsel_constexpr14 /*non-explicit*/ expected( U && value ) noexcept + ( + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value + ) + : contained( true ) + { + contained.construct_value( std::forward( value ) ); + } + + // construct error: + + template< typename G = E + nsel_REQUIRES_T( + std::is_constructible::value + && !std::is_convertible< G const &, E>::value /*=> explicit */ + ) + > + nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) + : contained( false ) + { + contained.construct_error( E{ error.error() } ); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_constructible::value + && std::is_convertible< G const &, E>::value /*=> non-explicit */ + ) + > + nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) + : contained( false ) + { + contained.construct_error( error.error() ); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_constructible::value + && !std::is_convertible< G&&, E>::value /*=> explicit */ + ) + > + nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) + : contained( false ) + { + contained.construct_error( E{ std::move( error.error() ) } ); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_constructible::value + && std::is_convertible< G&&, E>::value /*=> non-explicit */ + ) + > + nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) + : contained( false ) + { + contained.construct_error( std::move( error.error() ) ); + } + + // in-place construction, value + + template< typename... Args + nsel_REQUIRES_T( + std::is_constructible::value + ) + > + nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), Args&&... args ) + : contained( true ) + { + contained.emplace_value( std::forward( args )... ); + } + + template< typename U, typename... Args + nsel_REQUIRES_T( + std::is_constructible, Args&&...>::value + ) + > + nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) + : contained( true ) + { + contained.emplace_value( il, std::forward( args )... ); + } + + // in-place construction, error + + template< typename... Args + nsel_REQUIRES_T( + std::is_constructible::value + ) + > + nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) + : contained( false ) + { + contained.emplace_error( std::forward( args )... ); + } + + template< typename U, typename... Args + nsel_REQUIRES_T( + std::is_constructible, Args&&...>::value + ) + > + nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) + : contained( false ) + { + contained.emplace_error( il, std::forward( args )... ); + } + + // x.x.4.2 destructor + + // TODO: ~expected: triviality + // Effects: If T is not cv void and is_trivially_destructible_v is false and bool(*this), calls val.~T(). If is_trivially_destructible_v is false and !bool(*this), calls unexpect.~unexpected(). + // Remarks: If either T is cv void or is_trivially_destructible_v is true, and is_trivially_destructible_v is true, then this destructor shall be a trivial destructor. + + ~expected() + { + if ( has_value() ) contained.destruct_value(); + else contained.destruct_error(); + } + + // x.x.4.3 assignment + + expected & operator=( expected const & other ) + { + expected( other ).swap( *this ); + return *this; + } + + expected & operator=( expected && other ) noexcept + ( + std::is_nothrow_move_constructible< T>::value + && std::is_nothrow_move_assignable< T>::value + && std::is_nothrow_move_constructible::value // added for missing + && std::is_nothrow_move_assignable< E>::value ) // nothrow above + { + expected( std::move( other ) ).swap( *this ); + return *this; + } + + template< typename U + nsel_REQUIRES_T( + !std::is_same, typename std20::remove_cvref::type>::value + && std17::conjunction, std::is_same> >::value + && std::is_constructible::value + && std::is_assignable< T&,U>::value + && std::is_nothrow_move_constructible::value ) + > + expected & operator=( U && value ) + { + expected( std::forward( value ) ).swap( *this ); + return *this; + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_constructible::value && + std::is_copy_constructible::value // TODO: std::is_nothrow_copy_constructible + && std::is_copy_assignable::value + ) + > + expected & operator=( nonstd::unexpected_type const & error ) + { + expected( unexpect, error.error() ).swap( *this ); + return *this; + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_constructible::value && + std::is_move_constructible::value // TODO: std::is_nothrow_move_constructible + && std::is_move_assignable::value + ) + > + expected & operator=( nonstd::unexpected_type && error ) + { + expected( unexpect, std::move( error.error() ) ).swap( *this ); + return *this; + } + + template< typename... Args + nsel_REQUIRES_T( + std::is_nothrow_constructible::value + ) + > + value_type & emplace( Args &&... args ) + { + expected( nonstd_lite_in_place(T), std::forward(args)... ).swap( *this ); + return value(); + } + + template< typename U, typename... Args + nsel_REQUIRES_T( + std::is_nothrow_constructible&, Args&&...>::value + ) + > + value_type & emplace( std::initializer_list il, Args &&... args ) + { + expected( nonstd_lite_in_place(T), il, std::forward(args)... ).swap( *this ); + return value(); + } + + // x.x.4.4 swap + + template< typename U=T, typename G=E > + nsel_REQUIRES_R( void, + std17::is_swappable< U>::value + && std17::is_swappable::value + && ( std::is_move_constructible::value || std::is_move_constructible::value ) + ) + swap( expected & other ) noexcept + ( + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value + ) + { + using std::swap; + + if ( bool(*this) && bool(other) ) { swap( contained.value(), other.contained.value() ); } + else if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); } + else if ( bool(*this) && ! bool(other) ) { error_type t( std::move( other.error() ) ); + other.contained.destruct_error(); + other.contained.construct_value( std::move( contained.value() ) ); + contained.destruct_value(); + contained.construct_error( std::move( t ) ); + bool has_value = contained.has_value(); + bool other_has_value = other.has_value(); + other.contained.set_has_value(has_value); + contained.set_has_value(other_has_value); + } + else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); } + } + + // x.x.4.5 observers + + constexpr value_type const * operator ->() const + { + return assert( has_value() ), contained.value_ptr(); + } + + value_type * operator ->() + { + return assert( has_value() ), contained.value_ptr(); + } + + constexpr value_type const & operator *() const & + { + return assert( has_value() ), contained.value(); + } + + value_type & operator *() & + { + return assert( has_value() ), contained.value(); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + + constexpr value_type const && operator *() const && + { + return std::move( ( assert( has_value() ), contained.value() ) ); + } + + nsel_constexpr14 value_type && operator *() && + { + return std::move( ( assert( has_value() ), contained.value() ) ); + } + +#endif + + constexpr explicit operator bool() const noexcept + { + return has_value(); + } + + constexpr bool has_value() const noexcept + { + return contained.has_value(); + } + + nsel_DISABLE_MSVC_WARNINGS( 4702 ) // warning C4702: unreachable code, see issue 65. + + constexpr value_type const & value() const & + { + return has_value() + ? ( contained.value() ) + : ( error_traits::rethrow( contained.error() ), contained.value() ); + } + + value_type & value() & + { + return has_value() + ? ( contained.value() ) + : ( error_traits::rethrow( contained.error() ), contained.value() ); + } + nsel_RESTORE_MSVC_WARNINGS() + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + + constexpr value_type const && value() const && + { + return std::move( has_value() + ? ( contained.value() ) + : ( error_traits::rethrow( contained.error() ), contained.value() ) ); + } + + nsel_constexpr14 value_type && value() && + { + return std::move( has_value() + ? ( contained.value() ) + : ( error_traits::rethrow( contained.error() ), contained.value() ) ); + } + +#endif + + constexpr error_type const & error() const & + { + return assert( ! has_value() ), contained.error(); + } + + error_type & error() & + { + return assert( ! has_value() ), contained.error(); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + + constexpr error_type const && error() const && + { + return std::move( ( assert( ! has_value() ), contained.error() ) ); + } + + error_type && error() && + { + return std::move( ( assert( ! has_value() ), contained.error() ) ); + } + +#endif + + constexpr unexpected_type get_unexpected() const + { + return make_unexpected( contained.error() ); + } + + template< typename Ex > + bool has_exception() const + { + using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; + return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; + } + + template< typename U + nsel_REQUIRES_T( + std::is_copy_constructible< T>::value + && std::is_convertible::value + ) + > + value_type value_or( U && v ) const & + { + return has_value() + ? contained.value() + : static_cast( std::forward( v ) ); + } + + template< typename U + nsel_REQUIRES_T( + std::is_move_constructible< T>::value + && std::is_convertible::value + ) + > + value_type value_or( U && v ) && + { + return has_value() + ? std::move( contained.value() ) + : static_cast( std::forward( v ) ); + } + +#if nsel_P2505R >= 4 + template< typename G = E + nsel_REQUIRES_T( + std::is_copy_constructible< E >::value + && std::is_convertible< G, E >::value + ) + > + nsel_constexpr error_type error_or( G && e ) const & + { + return has_value() + ? static_cast< E >( std::forward< G >( e ) ) + : contained.error(); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_move_constructible< E >::value + && std::is_convertible< G, E >::value + ) + > + nsel_constexpr14 error_type error_or( G && e ) && + { + return has_value() + ? static_cast< E >( std::forward< G >( e ) ) + : std::move( contained.error() ); + } +#endif // nsel_P2505R >= 4 + +#if nsel_P2505R >= 3 + // Monadic operations (P2505) + template< typename F + nsel_REQUIRES_T( + detail::is_expected < detail::invoke_result_nocvref_t< F, value_type & > > ::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type & >::error_type, error_type >::value + && std::is_constructible< error_type, error_type & >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type & > and_then( F && f ) & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, value_type & >( detail::invoke( std::forward< F >( f ), value() ) ) + : detail::invoke_result_nocvref_t< F, value_type & >( unexpect, error() ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value + && std::is_constructible< error_type, const error_type & >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type & > and_then( F && f ) const & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const value_type & >( detail::invoke( std::forward< F >( f ), value() ) ) + : detail::invoke_result_nocvref_t< F, const value_type & >( unexpect, error() ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type && >::error_type, error_type >::value + && std::is_constructible< error_type, error_type && >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type && > and_then( F && f ) && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) ) + : detail::invoke_result_nocvref_t< F, value_type && >( unexpect, std::move( error() ) ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value + && std::is_constructible< error_type, const error_type && >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type && > and_then( F && f ) const && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) ) + : detail::invoke_result_nocvref_t< F, const value_type && >( unexpect, std::move( error() ) ); + } +#endif + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type, value_type >::value + && std::is_constructible< value_type, value_type & >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, error_type & >( value() ) + : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type, value_type >::value + && std::is_constructible< value_type, const value_type & >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const error_type & >( value() ) + : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type, value_type >::value + && std::is_constructible< value_type, value_type && >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, error_type && >( std::move( value() ) ) + : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type, value_type >::value + && std::is_constructible< value_type, const value_type && >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const error_type && >( std::move( value() ) ) + : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } +#endif + + template::value + && !std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value + && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type & > >::value + ) + > + nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type & >, error_type > transform( F && f ) & + { + return has_value() + ? expected< detail::transform_invoke_result_t< F, value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value + ) + > + nsel_constexpr14 expected< void, error_type > transform( F && f ) & + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + + template::value + && !std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value + && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type & > >::value + ) + > + nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type & >, error_type > transform( F && f ) const & + { + return has_value() + ? expected< detail::transform_invoke_result_t< F, const value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value + ) + > + nsel_constexpr expected< void, error_type > transform( F && f ) const & + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template::value + && !std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value + && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type && > >::value + ) + > + nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type && >, error_type > transform( F && f ) && + { + return has_value() + ? expected< detail::transform_invoke_result_t< F, value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) ) + : make_unexpected( std::move( error() ) ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value + ) + > + nsel_constexpr14 expected< void, error_type > transform( F && f ) && + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) + : make_unexpected( std::move( error() ) ); + } + + template::value + && !std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value + && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type && > >::value + ) + > + nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type && >, error_type > transform( F && f ) const && + { + return has_value() + ? expected< detail::transform_invoke_result_t< F, const value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) ) + : make_unexpected( std::move( error() ) ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value + ) + > + nsel_constexpr expected< void, error_type > transform( F && f ) const && + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) + : make_unexpected( std::move( error() ) ); + } +#endif + + template >::value + && std::is_constructible< value_type, value_type & >::value + ) + > + nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) & + { + return has_value() + ? expected< value_type, detail::transform_invoke_result_t< F, error_type & > >( in_place, **this ) + : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); + } + + template >::value + && std::is_constructible< value_type, const value_type & >::value + ) + > + nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const & + { + return has_value() + ? expected< value_type, detail::transform_invoke_result_t< F, const error_type & > >( in_place, **this ) + : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_constructible< value_type, value_type && >::value + ) + > + nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) && + { + return has_value() + ? expected< value_type, detail::transform_invoke_result_t< F, error_type && > >( in_place, std::move( **this ) ) + : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } + + template >::value + && std::is_constructible< value_type, const value_type && >::value + ) + > + nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const && + { + return has_value() + ? expected< value_type, detail::transform_invoke_result_t< F, const error_type && > >( in_place, std::move( **this ) ) + : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } +#endif +#endif // nsel_P2505R >= 3 + // unwrap() + +// template +// constexpr expected expected,E>::unwrap() const&; + +// template +// constexpr expected expected::unwrap() const&; + +// template +// expected expected, E>::unwrap() &&; + +// template +// template expected expected::unwrap() &&; + + // factories + +// template< typename Ex, typename F> +// expected catch_exception(F&& f); + +// template< typename F> +// expected())),E> map(F&& func) ; + +// template< typename F> +// 'see below' bind(F&& func); + +// template< typename F> +// expected catch_error(F&& f); + +// template< typename F> +// 'see below' then(F&& func); + +private: + detail::storage_t + < + T + ,E + , std::is_copy_constructible::value && std::is_copy_constructible::value + , std::is_move_constructible::value && std::is_move_constructible::value + > + contained; +}; + +/// class expected, void specialization + +template< typename E > +class expected +{ +private: + template< typename, typename > friend class expected; + +public: + using value_type = void; + using error_type = E; + using unexpected_type = nonstd::unexpected_type; + + // x.x.4.1 constructors + + constexpr expected() noexcept + : contained( true ) + {} + + nsel_constexpr14 expected( expected const & other ) = default; + nsel_constexpr14 expected( expected && other ) = default; + + constexpr explicit expected( nonstd_lite_in_place_t(void) ) + : contained( true ) + {} + + template< typename G = E + nsel_REQUIRES_T( + !std::is_convertible::value /*=> explicit */ + ) + > + nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) + : contained( false ) + { + contained.construct_error( E{ error.error() } ); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_convertible::value /*=> non-explicit */ + ) + > + nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) + : contained( false ) + { + contained.construct_error( error.error() ); + } + + template< typename G = E + nsel_REQUIRES_T( + !std::is_convertible::value /*=> explicit */ + ) + > + nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) + : contained( false ) + { + contained.construct_error( E{ std::move( error.error() ) } ); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_convertible::value /*=> non-explicit */ + ) + > + nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) + : contained( false ) + { + contained.construct_error( std::move( error.error() ) ); + } + + template< typename... Args + nsel_REQUIRES_T( + std::is_constructible::value + ) + > + nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) + : contained( false ) + { + contained.emplace_error( std::forward( args )... ); + } + + template< typename U, typename... Args + nsel_REQUIRES_T( + std::is_constructible, Args&&...>::value + ) + > + nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) + : contained( false ) + { + contained.emplace_error( il, std::forward( args )... ); + } + + // destructor + + ~expected() + { + if ( ! has_value() ) + { + contained.destruct_error(); + } + } + + // x.x.4.3 assignment + + expected & operator=( expected const & other ) + { + expected( other ).swap( *this ); + return *this; + } + + expected & operator=( expected && other ) noexcept + ( + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_constructible::value ) + { + expected( std::move( other ) ).swap( *this ); + return *this; + } + + void emplace() + { + expected().swap( *this ); + } + + // x.x.4.4 swap + + template< typename G = E > + nsel_REQUIRES_R( void, + std17::is_swappable::value + && std::is_move_constructible::value + ) + swap( expected & other ) noexcept + ( + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value + ) + { + using std::swap; + + if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); } + else if ( bool(*this) && ! bool(other) ) { contained.construct_error( std::move( other.error() ) ); + bool has_value = contained.has_value(); + bool other_has_value = other.has_value(); + other.contained.set_has_value(has_value); + contained.set_has_value(other_has_value); + } + else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); } + } + + // x.x.4.5 observers + + constexpr explicit operator bool() const noexcept + { + return has_value(); + } + + constexpr bool has_value() const noexcept + { + return contained.has_value(); + } + + void value() const + { + if ( ! has_value() ) + { + error_traits::rethrow( contained.error() ); + } + } + + constexpr error_type const & error() const & + { + return assert( ! has_value() ), contained.error(); + } + + error_type & error() & + { + return assert( ! has_value() ), contained.error(); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + + constexpr error_type const && error() const && + { + return std::move( ( assert( ! has_value() ), contained.error() ) ); + } + + error_type && error() && + { + return std::move( ( assert( ! has_value() ), contained.error() ) ); + } + +#endif + + constexpr unexpected_type get_unexpected() const + { + return make_unexpected( contained.error() ); + } + + template< typename Ex > + bool has_exception() const + { + using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; + return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; + } + +#if nsel_P2505R >= 4 + template< typename G = E + nsel_REQUIRES_T( + std::is_copy_constructible< E >::value + && std::is_convertible< G, E >::value + ) + > + nsel_constexpr error_type error_or( G && e ) const & + { + return has_value() + ? static_cast< E >( std::forward< G >( e ) ) + : contained.error(); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_move_constructible< E >::value + && std::is_convertible< G, E >::value + ) + > + nsel_constexpr14 error_type error_or( G && e ) && + { + return has_value() + ? static_cast< E >( std::forward< G >( e ) ) + : std::move( contained.error() ); + } +#endif // nsel_P2505R >= 4 + +#if nsel_P2505R >= 3 + // Monadic operations (P2505) + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value + && std::is_constructible< error_type, error_type & >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) & + { + return has_value() + ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) + : detail::invoke_result_nocvref_t< F >( unexpect, error() ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value + && std::is_constructible< error_type, const error_type & >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const & + { + return has_value() + ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) + : detail::invoke_result_nocvref_t< F >( unexpect, error() ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value + && std::is_constructible< error_type, error_type && >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) && + { + return has_value() + ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) + : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value + && std::is_constructible< error_type, const error_type && >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const && + { + return has_value() + ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) + : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) ); + } +#endif + + template >::value + && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, error_type & >() + : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); + } + + template >::value + && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const error_type & >() + : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, error_type && >() + : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } + + template >::value + && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const error_type && >() + : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } +#endif + + template::value + && !std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) & + { + return has_value() + ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr14 expected< void, error_type > transform( F && f ) & + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + + template::value + && !std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const & + { + return has_value() + ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr expected< void, error_type > transform( F && f ) const & + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template::value + && !std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) && + { + return has_value() + ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr14 expected< void, error_type > transform( F && f ) && + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + + template::value + && !std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const && + { + return has_value() + ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr expected< void, error_type > transform( F && f ) const && + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) + : make_unexpected( error() ); + } +#endif + + template >::value + ) + > + nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) & + { + return has_value() + ? expected< void, detail::transform_invoke_result_t< F, error_type & > >() + : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); + } + + template >::value + ) + > + nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const & + { + return has_value() + ? expected< void, detail::transform_invoke_result_t< F, const error_type & > >() + : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + ) + > + nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) && + { + return has_value() + ? expected< void, detail::transform_invoke_result_t< F, error_type && > >() + : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } + + template >::value + ) + > + nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const && + { + return has_value() + ? expected< void, detail::transform_invoke_result_t< F, const error_type && > >() + : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } +#endif +#endif // nsel_P2505R >= 3 + +// template constexpr 'see below' unwrap() const&; +// +// template 'see below' unwrap() &&; + + // factories + +// template< typename Ex, typename F> +// expected catch_exception(F&& f); +// +// template< typename F> +// expected map(F&& func) ; +// +// template< typename F> +// 'see below' bind(F&& func) ; +// +// template< typename F> +// expected catch_error(F&& f); +// +// template< typename F> +// 'see below' then(F&& func); + +private: + detail::storage_t + < + void + , E + , std::is_copy_constructible::value + , std::is_move_constructible::value + > + contained; +}; + +// x.x.4.6 expected<>: comparison operators + +template< typename T1, typename E1, typename T2, typename E2 + nsel_REQUIRES_T( + !std::is_void::value && !std::is_void::value + ) +> +constexpr bool operator==( expected const & x, expected const & y ) +{ + return bool(x) != bool(y) ? false : bool(x) ? *x == *y : x.error() == y.error(); +} + +template< typename T1, typename E1, typename T2, typename E2 + nsel_REQUIRES_T( + std::is_void::value && std::is_void::value + ) +> +constexpr bool operator==( expected const & x, expected const & y ) +{ + return bool(x) != bool(y) ? false : bool(x) || static_cast( x.error() == y.error() ); +} + +template< typename T1, typename E1, typename T2, typename E2 > +constexpr bool operator!=( expected const & x, expected const & y ) +{ + return !(x == y); +} + +#if nsel_P0323R <= 2 + +template< typename T, typename E > +constexpr bool operator<( expected const & x, expected const & y ) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template< typename T, typename E > +constexpr bool operator>( expected const & x, expected const & y ) +{ + return (y < x); +} + +template< typename T, typename E > +constexpr bool operator<=( expected const & x, expected const & y ) +{ + return !(y < x); +} + +template< typename T, typename E > +constexpr bool operator>=( expected const & x, expected const & y ) +{ + return !(x < y); +} + +#endif + +// x.x.4.7 expected: comparison with T + +template< typename T1, typename E1, typename T2 + nsel_REQUIRES_T( + !std::is_void::value + ) +> +constexpr bool operator==( expected const & x, T2 const & v ) +{ + return bool(x) ? *x == v : false; +} + +template< typename T1, typename E1, typename T2 + nsel_REQUIRES_T( + !std::is_void::value + ) +> +constexpr bool operator==(T2 const & v, expected const & x ) +{ + return bool(x) ? v == *x : false; +} + +template< typename T1, typename E1, typename T2 > +constexpr bool operator!=( expected const & x, T2 const & v ) +{ + return bool(x) ? *x != v : true; +} + +template< typename T1, typename E1, typename T2 > +constexpr bool operator!=( T2 const & v, expected const & x ) +{ + return bool(x) ? v != *x : true; +} + +#if nsel_P0323R <= 2 + +template< typename T, typename E > +constexpr bool operator<( expected const & x, T const & v ) +{ + return bool(x) ? *x < v : true; +} + +template< typename T, typename E > +constexpr bool operator<( T const & v, expected const & x ) +{ + return bool(x) ? v < *x : false; +} + +template< typename T, typename E > +constexpr bool operator>( T const & v, expected const & x ) +{ + return bool(x) ? *x < v : false; +} + +template< typename T, typename E > +constexpr bool operator>( expected const & x, T const & v ) +{ + return bool(x) ? v < *x : false; +} + +template< typename T, typename E > +constexpr bool operator<=( T const & v, expected const & x ) +{ + return bool(x) ? ! ( *x < v ) : false; +} + +template< typename T, typename E > +constexpr bool operator<=( expected const & x, T const & v ) +{ + return bool(x) ? ! ( v < *x ) : true; +} + +template< typename T, typename E > +constexpr bool operator>=( expected const & x, T const & v ) +{ + return bool(x) ? ! ( *x < v ) : false; +} + +template< typename T, typename E > +constexpr bool operator>=( T const & v, expected const & x ) +{ + return bool(x) ? ! ( v < *x ) : true; +} + +#endif // nsel_P0323R + +// x.x.4.8 expected: comparison with unexpected_type + +template< typename T1, typename E1 , typename E2 > +constexpr bool operator==( expected const & x, unexpected_type const & u ) +{ + return (!x) ? x.get_unexpected() == u : false; +} + +template< typename T1, typename E1 , typename E2 > +constexpr bool operator==( unexpected_type const & u, expected const & x ) +{ + return ( x == u ); +} + +template< typename T1, typename E1 , typename E2 > +constexpr bool operator!=( expected const & x, unexpected_type const & u ) +{ + return ! ( x == u ); +} + +template< typename T1, typename E1 , typename E2 > +constexpr bool operator!=( unexpected_type const & u, expected const & x ) +{ + return ! ( x == u ); +} + +#if nsel_P0323R <= 2 + +template< typename T, typename E > +constexpr bool operator<( expected const & x, unexpected_type const & u ) +{ + return (!x) ? ( x.get_unexpected() < u ) : false; +} + +template< typename T, typename E > +constexpr bool operator<( unexpected_type const & u, expected const & x ) +{ + return (!x) ? ( u < x.get_unexpected() ) : true ; +} + +template< typename T, typename E > +constexpr bool operator>( expected const & x, unexpected_type const & u ) +{ + return ( u < x ); +} + +template< typename T, typename E > +constexpr bool operator>( unexpected_type const & u, expected const & x ) +{ + return ( x < u ); +} + +template< typename T, typename E > +constexpr bool operator<=( expected const & x, unexpected_type const & u ) +{ + return ! ( u < x ); +} + +template< typename T, typename E > +constexpr bool operator<=( unexpected_type const & u, expected const & x) +{ + return ! ( x < u ); +} + +template< typename T, typename E > +constexpr bool operator>=( expected const & x, unexpected_type const & u ) +{ + return ! ( u > x ); +} + +template< typename T, typename E > +constexpr bool operator>=( unexpected_type const & u, expected const & x ) +{ + return ! ( x > u ); +} + +#endif // nsel_P0323R + +/// x.x.x Specialized algorithms + +template< typename T, typename E + nsel_REQUIRES_T( + ( std::is_void::value || std::is_move_constructible::value ) + && std::is_move_constructible::value + && std17::is_swappable::value + && std17::is_swappable::value ) +> +void swap( expected & x, expected & y ) noexcept ( noexcept ( x.swap(y) ) ) +{ + x.swap( y ); +} + +#if nsel_P0323R <= 3 + +template< typename T > +constexpr auto make_expected( T && v ) -> expected< typename std::decay::type > +{ + return expected< typename std::decay::type >( std::forward( v ) ); +} + +// expected specialization: + +auto inline make_expected() -> expected +{ + return expected( in_place ); +} + +template< typename T > +constexpr auto make_expected_from_current_exception() -> expected +{ + return expected( make_unexpected_from_current_exception() ); +} + +template< typename T > +auto make_expected_from_exception( std::exception_ptr v ) -> expected +{ + return expected( unexpected_type( std::forward( v ) ) ); +} + +template< typename T, typename E > +constexpr auto make_expected_from_error( E e ) -> expected::type> +{ + return expected::type>( make_unexpected( e ) ); +} + +template< typename F + nsel_REQUIRES_T( ! std::is_same::type, void>::value ) +> +/*nsel_constexpr14*/ +auto make_expected_from_call( F f ) -> expected< typename std::result_of::type > +{ + try + { + return make_expected( f() ); + } + catch (...) + { + return make_unexpected_from_current_exception(); + } +} + +template< typename F + nsel_REQUIRES_T( std::is_same::type, void>::value ) +> +/*nsel_constexpr14*/ +auto make_expected_from_call( F f ) -> expected +{ + try + { + f(); + return make_expected(); + } + catch (...) + { + return make_unexpected_from_current_exception(); + } +} + +#endif // nsel_P0323R + +} // namespace expected_lite + +using namespace expected_lite; + +// using expected_lite::expected; +// using ... + +} // namespace nonstd + +namespace std { + +// expected: hash support + +template< typename T, typename E > +struct hash< nonstd::expected > +{ + using result_type = std::size_t; + using argument_type = nonstd::expected; + + constexpr result_type operator()(argument_type const & arg) const + { + return arg ? std::hash{}(*arg) : result_type{}; + } +}; + +// TBD - ?? remove? see spec. +template< typename T, typename E > +struct hash< nonstd::expected > +{ + using result_type = std::size_t; + using argument_type = nonstd::expected; + + constexpr result_type operator()(argument_type const & arg) const + { + return arg ? std::hash{}(*arg) : result_type{}; + } +}; + +// TBD - implement +// bool(e), hash>()(e) shall evaluate to the hashing true; +// otherwise it evaluates to an unspecified value if E is exception_ptr or +// a combination of hashing false and hash()(e.error()). + +template< typename E > +struct hash< nonstd::expected > +{ +}; + +} // namespace std + +namespace nonstd { + +// void unexpected() is deprecated && removed in C++17 + +#if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141 +template< typename E > +using unexpected = unexpected_type; +#endif + +} // namespace nonstd + +#undef nsel_REQUIRES +#undef nsel_REQUIRES_0 +#undef nsel_REQUIRES_T + +nsel_RESTORE_WARNINGS() + +#endif // nsel_USES_STD_EXPECTED + +#endif // NONSTD_EXPECTED_LITE_HPP diff --git a/include/behaviortree_cpp/controls/fallback_node.h b/include/behaviortree_cpp/controls/fallback_node.h index a16bf5bf6..515e00e04 100644 --- a/include/behaviortree_cpp/controls/fallback_node.h +++ b/include/behaviortree_cpp/controls/fallback_node.h @@ -32,7 +32,7 @@ namespace BT class FallbackNode : public ControlNode { public: - FallbackNode(const std::string& name, bool make_aynch = false); + FallbackNode(const std::string& name, bool make_asynch = false); virtual ~FallbackNode() override = default; @@ -40,7 +40,7 @@ class FallbackNode : public ControlNode private: size_t current_child_idx_; - bool all_skipped_ = true; + size_t skipped_count_ = 0; bool asynch_ = false; virtual BT::NodeStatus tick() override; diff --git a/include/behaviortree_cpp/controls/sequence_node.h b/include/behaviortree_cpp/controls/sequence_node.h index 29da9b192..229170476 100644 --- a/include/behaviortree_cpp/controls/sequence_node.h +++ b/include/behaviortree_cpp/controls/sequence_node.h @@ -42,7 +42,7 @@ class SequenceNode : public ControlNode private: size_t current_child_idx_; - bool all_skipped_ = true; + size_t skipped_count_ = 0; bool asynch_ = false; TreeNode* getNextSibling(TreeNode* child); diff --git a/include/behaviortree_cpp/controls/sequence_with_memory_node.h b/include/behaviortree_cpp/controls/sequence_with_memory_node.h index f19dfc7d6..8bd351e72 100644 --- a/include/behaviortree_cpp/controls/sequence_with_memory_node.h +++ b/include/behaviortree_cpp/controls/sequence_with_memory_node.h @@ -42,7 +42,7 @@ class SequenceWithMemory : public ControlNode private: size_t current_child_idx_; - bool all_skipped_ = true; + size_t skipped_count_ = 0; virtual BT::NodeStatus tick() override; }; diff --git a/include/behaviortree_cpp/decorators/repeat_node.h b/include/behaviortree_cpp/decorators/repeat_node.h index b31b22a7e..14887e9bf 100644 --- a/include/behaviortree_cpp/decorators/repeat_node.h +++ b/include/behaviortree_cpp/decorators/repeat_node.h @@ -50,7 +50,6 @@ class RepeatNode : public DecoratorNode private: int num_cycles_; int repeat_count_; - bool all_skipped_ = true; bool read_parameter_from_ports_; static constexpr const char* NUM_CYCLES = "num_cycles"; diff --git a/include/behaviortree_cpp/decorators/retry_node.h b/include/behaviortree_cpp/decorators/retry_node.h index 0b39626b1..b3ffa1dfe 100644 --- a/include/behaviortree_cpp/decorators/retry_node.h +++ b/include/behaviortree_cpp/decorators/retry_node.h @@ -64,7 +64,6 @@ class RetryNode : public DecoratorNode private: int max_attempts_; int try_count_; - bool all_skipped_ = true; bool read_parameter_from_ports_; static constexpr const char* NUM_ATTEMPTS = "num_attempts"; diff --git a/include/behaviortree_cpp/flatbuffers/BT_logger_generated.h b/include/behaviortree_cpp/flatbuffers/BT_logger_generated.h deleted file mode 100644 index 088c8900c..000000000 --- a/include/behaviortree_cpp/flatbuffers/BT_logger_generated.h +++ /dev/null @@ -1,804 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - -#ifndef FLATBUFFERS_GENERATED_BTLOGGER_SERIALIZATION_H_ -#define FLATBUFFERS_GENERATED_BTLOGGER_SERIALIZATION_H_ - -#include "behaviortree_cpp/flatbuffers/flatbuffers.h" - -namespace Serialization -{ -struct PortModel; -struct PortModelBuilder; - -struct PortConfig; -struct PortConfigBuilder; - -struct TreeNode; -struct TreeNodeBuilder; - -struct NodeModel; -struct NodeModelBuilder; - -struct BehaviorTree; -struct BehaviorTreeBuilder; - -struct Timestamp; - -struct StatusChange; - -struct StatusChangeLog; -struct StatusChangeLogBuilder; - -enum class NodeStatus : int8_t -{ - IDLE = 0, - RUNNING = 1, - SUCCESS = 2, - FAILURE = 3, - MIN = IDLE, - MAX = FAILURE -}; - -inline const NodeStatus (&EnumValuesNodeStatus())[4] -{ - static const NodeStatus values[] = { NodeStatus::IDLE, NodeStatus::RUNNING, - NodeStatus::SUCCESS, NodeStatus::FAILURE }; - return values; -} - -inline const char* const* EnumNamesNodeStatus() -{ - static const char* const names[5] = { "IDLE", "RUNNING", "SUCCESS", "FAILURE", - nullptr }; - return names; -} - -inline const char* EnumNameNodeStatus(NodeStatus e) -{ - if(flatbuffers::IsOutRange(e, NodeStatus::IDLE, NodeStatus::FAILURE)) - return ""; - const size_t index = static_cast(e); - return EnumNamesNodeStatus()[index]; -} - -enum class NodeType : int8_t -{ - UNDEFINED = 0, - ACTION = 1, - CONDITION = 2, - CONTROL = 3, - DECORATOR = 4, - SUBTREE = 5, - MIN = UNDEFINED, - MAX = SUBTREE -}; - -inline const NodeType (&EnumValuesNodeType())[6] -{ - static const NodeType values[] = { NodeType::UNDEFINED, NodeType::ACTION, - NodeType::CONDITION, NodeType::CONTROL, - NodeType::DECORATOR, NodeType::SUBTREE }; - return values; -} - -inline const char* const* EnumNamesNodeType() -{ - static const char* const names[7] = { "UNDEFINED", "ACTION", "CONDITION", "CONTROL", - "DECORATOR", "SUBTREE", nullptr }; - return names; -} - -inline const char* EnumNameNodeType(NodeType e) -{ - if(flatbuffers::IsOutRange(e, NodeType::UNDEFINED, NodeType::SUBTREE)) - return ""; - const size_t index = static_cast(e); - return EnumNamesNodeType()[index]; -} - -enum class PortDirection : int8_t -{ - INPUT = 0, - OUTPUT = 1, - INOUT = 2, - MIN = INPUT, - MAX = INOUT -}; - -inline const PortDirection (&EnumValuesPortDirection())[3] -{ - static const PortDirection values[] = { PortDirection::INPUT, PortDirection::OUTPUT, - PortDirection::INOUT }; - return values; -} - -inline const char* const* EnumNamesPortDirection() -{ - static const char* const names[4] = { "INPUT", "OUTPUT", "INOUT", nullptr }; - return names; -} - -inline const char* EnumNamePortDirection(PortDirection e) -{ - if(flatbuffers::IsOutRange(e, PortDirection::INPUT, PortDirection::INOUT)) - return ""; - const size_t index = static_cast(e); - return EnumNamesPortDirection()[index]; -} - -FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Timestamp FLATBUFFERS_FINAL_CLASS -{ -private: - uint64_t usec_since_epoch_; - -public: - Timestamp() : usec_since_epoch_(0) - {} - Timestamp(uint64_t _usec_since_epoch) - : usec_since_epoch_(flatbuffers::EndianScalar(_usec_since_epoch)) - {} - uint64_t usec_since_epoch() const - { - return flatbuffers::EndianScalar(usec_since_epoch_); - } -}; -FLATBUFFERS_STRUCT_END(Timestamp, 8); - -FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) StatusChange FLATBUFFERS_FINAL_CLASS -{ -private: - uint16_t uid_; - int8_t prev_status_; - int8_t status_; - int32_t padding0__; - Serialization::Timestamp timestamp_; - -public: - StatusChange() : uid_(0), prev_status_(0), status_(0), padding0__(0), timestamp_() - { - (void)padding0__; - } - StatusChange(uint16_t _uid, Serialization::NodeStatus _prev_status, - Serialization::NodeStatus _status, - const Serialization::Timestamp& _timestamp) - : uid_(flatbuffers::EndianScalar(_uid)) - , prev_status_(flatbuffers::EndianScalar(static_cast(_prev_status))) - , status_(flatbuffers::EndianScalar(static_cast(_status))) - , padding0__(0) - , timestamp_(_timestamp) - { - (void)padding0__; - } - uint16_t uid() const - { - return flatbuffers::EndianScalar(uid_); - } - Serialization::NodeStatus prev_status() const - { - return static_cast( - flatbuffers::EndianScalar(prev_status_)); - } - Serialization::NodeStatus status() const - { - return static_cast(flatbuffers::EndianScalar(status_)); - } - const Serialization::Timestamp& timestamp() const - { - return timestamp_; - } -}; -FLATBUFFERS_STRUCT_END(StatusChange, 16); - -struct PortModel FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table -{ - typedef PortModelBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE - { - VT_PORT_NAME = 4, - VT_DIRECTION = 6, - VT_TYPE_INFO = 8, - VT_DESCRIPTION = 10 - }; - const flatbuffers::String* port_name() const - { - return GetPointer(VT_PORT_NAME); - } - Serialization::PortDirection direction() const - { - return static_cast(GetField(VT_DIRECTION, 0)); - } - const flatbuffers::String* type_info() const - { - return GetPointer(VT_TYPE_INFO); - } - const flatbuffers::String* description() const - { - return GetPointer(VT_DESCRIPTION); - } - bool Verify(flatbuffers::Verifier& verifier) const - { - return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_PORT_NAME) && - verifier.VerifyString(port_name()) && - VerifyField(verifier, VT_DIRECTION) && - VerifyOffset(verifier, VT_TYPE_INFO) && verifier.VerifyString(type_info()) && - VerifyOffset(verifier, VT_DESCRIPTION) && - verifier.VerifyString(description()) && verifier.EndTable(); - } -}; - -struct PortModelBuilder -{ - typedef PortModel Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_port_name(flatbuffers::Offset port_name) - { - fbb_.AddOffset(PortModel::VT_PORT_NAME, port_name); - } - void add_direction(Serialization::PortDirection direction) - { - fbb_.AddElement(PortModel::VT_DIRECTION, static_cast(direction), 0); - } - void add_type_info(flatbuffers::Offset type_info) - { - fbb_.AddOffset(PortModel::VT_TYPE_INFO, type_info); - } - void add_description(flatbuffers::Offset description) - { - fbb_.AddOffset(PortModel::VT_DESCRIPTION, description); - } - explicit PortModelBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) - { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() - { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreatePortModel( - flatbuffers::FlatBufferBuilder& _fbb, - flatbuffers::Offset port_name = 0, - Serialization::PortDirection direction = Serialization::PortDirection::INPUT, - flatbuffers::Offset type_info = 0, - flatbuffers::Offset description = 0) -{ - PortModelBuilder builder_(_fbb); - builder_.add_description(description); - builder_.add_type_info(type_info); - builder_.add_port_name(port_name); - builder_.add_direction(direction); - return builder_.Finish(); -} - -inline flatbuffers::Offset CreatePortModelDirect( - flatbuffers::FlatBufferBuilder& _fbb, const char* port_name = nullptr, - Serialization::PortDirection direction = Serialization::PortDirection::INPUT, - const char* type_info = nullptr, const char* description = nullptr) -{ - auto port_name__ = port_name ? _fbb.CreateString(port_name) : 0; - auto type_info__ = type_info ? _fbb.CreateString(type_info) : 0; - auto description__ = description ? _fbb.CreateString(description) : 0; - return Serialization::CreatePortModel(_fbb, port_name__, direction, type_info__, - description__); -} - -struct PortConfig FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table -{ - typedef PortConfigBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE - { - VT_PORT_NAME = 4, - VT_REMAP = 6 - }; - const flatbuffers::String* port_name() const - { - return GetPointer(VT_PORT_NAME); - } - const flatbuffers::String* remap() const - { - return GetPointer(VT_REMAP); - } - bool Verify(flatbuffers::Verifier& verifier) const - { - return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_PORT_NAME) && - verifier.VerifyString(port_name()) && VerifyOffset(verifier, VT_REMAP) && - verifier.VerifyString(remap()) && verifier.EndTable(); - } -}; - -struct PortConfigBuilder -{ - typedef PortConfig Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_port_name(flatbuffers::Offset port_name) - { - fbb_.AddOffset(PortConfig::VT_PORT_NAME, port_name); - } - void add_remap(flatbuffers::Offset remap) - { - fbb_.AddOffset(PortConfig::VT_REMAP, remap); - } - explicit PortConfigBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) - { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() - { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset -CreatePortConfig(flatbuffers::FlatBufferBuilder& _fbb, - flatbuffers::Offset port_name = 0, - flatbuffers::Offset remap = 0) -{ - PortConfigBuilder builder_(_fbb); - builder_.add_remap(remap); - builder_.add_port_name(port_name); - return builder_.Finish(); -} - -inline flatbuffers::Offset -CreatePortConfigDirect(flatbuffers::FlatBufferBuilder& _fbb, - const char* port_name = nullptr, const char* remap = nullptr) -{ - auto port_name__ = port_name ? _fbb.CreateString(port_name) : 0; - auto remap__ = remap ? _fbb.CreateString(remap) : 0; - return Serialization::CreatePortConfig(_fbb, port_name__, remap__); -} - -struct TreeNode FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table -{ - typedef TreeNodeBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE - { - VT_UID = 4, - VT_CHILDREN_UID = 6, - VT_STATUS = 8, - VT_INSTANCE_NAME = 10, - VT_REGISTRATION_NAME = 12, - VT_PORT_REMAPS = 14 - }; - uint16_t uid() const - { - return GetField(VT_UID, 0); - } - const flatbuffers::Vector* children_uid() const - { - return GetPointer*>(VT_CHILDREN_UID); - } - Serialization::NodeStatus status() const - { - return static_cast(GetField(VT_STATUS, 0)); - } - const flatbuffers::String* instance_name() const - { - return GetPointer(VT_INSTANCE_NAME); - } - const flatbuffers::String* registration_name() const - { - return GetPointer(VT_REGISTRATION_NAME); - } - const flatbuffers::Vector>* - port_remaps() const - { - return GetPointer< - const flatbuffers::Vector>*>( - VT_PORT_REMAPS); - } - bool Verify(flatbuffers::Verifier& verifier) const - { - return VerifyTableStart(verifier) && VerifyField(verifier, VT_UID) && - VerifyOffset(verifier, VT_CHILDREN_UID) && - verifier.VerifyVector(children_uid()) && - VerifyField(verifier, VT_STATUS) && - VerifyOffsetRequired(verifier, VT_INSTANCE_NAME) && - verifier.VerifyString(instance_name()) && - VerifyOffsetRequired(verifier, VT_REGISTRATION_NAME) && - verifier.VerifyString(registration_name()) && - VerifyOffset(verifier, VT_PORT_REMAPS) && - verifier.VerifyVector(port_remaps()) && - verifier.VerifyVectorOfTables(port_remaps()) && verifier.EndTable(); - } -}; - -struct TreeNodeBuilder -{ - typedef TreeNode Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_uid(uint16_t uid) - { - fbb_.AddElement(TreeNode::VT_UID, uid, 0); - } - void add_children_uid(flatbuffers::Offset> children_uid) - { - fbb_.AddOffset(TreeNode::VT_CHILDREN_UID, children_uid); - } - void add_status(Serialization::NodeStatus status) - { - fbb_.AddElement(TreeNode::VT_STATUS, static_cast(status), 0); - } - void add_instance_name(flatbuffers::Offset instance_name) - { - fbb_.AddOffset(TreeNode::VT_INSTANCE_NAME, instance_name); - } - void add_registration_name(flatbuffers::Offset registration_name) - { - fbb_.AddOffset(TreeNode::VT_REGISTRATION_NAME, registration_name); - } - void - add_port_remaps(flatbuffers::Offset< - flatbuffers::Vector>> - port_remaps) - { - fbb_.AddOffset(TreeNode::VT_PORT_REMAPS, port_remaps); - } - explicit TreeNodeBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) - { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() - { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - fbb_.Required(o, TreeNode::VT_INSTANCE_NAME); - fbb_.Required(o, TreeNode::VT_REGISTRATION_NAME); - return o; - } -}; - -inline flatbuffers::Offset -CreateTreeNode(flatbuffers::FlatBufferBuilder& _fbb, uint16_t uid = 0, - flatbuffers::Offset> children_uid = 0, - Serialization::NodeStatus status = Serialization::NodeStatus::IDLE, - flatbuffers::Offset instance_name = 0, - flatbuffers::Offset registration_name = 0, - flatbuffers::Offset< - flatbuffers::Vector>> - port_remaps = 0) -{ - TreeNodeBuilder builder_(_fbb); - builder_.add_port_remaps(port_remaps); - builder_.add_registration_name(registration_name); - builder_.add_instance_name(instance_name); - builder_.add_children_uid(children_uid); - builder_.add_uid(uid); - builder_.add_status(status); - return builder_.Finish(); -} - -inline flatbuffers::Offset CreateTreeNodeDirect( - flatbuffers::FlatBufferBuilder& _fbb, uint16_t uid = 0, - const std::vector* children_uid = nullptr, - Serialization::NodeStatus status = Serialization::NodeStatus::IDLE, - const char* instance_name = nullptr, const char* registration_name = nullptr, - const std::vector>* port_remaps = - nullptr) -{ - auto children_uid__ = children_uid ? _fbb.CreateVector(*children_uid) : 0; - auto instance_name__ = instance_name ? _fbb.CreateString(instance_name) : 0; - auto registration_name__ = registration_name ? _fbb.CreateString(registration_name) : 0; - auto port_remaps__ = - port_remaps ? _fbb.CreateVector>( - *port_remaps) : - 0; - return Serialization::CreateTreeNode(_fbb, uid, children_uid__, status, instance_name__, - registration_name__, port_remaps__); -} - -struct NodeModel FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table -{ - typedef NodeModelBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE - { - VT_REGISTRATION_NAME = 4, - VT_TYPE = 6, - VT_PORTS = 8 - }; - const flatbuffers::String* registration_name() const - { - return GetPointer(VT_REGISTRATION_NAME); - } - Serialization::NodeType type() const - { - return static_cast(GetField(VT_TYPE, 0)); - } - const flatbuffers::Vector>* ports() const - { - return GetPointer< - const flatbuffers::Vector>*>( - VT_PORTS); - } - bool Verify(flatbuffers::Verifier& verifier) const - { - return VerifyTableStart(verifier) && - VerifyOffsetRequired(verifier, VT_REGISTRATION_NAME) && - verifier.VerifyString(registration_name()) && - VerifyField(verifier, VT_TYPE) && VerifyOffset(verifier, VT_PORTS) && - verifier.VerifyVector(ports()) && verifier.VerifyVectorOfTables(ports()) && - verifier.EndTable(); - } -}; - -struct NodeModelBuilder -{ - typedef NodeModel Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_registration_name(flatbuffers::Offset registration_name) - { - fbb_.AddOffset(NodeModel::VT_REGISTRATION_NAME, registration_name); - } - void add_type(Serialization::NodeType type) - { - fbb_.AddElement(NodeModel::VT_TYPE, static_cast(type), 0); - } - void add_ports(flatbuffers::Offset< - flatbuffers::Vector>> - ports) - { - fbb_.AddOffset(NodeModel::VT_PORTS, ports); - } - explicit NodeModelBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) - { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() - { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - fbb_.Required(o, NodeModel::VT_REGISTRATION_NAME); - return o; - } -}; - -inline flatbuffers::Offset -CreateNodeModel(flatbuffers::FlatBufferBuilder& _fbb, - flatbuffers::Offset registration_name = 0, - Serialization::NodeType type = Serialization::NodeType::UNDEFINED, - flatbuffers::Offset< - flatbuffers::Vector>> - ports = 0) -{ - NodeModelBuilder builder_(_fbb); - builder_.add_ports(ports); - builder_.add_registration_name(registration_name); - builder_.add_type(type); - return builder_.Finish(); -} - -inline flatbuffers::Offset CreateNodeModelDirect( - flatbuffers::FlatBufferBuilder& _fbb, const char* registration_name = nullptr, - Serialization::NodeType type = Serialization::NodeType::UNDEFINED, - const std::vector>* ports = nullptr) -{ - auto registration_name__ = registration_name ? _fbb.CreateString(registration_name) : 0; - auto ports__ = - ports ? _fbb.CreateVector>(*ports) : - 0; - return Serialization::CreateNodeModel(_fbb, registration_name__, type, ports__); -} - -struct BehaviorTree FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table -{ - typedef BehaviorTreeBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE - { - VT_ROOT_UID = 4, - VT_NODES = 6, - VT_NODE_MODELS = 8 - }; - uint16_t root_uid() const - { - return GetField(VT_ROOT_UID, 0); - } - const flatbuffers::Vector>* nodes() const - { - return GetPointer< - const flatbuffers::Vector>*>( - VT_NODES); - } - const flatbuffers::Vector>* - node_models() const - { - return GetPointer< - const flatbuffers::Vector>*>( - VT_NODE_MODELS); - } - bool Verify(flatbuffers::Verifier& verifier) const - { - return VerifyTableStart(verifier) && VerifyField(verifier, VT_ROOT_UID) && - VerifyOffset(verifier, VT_NODES) && verifier.VerifyVector(nodes()) && - verifier.VerifyVectorOfTables(nodes()) && - VerifyOffset(verifier, VT_NODE_MODELS) && - verifier.VerifyVector(node_models()) && - verifier.VerifyVectorOfTables(node_models()) && verifier.EndTable(); - } -}; - -struct BehaviorTreeBuilder -{ - typedef BehaviorTree Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_root_uid(uint16_t root_uid) - { - fbb_.AddElement(BehaviorTree::VT_ROOT_UID, root_uid, 0); - } - void add_nodes(flatbuffers::Offset< - flatbuffers::Vector>> - nodes) - { - fbb_.AddOffset(BehaviorTree::VT_NODES, nodes); - } - void add_node_models(flatbuffers::Offset< - flatbuffers::Vector>> - node_models) - { - fbb_.AddOffset(BehaviorTree::VT_NODE_MODELS, node_models); - } - explicit BehaviorTreeBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) - { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() - { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateBehaviorTree( - flatbuffers::FlatBufferBuilder& _fbb, uint16_t root_uid = 0, - flatbuffers::Offset>> - nodes = 0, - flatbuffers::Offset< - flatbuffers::Vector>> - node_models = 0) -{ - BehaviorTreeBuilder builder_(_fbb); - builder_.add_node_models(node_models); - builder_.add_nodes(nodes); - builder_.add_root_uid(root_uid); - return builder_.Finish(); -} - -inline flatbuffers::Offset CreateBehaviorTreeDirect( - flatbuffers::FlatBufferBuilder& _fbb, uint16_t root_uid = 0, - const std::vector>* nodes = nullptr, - const std::vector>* node_models = - nullptr) -{ - auto nodes__ = - nodes ? _fbb.CreateVector>(*nodes) : 0; - auto node_models__ = - node_models ? - _fbb.CreateVector>(*node_models) : - 0; - return Serialization::CreateBehaviorTree(_fbb, root_uid, nodes__, node_models__); -} - -struct StatusChangeLog FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table -{ - typedef StatusChangeLogBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE - { - VT_BEHAVIOR_TREE = 4, - VT_STATE_CHANGES = 6 - }; - const Serialization::BehaviorTree* behavior_tree() const - { - return GetPointer(VT_BEHAVIOR_TREE); - } - const flatbuffers::Vector* state_changes() const - { - return GetPointer*>( - VT_STATE_CHANGES); - } - bool Verify(flatbuffers::Verifier& verifier) const - { - return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_BEHAVIOR_TREE) && - verifier.VerifyTable(behavior_tree()) && - VerifyOffset(verifier, VT_STATE_CHANGES) && - verifier.VerifyVector(state_changes()) && verifier.EndTable(); - } -}; - -struct StatusChangeLogBuilder -{ - typedef StatusChangeLog Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_behavior_tree(flatbuffers::Offset behavior_tree) - { - fbb_.AddOffset(StatusChangeLog::VT_BEHAVIOR_TREE, behavior_tree); - } - void add_state_changes( - flatbuffers::Offset> - state_changes) - { - fbb_.AddOffset(StatusChangeLog::VT_STATE_CHANGES, state_changes); - } - explicit StatusChangeLogBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) - { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() - { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateStatusChangeLog( - flatbuffers::FlatBufferBuilder& _fbb, - flatbuffers::Offset behavior_tree = 0, - flatbuffers::Offset> - state_changes = 0) -{ - StatusChangeLogBuilder builder_(_fbb); - builder_.add_state_changes(state_changes); - builder_.add_behavior_tree(behavior_tree); - return builder_.Finish(); -} - -inline flatbuffers::Offset CreateStatusChangeLogDirect( - flatbuffers::FlatBufferBuilder& _fbb, - flatbuffers::Offset behavior_tree = 0, - const std::vector* state_changes = nullptr) -{ - auto state_changes__ = - state_changes ? - _fbb.CreateVectorOfStructs(*state_changes) : - 0; - return Serialization::CreateStatusChangeLog(_fbb, behavior_tree, state_changes__); -} - -inline const Serialization::BehaviorTree* GetBehaviorTree(const void* buf) -{ - return flatbuffers::GetRoot(buf); -} - -inline const Serialization::BehaviorTree* GetSizePrefixedBehaviorTree(const void* buf) -{ - return flatbuffers::GetSizePrefixedRoot(buf); -} - -inline bool VerifyBehaviorTreeBuffer(flatbuffers::Verifier& verifier) -{ - return verifier.VerifyBuffer(nullptr); -} - -inline bool VerifySizePrefixedBehaviorTreeBuffer(flatbuffers::Verifier& verifier) -{ - return verifier.VerifySizePrefixedBuffer(nullptr); -} - -inline void -FinishBehaviorTreeBuffer(flatbuffers::FlatBufferBuilder& fbb, - flatbuffers::Offset root) -{ - fbb.Finish(root); -} - -inline void FinishSizePrefixedBehaviorTreeBuffer( - flatbuffers::FlatBufferBuilder& fbb, - flatbuffers::Offset root) -{ - fbb.FinishSizePrefixed(root); -} - -} // namespace Serialization - -#endif // FLATBUFFERS_GENERATED_BTLOGGER_SERIALIZATION_H_ diff --git a/include/behaviortree_cpp/flatbuffers/LICENSE.txt b/include/behaviortree_cpp/flatbuffers/LICENSE.txt deleted file mode 100644 index a4c5efd82..000000000 --- a/include/behaviortree_cpp/flatbuffers/LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2014 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/include/behaviortree_cpp/flatbuffers/flatbuffers.h b/include/behaviortree_cpp/flatbuffers/flatbuffers.h deleted file mode 100644 index a0acaf4dc..000000000 --- a/include/behaviortree_cpp/flatbuffers/flatbuffers.h +++ /dev/null @@ -1,3518 +0,0 @@ -/* - * Copyright 2014 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FLATBUFFERS_H_ -#define FLATBUFFERS_H_ - -#include "behaviortree_cpp/flatbuffers/base.h" -#include "behaviortree_cpp/flatbuffers/stl_emulation.h" - -#ifndef FLATBUFFERS_CPP98_STL -#include -#endif - -#if defined(FLATBUFFERS_NAN_DEFAULTS) -#include -#endif - -namespace flatbuffers -{ -// Generic 'operator==' with conditional specialisations. -// T e - new value of a scalar field. -// T def - default of scalar (is known at compile-time). -template -inline bool IsTheSameAs(T e, T def) -{ - return e == def; -} - -#if defined(FLATBUFFERS_NAN_DEFAULTS) && defined(FLATBUFFERS_HAS_NEW_STRTOD) && \ - (FLATBUFFERS_HAS_NEW_STRTOD > 0) -// Like `operator==(e, def)` with weak NaN if T=(float|double). -template -inline bool IsFloatTheSameAs(T e, T def) -{ - return (e == def) || ((def != def) && (e != e)); -} -template <> -inline bool IsTheSameAs(float e, float def) -{ - return IsFloatTheSameAs(e, def); -} -template <> -inline bool IsTheSameAs(double e, double def) -{ - return IsFloatTheSameAs(e, def); -} -#endif - -// Check 'v' is out of closed range [low; high]. -// Workaround for GCC warning [-Werror=type-limits]: -// comparison is always true due to limited range of data type. -template -inline bool IsOutRange(const T& v, const T& low, const T& high) -{ - return (v < low) || (high < v); -} - -// Check 'v' is in closed range [low; high]. -template -inline bool IsInRange(const T& v, const T& low, const T& high) -{ - return !IsOutRange(v, low, high); -} - -// Wrapper for uoffset_t to allow safe template specialization. -// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset). -template -struct Offset -{ - uoffset_t o; - Offset() : o(0) - {} - Offset(uoffset_t _o) : o(_o) - {} - Offset Union() const - { - return Offset(o); - } - bool IsNull() const - { - return !o; - } -}; - -inline void EndianCheck() -{ - int endiantest = 1; - // If this fails, see FLATBUFFERS_LITTLEENDIAN above. - FLATBUFFERS_ASSERT(*reinterpret_cast(&endiantest) == FLATBUFFERS_LITTLEENDIAN); - (void)endiantest; -} - -template -FLATBUFFERS_CONSTEXPR size_t AlignOf() -{ - // clang-format off - #ifdef _MSC_VER - return __alignof(T); - #else - #ifndef alignof - return __alignof__(T); - #else - return alignof(T); - #endif - #endif - // clang-format on -} - -// When we read serialized data from memory, in the case of most scalars, -// we want to just read T, but in the case of Offset, we want to actually -// perform the indirection and return a pointer. -// The template specialization below does just that. -// It is wrapped in a struct since function templates can't overload on the -// return type like this. -// The typedef is for the convenience of callers of this function -// (avoiding the need for a trailing return decltype) -template -struct IndirectHelper -{ - typedef T return_type; - typedef T mutable_return_type; - static const size_t element_stride = sizeof(T); - static return_type Read(const uint8_t* p, uoffset_t i) - { - return EndianScalar((reinterpret_cast(p))[i]); - } -}; -template -struct IndirectHelper> -{ - typedef const T* return_type; - typedef T* mutable_return_type; - static const size_t element_stride = sizeof(uoffset_t); - static return_type Read(const uint8_t* p, uoffset_t i) - { - p += i * sizeof(uoffset_t); - return reinterpret_cast(p + ReadScalar(p)); - } -}; -template -struct IndirectHelper -{ - typedef const T* return_type; - typedef T* mutable_return_type; - static const size_t element_stride = sizeof(T); - static return_type Read(const uint8_t* p, uoffset_t i) - { - return reinterpret_cast(p + i * sizeof(T)); - } -}; - -// An STL compatible iterator implementation for Vector below, effectively -// calling Get() for every element. -template -struct VectorIterator -{ - typedef std::random_access_iterator_tag iterator_category; - typedef IT value_type; - typedef ptrdiff_t difference_type; - typedef IT* pointer; - typedef IT& reference; - - VectorIterator(const uint8_t* data, uoffset_t i) - : data_(data + IndirectHelper::element_stride * i) - {} - VectorIterator(const VectorIterator& other) : data_(other.data_) - {} - VectorIterator() : data_(nullptr) - {} - - VectorIterator& operator=(const VectorIterator& other) - { - data_ = other.data_; - return *this; - } - - // clang-format off - #if !defined(FLATBUFFERS_CPP98_STL) - VectorIterator &operator=(VectorIterator &&other) { - data_ = other.data_; - return *this; - } - #endif // !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - - bool operator==(const VectorIterator& other) const - { - return data_ == other.data_; - } - - bool operator<(const VectorIterator& other) const - { - return data_ < other.data_; - } - - bool operator!=(const VectorIterator& other) const - { - return data_ != other.data_; - } - - difference_type operator-(const VectorIterator& other) const - { - return (data_ - other.data_) / IndirectHelper::element_stride; - } - - IT operator*() const - { - return IndirectHelper::Read(data_, 0); - } - - IT operator->() const - { - return IndirectHelper::Read(data_, 0); - } - - VectorIterator& operator++() - { - data_ += IndirectHelper::element_stride; - return *this; - } - - VectorIterator operator++(int) - { - VectorIterator temp(data_, 0); - data_ += IndirectHelper::element_stride; - return temp; - } - - VectorIterator operator+(const uoffset_t& offset) const - { - return VectorIterator(data_ + offset * IndirectHelper::element_stride, 0); - } - - VectorIterator& operator+=(const uoffset_t& offset) - { - data_ += offset * IndirectHelper::element_stride; - return *this; - } - - VectorIterator& operator--() - { - data_ -= IndirectHelper::element_stride; - return *this; - } - - VectorIterator operator--(int) - { - VectorIterator temp(data_, 0); - data_ -= IndirectHelper::element_stride; - return temp; - } - - VectorIterator operator-(const uoffset_t& offset) const - { - return VectorIterator(data_ - offset * IndirectHelper::element_stride, 0); - } - - VectorIterator& operator-=(const uoffset_t& offset) - { - data_ -= offset * IndirectHelper::element_stride; - return *this; - } - -private: - const uint8_t* data_; -}; - -template -struct VectorReverseIterator : public std::reverse_iterator -{ - explicit VectorReverseIterator(Iterator iter) : std::reverse_iterator(iter) - {} - - typename Iterator::value_type operator*() const - { - return *(std::reverse_iterator::current); - } - - typename Iterator::value_type operator->() const - { - return *(std::reverse_iterator::current); - } -}; - -struct String; - -// This is used as a helper type for accessing vectors. -// Vector::data() assumes the vector elements start after the length field. -template -class Vector -{ -public: - typedef VectorIterator::mutable_return_type> iterator; - typedef VectorIterator::return_type> const_iterator; - typedef VectorReverseIterator reverse_iterator; - typedef VectorReverseIterator const_reverse_iterator; - - uoffset_t size() const - { - return EndianScalar(length_); - } - - // Deprecated: use size(). Here for backwards compatibility. - FLATBUFFERS_ATTRIBUTE(deprecated("use size() instead")) - uoffset_t Length() const - { - return size(); - } - - typedef typename IndirectHelper::return_type return_type; - typedef typename IndirectHelper::mutable_return_type mutable_return_type; - typedef return_type value_type; - - return_type Get(uoffset_t i) const - { - FLATBUFFERS_ASSERT(i < size()); - return IndirectHelper::Read(Data(), i); - } - - return_type operator[](uoffset_t i) const - { - return Get(i); - } - - // If this is a Vector of enums, T will be its storage type, not the enum - // type. This function makes it convenient to retrieve value with enum - // type E. - template - E GetEnum(uoffset_t i) const - { - return static_cast(Get(i)); - } - - // If this a vector of unions, this does the cast for you. There's no check - // to make sure this is the right type! - template - const U* GetAs(uoffset_t i) const - { - return reinterpret_cast(Get(i)); - } - - // If this a vector of unions, this does the cast for you. There's no check - // to make sure this is actually a string! - const String* GetAsString(uoffset_t i) const - { - return reinterpret_cast(Get(i)); - } - - const void* GetStructFromOffset(size_t o) const - { - return reinterpret_cast(Data() + o); - } - - iterator begin() - { - return iterator(Data(), 0); - } - const_iterator begin() const - { - return const_iterator(Data(), 0); - } - - iterator end() - { - return iterator(Data(), size()); - } - const_iterator end() const - { - return const_iterator(Data(), size()); - } - - reverse_iterator rbegin() - { - return reverse_iterator(end() - 1); - } - const_reverse_iterator rbegin() const - { - return const_reverse_iterator(end() - 1); - } - - reverse_iterator rend() - { - return reverse_iterator(begin() - 1); - } - const_reverse_iterator rend() const - { - return const_reverse_iterator(begin() - 1); - } - - const_iterator cbegin() const - { - return begin(); - } - - const_iterator cend() const - { - return end(); - } - - const_reverse_iterator crbegin() const - { - return rbegin(); - } - - const_reverse_iterator crend() const - { - return rend(); - } - - // Change elements if you have a non-const pointer to this object. - // Scalars only. See reflection.h, and the documentation. - void Mutate(uoffset_t i, const T& val) - { - FLATBUFFERS_ASSERT(i < size()); - WriteScalar(data() + i, val); - } - - // Change an element of a vector of tables (or strings). - // "val" points to the new table/string, as you can obtain from - // e.g. reflection::AddFlatBuffer(). - void MutateOffset(uoffset_t i, const uint8_t* val) - { - FLATBUFFERS_ASSERT(i < size()); - static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types"); - WriteScalar(data() + i, - static_cast(val - (Data() + i * sizeof(uoffset_t)))); - } - - // Get a mutable pointer to tables/strings inside this vector. - mutable_return_type GetMutableObject(uoffset_t i) const - { - FLATBUFFERS_ASSERT(i < size()); - return const_cast(IndirectHelper::Read(Data(), i)); - } - - // The raw data in little endian format. Use with care. - const uint8_t* Data() const - { - return reinterpret_cast(&length_ + 1); - } - - uint8_t* Data() - { - return reinterpret_cast(&length_ + 1); - } - - // Similarly, but typed, much like std::vector::data - const T* data() const - { - return reinterpret_cast(Data()); - } - T* data() - { - return reinterpret_cast(Data()); - } - - template - return_type LookupByKey(K key) const - { - void* search_result = std::bsearch(&key, Data(), size(), - IndirectHelper::element_stride, KeyCompare); - - if(!search_result) - { - return nullptr; // Key not found. - } - - const uint8_t* element = reinterpret_cast(search_result); - - return IndirectHelper::Read(element, 0); - } - -protected: - // This class is only used to access pre-existing data. Don't ever - // try to construct these manually. - Vector(); - - uoffset_t length_; - -private: - // This class is a pointer. Copying will therefore create an invalid object. - // Private and unimplemented copy constructor. - Vector(const Vector&); - Vector& operator=(const Vector&); - - template - static int KeyCompare(const void* ap, const void* bp) - { - const K* key = reinterpret_cast(ap); - const uint8_t* data = reinterpret_cast(bp); - auto table = IndirectHelper::Read(data, 0); - - // std::bsearch compares with the operands transposed, so we negate the - // result here. - return -table->KeyCompareWithValue(*key); - } -}; - -// Represent a vector much like the template above, but in this case we -// don't know what the element types are (used with reflection.h). -class VectorOfAny -{ -public: - uoffset_t size() const - { - return EndianScalar(length_); - } - - const uint8_t* Data() const - { - return reinterpret_cast(&length_ + 1); - } - uint8_t* Data() - { - return reinterpret_cast(&length_ + 1); - } - -protected: - VectorOfAny(); - - uoffset_t length_; - -private: - VectorOfAny(const VectorOfAny&); - VectorOfAny& operator=(const VectorOfAny&); -}; - -#ifndef FLATBUFFERS_CPP98_STL -template -Vector>* VectorCast(Vector>* ptr) -{ - static_assert(std::is_base_of::value, "Unrelated types"); - return reinterpret_cast>*>(ptr); -} - -template -const Vector>* VectorCast(const Vector>* ptr) -{ - static_assert(std::is_base_of::value, "Unrelated types"); - return reinterpret_cast>*>(ptr); -} -#endif - -// Convenient helper function to get the length of any vector, regardless -// of whether it is null or not (the field is not set). -template -static inline size_t VectorLength(const Vector* v) -{ - return v ? v->size() : 0; -} - -// This is used as a helper type for accessing arrays. -template -class Array -{ - typedef typename flatbuffers::integral_constant::value> - scalar_tag; - typedef typename flatbuffers::conditional::type - IndirectHelperType; - -public: - typedef uint16_t size_type; - typedef typename IndirectHelper::return_type return_type; - typedef VectorIterator const_iterator; - typedef VectorReverseIterator const_reverse_iterator; - - FLATBUFFERS_CONSTEXPR uint16_t size() const - { - return length; - } - - return_type Get(uoffset_t i) const - { - FLATBUFFERS_ASSERT(i < size()); - return IndirectHelper::Read(Data(), i); - } - - return_type operator[](uoffset_t i) const - { - return Get(i); - } - - // If this is a Vector of enums, T will be its storage type, not the enum - // type. This function makes it convenient to retrieve value with enum - // type E. - template - E GetEnum(uoffset_t i) const - { - return static_cast(Get(i)); - } - - const_iterator begin() const - { - return const_iterator(Data(), 0); - } - const_iterator end() const - { - return const_iterator(Data(), size()); - } - - const_reverse_iterator rbegin() const - { - return const_reverse_iterator(end()); - } - const_reverse_iterator rend() const - { - return const_reverse_iterator(end()); - } - - const_iterator cbegin() const - { - return begin(); - } - const_iterator cend() const - { - return end(); - } - - const_reverse_iterator crbegin() const - { - return rbegin(); - } - const_reverse_iterator crend() const - { - return rend(); - } - - // Get a mutable pointer to elements inside this array. - // This method used to mutate arrays of structs followed by a @p Mutate - // operation. For primitive types use @p Mutate directly. - // @warning Assignments and reads to/from the dereferenced pointer are not - // automatically converted to the correct endianness. - typename flatbuffers::conditional::type - GetMutablePointer(uoffset_t i) const - { - FLATBUFFERS_ASSERT(i < size()); - return const_cast(&data()[i]); - } - - // Change elements if you have a non-const pointer to this object. - void Mutate(uoffset_t i, const T& val) - { - MutateImpl(scalar_tag(), i, val); - } - - // The raw data in little endian format. Use with care. - const uint8_t* Data() const - { - return data_; - } - - uint8_t* Data() - { - return data_; - } - - // Similarly, but typed, much like std::vector::data - const T* data() const - { - return reinterpret_cast(Data()); - } - T* data() - { - return reinterpret_cast(Data()); - } - - // Copy data from a span with endian conversion. - // If this Array and the span overlap, the behavior is undefined. - void CopyFromSpan(flatbuffers::span src) - { - const auto p1 = reinterpret_cast(src.data()); - const auto p2 = Data(); - FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) && - !(p2 >= p1 && p2 < (p1 + length))); - (void)p1; - (void)p2; - - CopyFromSpanImpl( - flatbuffers::integral_constant < bool, - !scalar_tag::value || sizeof(T) == 1 || FLATBUFFERS_LITTLEENDIAN > (), src); - } - -protected: - void MutateImpl(flatbuffers::integral_constant, uoffset_t i, const T& val) - { - FLATBUFFERS_ASSERT(i < size()); - WriteScalar(data() + i, val); - } - - void MutateImpl(flatbuffers::integral_constant, uoffset_t i, const T& val) - { - *(GetMutablePointer(i)) = val; - } - - void CopyFromSpanImpl(flatbuffers::integral_constant, - flatbuffers::span src) - { - // Use std::memcpy() instead of std::copy() to avoid preformance degradation - // due to aliasing if T is char or unsigned char. - // The size is known at compile time, so memcpy would be inlined. - std::memcpy(data(), src.data(), length * sizeof(T)); - } - - // Copy data from flatbuffers::span with endian conversion. - void CopyFromSpanImpl(flatbuffers::integral_constant, - flatbuffers::span src) - { - for(size_type k = 0; k < length; k++) - { - Mutate(k, src[k]); - } - } - - // This class is only used to access pre-existing data. Don't ever - // try to construct these manually. - // 'constexpr' allows us to use 'size()' at compile time. - // @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on - // a constructor. -#if defined(__cpp_constexpr) - constexpr Array(); -#else - Array(); -#endif - - uint8_t data_[length * sizeof(T)]; - -private: - // This class is a pointer. Copying will therefore create an invalid object. - // Private and unimplemented copy constructor. - Array(const Array&); - Array& operator=(const Array&); -}; - -// Specialization for Array[struct] with access using Offset pointer. -// This specialization used by idl_gen_text.cpp. -template -class Array, length> -{ - static_assert(flatbuffers::is_same::value, "unexpected type T"); - -public: - typedef const void* return_type; - - const uint8_t* Data() const - { - return data_; - } - - // Make idl_gen_text.cpp::PrintContainer happy. - return_type operator[](uoffset_t) const - { - FLATBUFFERS_ASSERT(false); - return nullptr; - } - -private: - // This class is only used to access pre-existing data. - Array(); - Array(const Array&); - Array& operator=(const Array&); - - uint8_t data_[1]; -}; - -// Cast a raw T[length] to a raw flatbuffers::Array -// without endian conversion. Use with care. -template -Array& CastToArray(T (&arr)[length]) -{ - return *reinterpret_cast*>(arr); -} - -template -const Array& CastToArray(const T (&arr)[length]) -{ - return *reinterpret_cast*>(arr); -} - -template -Array& CastToArrayOfEnum(T (&arr)[length]) -{ - static_assert(sizeof(E) == sizeof(T), "invalid enum type E"); - return *reinterpret_cast*>(arr); -} - -template -const Array& CastToArrayOfEnum(const T (&arr)[length]) -{ - static_assert(sizeof(E) == sizeof(T), "invalid enum type E"); - return *reinterpret_cast*>(arr); -} - -// Lexicographically compare two strings (possibly containing nulls), and -// return true if the first is less than the second. -static inline bool StringLessThan(const char* a_data, uoffset_t a_size, - const char* b_data, uoffset_t b_size) -{ - const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size)); - return cmp == 0 ? a_size < b_size : cmp < 0; -} - -struct String : public Vector -{ - const char* c_str() const - { - return reinterpret_cast(Data()); - } - std::string str() const - { - return std::string(c_str(), size()); - } - - // clang-format off - #ifdef FLATBUFFERS_HAS_STRING_VIEW - flatbuffers::string_view string_view() const { - return flatbuffers::string_view(c_str(), size()); - } - #endif // FLATBUFFERS_HAS_STRING_VIEW - // clang-format on - - bool operator<(const String& o) const - { - return StringLessThan(this->data(), this->size(), o.data(), o.size()); - } -}; - -// Convenience function to get std::string from a String returning an empty -// string on null pointer. -static inline std::string GetString(const String* str) -{ - return str ? str->str() : ""; -} - -// Convenience function to get char* from a String returning an empty string on -// null pointer. -static inline const char* GetCstring(const String* str) -{ - return str ? str->c_str() : ""; -} - -#ifdef FLATBUFFERS_HAS_STRING_VIEW -// Convenience function to get string_view from a String returning an empty -// string_view on null pointer. -static inline flatbuffers::string_view GetStringView(const String* str) -{ - return str ? str->string_view() : flatbuffers::string_view(); -} -#endif // FLATBUFFERS_HAS_STRING_VIEW - -// Allocator interface. This is flatbuffers-specific and meant only for -// `vector_downward` usage. -class Allocator -{ -public: - virtual ~Allocator() - {} - - // Allocate `size` bytes of memory. - virtual uint8_t* allocate(size_t size) = 0; - - // Deallocate `size` bytes of memory at `p` allocated by this allocator. - virtual void deallocate(uint8_t* p, size_t size) = 0; - - // Reallocate `new_size` bytes of memory, replacing the old region of size - // `old_size` at `p`. In contrast to a normal realloc, this grows downwards, - // and is intended specifcally for `vector_downward` use. - // `in_use_back` and `in_use_front` indicate how much of `old_size` is - // actually in use at each end, and needs to be copied. - virtual uint8_t* reallocate_downward(uint8_t* old_p, size_t old_size, size_t new_size, - size_t in_use_back, size_t in_use_front) - { - FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows - uint8_t* new_p = allocate(new_size); - memcpy_downward(old_p, old_size, new_p, new_size, in_use_back, in_use_front); - deallocate(old_p, old_size); - return new_p; - } - -protected: - // Called by `reallocate_downward` to copy memory from `old_p` of `old_size` - // to `new_p` of `new_size`. Only memory of size `in_use_front` and - // `in_use_back` will be copied from the front and back of the old memory - // allocation. - void memcpy_downward(uint8_t* old_p, size_t old_size, uint8_t* new_p, size_t new_size, - size_t in_use_back, size_t in_use_front) - { - memcpy(new_p + new_size - in_use_back, old_p + old_size - in_use_back, in_use_back); - memcpy(new_p, old_p, in_use_front); - } -}; - -// DefaultAllocator uses new/delete to allocate memory regions -class DefaultAllocator : public Allocator -{ -public: - uint8_t* allocate(size_t size) FLATBUFFERS_OVERRIDE - { - return new uint8_t[size]; - } - - void deallocate(uint8_t* p, size_t) FLATBUFFERS_OVERRIDE - { - delete[] p; - } - - static void dealloc(void* p, size_t) - { - delete[] static_cast(p); - } -}; - -// These functions allow for a null allocator to mean use the default allocator, -// as used by DetachedBuffer and vector_downward below. -// This is to avoid having a statically or dynamically allocated default -// allocator, or having to move it between the classes that may own it. -inline uint8_t* Allocate(Allocator* allocator, size_t size) -{ - return allocator ? allocator->allocate(size) : DefaultAllocator().allocate(size); -} - -inline void Deallocate(Allocator* allocator, uint8_t* p, size_t size) -{ - if(allocator) - allocator->deallocate(p, size); - else - DefaultAllocator().deallocate(p, size); -} - -inline uint8_t* ReallocateDownward(Allocator* allocator, uint8_t* old_p, size_t old_size, - size_t new_size, size_t in_use_back, - size_t in_use_front) -{ - return allocator ? allocator->reallocate_downward(old_p, old_size, new_size, - in_use_back, in_use_front) : - DefaultAllocator().reallocate_downward(old_p, old_size, new_size, - in_use_back, in_use_front); -} - -// DetachedBuffer is a finished flatbuffer memory region, detached from its -// builder. The original memory region and allocator are also stored so that -// the DetachedBuffer can manage the memory lifetime. -class DetachedBuffer -{ -public: - DetachedBuffer() - : allocator_(nullptr) - , own_allocator_(false) - , buf_(nullptr) - , reserved_(0) - , cur_(nullptr) - , size_(0) - {} - - DetachedBuffer(Allocator* allocator, bool own_allocator, uint8_t* buf, size_t reserved, - uint8_t* cur, size_t sz) - : allocator_(allocator) - , own_allocator_(own_allocator) - , buf_(buf) - , reserved_(reserved) - , cur_(cur) - , size_(sz) - {} - - // clang-format off - #if !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - DetachedBuffer(DetachedBuffer&& other) - : allocator_(other.allocator_) - , own_allocator_(other.own_allocator_) - , buf_(other.buf_) - , reserved_(other.reserved_) - , cur_(other.cur_) - , size_(other.size_) - { - other.reset(); - } - // clang-format off - #endif // !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - - // clang-format off - #if !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - DetachedBuffer& operator=(DetachedBuffer&& other) - { - if(this == &other) - return *this; - - destroy(); - - allocator_ = other.allocator_; - own_allocator_ = other.own_allocator_; - buf_ = other.buf_; - reserved_ = other.reserved_; - cur_ = other.cur_; - size_ = other.size_; - - other.reset(); - - return *this; - } - // clang-format off - #endif // !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - - ~DetachedBuffer() - { - destroy(); - } - - const uint8_t* data() const - { - return cur_; - } - - uint8_t* data() - { - return cur_; - } - - size_t size() const - { - return size_; - } - - // clang-format off - #if 0 // disabled for now due to the ordering of classes in this header - template - bool Verify() const { - Verifier verifier(data(), size()); - return verifier.Verify(nullptr); - } - - template - const T* GetRoot() const { - return flatbuffers::GetRoot(data()); - } - - template - T* GetRoot() { - return flatbuffers::GetRoot(data()); - } - #endif - // clang-format on - - // clang-format off - #if !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - // These may change access mode, leave these at end of public section - FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer& other)); - FLATBUFFERS_DELETE_FUNC(DetachedBuffer& operator=(const DetachedBuffer& other)); - // clang-format off - #endif // !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - -protected: - Allocator* allocator_; - bool own_allocator_; - uint8_t* buf_; - size_t reserved_; - uint8_t* cur_; - size_t size_; - - inline void destroy() - { - if(buf_) - Deallocate(allocator_, buf_, reserved_); - if(own_allocator_ && allocator_) - { - delete allocator_; - } - reset(); - } - - inline void reset() - { - allocator_ = nullptr; - own_allocator_ = false; - buf_ = nullptr; - reserved_ = 0; - cur_ = nullptr; - size_ = 0; - } -}; - -// This is a minimal replication of std::vector functionality, -// except growing from higher to lower addresses. i.e push_back() inserts data -// in the lowest address in the vector. -// Since this vector leaves the lower part unused, we support a "scratch-pad" -// that can be stored there for temporary data, to share the allocated space. -// Essentially, this supports 2 std::vectors in a single buffer. -class vector_downward -{ -public: - explicit vector_downward(size_t initial_size, Allocator* allocator, bool own_allocator, - size_t buffer_minalign) - : allocator_(allocator) - , own_allocator_(own_allocator) - , initial_size_(initial_size) - , buffer_minalign_(buffer_minalign) - , reserved_(0) - , buf_(nullptr) - , cur_(nullptr) - , scratch_(nullptr) - {} - - // clang-format off - #if !defined(FLATBUFFERS_CPP98_STL) - vector_downward(vector_downward &&other) - #else - vector_downward(vector_downward &other) - #endif // defined(FLATBUFFERS_CPP98_STL) - // clang-format on - : allocator_(other.allocator_) - , own_allocator_(other.own_allocator_) - , initial_size_(other.initial_size_) - , buffer_minalign_(other.buffer_minalign_) - , reserved_(other.reserved_) - , buf_(other.buf_) - , cur_(other.cur_) - , scratch_(other.scratch_) - { - // No change in other.allocator_ - // No change in other.initial_size_ - // No change in other.buffer_minalign_ - other.own_allocator_ = false; - other.reserved_ = 0; - other.buf_ = nullptr; - other.cur_ = nullptr; - other.scratch_ = nullptr; - } - - // clang-format off - #if !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - vector_downward& operator=(vector_downward&& other) - { - // Move construct a temporary and swap idiom - vector_downward temp(std::move(other)); - swap(temp); - return *this; - } - // clang-format off - #endif // defined(FLATBUFFERS_CPP98_STL) - // clang-format on - - ~vector_downward() - { - clear_buffer(); - clear_allocator(); - } - - void reset() - { - clear_buffer(); - clear(); - } - - void clear() - { - if(buf_) - { - cur_ = buf_ + reserved_; - } - else - { - reserved_ = 0; - cur_ = nullptr; - } - clear_scratch(); - } - - void clear_scratch() - { - scratch_ = buf_; - } - - void clear_allocator() - { - if(own_allocator_ && allocator_) - { - delete allocator_; - } - allocator_ = nullptr; - own_allocator_ = false; - } - - void clear_buffer() - { - if(buf_) - Deallocate(allocator_, buf_, reserved_); - buf_ = nullptr; - } - - // Relinquish the pointer to the caller. - uint8_t* release_raw(size_t& allocated_bytes, size_t& offset) - { - auto* buf = buf_; - allocated_bytes = reserved_; - offset = static_cast(cur_ - buf_); - - // release_raw only relinquishes the buffer ownership. - // Does not deallocate or reset the allocator. Destructor will do that. - buf_ = nullptr; - clear(); - return buf; - } - - // Relinquish the pointer to the caller. - DetachedBuffer release() - { - // allocator ownership (if any) is transferred to DetachedBuffer. - DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_, size()); - if(own_allocator_) - { - allocator_ = nullptr; - own_allocator_ = false; - } - buf_ = nullptr; - clear(); - return fb; - } - - size_t ensure_space(size_t len) - { - FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_); - if(len > static_cast(cur_ - scratch_)) - { - reallocate(len); - } - // Beyond this, signed offsets may not have enough range: - // (FlatBuffers > 2GB not supported). - FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE); - return len; - } - - inline uint8_t* make_space(size_t len) - { - size_t space = ensure_space(len); - cur_ -= space; - return cur_; - } - - // Returns nullptr if using the DefaultAllocator. - Allocator* get_custom_allocator() - { - return allocator_; - } - - uoffset_t size() const - { - return static_cast(reserved_ - static_cast(cur_ - buf_)); - } - - uoffset_t scratch_size() const - { - return static_cast(scratch_ - buf_); - } - - size_t capacity() const - { - return reserved_; - } - - uint8_t* data() const - { - FLATBUFFERS_ASSERT(cur_); - return cur_; - } - - uint8_t* scratch_data() const - { - FLATBUFFERS_ASSERT(buf_); - return buf_; - } - - uint8_t* scratch_end() const - { - FLATBUFFERS_ASSERT(scratch_); - return scratch_; - } - - uint8_t* data_at(size_t offset) const - { - return buf_ + reserved_ - offset; - } - - void push(const uint8_t* bytes, size_t num) - { - if(num > 0) - { - memcpy(make_space(num), bytes, num); - } - } - - // Specialized version of push() that avoids memcpy call for small data. - template - void push_small(const T& little_endian_t) - { - make_space(sizeof(T)); - *reinterpret_cast(cur_) = little_endian_t; - } - - template - void scratch_push_small(const T& t) - { - ensure_space(sizeof(T)); - *reinterpret_cast(scratch_) = t; - scratch_ += sizeof(T); - } - - // fill() is most frequently called with small byte counts (<= 4), - // which is why we're using loops rather than calling memset. - void fill(size_t zero_pad_bytes) - { - make_space(zero_pad_bytes); - for(size_t i = 0; i < zero_pad_bytes; i++) - cur_[i] = 0; - } - - // Version for when we know the size is larger. - // Precondition: zero_pad_bytes > 0 - void fill_big(size_t zero_pad_bytes) - { - memset(make_space(zero_pad_bytes), 0, zero_pad_bytes); - } - - void pop(size_t bytes_to_remove) - { - cur_ += bytes_to_remove; - } - void scratch_pop(size_t bytes_to_remove) - { - scratch_ -= bytes_to_remove; - } - - void swap(vector_downward& other) - { - using std::swap; - swap(allocator_, other.allocator_); - swap(own_allocator_, other.own_allocator_); - swap(initial_size_, other.initial_size_); - swap(buffer_minalign_, other.buffer_minalign_); - swap(reserved_, other.reserved_); - swap(buf_, other.buf_); - swap(cur_, other.cur_); - swap(scratch_, other.scratch_); - } - - void swap_allocator(vector_downward& other) - { - using std::swap; - swap(allocator_, other.allocator_); - swap(own_allocator_, other.own_allocator_); - } - -private: - // You shouldn't really be copying instances of this class. - FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward&)); - FLATBUFFERS_DELETE_FUNC(vector_downward& operator=(const vector_downward&)); - - Allocator* allocator_; - bool own_allocator_; - size_t initial_size_; - size_t buffer_minalign_; - size_t reserved_; - uint8_t* buf_; - uint8_t* cur_; // Points at location between empty (below) and used (above). - uint8_t* scratch_; // Points to the end of the scratchpad in use. - - void reallocate(size_t len) - { - auto old_reserved = reserved_; - auto old_size = size(); - auto old_scratch_size = scratch_size(); - reserved_ += (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_); - reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1); - if(buf_) - { - buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_, old_size, - old_scratch_size); - } - else - { - buf_ = Allocate(allocator_, reserved_); - } - cur_ = buf_ + reserved_ - old_size; - scratch_ = buf_ + old_scratch_size; - } -}; - -// Converts a Field ID to a virtual table offset. -inline voffset_t FieldIndexToOffset(voffset_t field_id) -{ - // Should correspond to what EndTable() below builds up. - const int fixed_fields = 2; // Vtable size and Object Size. - return static_cast((field_id + fixed_fields) * sizeof(voffset_t)); -} - -template -const T* data(const std::vector& v) -{ - // Eventually the returned pointer gets passed down to memcpy, so - // we need it to be non-null to avoid undefined behavior. - static uint8_t t; - return v.empty() ? reinterpret_cast(&t) : &v.front(); -} -template -T* data(std::vector& v) -{ - // Eventually the returned pointer gets passed down to memcpy, so - // we need it to be non-null to avoid undefined behavior. - static uint8_t t; - return v.empty() ? reinterpret_cast(&t) : &v.front(); -} - -/// @endcond - -/// @addtogroup flatbuffers_cpp_api -/// @{ -/// @class FlatBufferBuilder -/// @brief Helper class to hold data needed in creation of a FlatBuffer. -/// To serialize data, you typically call one of the `Create*()` functions in -/// the generated code, which in turn call a sequence of `StartTable`/ -/// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/ -/// `CreateVector` functions. Do this is depth-first order to build up a tree to -/// the root. `Finish()` wraps up the buffer ready for transport. -class FlatBufferBuilder -{ -public: - /// @brief Default constructor for FlatBufferBuilder. - /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults - /// to `1024`. - /// @param[in] allocator An `Allocator` to use. If null will use - /// `DefaultAllocator`. - /// @param[in] own_allocator Whether the builder/vector should own the - /// allocator. Defaults to / `false`. - /// @param[in] buffer_minalign Force the buffer to be aligned to the given - /// minimum alignment upon reallocation. Only needed if you intend to store - /// types with custom alignment AND you wish to read the buffer in-place - /// directly after creation. - explicit FlatBufferBuilder(size_t initial_size = 1024, Allocator* allocator = nullptr, - bool own_allocator = false, - size_t buffer_minalign = AlignOf()) - : buf_(initial_size, allocator, own_allocator, buffer_minalign) - , num_field_loc(0) - , max_voffset_(0) - , nested(false) - , finished(false) - , minalign_(1) - , force_defaults_(false) - , dedup_vtables_(true) - , string_pool(nullptr) - { - EndianCheck(); - } - - // clang-format off - /// @brief Move constructor for FlatBufferBuilder. - #if !defined(FLATBUFFERS_CPP98_STL) - FlatBufferBuilder(FlatBufferBuilder &&other) - #else - FlatBufferBuilder(FlatBufferBuilder &other) - #endif // #if !defined(FLATBUFFERS_CPP98_STL) - : buf_(1024, nullptr, false, AlignOf()), - num_field_loc(0), - max_voffset_(0), - nested(false), - finished(false), - minalign_(1), - force_defaults_(false), - dedup_vtables_(true), - string_pool(nullptr) { - EndianCheck(); - // Default construct and swap idiom. - // Lack of delegating constructors in vs2010 makes it more verbose than needed. - Swap(other); - } - // clang-format on - - // clang-format off - #if !defined(FLATBUFFERS_CPP98_STL) - // clang-format on - /// @brief Move assignment operator for FlatBufferBuilder. - FlatBufferBuilder& operator=(FlatBufferBuilder&& other) - { - // Move construct a temporary and swap idiom - FlatBufferBuilder temp(std::move(other)); - Swap(temp); - return *this; - } - // clang-format off - #endif // defined(FLATBUFFERS_CPP98_STL) - // clang-format on - - void Swap(FlatBufferBuilder& other) - { - using std::swap; - buf_.swap(other.buf_); - swap(num_field_loc, other.num_field_loc); - swap(max_voffset_, other.max_voffset_); - swap(nested, other.nested); - swap(finished, other.finished); - swap(minalign_, other.minalign_); - swap(force_defaults_, other.force_defaults_); - swap(dedup_vtables_, other.dedup_vtables_); - swap(string_pool, other.string_pool); - } - - ~FlatBufferBuilder() - { - if(string_pool) - delete string_pool; - } - - void Reset() - { - Clear(); // clear builder state - buf_.reset(); // deallocate buffer - } - - /// @brief Reset all the state in this FlatBufferBuilder so it can be reused - /// to construct another buffer. - void Clear() - { - ClearOffsets(); - buf_.clear(); - nested = false; - finished = false; - minalign_ = 1; - if(string_pool) - string_pool->clear(); - } - - /// @brief The current size of the serialized buffer, counting from the end. - /// @return Returns an `uoffset_t` with the current size of the buffer. - uoffset_t GetSize() const - { - return buf_.size(); - } - - /// @brief Get the serialized buffer (after you call `Finish()`). - /// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the - /// buffer. - uint8_t* GetBufferPointer() const - { - Finished(); - return buf_.data(); - } - - /// @brief Get the serialized buffer (after you call `Finish()`) as a span. - /// @return Returns a constructed flatbuffers::span that is a view over the - /// FlatBuffer data inside the buffer. - flatbuffers::span GetBufferSpan() const - { - Finished(); - return flatbuffers::span(buf_.data(), buf_.size()); - } - - /// @brief Get a pointer to an unfinished buffer. - /// @return Returns a `uint8_t` pointer to the unfinished buffer. - uint8_t* GetCurrentBufferPointer() const - { - return buf_.data(); - } - - /// @brief Get the released pointer to the serialized buffer. - /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards! - /// @return A `FlatBuffer` that owns the buffer and its allocator and - /// behaves similar to a `unique_ptr` with a deleter. - FLATBUFFERS_ATTRIBUTE(deprecated("use Release() instead")) - DetachedBuffer ReleaseBufferPointer() - { - Finished(); - return buf_.release(); - } - - /// @brief Get the released DetachedBuffer. - /// @return A `DetachedBuffer` that owns the buffer and its allocator. - DetachedBuffer Release() - { - Finished(); - return buf_.release(); - } - - /// @brief Get the released pointer to the serialized buffer. - /// @param size The size of the memory block containing - /// the serialized `FlatBuffer`. - /// @param offset The offset from the released pointer where the finished - /// `FlatBuffer` starts. - /// @return A raw pointer to the start of the memory block containing - /// the serialized `FlatBuffer`. - /// @remark If the allocator is owned, it gets deleted when the destructor is - /// called.. - uint8_t* ReleaseRaw(size_t& size, size_t& offset) - { - Finished(); - return buf_.release_raw(size, offset); - } - - /// @brief get the minimum alignment this buffer needs to be accessed - /// properly. This is only known once all elements have been written (after - /// you call Finish()). You can use this information if you need to embed - /// a FlatBuffer in some other buffer, such that you can later read it - /// without first having to copy it into its own buffer. - size_t GetBufferMinAlignment() const - { - Finished(); - return minalign_; - } - - /// @cond FLATBUFFERS_INTERNAL - void Finished() const - { - // If you get this assert, you're attempting to get access a buffer - // which hasn't been finished yet. Be sure to call - // FlatBufferBuilder::Finish with your root table. - // If you really need to access an unfinished buffer, call - // GetCurrentBufferPointer instead. - FLATBUFFERS_ASSERT(finished); - } - /// @endcond - - /// @brief In order to save space, fields that are set to their default value - /// don't get serialized into the buffer. - /// @param[in] fd When set to `true`, always serializes default values that - /// are set. Optional fields which are not set explicitly, will still not be - /// serialized. - void ForceDefaults(bool fd) - { - force_defaults_ = fd; - } - - /// @brief By default vtables are deduped in order to save space. - /// @param[in] dedup When set to `true`, dedup vtables. - void DedupVtables(bool dedup) - { - dedup_vtables_ = dedup; - } - - /// @cond FLATBUFFERS_INTERNAL - void Pad(size_t num_bytes) - { - buf_.fill(num_bytes); - } - - void TrackMinAlign(size_t elem_size) - { - if(elem_size > minalign_) - minalign_ = elem_size; - } - - void Align(size_t elem_size) - { - TrackMinAlign(elem_size); - buf_.fill(PaddingBytes(buf_.size(), elem_size)); - } - - void PushFlatBuffer(const uint8_t* bytes, size_t size) - { - PushBytes(bytes, size); - finished = true; - } - - void PushBytes(const uint8_t* bytes, size_t size) - { - buf_.push(bytes, size); - } - - void PopBytes(size_t amount) - { - buf_.pop(amount); - } - - template - void AssertScalarT() - { - // The code assumes power of 2 sizes and endian-swap-ability. - static_assert(flatbuffers::is_scalar::value, "T must be a scalar type"); - } - - // Write a single aligned scalar to the buffer - template - uoffset_t PushElement(T element) - { - AssertScalarT(); - T litle_endian_element = EndianScalar(element); - Align(sizeof(T)); - buf_.push_small(litle_endian_element); - return GetSize(); - } - - template - uoffset_t PushElement(Offset off) - { - // Special case for offsets: see ReferTo below. - return PushElement(ReferTo(off.o)); - } - - // When writing fields, we track where they are, so we can create correct - // vtables later. - void TrackField(voffset_t field, uoffset_t off) - { - FieldLoc fl = { off, field }; - buf_.scratch_push_small(fl); - num_field_loc++; - max_voffset_ = (std::max)(max_voffset_, field); - } - - // Like PushElement, but additionally tracks the field this represents. - template - void AddElement(voffset_t field, T e, T def) - { - // We don't serialize values equal to the default. - if(IsTheSameAs(e, def) && !force_defaults_) - return; - auto off = PushElement(e); - TrackField(field, off); - } - - template - void AddElement(voffset_t field, T e) - { - auto off = PushElement(e); - TrackField(field, off); - } - - template - void AddOffset(voffset_t field, Offset off) - { - if(off.IsNull()) - return; // Don't store. - AddElement(field, ReferTo(off.o), static_cast(0)); - } - - template - void AddStruct(voffset_t field, const T* structptr) - { - if(!structptr) - return; // Default, don't store. - Align(AlignOf()); - buf_.push_small(*structptr); - TrackField(field, GetSize()); - } - - void AddStructOffset(voffset_t field, uoffset_t off) - { - TrackField(field, off); - } - - // Offsets initially are relative to the end of the buffer (downwards). - // This function converts them to be relative to the current location - // in the buffer (when stored here), pointing upwards. - uoffset_t ReferTo(uoffset_t off) - { - // Align to ensure GetSize() below is correct. - Align(sizeof(uoffset_t)); - // Offset must refer to something already in buffer. - FLATBUFFERS_ASSERT(off && off <= GetSize()); - return GetSize() - off + static_cast(sizeof(uoffset_t)); - } - - void NotNested() - { - // If you hit this, you're trying to construct a Table/Vector/String - // during the construction of its parent table (between the MyTableBuilder - // and table.Finish(). - // Move the creation of these sub-objects to above the MyTableBuilder to - // not get this assert. - // Ignoring this assert may appear to work in simple cases, but the reason - // it is here is that storing objects in-line may cause vtable offsets - // to not fit anymore. It also leads to vtable duplication. - FLATBUFFERS_ASSERT(!nested); - // If you hit this, fields were added outside the scope of a table. - FLATBUFFERS_ASSERT(!num_field_loc); - } - - // From generated code (or from the parser), we call StartTable/EndTable - // with a sequence of AddElement calls in between. - uoffset_t StartTable() - { - NotNested(); - nested = true; - return GetSize(); - } - - // This finishes one serialized object by generating the vtable if it's a - // table, comparing it against existing vtables, and writing the - // resulting vtable offset. - uoffset_t EndTable(uoffset_t start) - { - // If you get this assert, a corresponding StartTable wasn't called. - FLATBUFFERS_ASSERT(nested); - // Write the vtable offset, which is the start of any Table. - // We fill it's value later. - auto vtableoffsetloc = PushElement(0); - // Write a vtable, which consists entirely of voffset_t elements. - // It starts with the number of offsets, followed by a type id, followed - // by the offsets themselves. In reverse: - // Include space for the last offset and ensure empty tables have a - // minimum size. - max_voffset_ = (std::max)(static_cast(max_voffset_ + sizeof(voffset_t)), - FieldIndexToOffset(0)); - buf_.fill_big(max_voffset_); - auto table_object_size = vtableoffsetloc - start; - // Vtable use 16bit offsets. - FLATBUFFERS_ASSERT(table_object_size < 0x10000); - WriteScalar(buf_.data() + sizeof(voffset_t), - static_cast(table_object_size)); - WriteScalar(buf_.data(), max_voffset_); - // Write the offsets into the table - for(auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc); - it < buf_.scratch_end(); it += sizeof(FieldLoc)) - { - auto field_location = reinterpret_cast(it); - auto pos = static_cast(vtableoffsetloc - field_location->off); - // If this asserts, it means you've set a field twice. - FLATBUFFERS_ASSERT(!ReadScalar(buf_.data() + field_location->id)); - WriteScalar(buf_.data() + field_location->id, pos); - } - ClearOffsets(); - auto vt1 = reinterpret_cast(buf_.data()); - auto vt1_size = ReadScalar(vt1); - auto vt_use = GetSize(); - // See if we already have generated a vtable with this exact same - // layout before. If so, make it point to the old one, remove this one. - if(dedup_vtables_) - { - for(auto it = buf_.scratch_data(); it < buf_.scratch_end(); it += sizeof(uoffset_t)) - { - auto vt_offset_ptr = reinterpret_cast(it); - auto vt2 = reinterpret_cast(buf_.data_at(*vt_offset_ptr)); - auto vt2_size = ReadScalar(vt2); - if(vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) - continue; - vt_use = *vt_offset_ptr; - buf_.pop(GetSize() - vtableoffsetloc); - break; - } - } - // If this is a new vtable, remember it. - if(vt_use == GetSize()) - { - buf_.scratch_push_small(vt_use); - } - // Fill the vtable offset we created above. - // The offset points from the beginning of the object to where the - // vtable is stored. - // Offsets default direction is downward in memory for future format - // flexibility (storing all vtables at the start of the file). - WriteScalar(buf_.data_at(vtableoffsetloc), - static_cast(vt_use) - static_cast(vtableoffsetloc)); - - nested = false; - return vtableoffsetloc; - } - - FLATBUFFERS_ATTRIBUTE(deprecated("call the version above instead")) - uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) - { - return EndTable(start); - } - - // This checks a required field has been set in a given table that has - // just been constructed. - template - void Required(Offset table, voffset_t field); - - uoffset_t StartStruct(size_t alignment) - { - Align(alignment); - return GetSize(); - } - - uoffset_t EndStruct() - { - return GetSize(); - } - - void ClearOffsets() - { - buf_.scratch_pop(num_field_loc * sizeof(FieldLoc)); - num_field_loc = 0; - max_voffset_ = 0; - } - - // Aligns such that when "len" bytes are written, an object can be written - // after it with "alignment" without padding. - void PreAlign(size_t len, size_t alignment) - { - TrackMinAlign(alignment); - buf_.fill(PaddingBytes(GetSize() + len, alignment)); - } - template - void PreAlign(size_t len) - { - AssertScalarT(); - PreAlign(len, sizeof(T)); - } - /// @endcond - - /// @brief Store a string in the buffer, which can contain any binary data. - /// @param[in] str A const char pointer to the data to be stored as a string. - /// @param[in] len The number of bytes that should be stored from `str`. - /// @return Returns the offset in the buffer where the string starts. - Offset CreateString(const char* str, size_t len) - { - NotNested(); - PreAlign(len + 1); // Always 0-terminated. - buf_.fill(1); - PushBytes(reinterpret_cast(str), len); - PushElement(static_cast(len)); - return Offset(GetSize()); - } - - /// @brief Store a string in the buffer, which is null-terminated. - /// @param[in] str A const char pointer to a C-string to add to the buffer. - /// @return Returns the offset in the buffer where the string starts. - Offset CreateString(const char* str) - { - return CreateString(str, strlen(str)); - } - - /// @brief Store a string in the buffer, which is null-terminated. - /// @param[in] str A char pointer to a C-string to add to the buffer. - /// @return Returns the offset in the buffer where the string starts. - Offset CreateString(char* str) - { - return CreateString(str, strlen(str)); - } - - /// @brief Store a string in the buffer, which can contain any binary data. - /// @param[in] str A const reference to a std::string to store in the buffer. - /// @return Returns the offset in the buffer where the string starts. - Offset CreateString(const std::string& str) - { - return CreateString(str.c_str(), str.length()); - } - - // clang-format off - #ifdef FLATBUFFERS_HAS_STRING_VIEW - /// @brief Store a string in the buffer, which can contain any binary data. - /// @param[in] str A const string_view to copy in to the buffer. - /// @return Returns the offset in the buffer where the string starts. - Offset CreateString(flatbuffers::string_view str) { - return CreateString(str.data(), str.size()); - } - #endif // FLATBUFFERS_HAS_STRING_VIEW - // clang-format on - - /// @brief Store a string in the buffer, which can contain any binary data. - /// @param[in] str A const pointer to a `String` struct to add to the buffer. - /// @return Returns the offset in the buffer where the string starts - Offset CreateString(const String* str) - { - return str ? CreateString(str->c_str(), str->size()) : 0; - } - - /// @brief Store a string in the buffer, which can contain any binary data. - /// @param[in] str A const reference to a std::string like type with support - /// of T::c_str() and T::length() to store in the buffer. - /// @return Returns the offset in the buffer where the string starts. - template - Offset CreateString(const T& str) - { - return CreateString(str.c_str(), str.length()); - } - - /// @brief Store a string in the buffer, which can contain any binary data. - /// If a string with this exact contents has already been serialized before, - /// instead simply returns the offset of the existing string. - /// @param[in] str A const char pointer to the data to be stored as a string. - /// @param[in] len The number of bytes that should be stored from `str`. - /// @return Returns the offset in the buffer where the string starts. - Offset CreateSharedString(const char* str, size_t len) - { - if(!string_pool) - string_pool = new StringOffsetMap(StringOffsetCompare(buf_)); - auto size_before_string = buf_.size(); - // Must first serialize the string, since the set is all offsets into - // buffer. - auto off = CreateString(str, len); - auto it = string_pool->find(off); - // If it exists we reuse existing serialized data! - if(it != string_pool->end()) - { - // We can remove the string we serialized. - buf_.pop(buf_.size() - size_before_string); - return *it; - } - // Record this string for future use. - string_pool->insert(off); - return off; - } - -#ifdef FLATBUFFERS_HAS_STRING_VIEW - /// @brief Store a string in the buffer, which can contain any binary data. - /// If a string with this exact contents has already been serialized before, - /// instead simply returns the offset of the existing string. - /// @param[in] str A const std::string_view to store in the buffer. - /// @return Returns the offset in the buffer where the string starts - Offset CreateSharedString(const flatbuffers::string_view str) - { - return CreateSharedString(str.data(), str.size()); - } -#else - /// @brief Store a string in the buffer, which null-terminated. - /// If a string with this exact contents has already been serialized before, - /// instead simply returns the offset of the existing string. - /// @param[in] str A const char pointer to a C-string to add to the buffer. - /// @return Returns the offset in the buffer where the string starts. - Offset CreateSharedString(const char* str) - { - return CreateSharedString(str, strlen(str)); - } - - /// @brief Store a string in the buffer, which can contain any binary data. - /// If a string with this exact contents has already been serialized before, - /// instead simply returns the offset of the existing string. - /// @param[in] str A const reference to a std::string to store in the buffer. - /// @return Returns the offset in the buffer where the string starts. - Offset CreateSharedString(const std::string& str) - { - return CreateSharedString(str.c_str(), str.length()); - } -#endif - - /// @brief Store a string in the buffer, which can contain any binary data. - /// If a string with this exact contents has already been serialized before, - /// instead simply returns the offset of the existing string. - /// @param[in] str A const pointer to a `String` struct to add to the buffer. - /// @return Returns the offset in the buffer where the string starts - Offset CreateSharedString(const String* str) - { - return CreateSharedString(str->c_str(), str->size()); - } - - /// @cond FLATBUFFERS_INTERNAL - uoffset_t EndVector(size_t len) - { - FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector. - nested = false; - return PushElement(static_cast(len)); - } - - void StartVector(size_t len, size_t elemsize) - { - NotNested(); - nested = true; - PreAlign(len * elemsize); - PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t. - } - - // Call this right before StartVector/CreateVector if you want to force the - // alignment to be something different than what the element size would - // normally dictate. - // This is useful when storing a nested_flatbuffer in a vector of bytes, - // or when storing SIMD floats, etc. - void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) - { - FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment)); - PreAlign(len * elemsize, alignment); - } - - // Similar to ForceVectorAlignment but for String fields. - void ForceStringAlignment(size_t len, size_t alignment) - { - FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment)); - PreAlign((len + 1) * sizeof(char), alignment); - } - - /// @endcond - - /// @brief Serialize an array into a FlatBuffer `vector`. - /// @tparam T The data type of the array elements. - /// @param[in] v A pointer to the array of type `T` to serialize into the - /// buffer as a `vector`. - /// @param[in] len The number of elements to serialize. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVector(const T* v, size_t len) - { - // If this assert hits, you're specifying a template argument that is - // causing the wrong overload to be selected, remove it. - AssertScalarT(); - StartVector(len, sizeof(T)); - if(len == 0) - { - return Offset>(EndVector(len)); - } - // clang-format off - #if FLATBUFFERS_LITTLEENDIAN - PushBytes(reinterpret_cast(v), len * sizeof(T)); - #else - if (sizeof(T) == 1) { - PushBytes(reinterpret_cast(v), len); - } else { - for (auto i = len; i > 0; ) { - PushElement(v[--i]); - } - } - #endif - // clang-format on - return Offset>(EndVector(len)); - } - - template - Offset>> CreateVector(const Offset* v, size_t len) - { - StartVector(len, sizeof(Offset)); - for(auto i = len; i > 0;) - { - PushElement(v[--i]); - } - return Offset>>(EndVector(len)); - } - - /// @brief Serialize a `std::vector` into a FlatBuffer `vector`. - /// @tparam T The data type of the `std::vector` elements. - /// @param v A const reference to the `std::vector` to serialize into the - /// buffer as a `vector`. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVector(const std::vector& v) - { - return CreateVector(data(v), v.size()); - } - - // vector may be implemented using a bit-set, so we can't access it as - // an array. Instead, read elements manually. - // Background: https://isocpp.org/blog/2012/11/on-vectorbool - Offset> CreateVector(const std::vector& v) - { - StartVector(v.size(), sizeof(uint8_t)); - for(auto i = v.size(); i > 0;) - { - PushElement(static_cast(v[--i])); - } - return Offset>(EndVector(v.size())); - } - - // clang-format off - #ifndef FLATBUFFERS_CPP98_STL - /// @brief Serialize values returned by a function into a FlatBuffer `vector`. - /// This is a convenience function that takes care of iteration for you. - /// @tparam T The data type of the `std::vector` elements. - /// @param f A function that takes the current iteration 0..vector_size-1 and - /// returns any type that you can construct a FlatBuffers vector out of. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template Offset> CreateVector(size_t vector_size, - const std::function &f) { - std::vector elems(vector_size); - for (size_t i = 0; i < vector_size; i++) elems[i] = f(i); - return CreateVector(elems); - } - #endif - // clang-format on - - /// @brief Serialize values returned by a function into a FlatBuffer `vector`. - /// This is a convenience function that takes care of iteration for you. - /// @tparam T The data type of the `std::vector` elements. - /// @param f A function that takes the current iteration 0..vector_size-1, - /// and the state parameter returning any type that you can construct a - /// FlatBuffers vector out of. - /// @param state State passed to f. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVector(size_t vector_size, F f, S* state) - { - std::vector elems(vector_size); - for(size_t i = 0; i < vector_size; i++) - elems[i] = f(i, state); - return CreateVector(elems); - } - - /// @brief Serialize a `std::vector` into a FlatBuffer `vector`. - /// This is a convenience function for a common case. - /// @param v A const reference to the `std::vector` to serialize into the - /// buffer as a `vector`. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - Offset>> CreateVectorOfStrings(const std::vector& v) - { - std::vector> offsets(v.size()); - for(size_t i = 0; i < v.size(); i++) - offsets[i] = CreateString(v[i]); - return CreateVector(offsets); - } - - /// @brief Serialize an array of structs into a FlatBuffer `vector`. - /// @tparam T The data type of the struct array elements. - /// @param[in] v A pointer to the array of type `T` to serialize into the - /// buffer as a `vector`. - /// @param[in] len The number of elements to serialize. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfStructs(const T* v, size_t len) - { - StartVector(len * sizeof(T) / AlignOf(), AlignOf()); - PushBytes(reinterpret_cast(v), sizeof(T) * len); - return Offset>(EndVector(len)); - } - - /// @brief Serialize an array of native structs into a FlatBuffer `vector`. - /// @tparam T The data type of the struct array elements. - /// @tparam S The data type of the native struct array elements. - /// @param[in] v A pointer to the array of type `S` to serialize into the - /// buffer as a `vector`. - /// @param[in] len The number of elements to serialize. - /// @param[in] pack_func Pointer to a function to convert the native struct - /// to the FlatBuffer struct. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfNativeStructs(const S* v, size_t len, - T((*const pack_func)(const S&))) - { - FLATBUFFERS_ASSERT(pack_func); - std::vector vv(len); - std::transform(v, v + len, vv.begin(), pack_func); - return CreateVectorOfStructs(data(vv), vv.size()); - } - - /// @brief Serialize an array of native structs into a FlatBuffer `vector`. - /// @tparam T The data type of the struct array elements. - /// @tparam S The data type of the native struct array elements. - /// @param[in] v A pointer to the array of type `S` to serialize into the - /// buffer as a `vector`. - /// @param[in] len The number of elements to serialize. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfNativeStructs(const S* v, size_t len) - { - extern T Pack(const S&); - return CreateVectorOfNativeStructs(v, len, Pack); - } - - // clang-format off - #ifndef FLATBUFFERS_CPP98_STL - /// @brief Serialize an array of structs into a FlatBuffer `vector`. - /// @tparam T The data type of the struct array elements. - /// @param[in] filler A function that takes the current iteration 0..vector_size-1 - /// and a pointer to the struct that must be filled. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - /// This is mostly useful when flatbuffers are generated with mutation - /// accessors. - template Offset> CreateVectorOfStructs( - size_t vector_size, const std::function &filler) { - T* structs = StartVectorOfStructs(vector_size); - for (size_t i = 0; i < vector_size; i++) { - filler(i, structs); - structs++; - } - return EndVectorOfStructs(vector_size); - } - #endif - // clang-format on - - /// @brief Serialize an array of structs into a FlatBuffer `vector`. - /// @tparam T The data type of the struct array elements. - /// @param[in] f A function that takes the current iteration 0..vector_size-1, - /// a pointer to the struct that must be filled and the state argument. - /// @param[in] state Arbitrary state to pass to f. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - /// This is mostly useful when flatbuffers are generated with mutation - /// accessors. - template - Offset> CreateVectorOfStructs(size_t vector_size, F f, S* state) - { - T* structs = StartVectorOfStructs(vector_size); - for(size_t i = 0; i < vector_size; i++) - { - f(i, structs, state); - structs++; - } - return EndVectorOfStructs(vector_size); - } - - /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`. - /// @tparam T The data type of the `std::vector` struct elements. - /// @param[in] v A const reference to the `std::vector` of structs to - /// serialize into the buffer as a `vector`. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfStructs(const std::vector& v) - { - return CreateVectorOfStructs(data(v), v.size()); - } - - /// @brief Serialize a `std::vector` of native structs into a FlatBuffer - /// `vector`. - /// @tparam T The data type of the `std::vector` struct elements. - /// @tparam S The data type of the `std::vector` native struct elements. - /// @param[in] v A const reference to the `std::vector` of structs to - /// serialize into the buffer as a `vector`. - /// @param[in] pack_func Pointer to a function to convert the native struct - /// to the FlatBuffer struct. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfNativeStructs(const std::vector& v, - T((*const pack_func)(const S&))) - { - return CreateVectorOfNativeStructs(data(v), v.size(), pack_func); - } - - /// @brief Serialize a `std::vector` of native structs into a FlatBuffer - /// `vector`. - /// @tparam T The data type of the `std::vector` struct elements. - /// @tparam S The data type of the `std::vector` native struct elements. - /// @param[in] v A const reference to the `std::vector` of structs to - /// serialize into the buffer as a `vector`. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfNativeStructs(const std::vector& v) - { - return CreateVectorOfNativeStructs(data(v), v.size()); - } - - /// @cond FLATBUFFERS_INTERNAL - template - struct StructKeyComparator - { - bool operator()(const T& a, const T& b) const - { - return a.KeyCompareLessThan(&b); - } - - FLATBUFFERS_DELETE_FUNC(StructKeyComparator& operator=(const StructKeyComparator&)); - }; - /// @endcond - - /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector` - /// in sorted order. - /// @tparam T The data type of the `std::vector` struct elements. - /// @param[in] v A const reference to the `std::vector` of structs to - /// serialize into the buffer as a `vector`. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfSortedStructs(std::vector* v) - { - return CreateVectorOfSortedStructs(data(*v), v->size()); - } - - /// @brief Serialize a `std::vector` of native structs into a FlatBuffer - /// `vector` in sorted order. - /// @tparam T The data type of the `std::vector` struct elements. - /// @tparam S The data type of the `std::vector` native struct elements. - /// @param[in] v A const reference to the `std::vector` of structs to - /// serialize into the buffer as a `vector`. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfSortedNativeStructs(std::vector* v) - { - return CreateVectorOfSortedNativeStructs(data(*v), v->size()); - } - - /// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted - /// order. - /// @tparam T The data type of the struct array elements. - /// @param[in] v A pointer to the array of type `T` to serialize into the - /// buffer as a `vector`. - /// @param[in] len The number of elements to serialize. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfSortedStructs(T* v, size_t len) - { - std::sort(v, v + len, StructKeyComparator()); - return CreateVectorOfStructs(v, len); - } - - /// @brief Serialize an array of native structs into a FlatBuffer `vector` in - /// sorted order. - /// @tparam T The data type of the struct array elements. - /// @tparam S The data type of the native struct array elements. - /// @param[in] v A pointer to the array of type `S` to serialize into the - /// buffer as a `vector`. - /// @param[in] len The number of elements to serialize. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset> CreateVectorOfSortedNativeStructs(S* v, size_t len) - { - extern T Pack(const S&); - typedef T (*Pack_t)(const S&); - std::vector vv(len); - std::transform(v, v + len, vv.begin(), static_cast(Pack)); - return CreateVectorOfSortedStructs(vv, len); - } - - /// @cond FLATBUFFERS_INTERNAL - template - struct TableKeyComparator - { - TableKeyComparator(vector_downward& buf) : buf_(buf) - {} - TableKeyComparator(const TableKeyComparator& other) : buf_(other.buf_) - {} - bool operator()(const Offset& a, const Offset& b) const - { - auto table_a = reinterpret_cast(buf_.data_at(a.o)); - auto table_b = reinterpret_cast(buf_.data_at(b.o)); - return table_a->KeyCompareLessThan(table_b); - } - vector_downward& buf_; - - private: - FLATBUFFERS_DELETE_FUNC( - TableKeyComparator& operator=(const TableKeyComparator& other)); - }; - /// @endcond - - /// @brief Serialize an array of `table` offsets as a `vector` in the buffer - /// in sorted order. - /// @tparam T The data type that the offset refers to. - /// @param[in] v An array of type `Offset` that contains the `table` - /// offsets to store in the buffer in sorted order. - /// @param[in] len The number of elements to store in the `vector`. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset>> CreateVectorOfSortedTables(Offset* v, size_t len) - { - std::sort(v, v + len, TableKeyComparator(buf_)); - return CreateVector(v, len); - } - - /// @brief Serialize an array of `table` offsets as a `vector` in the buffer - /// in sorted order. - /// @tparam T The data type that the offset refers to. - /// @param[in] v An array of type `Offset` that contains the `table` - /// offsets to store in the buffer in sorted order. - /// @return Returns a typed `Offset` into the serialized data indicating - /// where the vector is stored. - template - Offset>> CreateVectorOfSortedTables(std::vector>* v) - { - return CreateVectorOfSortedTables(data(*v), v->size()); - } - - /// @brief Specialized version of `CreateVector` for non-copying use cases. - /// Write the data any time later to the returned buffer pointer `buf`. - /// @param[in] len The number of elements to store in the `vector`. - /// @param[in] elemsize The size of each element in the `vector`. - /// @param[out] buf A pointer to a `uint8_t` pointer that can be - /// written to at a later time to serialize the data into a `vector` - /// in the buffer. - uoffset_t CreateUninitializedVector(size_t len, size_t elemsize, uint8_t** buf) - { - NotNested(); - StartVector(len, elemsize); - buf_.make_space(len * elemsize); - auto vec_start = GetSize(); - auto vec_end = EndVector(len); - *buf = buf_.data_at(vec_start); - return vec_end; - } - - /// @brief Specialized version of `CreateVector` for non-copying use cases. - /// Write the data any time later to the returned buffer pointer `buf`. - /// @tparam T The data type of the data that will be stored in the buffer - /// as a `vector`. - /// @param[in] len The number of elements to store in the `vector`. - /// @param[out] buf A pointer to a pointer of type `T` that can be - /// written to at a later time to serialize the data into a `vector` - /// in the buffer. - template - Offset> CreateUninitializedVector(size_t len, T** buf) - { - AssertScalarT(); - return CreateUninitializedVector(len, sizeof(T), reinterpret_cast(buf)); - } - - template - Offset> CreateUninitializedVectorOfStructs(size_t len, T** buf) - { - return CreateUninitializedVector(len, sizeof(T), reinterpret_cast(buf)); - } - - // @brief Create a vector of scalar type T given as input a vector of scalar - // type U, useful with e.g. pre "enum class" enums, or any existing scalar - // data of the wrong type. - template - Offset> CreateVectorScalarCast(const U* v, size_t len) - { - AssertScalarT(); - AssertScalarT(); - StartVector(len, sizeof(T)); - for(auto i = len; i > 0;) - { - PushElement(static_cast(v[--i])); - } - return Offset>(EndVector(len)); - } - - /// @brief Write a struct by itself, typically to be part of a union. - template - Offset CreateStruct(const T& structobj) - { - NotNested(); - Align(AlignOf()); - buf_.push_small(structobj); - return Offset(GetSize()); - } - - /// @brief The length of a FlatBuffer file header. - static const size_t kFileIdentifierLength = 4; - - /// @brief Finish serializing a buffer by writing the root offset. - /// @param[in] file_identifier If a `file_identifier` is given, the buffer - /// will be prefixed with a standard FlatBuffers file header. - template - void Finish(Offset root, const char* file_identifier = nullptr) - { - Finish(root.o, file_identifier, false); - } - - /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the - /// buffer following the size field). These buffers are NOT compatible - /// with standard buffers created by Finish, i.e. you can't call GetRoot - /// on them, you have to use GetSizePrefixedRoot instead. - /// All >32 bit quantities in this buffer will be aligned when the whole - /// size pre-fixed buffer is aligned. - /// These kinds of buffers are useful for creating a stream of FlatBuffers. - template - void FinishSizePrefixed(Offset root, const char* file_identifier = nullptr) - { - Finish(root.o, file_identifier, true); - } - - void SwapBufAllocator(FlatBufferBuilder& other) - { - buf_.swap_allocator(other.buf_); - } - -protected: - // You shouldn't really be copying instances of this class. - FlatBufferBuilder(const FlatBufferBuilder&); - FlatBufferBuilder& operator=(const FlatBufferBuilder&); - - void Finish(uoffset_t root, const char* file_identifier, bool size_prefix) - { - NotNested(); - buf_.clear_scratch(); - // This will cause the whole buffer to be aligned. - PreAlign((size_prefix ? sizeof(uoffset_t) : 0) + sizeof(uoffset_t) + - (file_identifier ? kFileIdentifierLength : 0), - minalign_); - if(file_identifier) - { - FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength); - PushBytes(reinterpret_cast(file_identifier), kFileIdentifierLength); - } - PushElement(ReferTo(root)); // Location of root. - if(size_prefix) - { - PushElement(GetSize()); - } - finished = true; - } - - struct FieldLoc - { - uoffset_t off; - voffset_t id; - }; - - vector_downward buf_; - - // Accumulating offsets of table members while it is being built. - // We store these in the scratch pad of buf_, after the vtable offsets. - uoffset_t num_field_loc; - // Track how much of the vtable is in use, so we can output the most compact - // possible vtable. - voffset_t max_voffset_; - - // Ensure objects are not nested. - bool nested; - - // Ensure the buffer is finished before it is being accessed. - bool finished; - - size_t minalign_; - - bool force_defaults_; // Serialize values equal to their defaults anyway. - - bool dedup_vtables_; - - struct StringOffsetCompare - { - StringOffsetCompare(const vector_downward& buf) : buf_(&buf) - {} - bool operator()(const Offset& a, const Offset& b) const - { - auto stra = reinterpret_cast(buf_->data_at(a.o)); - auto strb = reinterpret_cast(buf_->data_at(b.o)); - return StringLessThan(stra->data(), stra->size(), strb->data(), strb->size()); - } - const vector_downward* buf_; - }; - - // For use with CreateSharedString. Instantiated on first use only. - typedef std::set, StringOffsetCompare> StringOffsetMap; - StringOffsetMap* string_pool; - -private: - // Allocates space for a vector of structures. - // Must be completed with EndVectorOfStructs(). - template - T* StartVectorOfStructs(size_t vector_size) - { - StartVector(vector_size * sizeof(T) / AlignOf(), AlignOf()); - return reinterpret_cast(buf_.make_space(vector_size * sizeof(T))); - } - - // End the vector of structues in the flatbuffers. - // Vector should have previously be started with StartVectorOfStructs(). - template - Offset> EndVectorOfStructs(size_t vector_size) - { - return Offset>(EndVector(vector_size)); - } -}; -/// @} - -/// @cond FLATBUFFERS_INTERNAL -// Helpers to get a typed pointer to the root object contained in the buffer. -template -T* GetMutableRoot(void* buf) -{ - EndianCheck(); - return reinterpret_cast(reinterpret_cast(buf) + - EndianScalar(*reinterpret_cast(buf))); -} - -template -const T* GetRoot(const void* buf) -{ - return GetMutableRoot(const_cast(buf)); -} - -template -const T* GetSizePrefixedRoot(const void* buf) -{ - return GetRoot(reinterpret_cast(buf) + sizeof(uoffset_t)); -} - -/// Helpers to get a typed pointer to objects that are currently being built. -/// @warning Creating new objects will lead to reallocations and invalidates -/// the pointer! -template -T* GetMutableTemporaryPointer(FlatBufferBuilder& fbb, Offset offset) -{ - return reinterpret_cast(fbb.GetCurrentBufferPointer() + fbb.GetSize() - offset.o); -} - -template -const T* GetTemporaryPointer(FlatBufferBuilder& fbb, Offset offset) -{ - return GetMutableTemporaryPointer(fbb, offset); -} - -/// @brief Get a pointer to the the file_identifier section of the buffer. -/// @return Returns a const char pointer to the start of the file_identifier -/// characters in the buffer. The returned char * has length -/// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'. -/// This function is UNDEFINED for FlatBuffers whose schema does not include -/// a file_identifier (likely points at padding or the start of a the root -/// vtable). -inline const char* GetBufferIdentifier(const void* buf, bool size_prefixed = false) -{ - return reinterpret_cast(buf) + - ((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t)); -} - -// Helper to see if the identifier in a buffer has the expected value. -inline bool BufferHasIdentifier(const void* buf, const char* identifier, - bool size_prefixed = false) -{ - return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier, - FlatBufferBuilder::kFileIdentifierLength) == 0; -} - -// Helper class to verify the integrity of a FlatBuffer -class Verifier FLATBUFFERS_FINAL_CLASS -{ -public: - Verifier(const uint8_t* buf, size_t buf_len, uoffset_t _max_depth = 64, - uoffset_t _max_tables = 1000000, bool _check_alignment = true) - : buf_(buf) - , size_(buf_len) - , depth_(0) - , max_depth_(_max_depth) - , num_tables_(0) - , max_tables_(_max_tables) - , upper_bound_(0) - , check_alignment_(_check_alignment) - { - FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE); - } - - // Central location where any verification failures register. - bool Check(bool ok) const - { - // clang-format off - #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE - FLATBUFFERS_ASSERT(ok); - #endif - #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE - if (!ok) - upper_bound_ = 0; - #endif - // clang-format on - return ok; - } - - // Verify any range within the buffer. - bool Verify(size_t elem, size_t elem_len) const - { - // clang-format off - #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE - auto upper_bound = elem + elem_len; - if (upper_bound_ < upper_bound) - upper_bound_ = upper_bound; - #endif - // clang-format on - return Check(elem_len < size_ && elem <= size_ - elem_len); - } - - template - bool VerifyAlignment(size_t elem) const - { - return Check((elem & (sizeof(T) - 1)) == 0 || !check_alignment_); - } - - // Verify a range indicated by sizeof(T). - template - bool Verify(size_t elem) const - { - return VerifyAlignment(elem) && Verify(elem, sizeof(T)); - } - - bool VerifyFromPointer(const uint8_t* p, size_t len) - { - auto o = static_cast(p - buf_); - return Verify(o, len); - } - - // Verify relative to a known-good base pointer. - bool Verify(const uint8_t* base, voffset_t elem_off, size_t elem_len) const - { - return Verify(static_cast(base - buf_) + elem_off, elem_len); - } - - template - bool Verify(const uint8_t* base, voffset_t elem_off) const - { - return Verify(static_cast(base - buf_) + elem_off, sizeof(T)); - } - - // Verify a pointer (may be NULL) of a table type. - template - bool VerifyTable(const T* table) - { - return !table || table->Verify(*this); - } - - // Verify a pointer (may be NULL) of any vector type. - template - bool VerifyVector(const Vector* vec) const - { - return !vec || VerifyVectorOrString(reinterpret_cast(vec), sizeof(T)); - } - - // Verify a pointer (may be NULL) of a vector to struct. - template - bool VerifyVector(const Vector* vec) const - { - return VerifyVector(reinterpret_cast*>(vec)); - } - - // Verify a pointer (may be NULL) to string. - bool VerifyString(const String* str) const - { - size_t end; - return !str || - (VerifyVectorOrString(reinterpret_cast(str), 1, &end) && - Verify(end, 1) && // Must have terminator - Check(buf_[end] == '\0')); // Terminating byte must be 0. - } - - // Common code between vectors and strings. - bool VerifyVectorOrString(const uint8_t* vec, size_t elem_size, - size_t* end = nullptr) const - { - auto veco = static_cast(vec - buf_); - // Check we can read the size field. - if(!Verify(veco)) - return false; - // Check the whole array. If this is a string, the byte past the array - // must be 0. - auto size = ReadScalar(vec); - auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size; - if(!Check(size < max_elems)) - return false; // Protect against byte_size overflowing. - auto byte_size = sizeof(size) + elem_size * size; - if(end) - *end = veco + byte_size; - return Verify(veco, byte_size); - } - - // Special case for string contents, after the above has been called. - bool VerifyVectorOfStrings(const Vector>* vec) const - { - if(vec) - { - for(uoffset_t i = 0; i < vec->size(); i++) - { - if(!VerifyString(vec->Get(i))) - return false; - } - } - return true; - } - - // Special case for table contents, after the above has been called. - template - bool VerifyVectorOfTables(const Vector>* vec) - { - if(vec) - { - for(uoffset_t i = 0; i < vec->size(); i++) - { - if(!vec->Get(i)->Verify(*this)) - return false; - } - } - return true; - } - - __supress_ubsan__("unsigned-integer-overflow") bool VerifyTableStart( - const uint8_t* table) - { - // Check the vtable offset. - auto tableo = static_cast(table - buf_); - if(!Verify(tableo)) - return false; - // This offset may be signed, but doing the subtraction unsigned always - // gives the result we want. - auto vtableo = tableo - static_cast(ReadScalar(table)); - // Check the vtable size field, then check vtable fits in its entirety. - return VerifyComplexity() && Verify(vtableo) && - VerifyAlignment(ReadScalar(buf_ + vtableo)) && - Verify(vtableo, ReadScalar(buf_ + vtableo)); - } - - template - bool VerifyBufferFromStart(const char* identifier, size_t start) - { - if(identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) && - BufferHasIdentifier(buf_ + start, identifier)))) - { - return false; - } - - // Call T::Verify, which must be in the generated code for this type. - auto o = VerifyOffset(start); - return o && reinterpret_cast(buf_ + start + o)->Verify(*this) - // clang-format off - #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE - && GetComputedSize() - #endif - ; - // clang-format on - } - - // Verify this whole buffer, starting with root type T. - template - bool VerifyBuffer() - { - return VerifyBuffer(nullptr); - } - - template - bool VerifyBuffer(const char* identifier) - { - return VerifyBufferFromStart(identifier, 0); - } - - template - bool VerifySizePrefixedBuffer(const char* identifier) - { - return Verify(0U) && - ReadScalar(buf_) == size_ - sizeof(uoffset_t) && - VerifyBufferFromStart(identifier, sizeof(uoffset_t)); - } - - uoffset_t VerifyOffset(size_t start) const - { - if(!Verify(start)) - return 0; - auto o = ReadScalar(buf_ + start); - // May not point to itself. - if(!Check(o != 0)) - return 0; - // Can't wrap around / buffers are max 2GB. - if(!Check(static_cast(o) >= 0)) - return 0; - // Must be inside the buffer to create a pointer from it (pointer outside - // buffer is UB). - if(!Verify(start + o, 1)) - return 0; - return o; - } - - uoffset_t VerifyOffset(const uint8_t* base, voffset_t start) const - { - return VerifyOffset(static_cast(base - buf_) + start); - } - - // Called at the start of a table to increase counters measuring data - // structure depth and amount, and possibly bails out with false if - // limits set by the constructor have been hit. Needs to be balanced - // with EndTable(). - bool VerifyComplexity() - { - depth_++; - num_tables_++; - return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_); - } - - // Called at the end of a table to pop the depth count. - bool EndTable() - { - depth_--; - return true; - } - - // Returns the message size in bytes - size_t GetComputedSize() const - { - // clang-format off - #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE - uintptr_t size = upper_bound_; - // Align the size to uoffset_t - size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1); - return (size > size_) ? 0 : size; - #else - // Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work. - (void)upper_bound_; - FLATBUFFERS_ASSERT(false); - return 0; - #endif - // clang-format on - } - -private: - const uint8_t* buf_; - size_t size_; - uoffset_t depth_; - uoffset_t max_depth_; - uoffset_t num_tables_; - uoffset_t max_tables_; - mutable size_t upper_bound_; - bool check_alignment_; -}; - -// Convenient way to bundle a buffer and its length, to pass it around -// typed by its root. -// A BufferRef does not own its buffer. -struct BufferRefBase -{ -}; // for std::is_base_of -template -struct BufferRef : BufferRefBase -{ - BufferRef() : buf(nullptr), len(0), must_free(false) - {} - BufferRef(uint8_t* _buf, uoffset_t _len) : buf(_buf), len(_len), must_free(false) - {} - - ~BufferRef() - { - if(must_free) - free(buf); - } - - const T* GetRoot() const - { - return flatbuffers::GetRoot(buf); - } - - bool Verify() - { - Verifier verifier(buf, len); - return verifier.VerifyBuffer(nullptr); - } - - uint8_t* buf; - uoffset_t len; - bool must_free; -}; - -// "structs" are flat structures that do not have an offset table, thus -// always have all members present and do not support forwards/backwards -// compatible extensions. - -class Struct FLATBUFFERS_FINAL_CLASS -{ -public: - template - T GetField(uoffset_t o) const - { - return ReadScalar(&data_[o]); - } - - template - T GetStruct(uoffset_t o) const - { - return reinterpret_cast(&data_[o]); - } - - const uint8_t* GetAddressOf(uoffset_t o) const - { - return &data_[o]; - } - uint8_t* GetAddressOf(uoffset_t o) - { - return &data_[o]; - } - -private: - // private constructor & copy constructor: you obtain instances of this - // class by pointing to existing data only - Struct(); - Struct(const Struct&); - Struct& operator=(const Struct&); - - uint8_t data_[1]; -}; - -// "tables" use an offset table (possibly shared) that allows fields to be -// omitted and added at will, but uses an extra indirection to read. -class Table -{ -public: - const uint8_t* GetVTable() const - { - return data_ - ReadScalar(data_); - } - - // This gets the field offset for any of the functions below it, or 0 - // if the field was not present. - voffset_t GetOptionalFieldOffset(voffset_t field) const - { - // The vtable offset is always at the start. - auto vtable = GetVTable(); - // The first element is the size of the vtable (fields + type id + itself). - auto vtsize = ReadScalar(vtable); - // If the field we're accessing is outside the vtable, we're reading older - // data, so it's the same as if the offset was 0 (not present). - return field < vtsize ? ReadScalar(vtable + field) : 0; - } - - template - T GetField(voffset_t field, T defaultval) const - { - auto field_offset = GetOptionalFieldOffset(field); - return field_offset ? ReadScalar(data_ + field_offset) : defaultval; - } - - template - P GetPointer(voffset_t field) - { - auto field_offset = GetOptionalFieldOffset(field); - auto p = data_ + field_offset; - return field_offset ? reinterpret_cast

(p + ReadScalar(p)) : nullptr; - } - template - P GetPointer(voffset_t field) const - { - return const_cast(this)->GetPointer

(field); - } - - template - P GetStruct(voffset_t field) const - { - auto field_offset = GetOptionalFieldOffset(field); - auto p = const_cast(data_ + field_offset); - return field_offset ? reinterpret_cast

(p) : nullptr; - } - - template - flatbuffers::Optional GetOptional(voffset_t field) const - { - auto field_offset = GetOptionalFieldOffset(field); - auto p = data_ + field_offset; - return field_offset ? Optional(static_cast(ReadScalar(p))) : - Optional(); - } - - template - bool SetField(voffset_t field, T val, T def) - { - auto field_offset = GetOptionalFieldOffset(field); - if(!field_offset) - return IsTheSameAs(val, def); - WriteScalar(data_ + field_offset, val); - return true; - } - template - bool SetField(voffset_t field, T val) - { - auto field_offset = GetOptionalFieldOffset(field); - if(!field_offset) - return false; - WriteScalar(data_ + field_offset, val); - return true; - } - - bool SetPointer(voffset_t field, const uint8_t* val) - { - auto field_offset = GetOptionalFieldOffset(field); - if(!field_offset) - return false; - WriteScalar(data_ + field_offset, - static_cast(val - (data_ + field_offset))); - return true; - } - - uint8_t* GetAddressOf(voffset_t field) - { - auto field_offset = GetOptionalFieldOffset(field); - return field_offset ? data_ + field_offset : nullptr; - } - const uint8_t* GetAddressOf(voffset_t field) const - { - return const_cast(this)->GetAddressOf(field); - } - - bool CheckField(voffset_t field) const - { - return GetOptionalFieldOffset(field) != 0; - } - - // Verify the vtable of this table. - // Call this once per table, followed by VerifyField once per field. - bool VerifyTableStart(Verifier& verifier) const - { - return verifier.VerifyTableStart(data_); - } - - // Verify a particular field. - template - bool VerifyField(const Verifier& verifier, voffset_t field) const - { - // Calling GetOptionalFieldOffset should be safe now thanks to - // VerifyTable(). - auto field_offset = GetOptionalFieldOffset(field); - // Check the actual field. - return !field_offset || verifier.Verify(data_, field_offset); - } - - // VerifyField for required fields. - template - bool VerifyFieldRequired(const Verifier& verifier, voffset_t field) const - { - auto field_offset = GetOptionalFieldOffset(field); - return verifier.Check(field_offset != 0) && verifier.Verify(data_, field_offset); - } - - // Versions for offsets. - bool VerifyOffset(const Verifier& verifier, voffset_t field) const - { - auto field_offset = GetOptionalFieldOffset(field); - return !field_offset || verifier.VerifyOffset(data_, field_offset); - } - - bool VerifyOffsetRequired(const Verifier& verifier, voffset_t field) const - { - auto field_offset = GetOptionalFieldOffset(field); - return verifier.Check(field_offset != 0) && - verifier.VerifyOffset(data_, field_offset); - } - -private: - // private constructor & copy constructor: you obtain instances of this - // class by pointing to existing data only - Table(); - Table(const Table& other); - Table& operator=(const Table&); - - uint8_t data_[1]; -}; - -// This specialization allows avoiding warnings like: -// MSVC C4800: type: forcing value to bool 'true' or 'false'. -template <> -inline flatbuffers::Optional -Table::GetOptional(voffset_t field) const -{ - auto field_offset = GetOptionalFieldOffset(field); - auto p = data_ + field_offset; - return field_offset ? Optional(ReadScalar(p) != 0) : Optional(); -} - -template -void FlatBufferBuilder::Required(Offset table, voffset_t field) -{ - auto table_ptr = reinterpret_cast(buf_.data_at(table.o)); - bool ok = table_ptr->GetOptionalFieldOffset(field) != 0; - // If this fails, the caller will show what field needs to be set. - FLATBUFFERS_ASSERT(ok); - (void)ok; -} - -/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e. -/// it is the opposite transformation of GetRoot(). -/// This may be useful if you want to pass on a root and have the recipient -/// delete the buffer afterwards. -inline const uint8_t* GetBufferStartFromRootPointer(const void* root) -{ - auto table = reinterpret_cast(root); - auto vtable = table->GetVTable(); - // Either the vtable is before the root or after the root. - auto start = (std::min)(vtable, reinterpret_cast(root)); - // Align to at least sizeof(uoffset_t). - start = reinterpret_cast(reinterpret_cast(start) & - ~(sizeof(uoffset_t) - 1)); - // Additionally, there may be a file_identifier in the buffer, and the root - // offset. The buffer may have been aligned to any size between - // sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align"). - // Sadly, the exact alignment is only known when constructing the buffer, - // since it depends on the presence of values with said alignment properties. - // So instead, we simply look at the next uoffset_t values (root, - // file_identifier, and alignment padding) to see which points to the root. - // None of the other values can "impersonate" the root since they will either - // be 0 or four ASCII characters. - static_assert(FlatBufferBuilder::kFileIdentifierLength == sizeof(uoffset_t), "file_" - "identifie" - "r " - "is " - "assumed " - "to be " - "the same " - "size as " - "uoffset_" - "t"); - for(auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1; - possible_roots; possible_roots--) - { - start -= sizeof(uoffset_t); - if(ReadScalar(start) + start == reinterpret_cast(root)) - return start; - } - // We didn't find the root, either the "root" passed isn't really a root, - // or the buffer is corrupt. - // Assert, because calling this function with bad data may cause reads - // outside of buffer boundaries. - FLATBUFFERS_ASSERT(false); - return nullptr; -} - -/// @brief This return the prefixed size of a FlatBuffer. -inline uoffset_t GetPrefixedSize(const uint8_t* buf) -{ - return ReadScalar(buf); -} - -// Base class for native objects (FlatBuffer data de-serialized into native -// C++ data structures). -// Contains no functionality, purely documentative. -struct NativeTable -{ -}; - -/// @brief Function types to be used with resolving hashes into objects and -/// back again. The resolver gets a pointer to a field inside an object API -/// object that is of the type specified in the schema using the attribute -/// `cpp_type` (it is thus important whatever you write to this address -/// matches that type). The value of this field is initially null, so you -/// may choose to implement a delayed binding lookup using this function -/// if you wish. The resolver does the opposite lookup, for when the object -/// is being serialized again. -typedef uint64_t hash_value_t; -// clang-format off -#ifdef FLATBUFFERS_CPP98_STL - typedef void (*resolver_function_t)(void **pointer_adr, hash_value_t hash); - typedef hash_value_t (*rehasher_function_t)(void *pointer); -#else - typedef std::function - resolver_function_t; - typedef std::function rehasher_function_t; -#endif -// clang-format on - -// Helper function to test if a field is present, using any of the field -// enums in the generated code. -// `table` must be a generated table type. Since this is a template parameter, -// this is not typechecked to be a subclass of Table, so beware! -// Note: this function will return false for fields equal to the default -// value, since they're not stored in the buffer (unless force_defaults was -// used). -template -bool IsFieldPresent(const T* table, typename T::FlatBuffersVTableOffset field) -{ - // Cast, since Table is a private baseclass of any table types. - return reinterpret_cast(table)->CheckField(static_cast(field)); -} - -// Utility function for reverse lookups on the EnumNames*() functions -// (in the generated C++ code) -// names must be NULL terminated. -inline int LookupEnum(const char** names, const char* name) -{ - for(const char** p = names; *p; p++) - if(!strcmp(*p, name)) - return static_cast(p - names); - return -1; -} - -// These macros allow us to layout a struct with a guarantee that they'll end -// up looking the same on different compilers and platforms. -// It does this by disallowing the compiler to do any padding, and then -// does padding itself by inserting extra padding fields that make every -// element aligned to its own size. -// Additionally, it manually sets the alignment of the struct as a whole, -// which is typically its largest element, or a custom size set in the schema -// by the force_align attribute. -// These are used in the generated code only. - -// clang-format off -#if defined(_MSC_VER) - #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ - __pragma(pack(1)) \ - struct __declspec(align(alignment)) - #define FLATBUFFERS_STRUCT_END(name, size) \ - __pragma(pack()) \ - static_assert(sizeof(name) == size, "compiler breaks packing rules") -#elif defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) - #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ - _Pragma("pack(1)") \ - struct __attribute__((aligned(alignment))) - #define FLATBUFFERS_STRUCT_END(name, size) \ - _Pragma("pack()") \ - static_assert(sizeof(name) == size, "compiler breaks packing rules") -#else - #error Unknown compiler, please define structure alignment macros -#endif -// clang-format on - -// Minimal reflection via code generation. -// Besides full-fat reflection (see reflection.h) and parsing/printing by -// loading schemas (see idl.h), we can also have code generation for mimimal -// reflection data which allows pretty-printing and other uses without needing -// a schema or a parser. -// Generate code with --reflect-types (types only) or --reflect-names (names -// also) to enable. -// See minireflect.h for utilities using this functionality. - -// These types are organized slightly differently as the ones in idl.h. -enum SequenceType -{ - ST_TABLE, - ST_STRUCT, - ST_UNION, - ST_ENUM -}; - -// Scalars have the same order as in idl.h -// clang-format off -#define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \ - ET(ET_UTYPE) \ - ET(ET_BOOL) \ - ET(ET_CHAR) \ - ET(ET_UCHAR) \ - ET(ET_SHORT) \ - ET(ET_USHORT) \ - ET(ET_INT) \ - ET(ET_UINT) \ - ET(ET_LONG) \ - ET(ET_ULONG) \ - ET(ET_FLOAT) \ - ET(ET_DOUBLE) \ - ET(ET_STRING) \ - ET(ET_SEQUENCE) // See SequenceType. - -enum ElementaryType { - #define FLATBUFFERS_ET(E) E, - FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) - #undef FLATBUFFERS_ET -}; - -inline const char * const *ElementaryTypeNames() { - static const char * const names[] = { - #define FLATBUFFERS_ET(E) #E, - FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) - #undef FLATBUFFERS_ET - }; - return names; -} -// clang-format on - -// Basic type info cost just 16bits per field! -// We're explicitly defining the signedness since the signedness of integer -// bitfields is otherwise implementation-defined and causes warnings on older -// GCC compilers. -struct TypeCode -{ - // ElementaryType - unsigned short base_type : 4; - // Either vector (in table) or array (in struct) - unsigned short is_repeating : 1; - // Index into type_refs below, or -1 for none. - signed short sequence_ref : 11; -}; - -static_assert(sizeof(TypeCode) == 2, "TypeCode"); - -struct TypeTable; - -// Signature of the static method present in each type. -typedef const TypeTable* (*TypeFunction)(); - -struct TypeTable -{ - SequenceType st; - size_t num_elems; // of type_codes, values, names (but not type_refs). - const TypeCode* type_codes; // num_elems count - const TypeFunction* type_refs; // less than num_elems entries (see TypeCode). - const int16_t* array_sizes; // less than num_elems entries (see TypeCode). - const int64_t* values; // Only set for non-consecutive enum/union or structs. - const char* const* names; // Only set if compiled with --reflect-names. -}; - -// String which identifies the current version of FlatBuffers. -// flatbuffer_version_string is used by Google developers to identify which -// applications uploaded to Google Play are using this library. This allows -// the development team at Google to determine the popularity of the library. -// How it works: Applications that are uploaded to the Google Play Store are -// scanned for this version string. We track which applications are using it -// to measure popularity. You are free to remove it (of course) but we would -// appreciate if you left it in. - -// Weak linkage is culled by VS & doesn't work on cygwin. -// clang-format off -#if !defined(_WIN32) && !defined(__CYGWIN__) - -extern volatile __attribute__((weak)) const char *flatbuffer_version_string; -volatile __attribute__((weak)) const char *flatbuffer_version_string = - "FlatBuffers " - FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." - FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." - FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); - -#endif // !defined(_WIN32) && !defined(__CYGWIN__) - -#define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\ - inline E operator | (E lhs, E rhs){\ - return E(T(lhs) | T(rhs));\ - }\ - inline E operator & (E lhs, E rhs){\ - return E(T(lhs) & T(rhs));\ - }\ - inline E operator ^ (E lhs, E rhs){\ - return E(T(lhs) ^ T(rhs));\ - }\ - inline E operator ~ (E lhs){\ - return E(~T(lhs));\ - }\ - inline E operator |= (E &lhs, E rhs){\ - lhs = lhs | rhs;\ - return lhs;\ - }\ - inline E operator &= (E &lhs, E rhs){\ - lhs = lhs & rhs;\ - return lhs;\ - }\ - inline E operator ^= (E &lhs, E rhs){\ - lhs = lhs ^ rhs;\ - return lhs;\ - }\ - inline bool operator !(E rhs) \ - {\ - return !bool(T(rhs)); \ - } -/// @endcond -} // namespace flatbuffers - -// clang-format on - -#endif // FLATBUFFERS_H_ diff --git a/include/behaviortree_cpp/flatbuffers/stl_emulation.h b/include/behaviortree_cpp/flatbuffers/stl_emulation.h deleted file mode 100644 index 7aaca4e6d..000000000 --- a/include/behaviortree_cpp/flatbuffers/stl_emulation.h +++ /dev/null @@ -1,673 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FLATBUFFERS_STL_EMULATION_H_ -#define FLATBUFFERS_STL_EMULATION_H_ - -// clang-format off -#include "behaviortree_cpp/flatbuffers/base.h" - -#include -#include -#include -#include -#include - -#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL) - #define FLATBUFFERS_CPP98_STL -#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL) - -#if defined(FLATBUFFERS_CPP98_STL) - #include -#endif // defined(FLATBUFFERS_CPP98_STL) - -// Detect C++17 compatible compiler. -// __cplusplus >= 201703L - a compiler has support of 'static inline' variables. -#if defined(FLATBUFFERS_USE_STD_OPTIONAL) \ - || (defined(__cplusplus) && __cplusplus >= 201703L) \ - || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)) - #include - #ifndef FLATBUFFERS_USE_STD_OPTIONAL - #define FLATBUFFERS_USE_STD_OPTIONAL - #endif -#endif // defined(FLATBUFFERS_USE_STD_OPTIONAL) ... - -// The __cpp_lib_span is the predefined feature macro. -#if defined(FLATBUFFERS_USE_STD_SPAN) - #include -#elif defined(__cpp_lib_span) && defined(__has_include) - #if __has_include() - #include - #define FLATBUFFERS_USE_STD_SPAN - #endif -#else - // Disable non-trivial ctors if FLATBUFFERS_SPAN_MINIMAL defined. - #if !defined(FLATBUFFERS_TEMPLATES_ALIASES) || defined(FLATBUFFERS_CPP98_STL) - #define FLATBUFFERS_SPAN_MINIMAL - #else - // Enable implicit construction of a span from a std::array. - #include - #endif -#endif // defined(FLATBUFFERS_USE_STD_SPAN) - -// This header provides backwards compatibility for C++98 STLs like stlport. -namespace flatbuffers { - -// Retrieve ::back() from a string in a way that is compatible with pre C++11 -// STLs (e.g stlport). -inline char& string_back(std::string &value) { - return value[value.length() - 1]; -} - -inline char string_back(const std::string &value) { - return value[value.length() - 1]; -} - -// Helper method that retrieves ::data() from a vector in a way that is -// compatible with pre C++11 STLs (e.g stlport). -template inline T *vector_data(std::vector &vector) { - // In some debug environments, operator[] does bounds checking, so &vector[0] - // can't be used. - return vector.empty() ? nullptr : &vector[0]; -} - -template inline const T *vector_data( - const std::vector &vector) { - return vector.empty() ? nullptr : &vector[0]; -} - -template -inline void vector_emplace_back(std::vector *vector, V &&data) { - #if defined(FLATBUFFERS_CPP98_STL) - vector->push_back(data); - #else - vector->emplace_back(std::forward(data)); - #endif // defined(FLATBUFFERS_CPP98_STL) -} - -#ifndef FLATBUFFERS_CPP98_STL - #if defined(FLATBUFFERS_TEMPLATES_ALIASES) - template - using numeric_limits = std::numeric_limits; - #else - template class numeric_limits : - public std::numeric_limits {}; - #endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) -#else - template class numeric_limits : - public std::numeric_limits { - public: - // Android NDK fix. - static T lowest() { - return std::numeric_limits::min(); - } - }; - - template <> class numeric_limits : - public std::numeric_limits { - public: - static float lowest() { return -FLT_MAX; } - }; - - template <> class numeric_limits : - public std::numeric_limits { - public: - static double lowest() { return -DBL_MAX; } - }; - - template <> class numeric_limits { - public: - static unsigned long long min() { return 0ULL; } - static unsigned long long max() { return ~0ULL; } - static unsigned long long lowest() { - return numeric_limits::min(); - } - }; - - template <> class numeric_limits { - public: - static long long min() { - return static_cast(1ULL << ((sizeof(long long) << 3) - 1)); - } - static long long max() { - return static_cast( - (1ULL << ((sizeof(long long) << 3) - 1)) - 1); - } - static long long lowest() { - return numeric_limits::min(); - } - }; -#endif // FLATBUFFERS_CPP98_STL - -#if defined(FLATBUFFERS_TEMPLATES_ALIASES) - #ifndef FLATBUFFERS_CPP98_STL - template using is_scalar = std::is_scalar; - template using is_same = std::is_same; - template using is_floating_point = std::is_floating_point; - template using is_unsigned = std::is_unsigned; - template using is_enum = std::is_enum; - template using make_unsigned = std::make_unsigned; - template - using conditional = std::conditional; - template - using integral_constant = std::integral_constant; - template - using bool_constant = integral_constant; - #else - // Map C++ TR1 templates defined by stlport. - template using is_scalar = std::tr1::is_scalar; - template using is_same = std::tr1::is_same; - template using is_floating_point = - std::tr1::is_floating_point; - template using is_unsigned = std::tr1::is_unsigned; - template using is_enum = std::tr1::is_enum; - // Android NDK doesn't have std::make_unsigned or std::tr1::make_unsigned. - template struct make_unsigned { - static_assert(is_unsigned::value, "Specialization not implemented!"); - using type = T; - }; - template<> struct make_unsigned { using type = unsigned char; }; - template<> struct make_unsigned { using type = unsigned short; }; - template<> struct make_unsigned { using type = unsigned int; }; - template<> struct make_unsigned { using type = unsigned long; }; - template<> - struct make_unsigned { using type = unsigned long long; }; - template - using conditional = std::tr1::conditional; - template - using integral_constant = std::tr1::integral_constant; - template - using bool_constant = integral_constant; - #endif // !FLATBUFFERS_CPP98_STL -#else - // MSVC 2010 doesn't support C++11 aliases. - template struct is_scalar : public std::is_scalar {}; - template struct is_same : public std::is_same {}; - template struct is_floating_point : - public std::is_floating_point {}; - template struct is_unsigned : public std::is_unsigned {}; - template struct is_enum : public std::is_enum {}; - template struct make_unsigned : public std::make_unsigned {}; - template - struct conditional : public std::conditional {}; - template - struct integral_constant : public std::integral_constant {}; - template - struct bool_constant : public integral_constant {}; -#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) - -#ifndef FLATBUFFERS_CPP98_STL - #if defined(FLATBUFFERS_TEMPLATES_ALIASES) - template using unique_ptr = std::unique_ptr; - #else - // MSVC 2010 doesn't support C++11 aliases. - // We're manually "aliasing" the class here as we want to bring unique_ptr - // into the flatbuffers namespace. We have unique_ptr in the flatbuffers - // namespace we have a completely independent implementation (see below) - // for C++98 STL implementations. - template class unique_ptr : public std::unique_ptr { - public: - unique_ptr() {} - explicit unique_ptr(T* p) : std::unique_ptr(p) {} - unique_ptr(std::unique_ptr&& u) { *this = std::move(u); } - unique_ptr(unique_ptr&& u) { *this = std::move(u); } - unique_ptr& operator=(std::unique_ptr&& u) { - std::unique_ptr::reset(u.release()); - return *this; - } - unique_ptr& operator=(unique_ptr&& u) { - std::unique_ptr::reset(u.release()); - return *this; - } - unique_ptr& operator=(T* p) { - return std::unique_ptr::operator=(p); - } - }; - #endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) -#else - // Very limited implementation of unique_ptr. - // This is provided simply to allow the C++ code generated from the default - // settings to function in C++98 environments with no modifications. - template class unique_ptr { - public: - typedef T element_type; - - unique_ptr() : ptr_(nullptr) {} - explicit unique_ptr(T* p) : ptr_(p) {} - unique_ptr(unique_ptr&& u) : ptr_(nullptr) { reset(u.release()); } - unique_ptr(const unique_ptr& u) : ptr_(nullptr) { - reset(const_cast(&u)->release()); - } - ~unique_ptr() { reset(); } - - unique_ptr& operator=(const unique_ptr& u) { - reset(const_cast(&u)->release()); - return *this; - } - - unique_ptr& operator=(unique_ptr&& u) { - reset(u.release()); - return *this; - } - - unique_ptr& operator=(T* p) { - reset(p); - return *this; - } - - const T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const noexcept { return ptr_; } - explicit operator bool() const { return ptr_ != nullptr; } - - // modifiers - T* release() { - T* value = ptr_; - ptr_ = nullptr; - return value; - } - - void reset(T* p = nullptr) { - T* value = ptr_; - ptr_ = p; - if (value) delete value; - } - - void swap(unique_ptr& u) { - T* temp_ptr = ptr_; - ptr_ = u.ptr_; - u.ptr_ = temp_ptr; - } - - private: - T* ptr_; - }; - - template bool operator==(const unique_ptr& x, - const unique_ptr& y) { - return x.get() == y.get(); - } - - template bool operator==(const unique_ptr& x, - const D* y) { - return static_cast(x.get()) == y; - } - - template bool operator==(const unique_ptr& x, intptr_t y) { - return reinterpret_cast(x.get()) == y; - } - - template bool operator!=(const unique_ptr& x, decltype(nullptr)) { - return !!x; - } - - template bool operator!=(decltype(nullptr), const unique_ptr& x) { - return !!x; - } - - template bool operator==(const unique_ptr& x, decltype(nullptr)) { - return !x; - } - - template bool operator==(decltype(nullptr), const unique_ptr& x) { - return !x; - } - -#endif // !FLATBUFFERS_CPP98_STL - -#ifdef FLATBUFFERS_USE_STD_OPTIONAL -template -using Optional = std::optional; -using nullopt_t = std::nullopt_t; -inline constexpr nullopt_t nullopt = std::nullopt; - -#else -// Limited implementation of Optional type for a scalar T. -// This implementation limited by trivial types compatible with -// std::is_arithmetic or std::is_enum type traits. - -// A tag to indicate an empty flatbuffers::optional. -struct nullopt_t { - explicit FLATBUFFERS_CONSTEXPR_CPP11 nullopt_t(int) {} -}; - -#if defined(FLATBUFFERS_CONSTEXPR_DEFINED) - namespace internal { - template struct nullopt_holder { - static constexpr nullopt_t instance_ = nullopt_t(0); - }; - template - constexpr nullopt_t nullopt_holder::instance_; - } - static constexpr const nullopt_t &nullopt = internal::nullopt_holder::instance_; - -#else - namespace internal { - template struct nullopt_holder { - static const nullopt_t instance_; - }; - template - const nullopt_t nullopt_holder::instance_ = nullopt_t(0); - } - static const nullopt_t &nullopt = internal::nullopt_holder::instance_; - -#endif - -template -class Optional FLATBUFFERS_FINAL_CLASS { - // Non-scalar 'T' would extremely complicated Optional. - // Use is_scalar checking because flatbuffers flatbuffers::is_arithmetic - // isn't implemented. - static_assert(flatbuffers::is_scalar::value, "unexpected type T"); - - public: - ~Optional() {} - - FLATBUFFERS_CONSTEXPR_CPP11 Optional() FLATBUFFERS_NOEXCEPT - : value_(), has_value_(false) {} - - FLATBUFFERS_CONSTEXPR_CPP11 Optional(nullopt_t) FLATBUFFERS_NOEXCEPT - : value_(), has_value_(false) {} - - FLATBUFFERS_CONSTEXPR_CPP11 Optional(T val) FLATBUFFERS_NOEXCEPT - : value_(val), has_value_(true) {} - - FLATBUFFERS_CONSTEXPR_CPP11 Optional(const Optional &other) FLATBUFFERS_NOEXCEPT - : value_(other.value_), has_value_(other.has_value_) {} - - FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(const Optional &other) FLATBUFFERS_NOEXCEPT { - value_ = other.value_; - has_value_ = other.has_value_; - return *this; - } - - FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(nullopt_t) FLATBUFFERS_NOEXCEPT { - value_ = T(); - has_value_ = false; - return *this; - } - - FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(T val) FLATBUFFERS_NOEXCEPT { - value_ = val; - has_value_ = true; - return *this; - } - - void reset() FLATBUFFERS_NOEXCEPT { - *this = nullopt; - } - - void swap(Optional &other) FLATBUFFERS_NOEXCEPT { - std::swap(value_, other.value_); - std::swap(has_value_, other.has_value_); - } - - FLATBUFFERS_CONSTEXPR_CPP11 FLATBUFFERS_EXPLICIT_CPP11 operator bool() const FLATBUFFERS_NOEXCEPT { - return has_value_; - } - - FLATBUFFERS_CONSTEXPR_CPP11 bool has_value() const FLATBUFFERS_NOEXCEPT { - return has_value_; - } - - FLATBUFFERS_CONSTEXPR_CPP11 const T& operator*() const FLATBUFFERS_NOEXCEPT { - return value_; - } - - const T& value() const { - FLATBUFFERS_ASSERT(has_value()); - return value_; - } - - T value_or(T default_value) const FLATBUFFERS_NOEXCEPT { - return has_value() ? value_ : default_value; - } - - private: - T value_; - bool has_value_; -}; - -template -FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& opt, nullopt_t) FLATBUFFERS_NOEXCEPT { - return !opt; -} -template -FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(nullopt_t, const Optional& opt) FLATBUFFERS_NOEXCEPT { - return !opt; -} - -template -FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& lhs, const U& rhs) FLATBUFFERS_NOEXCEPT { - return static_cast(lhs) && (*lhs == rhs); -} - -template -FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const T& lhs, const Optional& rhs) FLATBUFFERS_NOEXCEPT { - return static_cast(rhs) && (lhs == *rhs); -} - -template -FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& lhs, const Optional& rhs) FLATBUFFERS_NOEXCEPT { - return static_cast(lhs) != static_cast(rhs) - ? false - : !static_cast(lhs) ? false : (*lhs == *rhs); -} -#endif // FLATBUFFERS_USE_STD_OPTIONAL - - -// Very limited and naive partial implementation of C++20 std::span. -#if defined(FLATBUFFERS_USE_STD_SPAN) - inline constexpr std::size_t dynamic_extent = std::dynamic_extent; - template - using span = std::span; - -#else // !defined(FLATBUFFERS_USE_STD_SPAN) -FLATBUFFERS_CONSTEXPR std::size_t dynamic_extent = static_cast(-1); - -// Exclude this code if MSVC2010 or non-STL Android is active. -// The non-STL Android doesn't have `std::is_convertible` required for SFINAE. -#if !defined(FLATBUFFERS_SPAN_MINIMAL) -namespace internal { - // This is SFINAE helper class for checking of a common condition: - // > This overload only participates in overload resolution - // > Check whether a pointer to an array of U can be converted - // > to a pointer to an array of E. - // This helper is used for checking of 'U -> const U'. - template - struct is_span_convertable { - using type = - typename std::conditional::value - && (Extent == dynamic_extent || N == Extent), - int, void>::type; - }; - -} // namespace internal -#endif // !defined(FLATBUFFERS_SPAN_MINIMAL) - -// T - element type; must be a complete type that is not an abstract -// class type. -// Extent - the number of elements in the sequence, or dynamic. -template -class span FLATBUFFERS_FINAL_CLASS { - public: - typedef T element_type; - typedef T& reference; - typedef const T& const_reference; - typedef T* pointer; - typedef const T* const_pointer; - typedef std::size_t size_type; - - static FLATBUFFERS_CONSTEXPR size_type extent = Extent; - - // Returns the number of elements in the span. - FLATBUFFERS_CONSTEXPR_CPP11 size_type size() const FLATBUFFERS_NOEXCEPT { - return count_; - } - - // Returns the size of the sequence in bytes. - FLATBUFFERS_CONSTEXPR_CPP11 - size_type size_bytes() const FLATBUFFERS_NOEXCEPT { - return size() * sizeof(element_type); - } - - // Checks if the span is empty. - FLATBUFFERS_CONSTEXPR_CPP11 bool empty() const FLATBUFFERS_NOEXCEPT { - return size() == 0; - } - - // Returns a pointer to the beginning of the sequence. - FLATBUFFERS_CONSTEXPR_CPP11 pointer data() const FLATBUFFERS_NOEXCEPT { - return data_; - } - - // Returns a reference to the idx-th element of the sequence. - // The behavior is undefined if the idx is greater than or equal to size(). - FLATBUFFERS_CONSTEXPR_CPP11 reference operator[](size_type idx) const { - return data()[idx]; - } - - FLATBUFFERS_CONSTEXPR_CPP11 span(const span &other) FLATBUFFERS_NOEXCEPT - : data_(other.data_), count_(other.count_) {} - - FLATBUFFERS_CONSTEXPR_CPP14 span &operator=(const span &other) - FLATBUFFERS_NOEXCEPT { - data_ = other.data_; - count_ = other.count_; - } - - // Limited implementation of - // `template constexpr std::span(It first, size_type count);`. - // - // Constructs a span that is a view over the range [first, first + count); - // the resulting span has: data() == first and size() == count. - // The behavior is undefined if [first, first + count) is not a valid range, - // or if (extent != flatbuffers::dynamic_extent && count != extent). - FLATBUFFERS_CONSTEXPR_CPP11 - explicit span(pointer first, size_type count) FLATBUFFERS_NOEXCEPT - : data_ (Extent == dynamic_extent ? first : (Extent == count ? first : nullptr)), - count_(Extent == dynamic_extent ? count : (Extent == count ? Extent : 0)) { - // Make span empty if the count argument is incompatible with span. - } - - // Exclude this code if MSVC2010 is active. The MSVC2010 isn't C++11 - // compliant, it doesn't support default template arguments for functions. - #if defined(FLATBUFFERS_SPAN_MINIMAL) - FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr), - count_(0) { - static_assert(extent == 0 || extent == dynamic_extent, "invalid span"); - } - - #else - // Constructs an empty span whose data() == nullptr and size() == 0. - // This overload only participates in overload resolution if - // extent == 0 || extent == flatbuffers::dynamic_extent. - // A dummy template argument N is need dependency for SFINAE. - template::type = 0> - FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr), - count_(0) { - static_assert(extent == 0 || extent == dynamic_extent, "invalid span"); - } - - // Constructs a span that is a view over the array arr; the resulting span - // has size() == N and data() == std::data(arr). These overloads only - // participate in overload resolution if - // extent == std::dynamic_extent || N == extent is true and - // std::remove_pointer_t(*)[] - // is convertible to element_type (*)[]. - template::type = 0> - FLATBUFFERS_CONSTEXPR_CPP11 span(element_type (&arr)[N]) FLATBUFFERS_NOEXCEPT - : data_(arr), count_(N) {} - - template::type = 0> - FLATBUFFERS_CONSTEXPR_CPP11 span(std::array &arr) FLATBUFFERS_NOEXCEPT - : data_(arr.data()), count_(N) {} - - //template - //FLATBUFFERS_CONSTEXPR_CPP11 span(std::array &arr) FLATBUFFERS_NOEXCEPT - // : data_(arr.data()), count_(N) {} - - template::type = 0> - FLATBUFFERS_CONSTEXPR_CPP11 span(const std::array &arr) FLATBUFFERS_NOEXCEPT - : data_(arr.data()), count_(N) {} - - // Converting constructor from another span s; - // the resulting span has size() == s.size() and data() == s.data(). - // This overload only participates in overload resolution - // if extent == std::dynamic_extent || N == extent is true and U (*)[] - // is convertible to element_type (*)[]. - template::type = 0> - FLATBUFFERS_CONSTEXPR_CPP11 span(const flatbuffers::span &s) FLATBUFFERS_NOEXCEPT - : span(s.data(), s.size()) { - } - - #endif // !defined(FLATBUFFERS_SPAN_MINIMAL) - - private: - // This is a naive implementation with 'count_' member even if (Extent != dynamic_extent). - pointer const data_; - const size_type count_; -}; - - #if !defined(FLATBUFFERS_SPAN_MINIMAL) - template - FLATBUFFERS_CONSTEXPR_CPP11 - flatbuffers::span make_span(U(&arr)[N]) FLATBUFFERS_NOEXCEPT { - return span(arr); - } - - template - FLATBUFFERS_CONSTEXPR_CPP11 - flatbuffers::span make_span(const U(&arr)[N]) FLATBUFFERS_NOEXCEPT { - return span(arr); - } - - template - FLATBUFFERS_CONSTEXPR_CPP11 - flatbuffers::span make_span(std::array &arr) FLATBUFFERS_NOEXCEPT { - return span(arr); - } - - template - FLATBUFFERS_CONSTEXPR_CPP11 - flatbuffers::span make_span(const std::array &arr) FLATBUFFERS_NOEXCEPT { - return span(arr); - } - - template - FLATBUFFERS_CONSTEXPR_CPP11 - flatbuffers::span make_span(U *first, std::size_t count) FLATBUFFERS_NOEXCEPT { - return span(first, count); - } - - template - FLATBUFFERS_CONSTEXPR_CPP11 - flatbuffers::span make_span(const U *first, std::size_t count) FLATBUFFERS_NOEXCEPT { - return span(first, count); - } -#endif - -#endif // defined(FLATBUFFERS_USE_STD_SPAN) - -} // namespace flatbuffers - -#endif // FLATBUFFERS_STL_EMULATION_H_ diff --git a/include/behaviortree_cpp/json_export.h b/include/behaviortree_cpp/json_export.h index b478a8f64..9274ad788 100644 --- a/include/behaviortree_cpp/json_export.h +++ b/include/behaviortree_cpp/json_export.h @@ -2,7 +2,7 @@ #include "behaviortree_cpp/basic_types.h" #include "behaviortree_cpp/utils/safe_any.hpp" -#include "behaviortree_cpp/contrib/expected.hpp" +#include "behaviortree_cpp/basic_types.h" // Use the version nlohmann::json embedded in BT.CPP #include "behaviortree_cpp/contrib/json.hpp" @@ -62,7 +62,7 @@ class JsonExporter /// This information is needed to create a BT::Blackboard::entry using Entry = std::pair; - using ExpectedEntry = nonstd::expected_lite::expected; + using ExpectedEntry = nonstd::expected; /** * @brief fromJson will return an Entry (value wrappedn in Any + TypeInfo) @@ -73,14 +73,32 @@ class JsonExporter */ ExpectedEntry fromJson(const nlohmann::json& source) const; - /// Same as the other, but providing the specific type + /// Same as the other, but providing the specific type, + /// To be preferred if the JSON doesn't contain the field [__type] ExpectedEntry fromJson(const nlohmann::json& source, std::type_index type) const; + template + Expected fromJson(const nlohmann::json& source) const; + /// Register new JSON converters with addConverter(). /// You should have used first the macro BT_JSON_CONVERTER template void addConverter(); + /** + * @brief addConverter register a to_json function that converts a json to a type T. + * + * @param to_json the function with signature void(const T&, nlohmann::json&) + * @param add_type if true, add a field called [__type] with the name ofthe type. + * */ + template + void addConverter(std::function to_json, + bool add_type = true); + + /// Register custom from_json converter directly. + template + void addConverter(std::function from_json); + private: using ToJonConverter = std::function; using FromJonConverter = std::function; @@ -90,6 +108,22 @@ class JsonExporter std::unordered_map type_names_; }; +template +inline Expected JsonExporter::fromJson(const nlohmann::json& source) const +{ + auto res = fromJson(source); + if(!res) + { + return nonstd::expected_lite::make_unexpected(res.error()); + } + auto casted = res->first.tryCast(); + if(!casted) + { + return nonstd::expected_lite::make_unexpected(casted.error()); + } + return *casted; +} + //------------------------------------------------------------------- template @@ -117,6 +151,33 @@ inline void JsonExporter::addConverter() from_json_converters_.insert({ typeid(T), from_converter }); } +template +inline void JsonExporter::addConverter( + std::function func, bool add_type) +{ + auto converter = [func, add_type](const BT::Any& entry, nlohmann::json& json) { + func(entry.cast(), json); + if(add_type) + { + json["__type"] = BT::demangle(typeid(T)); + } + }; + to_json_converters_.insert({ typeid(T), std::move(converter) }); +} + +template +inline void +JsonExporter::addConverter(std::function func) +{ + auto converter = [func](const nlohmann::json& json) -> Entry { + T tmp; + func(json, tmp); + return { BT::Any(tmp), BT::TypeInfo::Create() }; + }; + type_names_.insert({ BT::demangle(typeid(T)), BT::TypeInfo::Create() }); + from_json_converters_.insert({ typeid(T), std::move(converter) }); +} + template inline void RegisterJsonDefinition() { diff --git a/include/behaviortree_cpp/loggers/abstract_logger.h b/include/behaviortree_cpp/loggers/abstract_logger.h index 25df2fc28..be994944c 100644 --- a/include/behaviortree_cpp/loggers/abstract_logger.h +++ b/include/behaviortree_cpp/loggers/abstract_logger.h @@ -61,6 +61,7 @@ class StatusChangeLogger std::vector subscribers_; TimestampType type_; BT::TimePoint first_timestamp_ = {}; + std::mutex callback_mutex_; }; //-------------------------------------------- @@ -72,6 +73,7 @@ inline StatusChangeLogger::StatusChangeLogger(TreeNode* root_node) auto subscribeCallback = [this](TimePoint timestamp, const TreeNode& node, NodeStatus prev, NodeStatus status) { + std::unique_lock lk(callback_mutex_); if(enabled_ && (status != NodeStatus::IDLE || show_transition_to_idle_)) { if(type_ == TimestampType::absolute) diff --git a/include/behaviortree_cpp/loggers/bt_cout_logger.h b/include/behaviortree_cpp/loggers/bt_cout_logger.h index 8eb5c451a..e047c0576 100644 --- a/include/behaviortree_cpp/loggers/bt_cout_logger.h +++ b/include/behaviortree_cpp/loggers/bt_cout_logger.h @@ -13,8 +13,6 @@ namespace BT class StdCoutLogger : public StatusChangeLogger { - static std::atomic ref_count; - public: StdCoutLogger(const BT::Tree& tree); ~StdCoutLogger() override; diff --git a/include/behaviortree_cpp/loggers/bt_file_logger.h b/include/behaviortree_cpp/loggers/bt_file_logger.h deleted file mode 100644 index 8b98517a3..000000000 --- a/include/behaviortree_cpp/loggers/bt_file_logger.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef BT_FILE_LOGGER_H -#define BT_FILE_LOGGER_H - -#include -#include -#include -#include "behaviortree_cpp/loggers/abstract_logger.h" -#include "behaviortree_cpp/flatbuffers/bt_flatbuffer_helper.h" - -namespace BT -{ - -class [[deprecated("Use FileLogger2 instead")]] FileLogger : public StatusChangeLogger -{ -public: - FileLogger(const Tree& tree, const char* filename, uint16_t buffer_size = 10); - - virtual ~FileLogger() override; - - virtual void callback(Duration timestamp, const TreeNode& node, NodeStatus prev_status, - NodeStatus status) override; - - virtual void flush() override; - -private: - std::ofstream file_os_; - - std::chrono::high_resolution_clock::time_point start_time; - - std::vector buffer_; - - size_t buffer_max_size_; -}; - -} // namespace BT - -#endif // BT_FILE_LOGGER_H diff --git a/include/behaviortree_cpp/loggers/bt_minitrace_logger.h b/include/behaviortree_cpp/loggers/bt_minitrace_logger.h index 4a196d36d..38efa9140 100644 --- a/include/behaviortree_cpp/loggers/bt_minitrace_logger.h +++ b/include/behaviortree_cpp/loggers/bt_minitrace_logger.h @@ -1,15 +1,11 @@ -#ifndef BT_MINITRACE_LOGGER_H -#define BT_MINITRACE_LOGGER_H +#pragma once -#include #include "behaviortree_cpp/loggers/abstract_logger.h" namespace BT { class MinitraceLogger : public StatusChangeLogger { - static std::atomic ref_count; - public: MinitraceLogger(const BT::Tree& tree, const char* filename_json); @@ -25,5 +21,3 @@ class MinitraceLogger : public StatusChangeLogger }; } // namespace BT - -#endif // BT_MINITRACE_LOGGER_H diff --git a/include/behaviortree_cpp/scripting/operators.hpp b/include/behaviortree_cpp/scripting/operators.hpp index 5f4a6f7c9..30c4844ea 100644 --- a/include/behaviortree_cpp/scripting/operators.hpp +++ b/include/behaviortree_cpp/scripting/operators.hpp @@ -28,7 +28,7 @@ using SimpleString = SafeAny::SimpleString; using expr_ptr = std::shared_ptr; // extended strin to number that consider enums and booleans -double StringToDouble(const Any& value, const Environment& env) +inline double StringToDouble(const Any& value, const Environment& env) { const auto str = value.cast(); if(str == "true") diff --git a/include/behaviortree_cpp/tree_node.h b/include/behaviortree_cpp/tree_node.h index 55b654cda..1061b2528 100644 --- a/include/behaviortree_cpp/tree_node.h +++ b/include/behaviortree_cpp/tree_node.h @@ -166,6 +166,8 @@ class TreeNode using PreTickCallback = std::function; using PostTickCallback = std::function; + using TickMonitorCallback = + std::function; /** * @brief subscribeToStatusChange is used to attach a callback to a status change. @@ -181,9 +183,9 @@ class TreeNode /** This method attaches to the TreeNode a callback with signature: * - * Optional myCallback(TreeNode& node) + * NodeStatus callback(TreeNode& node) * - * This callback is executed BEFORE the tick() and, if it returns a valid Optional, + * This callback is executed BEFORE the tick() and, if it returns SUCCESS or FAILURE, * the actual tick() will NOT be executed and this result will be returned instead. * * This is useful to inject a "dummy" implementation of the TreeNode at run-time @@ -193,13 +195,23 @@ class TreeNode /** * This method attaches to the TreeNode a callback with signature: * - * Optional myCallback(TreeNode& node, NodeStatus new_status) + * NodeStatus myCallback(TreeNode& node, NodeStatus status) * - * This callback is executed AFTER the tick() and, if it returns a valid Optional, + * This callback is executed AFTER the tick() and, if it returns SUCCESS or FAILURE, * the value returned by the actual tick() is overriden with this one. */ void setPostTickFunction(PostTickCallback callback); + /** + * This method attaches to the TreeNode a callback with signature: + * + * void myCallback(TreeNode& node, NodeStatus status, std::chrono::microseconds duration) + * + * This callback is executed AFTER the tick() and will inform the user about its status and + * the execution time. Works only if the tick was not substituted by a pre-condition. + */ + void setTickMonitorCallback(TickMonitorCallback callback); + /// The unique identifier of this instance of treeNode. /// It is assigneld by the factory [[nodiscard]] uint16_t UID() const; @@ -246,7 +258,7 @@ class TreeNode template [[nodiscard]] Expected getInput(const std::string& key) const { - T out; + T out{}; auto res = getInput(key, out); return (res) ? Expected(out) : nonstd::make_unexpected(res.error()); } @@ -457,6 +469,13 @@ inline Expected TreeNode::getInputStamped(const std::string& key, { port_value_str = input_port_it->second; } + else if(!config().manifest) + { + return nonstd::make_unexpected(StrCat("getInput() of node '", fullPath(), + "' failed because the manifest is " + "nullptr (WTF?) and the key: [", + key, "] is missing")); + } else { // maybe it is declared with a default value in the manifest diff --git a/package.xml b/package.xml index d8e2c393d..c4cb75729 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp - 4.6.0 + 4.6.2 This package provides the Behavior Trees core library. diff --git a/sample_nodes/CMakeLists.txt b/sample_nodes/CMakeLists.txt index e8aaafffe..217fec77d 100644 --- a/sample_nodes/CMakeLists.txt +++ b/sample_nodes/CMakeLists.txt @@ -33,3 +33,15 @@ target_link_libraries(movebase_node_dyn PRIVATE ${BTCPP_LIBRARY}) target_compile_definitions(movebase_node_dyn PRIVATE BT_PLUGIN_EXPORT ) set_target_properties(movebase_node_dyn PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${BTCPP_BIN_DESTINATION} ) + +###################################################### +# INSTALL plugins for other packages to load + +INSTALL(TARGETS + crossdoor_nodes_dyn + dummy_nodes_dyn + movebase_node_dyn + LIBRARY DESTINATION share/${PROJECT_NAME}/bt_plugins + ARCHIVE DESTINATION share/${PROJECT_NAME}/bt_plugins + RUNTIME DESTINATION share/${PROJECT_NAME}/bt_plugins +) diff --git a/sample_nodes/crossdoor_nodes.cpp b/sample_nodes/crossdoor_nodes.cpp index c9b0f0b82..29463c451 100644 --- a/sample_nodes/crossdoor_nodes.cpp +++ b/sample_nodes/crossdoor_nodes.cpp @@ -74,3 +74,11 @@ void CrossDoor::reset() _door_locked = true; _pick_attempts = 0; } + +// This function must be implemented in the .cpp file to create +// a plugin that can be loaded at run-time +BT_REGISTER_NODES(factory) +{ + static CrossDoor cross_door; + cross_door.registerNodes(factory); +} diff --git a/src/blackboard.cpp b/src/blackboard.cpp index 845a60277..0f1f304db 100644 --- a/src/blackboard.cpp +++ b/src/blackboard.cpp @@ -49,14 +49,7 @@ Blackboard::getEntry(const std::string& key) const // special syntax: "@" will always refer to the root BB if(StartWith(key, '@')) { - if(auto parent = parent_bb_.lock()) - { - return parent->getEntry(key); - } - else - { - return getEntry(key.substr(1, key.size() - 1)); - } + return rootBlackboard()->getEntry(key.substr(1, key.size() - 1)); } std::unique_lock lock(mutex_); @@ -150,14 +143,7 @@ void Blackboard::createEntry(const std::string& key, const TypeInfo& info) { if(StartWith(key, '@')) { - if(auto parent = parent_bb_.lock()) - { - parent->createEntry(key, info); - } - else - { - createEntryImpl(key.substr(1, key.size() - 1), info); - } + rootBlackboard()->createEntryImpl(key.substr(1, key.size() - 1), info); } else { @@ -318,4 +304,22 @@ Blackboard::Entry& Blackboard::Entry::operator=(const Entry& other) return *this; } +Blackboard* BT::Blackboard::rootBlackboard() +{ + auto bb = static_cast(*this).rootBlackboard(); + return const_cast(bb); +} + +const Blackboard* BT::Blackboard::rootBlackboard() const +{ + const Blackboard* bb = this; + Blackboard::Ptr prev = parent_bb_.lock(); + while(prev) + { + bb = prev.get(); + prev = bb->parent_bb_.lock(); + } + return bb; +} + } // namespace BT diff --git a/src/controls/fallback_node.cpp b/src/controls/fallback_node.cpp index 42c05d76d..1654e3f2a 100644 --- a/src/controls/fallback_node.cpp +++ b/src/controls/fallback_node.cpp @@ -15,11 +15,8 @@ namespace BT { -FallbackNode::FallbackNode(const std::string& name, bool make_aynch) - : ControlNode::ControlNode(name, {}) - , current_child_idx_(0) - , all_skipped_(true) - , asynch_(make_aynch) +FallbackNode::FallbackNode(const std::string& name, bool make_asynch) + : ControlNode::ControlNode(name, {}), current_child_idx_(0), asynch_(make_asynch) { if(asynch_) setRegistrationID("AsyncFallback"); @@ -33,7 +30,7 @@ NodeStatus FallbackNode::tick() if(status() == NodeStatus::IDLE) { - all_skipped_ = true; + skipped_count_ = 0; } setStatus(NodeStatus::RUNNING); @@ -45,9 +42,6 @@ NodeStatus FallbackNode::tick() auto prev_status = current_child_node->status(); const NodeStatus child_status = current_child_node->executeTick(); - // switch to RUNNING state as soon as you find an active child - all_skipped_ &= (child_status == NodeStatus::SKIPPED); - switch(child_status) { case NodeStatus::RUNNING: { @@ -73,6 +67,7 @@ NodeStatus FallbackNode::tick() case NodeStatus::SKIPPED: { // It was requested to skip this node current_child_idx_++; + skipped_count_++; } break; case NodeStatus::IDLE: { @@ -89,7 +84,7 @@ NodeStatus FallbackNode::tick() } // Skip if ALL the nodes have been skipped - return all_skipped_ ? NodeStatus::SKIPPED : NodeStatus::FAILURE; + return (skipped_count_ == children_count) ? NodeStatus::SKIPPED : NodeStatus::FAILURE; } void FallbackNode::halt() diff --git a/src/controls/sequence_node.cpp b/src/controls/sequence_node.cpp index ef3d05243..c1122c600 100644 --- a/src/controls/sequence_node.cpp +++ b/src/controls/sequence_node.cpp @@ -16,10 +16,7 @@ namespace BT { SequenceNode::SequenceNode(const std::string& name, bool make_async) - : ControlNode::ControlNode(name, {}) - , current_child_idx_(0) - , all_skipped_(true) - , asynch_(make_async) + : ControlNode::ControlNode(name, {}), current_child_idx_(0), asynch_(make_async) { if(asynch_) setRegistrationID("AsyncSequence"); @@ -49,7 +46,7 @@ NodeStatus SequenceNode::tick() if(status() == NodeStatus::IDLE) { - all_skipped_ = true; + skipped_count_ = 0; } setStatus(NodeStatus::RUNNING); @@ -59,9 +56,6 @@ NodeStatus SequenceNode::tick() auto prev_status = current_child_node->status(); const NodeStatus child_status = current_child_node->executeTick(); - // switch to RUNNING state as soon as you find an active child - all_skipped_ &= (child_status == NodeStatus::SKIPPED); - switch(child_status) { case NodeStatus::RUNNING: { @@ -89,6 +83,7 @@ NodeStatus SequenceNode::tick() case NodeStatus::SKIPPED: { // It was requested to skip this node current_child_idx_++; + skipped_count_++; } break; @@ -102,7 +97,7 @@ NodeStatus SequenceNode::tick() resetChildren(); current_child_idx_ = 0; // Skip if ALL the nodes have been skipped - return all_skipped_ ? NodeStatus::SKIPPED : NodeStatus::SUCCESS; + return (skipped_count_ == children_count) ? NodeStatus::SKIPPED : NodeStatus::SUCCESS; } } // namespace BT \ No newline at end of file diff --git a/src/controls/sequence_with_memory_node.cpp b/src/controls/sequence_with_memory_node.cpp index 91255fe9f..f47c798b6 100644 --- a/src/controls/sequence_with_memory_node.cpp +++ b/src/controls/sequence_with_memory_node.cpp @@ -27,7 +27,7 @@ NodeStatus SequenceWithMemory::tick() if(status() == NodeStatus::IDLE) { - all_skipped_ = true; + skipped_count_ = 0; } setStatus(NodeStatus::RUNNING); @@ -38,9 +38,6 @@ NodeStatus SequenceWithMemory::tick() auto prev_status = current_child_node->status(); const NodeStatus child_status = current_child_node->executeTick(); - // switch to RUNNING state as soon as you find an active child - all_skipped_ &= (child_status == NodeStatus::SKIPPED); - switch(child_status) { case NodeStatus::RUNNING: { @@ -71,6 +68,7 @@ NodeStatus SequenceWithMemory::tick() case NodeStatus::SKIPPED: { // It was requested to skip this node current_child_idx_++; + skipped_count_++; } break; @@ -87,7 +85,7 @@ NodeStatus SequenceWithMemory::tick() current_child_idx_ = 0; } // Skip if ALL the nodes have been skipped - return all_skipped_ ? NodeStatus::SKIPPED : NodeStatus::SUCCESS; + return (skipped_count_ == children_count) ? NodeStatus::SKIPPED : NodeStatus::SUCCESS; } void SequenceWithMemory::halt() diff --git a/src/decorators/repeat_node.cpp b/src/decorators/repeat_node.cpp index de15e90d3..d6b6f7c68 100644 --- a/src/decorators/repeat_node.cpp +++ b/src/decorators/repeat_node.cpp @@ -43,10 +43,6 @@ NodeStatus RepeatNode::tick() } bool do_loop = repeat_count_ < num_cycles_ || num_cycles_ == -1; - if(status() == NodeStatus::IDLE) - { - all_skipped_ = true; - } setStatus(NodeStatus::RUNNING); while(do_loop) @@ -54,9 +50,6 @@ NodeStatus RepeatNode::tick() NodeStatus const prev_status = child_node_->status(); NodeStatus child_status = child_node_->executeTick(); - // switch to RUNNING state as soon as you find an active child - all_skipped_ &= (child_status == NodeStatus::SKIPPED); - switch(child_status) { case NodeStatus::SUCCESS: { @@ -99,7 +92,7 @@ NodeStatus RepeatNode::tick() } repeat_count_ = 0; - return all_skipped_ ? NodeStatus::SKIPPED : NodeStatus::SUCCESS; + return NodeStatus::SUCCESS; } void RepeatNode::halt() diff --git a/src/decorators/retry_node.cpp b/src/decorators/retry_node.cpp index bf2819ddc..81b2bb6ec 100644 --- a/src/decorators/retry_node.cpp +++ b/src/decorators/retry_node.cpp @@ -50,11 +50,6 @@ NodeStatus RetryNode::tick() } bool do_loop = try_count_ < max_attempts_ || max_attempts_ == -1; - - if(status() == NodeStatus::IDLE) - { - all_skipped_ = true; - } setStatus(NodeStatus::RUNNING); while(do_loop) @@ -62,9 +57,6 @@ NodeStatus RetryNode::tick() NodeStatus prev_status = child_node_->status(); NodeStatus child_status = child_node_->executeTick(); - // switch to RUNNING state as soon as you find an active child - all_skipped_ &= (child_status == NodeStatus::SKIPPED); - switch(child_status) { case NodeStatus::SUCCESS: { @@ -107,7 +99,7 @@ NodeStatus RetryNode::tick() } try_count_ = 0; - return all_skipped_ ? NodeStatus::SKIPPED : NodeStatus::FAILURE; + return NodeStatus::FAILURE; } } // namespace BT diff --git a/src/loggers/bt_cout_logger.cpp b/src/loggers/bt_cout_logger.cpp index d896aa5a8..1361f0733 100644 --- a/src/loggers/bt_cout_logger.cpp +++ b/src/loggers/bt_cout_logger.cpp @@ -2,20 +2,11 @@ namespace BT { -std::atomic StdCoutLogger::ref_count(false); StdCoutLogger::StdCoutLogger(const BT::Tree& tree) : StatusChangeLogger(tree.rootNode()) -{ - bool expected = false; - if(!ref_count.compare_exchange_strong(expected, true)) - { - throw LogicError("Only one instance of StdCoutLogger shall be created"); - } -} +{} StdCoutLogger::~StdCoutLogger() -{ - ref_count.store(false); -} +{} void StdCoutLogger::callback(Duration timestamp, const TreeNode& node, NodeStatus prev_status, NodeStatus status) @@ -35,7 +26,6 @@ void StdCoutLogger::callback(Duration timestamp, const TreeNode& node, void StdCoutLogger::flush() { std::cout << std::flush; - ref_count = false; } } // namespace BT \ No newline at end of file diff --git a/src/loggers/bt_file_logger.cpp b/src/loggers/bt_file_logger.cpp deleted file mode 100644 index 324e926de..000000000 --- a/src/loggers/bt_file_logger.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "behaviortree_cpp/loggers/bt_file_logger.h" -#include "behaviortree_cpp/flatbuffers/bt_flatbuffer_helper.h" - -namespace BT -{ -FileLogger::FileLogger(const BT::Tree& tree, const char* filename, uint16_t buffer_size) - : StatusChangeLogger(tree.rootNode()), buffer_max_size_(buffer_size) -{ - if(buffer_max_size_ != 0) - { - buffer_.reserve(buffer_max_size_); - } - - enableTransitionToIdle(true); - - flatbuffers::FlatBufferBuilder builder(1024); - CreateFlatbuffersBehaviorTree(builder, tree); - - //------------------------------------- - - file_os_.open(filename, std::ofstream::binary | std::ofstream::out); - - // serialize the length of the buffer in the first 4 bytes - char size_buff[4]; - flatbuffers::WriteScalar(size_buff, static_cast(builder.GetSize())); - - file_os_.write(size_buff, 4); - file_os_.write(reinterpret_cast(builder.GetBufferPointer()), - builder.GetSize()); -} - -FileLogger::~FileLogger() -{ - this->flush(); - file_os_.close(); -} - -void FileLogger::callback(Duration timestamp, const TreeNode& node, - NodeStatus prev_status, NodeStatus status) -{ - SerializedTransition buffer = - SerializeTransition(node.UID(), timestamp, prev_status, status); - - if(buffer_max_size_ == 0) - { - file_os_.write(reinterpret_cast(buffer.data()), buffer.size()); - } - else - { - buffer_.push_back(buffer); - if(buffer_.size() >= buffer_max_size_) - { - this->flush(); - } - } -} - -void FileLogger::flush() -{ - for(const auto& array : buffer_) - { - file_os_.write(reinterpret_cast(array.data()), array.size()); - } - file_os_.flush(); - buffer_.clear(); -} -} // namespace BT diff --git a/src/loggers/bt_file_logger_v2.cpp b/src/loggers/bt_file_logger_v2.cpp index 54e4902f2..40d39381d 100644 --- a/src/loggers/bt_file_logger_v2.cpp +++ b/src/loggers/bt_file_logger_v2.cpp @@ -1,6 +1,6 @@ #include "behaviortree_cpp/loggers/bt_file_logger_v2.h" -#include "behaviortree_cpp/flatbuffers/base.h" #include "behaviortree_cpp/xml_parsing.h" +#include "flatbuffers/base.h" namespace BT { diff --git a/src/loggers/bt_minitrace_logger.cpp b/src/loggers/bt_minitrace_logger.cpp index 6b0bf7118..69d6d0b16 100644 --- a/src/loggers/bt_minitrace_logger.cpp +++ b/src/loggers/bt_minitrace_logger.cpp @@ -6,17 +6,10 @@ namespace BT { -std::atomic MinitraceLogger::ref_count(false); MinitraceLogger::MinitraceLogger(const Tree& tree, const char* filename_json) : StatusChangeLogger(tree.rootNode()) { - bool expected = false; - if(!ref_count.compare_exchange_strong(expected, true)) - { - throw LogicError("Only one instance of MinitraceLogger shall be created"); - } - mtr_register_sigint_handler(); mtr_init(filename_json); this->enableTransitionToIdle(true); @@ -26,7 +19,6 @@ MinitraceLogger::~MinitraceLogger() { mtr_flush(); mtr_shutdown(); - ref_count = false; } const char* toConstStr(NodeType type) @@ -68,6 +60,7 @@ void MinitraceLogger::callback(Duration /*timestamp*/, const TreeNode& node, { MTR_END(category, name); } + mtr_flush(); } void MinitraceLogger::flush() diff --git a/src/tree_node.cpp b/src/tree_node.cpp index ca22d7956..810a623e6 100644 --- a/src/tree_node.cpp +++ b/src/tree_node.cpp @@ -38,9 +38,9 @@ struct TreeNode::PImpl std::string registration_ID; - PreTickCallback substitution_callback; - - PostTickCallback post_condition_callback; + PreTickCallback pre_tick_callback; + PostTickCallback post_tick_callback; + TickMonitorCallback tick_monitor_callback; std::mutex callback_injection_mutex; @@ -71,6 +71,15 @@ TreeNode::~TreeNode() NodeStatus TreeNode::executeTick() { auto new_status = _p->status; + PreTickCallback pre_tick; + PostTickCallback post_tick; + TickMonitorCallback monitor_tick; + { + std::scoped_lock lk(_p->callback_injection_mutex); + pre_tick = _p->pre_tick_callback; + post_tick = _p->post_tick_callback; + monitor_tick = _p->tick_monitor_callback; + } // a pre-condition may return the new status. // In this case it override the actual tick() @@ -82,28 +91,33 @@ NodeStatus TreeNode::executeTick() { // injected pre-callback bool substituted = false; - if(!isStatusCompleted(_p->status)) + if(pre_tick && !isStatusCompleted(_p->status)) { - PreTickCallback callback; - { - std::unique_lock lk(_p->callback_injection_mutex); - callback = _p->substitution_callback; - } - if(callback) + auto override_status = pre_tick(*this); + if(isStatusCompleted(override_status)) { - auto override_status = callback(*this); - if(isStatusCompleted(override_status)) - { - // don't execute the actual tick() - substituted = true; - new_status = override_status; - } + // don't execute the actual tick() + substituted = true; + new_status = override_status; } } // Call the ACTUAL tick if(!substituted) { + using namespace std::chrono; + + auto t1 = steady_clock::now(); + // trick to prevent the compile from reordering the order of execution. See #861 + // This makes sure that the code is executed at the end of this scope + std::shared_ptr execute_later(nullptr, [&](...) { + auto t2 = steady_clock::now(); + if(monitor_tick) + { + monitor_tick(*this, new_status, duration_cast(t2 - t1)); + } + }); + new_status = tick(); } } @@ -112,18 +126,14 @@ NodeStatus TreeNode::executeTick() if(isStatusCompleted(new_status)) { checkPostConditions(new_status); - PostTickCallback callback; - { - std::unique_lock lk(_p->callback_injection_mutex); - callback = _p->post_condition_callback; - } - if(callback) + } + + if(post_tick) + { + auto override_status = post_tick(*this, new_status); + if(isStatusCompleted(override_status)) { - auto override_status = callback(*this, new_status); - if(isStatusCompleted(override_status)) - { - new_status = override_status; - } + new_status = override_status; } } @@ -315,13 +325,19 @@ TreeNode::subscribeToStatusChange(TreeNode::StatusChangeCallback callback) void TreeNode::setPreTickFunction(PreTickCallback callback) { std::unique_lock lk(_p->callback_injection_mutex); - _p->substitution_callback = callback; + _p->pre_tick_callback = callback; } void TreeNode::setPostTickFunction(PostTickCallback callback) { std::unique_lock lk(_p->callback_injection_mutex); - _p->post_condition_callback = callback; + _p->post_tick_callback = callback; +} + +void TreeNode::setTickMonitorCallback(TickMonitorCallback callback) +{ + std::unique_lock lk(_p->callback_injection_mutex); + _p->tick_monitor_callback = callback; } uint16_t TreeNode::UID() const diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 47cffe589..1e9c2b2e7 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -19,6 +19,12 @@ #include #include +#if defined(_MSVC_LANG) && !defined(__clang__) +#define __bt_cplusplus (_MSC_VER == 1900 ? 201103L : _MSVC_LANG) +#else +#define __bt_cplusplus __cplusplus +#endif + #if defined(__linux) || defined(__linux__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wattributes" @@ -254,7 +260,12 @@ void XMLParser::PImpl::loadDocImpl(XMLDocument* doc, bool add_includes) break; } - std::filesystem::path file_path(incl_node->Attribute("path")); +#if __bt_cplusplus >= 202002L + auto file_path(std::filesystem::path(incl_node->Attribute("path"))); +#else + auto file_path(std::filesystem::u8path(incl_node->Attribute("path"))); +#endif + const char* ros_pkg_relative_path = incl_node->Attribute("ros_pkg"); if(ros_pkg_relative_path) @@ -402,107 +413,107 @@ void VerifyXML(const std::string& xml_text, } //------------------------------------------------- + int behavior_tree_count = 0; + for(auto child = xml_root->FirstChildElement(); child != nullptr; + child = child->NextSiblingElement()) + { + behavior_tree_count++; + } + // function to be called recursively std::function recursiveStep; recursiveStep = [&](const XMLElement* node) { const int children_count = ChildrenCount(node); const std::string name = node->Name(); + const std::string ID = node->Attribute("ID") ? node->Attribute("ID") : ""; + const int line_number = node->GetLineNum(); + if(name == "Decorator") { if(children_count != 1) { - ThrowError(node->GetLineNum(), "The node must have exactly 1 " - "child"); + ThrowError(line_number, "The tag must have exactly 1 " + "child"); } - if(!node->Attribute("ID")) + if(ID.empty()) { - ThrowError(node->GetLineNum(), "The node must have the " - "attribute [ID]"); + ThrowError(line_number, "The tag must have the " + "attribute [ID]"); } } else if(name == "Action") { if(children_count != 0) { - ThrowError(node->GetLineNum(), "The node must not have any " - "child"); + ThrowError(line_number, "The tag must not have any " + "child"); } - if(!node->Attribute("ID")) + if(ID.empty()) { - ThrowError(node->GetLineNum(), "The node must have the " - "attribute [ID]"); + ThrowError(line_number, "The tag must have the " + "attribute [ID]"); } } else if(name == "Condition") { if(children_count != 0) { - ThrowError(node->GetLineNum(), "The node must not have any " - "child"); + ThrowError(line_number, "The tag must not have any " + "child"); } - if(!node->Attribute("ID")) + if(ID.empty()) { - ThrowError(node->GetLineNum(), "The node must have the " - "attribute [ID]"); + ThrowError(line_number, "The tag must have the " + "attribute [ID]"); } } else if(name == "Control") { if(children_count == 0) { - ThrowError(node->GetLineNum(), "The node must have at least 1 " - "child"); + ThrowError(line_number, "The tag must have at least 1 " + "child"); } - if(!node->Attribute("ID")) + if(ID.empty()) { - ThrowError(node->GetLineNum(), "The node must have the " - "attribute [ID]"); + ThrowError(line_number, "The tag must have the " + "attribute [ID]"); } } - else if(name == "Sequence" || name == "ReactiveSequence" || - name == "SequenceWithMemory" || name == "Fallback") + else if(name == "SubTree") { - if(children_count == 0) + if(children_count != 0) { - std::string name_attr; - if(node->Attribute("name")) - { - name_attr = "(`" + std::string(node->Attribute("name")) + "`)"; - } - ThrowError(node->GetLineNum(), std::string("A Control node must have at least 1 " - "child, error in XML node `") + - node->Name() + name_attr + "`"); + ThrowError(line_number, " should not have any child"); } - } - else if(name == "SubTree") - { - auto child = node->FirstChildElement(); - - if(child) + if(ID.empty()) { - if(StrEqual(child->Name(), "remap")) - { - ThrowError(node->GetLineNum(), " was deprecated"); - } - else - { - ThrowError(node->GetLineNum(), " should not have any child"); - } + ThrowError(line_number, "The tag must have the " + "attribute [ID]"); } - - if(!node->Attribute("ID")) + if(registered_nodes.count(ID) != 0) { - ThrowError(node->GetLineNum(), "The node must have the " - "attribute [ID]"); + ThrowError(line_number, "The attribute [ID] of tag must " + "not use the name of a registered Node"); } } else if(name == "BehaviorTree") { + if(ID.empty() && behavior_tree_count > 1) + { + ThrowError(line_number, "The tag must have the " + "attribute [ID]"); + } if(children_count != 1) { - ThrowError(node->GetLineNum(), "The node must have exactly 1 " - "child"); + ThrowError(line_number, "The tag must have exactly 1 " + "child"); + } + if(registered_nodes.count(ID) != 0) + { + ThrowError(line_number, "The attribute [ID] of tag " + "must not use the name of a registered Node"); } } else @@ -512,26 +523,31 @@ void VerifyXML(const std::string& xml_text, bool found = (search != registered_nodes.end()); if(!found) { - ThrowError(node->GetLineNum(), std::string("Node not recognized: ") + name); + ThrowError(line_number, std::string("Node not recognized: ") + name); } if(search->second == NodeType::DECORATOR) { if(children_count != 1) { - ThrowError(node->GetLineNum(), + ThrowError(line_number, std::string("The node <") + name + "> must have exactly 1 child"); } } + else if(search->second == NodeType::CONTROL) + { + if(children_count == 0) + { + ThrowError(line_number, + std::string("The node <") + name + "> must have 1 or more children"); + } + } } //recursion - if(name != "SubTree") + for(auto child = node->FirstChildElement(); child != nullptr; + child = child->NextSiblingElement()) { - for(auto child = node->FirstChildElement(); child != nullptr; - child = child->NextSiblingElement()) - { - recursiveStep(child); - } + recursiveStep(child); } }; @@ -654,8 +670,10 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element, if(port_model_it == manifest->ports.end()) { throw RuntimeError(StrCat("a port with name [", port_name, - "] is found in the XML, but not in the " - "providedPorts()")); + "] is found in the XML (<", element->Name(), + ">, line ", std::to_string(att->GetLineNum()), + ") but not in the providedPorts() of its " + "registered node type.")); } else { diff --git a/tests/gtest_blackboard.cpp b/tests/gtest_blackboard.cpp index c6caaa464..fcbc272a3 100644 --- a/tests/gtest_blackboard.cpp +++ b/tests/gtest_blackboard.cpp @@ -583,11 +583,18 @@ TEST(BlackboardTest, RootBlackboard) + + + +