From 5068d34c08f951a7ea6257d305a1627b09a95817 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 19:44:55 +0200 Subject: Adding upstream version 0.11.1. Signed-off-by: Daniel Baumann --- src/third-party/scnlib/include/scn/all.h | 26 + src/third-party/scnlib/include/scn/detail/args.h | 619 ++++ src/third-party/scnlib/include/scn/detail/config.h | 466 +++ .../scnlib/include/scn/detail/context.h | 126 + src/third-party/scnlib/include/scn/detail/error.h | 136 + src/third-party/scnlib/include/scn/detail/file.h | 568 ++++ src/third-party/scnlib/include/scn/detail/fwd.h | 204 ++ src/third-party/scnlib/include/scn/detail/locale.h | 595 ++++ .../scnlib/include/scn/detail/parse_context.h | 581 ++++ src/third-party/scnlib/include/scn/detail/range.h | 598 ++++ src/third-party/scnlib/include/scn/detail/result.h | 595 ++++ .../scnlib/include/scn/detail/vectored.h | 166 ++ .../scnlib/include/scn/detail/visitor.h | 248 ++ src/third-party/scnlib/include/scn/fwd.h | 23 + src/third-party/scnlib/include/scn/istream.h | 23 + .../scnlib/include/scn/ranges/custom_impl.h | 1632 +++++++++++ src/third-party/scnlib/include/scn/ranges/ranges.h | 49 + .../scnlib/include/scn/ranges/std_impl.h | 67 + src/third-party/scnlib/include/scn/ranges/util.h | 419 +++ src/third-party/scnlib/include/scn/reader/common.h | 1663 +++++++++++ src/third-party/scnlib/include/scn/reader/float.h | 246 ++ src/third-party/scnlib/include/scn/reader/int.h | 537 ++++ src/third-party/scnlib/include/scn/reader/reader.h | 111 + src/third-party/scnlib/include/scn/reader/string.h | 1336 +++++++++ src/third-party/scnlib/include/scn/reader/types.h | 220 ++ src/third-party/scnlib/include/scn/scan/common.h | 131 + src/third-party/scnlib/include/scn/scan/getline.h | 186 ++ src/third-party/scnlib/include/scn/scan/ignore.h | 189 ++ src/third-party/scnlib/include/scn/scan/istream.h | 147 + src/third-party/scnlib/include/scn/scan/list.h | 450 +++ src/third-party/scnlib/include/scn/scan/scan.h | 444 +++ src/third-party/scnlib/include/scn/scan/vscan.h | 208 ++ src/third-party/scnlib/include/scn/scn.h | 26 + src/third-party/scnlib/include/scn/tuple_return.h | 23 + .../scnlib/include/scn/tuple_return/tuple_return.h | 123 + .../scnlib/include/scn/tuple_return/util.h | 176 ++ .../scnlib/include/scn/unicode/common.h | 139 + .../scnlib/include/scn/unicode/unicode.h | 243 ++ src/third-party/scnlib/include/scn/unicode/utf16.h | 139 + src/third-party/scnlib/include/scn/unicode/utf8.h | 297 ++ .../scnlib/include/scn/util/algorithm.h | 80 + src/third-party/scnlib/include/scn/util/array.h | 105 + src/third-party/scnlib/include/scn/util/expected.h | 158 ++ src/third-party/scnlib/include/scn/util/math.h | 121 + src/third-party/scnlib/include/scn/util/memory.h | 404 +++ src/third-party/scnlib/include/scn/util/meta.h | 77 + src/third-party/scnlib/include/scn/util/optional.h | 105 + .../scnlib/include/scn/util/small_vector.h | 788 ++++++ src/third-party/scnlib/include/scn/util/span.h | 240 ++ .../scnlib/include/scn/util/string_view.h | 270 ++ .../scnlib/include/scn/util/unique_ptr.h | 118 + src/third-party/scnlib/licenses/README.md | 25 + .../scnlib/licenses/fast_float-apache.txt | 190 ++ src/third-party/scnlib/licenses/fast_float-mit.txt | 27 + src/third-party/scnlib/licenses/fmt.rst | 27 + src/third-party/scnlib/licenses/nanorange.txt | 23 + src/third-party/scnlib/licenses/utfcpp.txt | 23 + src/third-party/scnlib/src/Makefile.am | 65 + .../single_include/fast_float/fast_float.h | 2981 ++++++++++++++++++++ src/third-party/scnlib/src/file.cpp | 311 ++ src/third-party/scnlib/src/locale.cpp | 668 +++++ src/third-party/scnlib/src/reader_float.cpp | 433 +++ src/third-party/scnlib/src/reader_int.cpp | 372 +++ src/third-party/scnlib/src/vscan.cpp | 80 + 64 files changed, 21866 insertions(+) create mode 100644 src/third-party/scnlib/include/scn/all.h create mode 100644 src/third-party/scnlib/include/scn/detail/args.h create mode 100644 src/third-party/scnlib/include/scn/detail/config.h create mode 100644 src/third-party/scnlib/include/scn/detail/context.h create mode 100644 src/third-party/scnlib/include/scn/detail/error.h create mode 100644 src/third-party/scnlib/include/scn/detail/file.h create mode 100644 src/third-party/scnlib/include/scn/detail/fwd.h create mode 100644 src/third-party/scnlib/include/scn/detail/locale.h create mode 100644 src/third-party/scnlib/include/scn/detail/parse_context.h create mode 100644 src/third-party/scnlib/include/scn/detail/range.h create mode 100644 src/third-party/scnlib/include/scn/detail/result.h create mode 100644 src/third-party/scnlib/include/scn/detail/vectored.h create mode 100644 src/third-party/scnlib/include/scn/detail/visitor.h create mode 100644 src/third-party/scnlib/include/scn/fwd.h create mode 100644 src/third-party/scnlib/include/scn/istream.h create mode 100644 src/third-party/scnlib/include/scn/ranges/custom_impl.h create mode 100644 src/third-party/scnlib/include/scn/ranges/ranges.h create mode 100644 src/third-party/scnlib/include/scn/ranges/std_impl.h create mode 100644 src/third-party/scnlib/include/scn/ranges/util.h create mode 100644 src/third-party/scnlib/include/scn/reader/common.h create mode 100644 src/third-party/scnlib/include/scn/reader/float.h create mode 100644 src/third-party/scnlib/include/scn/reader/int.h create mode 100644 src/third-party/scnlib/include/scn/reader/reader.h create mode 100644 src/third-party/scnlib/include/scn/reader/string.h create mode 100644 src/third-party/scnlib/include/scn/reader/types.h create mode 100644 src/third-party/scnlib/include/scn/scan/common.h create mode 100644 src/third-party/scnlib/include/scn/scan/getline.h create mode 100644 src/third-party/scnlib/include/scn/scan/ignore.h create mode 100644 src/third-party/scnlib/include/scn/scan/istream.h create mode 100644 src/third-party/scnlib/include/scn/scan/list.h create mode 100644 src/third-party/scnlib/include/scn/scan/scan.h create mode 100644 src/third-party/scnlib/include/scn/scan/vscan.h create mode 100644 src/third-party/scnlib/include/scn/scn.h create mode 100644 src/third-party/scnlib/include/scn/tuple_return.h create mode 100644 src/third-party/scnlib/include/scn/tuple_return/tuple_return.h create mode 100644 src/third-party/scnlib/include/scn/tuple_return/util.h create mode 100644 src/third-party/scnlib/include/scn/unicode/common.h create mode 100644 src/third-party/scnlib/include/scn/unicode/unicode.h create mode 100644 src/third-party/scnlib/include/scn/unicode/utf16.h create mode 100644 src/third-party/scnlib/include/scn/unicode/utf8.h create mode 100644 src/third-party/scnlib/include/scn/util/algorithm.h create mode 100644 src/third-party/scnlib/include/scn/util/array.h create mode 100644 src/third-party/scnlib/include/scn/util/expected.h create mode 100644 src/third-party/scnlib/include/scn/util/math.h create mode 100644 src/third-party/scnlib/include/scn/util/memory.h create mode 100644 src/third-party/scnlib/include/scn/util/meta.h create mode 100644 src/third-party/scnlib/include/scn/util/optional.h create mode 100644 src/third-party/scnlib/include/scn/util/small_vector.h create mode 100644 src/third-party/scnlib/include/scn/util/span.h create mode 100644 src/third-party/scnlib/include/scn/util/string_view.h create mode 100644 src/third-party/scnlib/include/scn/util/unique_ptr.h create mode 100644 src/third-party/scnlib/licenses/README.md create mode 100644 src/third-party/scnlib/licenses/fast_float-apache.txt create mode 100644 src/third-party/scnlib/licenses/fast_float-mit.txt create mode 100644 src/third-party/scnlib/licenses/fmt.rst create mode 100644 src/third-party/scnlib/licenses/nanorange.txt create mode 100644 src/third-party/scnlib/licenses/utfcpp.txt create mode 100644 src/third-party/scnlib/src/Makefile.am create mode 100644 src/third-party/scnlib/src/deps/fast_float/single_include/fast_float/fast_float.h create mode 100644 src/third-party/scnlib/src/file.cpp create mode 100644 src/third-party/scnlib/src/locale.cpp create mode 100644 src/third-party/scnlib/src/reader_float.cpp create mode 100644 src/third-party/scnlib/src/reader_int.cpp create mode 100644 src/third-party/scnlib/src/vscan.cpp (limited to 'src/third-party/scnlib') diff --git a/src/third-party/scnlib/include/scn/all.h b/src/third-party/scnlib/include/scn/all.h new file mode 100644 index 0000000..b69e822 --- /dev/null +++ b/src/third-party/scnlib/include/scn/all.h @@ -0,0 +1,26 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_ALL_H +#define SCN_ALL_H + +#include "scn.h" + +#include "istream.h" +#include "tuple_return.h" + +#endif // SCN_ALL_H diff --git a/src/third-party/scnlib/include/scn/detail/args.h b/src/third-party/scnlib/include/scn/detail/args.h new file mode 100644 index 0000000..dd67852 --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/args.h @@ -0,0 +1,619 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_ARGS_H +#define SCN_DETAIL_ARGS_H + +#include "../reader/common.h" +#include "../util/array.h" + +SCN_GCC_PUSH +SCN_GCC_IGNORE("-Wnoexcept") +#include +SCN_GCC_POP + +namespace scn { + SCN_BEGIN_NAMESPACE + + /** + * Allows reading an rvalue. + * Stores an rvalue and returns an lvalue reference to it via `operator()`. + * Create one with \ref temp. + */ + template + struct temporary { + temporary(T&& val) : value(SCN_MOVE(val)) {} + + T& operator()() && noexcept + { + return value; + } + + T value; + }; + /** + * Factory function for \ref temporary. + * + * Canonical use case is with \ref scn::span: + * \code{.cpp} + * std::vector buffer(32, '\0'); + * auto result = scn::scan("123", "{}", scn::temp(scn::make_span(buffer))); + * // buffer == "123" + * \endcode + */ + template ::value>::type* = nullptr> + temporary temp(T&& val) + { + return {SCN_FWD(val)}; + } + + namespace detail { + enum type { + none_type = 0, + // signed integer + schar_type, + short_type, + int_type, + long_type, + long_long_type, + // unsigned integer + uchar_type, + ushort_type, + uint_type, + ulong_type, + ulong_long_type, + // other integral types + bool_type, + char_type, + code_point_type, + last_integer_type = code_point_type, + // floats + float_type, + double_type, + long_double_type, + last_numeric_type = long_double_type, + // other + buffer_type, + string_type, + string_view_type, + + custom_type, + last_type = custom_type + }; + + constexpr bool is_integral(type t) noexcept + { + return t > none_type && t <= last_integer_type; + } + constexpr bool is_arithmetic(type t) noexcept + { + return t > none_type && t <= last_numeric_type; + } + + struct custom_value { + // using scan_type = error (*)(void*, Context&, ParseCtx&); + + void* value; + void (*scan)(); + }; + + template + error scan_custom_arg(void* arg, Context& ctx, ParseCtx& pctx) noexcept + { + return visitor_boilerplate>(*static_cast(arg), ctx, + pctx); + } + + struct monostate { + }; + + template + struct ctx_tag { + }; + template + struct parse_ctx_tag { + }; + + class value { + public: + constexpr value() noexcept : m_empty{} {} + + template + explicit SCN_CONSTEXPR14 value(T& val) noexcept + : m_value(std::addressof(val)) + { + } + + template + value(ctx_tag, parse_ctx_tag, T& val) noexcept + : m_custom( + custom_value{std::addressof(val), + reinterpret_cast( + &scan_custom_arg)}) + { + } + + template + SCN_CONSTEXPR14 T& get_as() noexcept + { + return *static_cast(m_value); + } + template + constexpr const T& get_as() const noexcept + { + return *static_cast(m_value); + } + + SCN_CONSTEXPR14 custom_value& get_custom() noexcept + { + return m_custom; + } + SCN_NODISCARD constexpr const custom_value& get_custom() + const noexcept + { + return m_custom; + } + + private: + union { + monostate m_empty; + void* m_value; + custom_value m_custom; + }; + }; + + template + struct init { + T* val; + static const type type_tag = Type; + + constexpr init(T& v) : val(std::addressof(v)) {} + template + SCN_CONSTEXPR14 value get() + { + SCN_EXPECT(val != nullptr); + return value{*val}; + } + }; + template + struct init { + T* val; + static const type type_tag = custom_type; + + constexpr init(T& v) : val(std::addressof(v)) {} + template + SCN_CONSTEXPR14 value get() + { + SCN_EXPECT(val != nullptr); + return {ctx_tag{}, parse_ctx_tag{}, *val}; + } + }; + + template + SCN_CONSTEXPR14 basic_arg make_arg(T& value) noexcept; + +#define SCN_MAKE_VALUE(Tag, Type) \ + template \ + constexpr init make_value(Type& val, \ + priority_tag<1>) noexcept \ + { \ + return val; \ + } + + SCN_MAKE_VALUE(schar_type, signed char) + SCN_MAKE_VALUE(short_type, short) + SCN_MAKE_VALUE(int_type, int) + SCN_MAKE_VALUE(long_type, long) + SCN_MAKE_VALUE(long_long_type, long long) + + SCN_MAKE_VALUE(uchar_type, unsigned char) + SCN_MAKE_VALUE(ushort_type, unsigned short) + SCN_MAKE_VALUE(uint_type, unsigned) + SCN_MAKE_VALUE(ulong_type, unsigned long) + SCN_MAKE_VALUE(ulong_long_type, unsigned long long) + + SCN_MAKE_VALUE(bool_type, bool) + SCN_MAKE_VALUE(code_point_type, code_point) + + SCN_MAKE_VALUE(float_type, float) + SCN_MAKE_VALUE(double_type, double) + SCN_MAKE_VALUE(long_double_type, long double) + + SCN_MAKE_VALUE(buffer_type, span) + SCN_MAKE_VALUE(string_type, std::basic_string) + SCN_MAKE_VALUE(string_view_type, basic_string_view) + + template + constexpr init make_value( + CharT& val, + priority_tag<1>) noexcept + { + return val; + } + + template + constexpr inline auto make_value(T& val, priority_tag<0>) noexcept + -> init + { + return val; + } + + enum : size_t { + packed_arg_bitsize = 5, + packed_arg_mask = (1 << packed_arg_bitsize) - 1, + max_packed_args = (sizeof(size_t) * 8 - 1) / packed_arg_bitsize, + is_unpacked_bit = size_t{1} << (sizeof(size_t) * 8ull - 1ull) + }; + } // namespace detail + + SCN_CLANG_PUSH + SCN_CLANG_IGNORE("-Wpadded") + + /// Type-erased scanning argument. + template + class SCN_TRIVIAL_ABI basic_arg { + public: + using char_type = CharT; + + class handle { + public: + explicit handle(detail::custom_value custom) : m_custom(custom) {} + + template + error scan(Context& ctx, ParseCtx& pctx) + { + return reinterpret_cast( + m_custom.scan)(m_custom.value, ctx, pctx); + } + + private: + detail::custom_value m_custom; + }; + + constexpr basic_arg() = default; + + constexpr explicit operator bool() const noexcept + { + return m_type != detail::none_type; + } + + SCN_NODISCARD constexpr detail::type type() const noexcept + { + return type; + } + SCN_NODISCARD constexpr bool is_integral() const noexcept + { + return detail::is_integral(m_type); + } + SCN_NODISCARD constexpr bool is_arithmetic() const noexcept + { + return detail::is_arithmetic(m_type); + } + + private: + constexpr basic_arg(detail::value v, detail::type t) noexcept + : m_value(v), m_type(t) + { + } + + template + friend SCN_CONSTEXPR14 basic_arg detail::make_arg(T& value) noexcept; + + template + friend SCN_CONSTEXPR14 error visit_arg(Visitor&& vis, + basic_arg& arg); + + friend class basic_args; + + detail::value m_value; + detail::type m_type{detail::none_type}; + }; + + SCN_CLANG_POP + + template + SCN_CONSTEXPR14 error visit_arg(Visitor&& vis, basic_arg& arg) + { + switch (arg.m_type) { + case detail::none_type: + break; + + case detail::schar_type: + return vis(arg.m_value.template get_as()); + case detail::short_type: + return vis(arg.m_value.template get_as()); + case detail::int_type: + return vis(arg.m_value.template get_as()); + case detail::long_type: + return vis(arg.m_value.template get_as()); + case detail::long_long_type: + return vis(arg.m_value.template get_as()); + + case detail::uchar_type: + return vis(arg.m_value.template get_as()); + case detail::ushort_type: + return vis(arg.m_value.template get_as()); + case detail::uint_type: + return vis(arg.m_value.template get_as()); + case detail::ulong_type: + return vis(arg.m_value.template get_as()); + case detail::ulong_long_type: + return vis(arg.m_value.template get_as()); + + case detail::bool_type: + return vis(arg.m_value.template get_as()); + case detail::char_type: + return vis(arg.m_value.template get_as()); + case detail::code_point_type: + return vis(arg.m_value.template get_as()); + + case detail::float_type: + return vis(arg.m_value.template get_as()); + case detail::double_type: + return vis(arg.m_value.template get_as()); + case detail::long_double_type: + return vis(arg.m_value.template get_as()); + + case detail::buffer_type: + return vis(arg.m_value.template get_as>()); + case detail::string_type: + return vis( + arg.m_value.template get_as>()); + case detail::string_view_type: + return vis( + arg.m_value.template get_as>()); + + case detail::custom_type: + return vis(typename basic_arg::handle( + arg.m_value.get_custom())); + + SCN_CLANG_PUSH + SCN_CLANG_IGNORE("-Wcovered-switch-default") + default: + return vis(detail::monostate{}); + SCN_CLANG_POP + } + SCN_UNREACHABLE; + } + + namespace detail { + template + struct get_type { + using value_type = decltype(make_value( + SCN_DECLVAL(typename std::remove_reference< + typename std::remove_cv::type>::type&), + SCN_DECLVAL(priority_tag<1>))); + static const type value = value_type::type_tag; + }; + + template + constexpr size_t get_types() + { + return 0; + } + template + constexpr size_t get_types() + { + return static_cast(get_type::value) | + (get_types() << 5); + } + + template + SCN_CONSTEXPR14 basic_arg make_arg(T& value) noexcept + { + basic_arg arg; + arg.m_type = get_type::value; + arg.m_value = make_value(value, priority_tag<1>{}) + .template get(); + return arg; + } + + template + inline auto make_arg(T& v) -> + typename std::enable_if::type + { + return make_value(v, priority_tag<1>{}) + .template get(); + } + template + inline auto make_arg(T& v) -> typename std:: + enable_if>::type + { + return make_arg(v); + } + } // namespace detail + + template + class arg_store { + static constexpr const size_t num_args = sizeof...(Args); + static const bool is_packed = num_args < detail::max_packed_args; + + friend class basic_args; + + static constexpr size_t get_types() + { + return is_packed ? detail::get_types() + : detail::is_unpacked_bit | num_args; + } + + public: + static constexpr size_t types = get_types(); + using arg_type = basic_arg; + + using value_type = + typename std::conditional::type; + static constexpr size_t data_size = + num_args + (is_packed && num_args != 0 ? 0 : 1); + + template + SCN_CONSTEXPR14 arg_store(detail::ctx_tag, + detail::parse_ctx_tag, + Args&... a) noexcept + : m_data{{detail::make_arg(a)...}} + { + } + + SCN_CONSTEXPR14 span data() noexcept + { + return make_span(m_data.data(), + static_cast(m_data.size())); + } + + private: + detail::array m_data; + }; + + template + arg_store make_args(Args&... args) + { + return {detail::ctx_tag(), detail::parse_ctx_tag(), + args...}; + } + template + arg_store make_args_for(WrappedRange&, + Format, + Args&... args) + { + using context_type = basic_context; + using parse_context_type = + typename detail::parse_context_template_for_format< + Format>::template type; + return {detail::ctx_tag(), + detail::parse_ctx_tag(), args...}; + } + + template + class basic_args { + public: + using arg_type = basic_arg; + + constexpr basic_args() noexcept = default; + + template + SCN_CONSTEXPR14 basic_args(arg_store& store) noexcept + : m_types(store.types) + { + set_data(store.m_data.data()); + } + + SCN_CONSTEXPR14 basic_args(span args) noexcept + : m_types(detail::is_unpacked_bit | args.size()) + { + set_data(args.data()); + } + + SCN_CONSTEXPR14 arg_type get(std::ptrdiff_t i) const noexcept + { + return do_get(i); + } + + SCN_NODISCARD SCN_CONSTEXPR14 bool check_id( + std::ptrdiff_t i) const noexcept + { + if (!is_packed()) { + return static_cast(i) < + (m_types & + ~static_cast(detail::is_unpacked_bit)); + } + return type(i) != detail::none_type; + } + + SCN_NODISCARD constexpr size_t max_size() const noexcept + { + return is_packed() + ? static_cast(detail::max_packed_args) + : m_types & + ~static_cast(detail::is_unpacked_bit); + } + + private: + size_t m_types{0}; + union { + detail::value* m_values; + arg_type* m_args; + }; + + SCN_NODISCARD constexpr bool is_packed() const noexcept + { + return (m_types & detail::is_unpacked_bit) == 0; + } + + SCN_NODISCARD SCN_CONSTEXPR14 typename detail::type type( + std::ptrdiff_t i) const noexcept + { + size_t shift = static_cast(i) * detail::packed_arg_bitsize; + return static_cast( + (static_cast(m_types) >> shift) & + detail::packed_arg_mask); + } + + SCN_CONSTEXPR14 void set_data(detail::value* values) noexcept + { + m_values = values; + } + SCN_CONSTEXPR14 void set_data(arg_type* args) noexcept + { + m_args = args; + } + + SCN_CONSTEXPR14 arg_type do_get(std::ptrdiff_t i) const noexcept + { + SCN_EXPECT(i >= 0); + + arg_type arg; + if (!is_packed()) { + auto num_args = static_cast(max_size()); + if (SCN_LIKELY(i < num_args)) { + arg = m_args[i]; + } + return arg; + } + + SCN_EXPECT(m_values); + if (SCN_UNLIKELY( + i > static_cast(detail::max_packed_args))) { + return arg; + } + + arg.m_type = type(i); + if (arg.m_type == detail::none_type) { + return arg; + } + arg.m_value = m_values[i]; + return arg; + } + }; + + SCN_END_NAMESPACE +} // namespace scn + +#endif // SCN_DETAIL_ARGS_H diff --git a/src/third-party/scnlib/include/scn/detail/config.h b/src/third-party/scnlib/include/scn/detail/config.h new file mode 100644 index 0000000..81d054c --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/config.h @@ -0,0 +1,466 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_CONFIG_H +#define SCN_DETAIL_CONFIG_H + +#include + +#define SCN_STD_11 201103L +#define SCN_STD_14 201402L +#define SCN_STD_17 201703L + +#define SCN_COMPILER(major, minor, patch) \ + ((major)*10000000 /* 10,000,000 */ + (minor)*10000 /* 10,000 */ + (patch)) +#define SCN_VERSION SCN_COMPILER(1, 1, 2) + +#ifdef __INTEL_COMPILER +// Intel +#define SCN_INTEL \ + SCN_COMPILER(__INTEL_COMPILER / 100, (__INTEL_COMPILER / 10) % 10, \ + __INTEL_COMPILER % 10) +#elif defined(_MSC_VER) && defined(_MSC_FULL_VER) +// MSVC +#if _MSC_VER == _MSC_FULL_VER / 10000 +#define SCN_MSVC \ + SCN_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) +#else +#define SCN_MSVC \ + SCN_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 10, \ + _MSC_FULL_VER % 100000) +#endif // _MSC_VER == _MSC_FULL_VER / 10000 +#elif defined(__clang__) && defined(__clang_minor__) && \ + defined(__clang_patchlevel__) +// Clang +#define SCN_CLANG \ + SCN_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + defined(__GNUC_PATCHLEVEL__) +// GCC +#define SCN_GCC SCN_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#endif + +#ifndef SCN_INTEL +#define SCN_INTEL 0 +#endif +#ifndef SCN_MSVC +#define SCN_MSVC 0 +#endif +#ifndef SCN_CLANG +#define SCN_CLANG 0 +#endif +#ifndef SCN_GCC +#define SCN_GCC 0 +#endif + +// Pretending to be gcc (clang, icc, etc.) +#ifdef __GNUC__ + +#ifdef __GNUC_MINOR__ +#define SCN_GCC_COMPAT_MINOR __GNUC_MINOR__ +#else +#define SCN_GCC_COMPAT_MINOR 0 +#endif + +#ifdef __GNUC_PATCHLEVEL__ +#define SCN_GCC_COMPAT_PATCHLEVEL __GNUC_PATCHLEVEL__ +#else +#define SCN_GCC_COMPAT_PATCHLEVEL 0 +#endif + +#define SCN_GCC_COMPAT \ + SCN_COMPILER(__GNUC__, SCN_GCC_COMPAT_MINOR, SCN_GCC_COMPAT_PATCHLEVEL) +#else +#define SCN_GCC_COMPAT 0 +#endif // #ifdef __GNUC__ + +#define SCN_STRINGIFY_APPLY(x) #x +#define SCN_STRINGIFY(x) SCN_STRINGIFY_APPLY(x) + +// POSIX +#if defined(__unix__) || defined(__APPLE__) +#define SCN_POSIX 1 +#else +#define SCN_POSIX 0 +#endif + +#if defined(__APPLE__) +#define SCN_APPLE 1 +#else +#define SCN_APPLE 0 +#endif + +// Windows +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && \ + !defined(__CYGWIN__) +#define SCN_WINDOWS 1 +#else +#define SCN_WINDOWS 0 +#endif + +#ifdef _MSVC_LANG +#define SCN_MSVC_LANG _MSVC_LANG +#else +#define SCN_MSVC_LANG 0 +#endif + +// Standard version +#if SCN_MSVC +#define SCN_STD SCN_MSVC_LANG +#else +#define SCN_STD __cplusplus +#endif + +// Warning control +#if SCN_GCC +#define SCN_PRAGMA_APPLY(x) _Pragma(#x) + +#define SCN_GCC_PUSH _Pragma("GCC diagnostic push") +#define SCN_GCC_POP _Pragma("GCC diagnostic pop") + +#define SCN_GCC_IGNORE(x) SCN_PRAGMA_APPLY(GCC diagnostic ignored x) +#else +#define SCN_GCC_PUSH +#define SCN_GCC_POP +#define SCN_GCC_IGNORE(x) +#endif + +#if SCN_CLANG +#define SCN_PRAGMA_APPLY(x) _Pragma(#x) + +#define SCN_CLANG_PUSH _Pragma("clang diagnostic push") +#define SCN_CLANG_POP _Pragma("clang diagnostic pop") + +#define SCN_CLANG_IGNORE(x) SCN_PRAGMA_APPLY(clang diagnostic ignored x) + +#if SCN_CLANG >= SCN_COMPILER(3, 9, 0) +#define SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE \ + SCN_CLANG_PUSH SCN_CLANG_IGNORE("-Wundefined-func-template") +#define SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE SCN_CLANG_POP +#else +#define SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE +#define SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE +#endif + +#else +#define SCN_CLANG_PUSH +#define SCN_CLANG_POP +#define SCN_CLANG_IGNORE(x) +#define SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE +#define SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE +#endif + +#if SCN_GCC_COMPAT && defined(SCN_PRAGMA_APPLY) +#define SCN_GCC_COMPAT_PUSH SCN_PRAGMA_APPLY(GCC diagnostic push) +#define SCN_GCC_COMPAT_POP SCN_PRAGMA_APPLY(GCC diagnostic pop) +#define SCN_GCC_COMPAT_IGNORE(x) SCN_PRAGMA_APPLY(GCC diagnostic ignored x) +#else +#define SCN_GCC_COMPAT_PUSH +#define SCN_GCC_COMPAT_POP +#define SCN_GCC_COMPAT_IGNORE(x) +#endif + +#if SCN_MSVC +#define SCN_MSVC_PUSH __pragma(warning(push)) +#define SCN_MSVC_POP __pragma(warning(pop)) + +#define SCN_MSVC_IGNORE(x) __pragma(warning(disable : x)) +#else +#define SCN_MSVC_PUSH +#define SCN_MSVC_POP +#define SCN_MSVC_IGNORE(x) +#endif + +#ifndef SCN_PREDEFINE_VSCAN_OVERLOADS +#define SCN_PREDEFINE_VSCAN_OVERLOADS 0 +#endif + +#ifdef __cpp_exceptions +#define SCN_HAS_EXCEPTIONS 1 +#endif +#if !defined(SCN_HAS_EXCEPTIONS) && defined(__EXCEPTIONS) +#define SCN_HAS_EXCEPTIONS 1 +#endif +#if !defined(SCN_HAS_EXCEPTIONS) && defined(_HAS_EXCEPTIONS) +#if _HAS_EXCEPTIONS +#define SCN_HAS_EXCEPTIONS 1 +#else +#define SCN_HAS_EXCEPTIONS 0 +#endif +#endif +#if !defined(SCN_HAS_EXCEPTIONS) && !defined(_CPPUNWIND) +#define SCN_HAS_EXCEPTIONS 0 +#endif +#ifndef SCN_HAS_EXCEPTIONS +#define SCN_HAS_EXCEPTIONS 0 +#endif + +#if SCN_HAS_EXCEPTIONS +#define SCN_TRY try +#define SCN_CATCH(x) catch (x) +#define SCN_THROW(x) throw x +#define SCN_RETHROW throw +#else +#define SCN_TRY if (true) +#define SCN_CATCH(x) if (false) +#define SCN_THROW(x) ::std::abort() +#define SCN_RETHROW ::std::abort() +#endif + +#ifdef __has_include +#define SCN_HAS_INCLUDE(x) __has_include(x) +#else +#define SCN_HAS_INCLUDE(x) 0 +#endif + +#ifdef __has_cpp_attribute +#define SCN_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +#define SCN_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#ifdef __has_feature +#define SCN_HAS_FEATURE(x) __has_feature(x) +#else +#define SCN_HAS_FEATURE(x) 0 +#endif + +#ifdef __has_builtin +#define SCN_HAS_BUILTIN(x) __has_builtin(x) +#else +#define SCN_HAS_BUILTIN(x) 0 +#endif + +#if SCN_HAS_INCLUDE() +#include +#endif + +#if defined(_SCN_DOXYGEN) && _SCN_DOXYGEN +#define SCN_DOXYGEN 1 +#else +#define SCN_DOXYGEN 0 +#endif + +// Detect constexpr +#if defined(__cpp_constexpr) +#if __cpp_constexpr >= 201304 +#define SCN_HAS_RELAXED_CONSTEXPR 1 +#else +#define SCN_HAS_RELAXED_CONSTEXPR 0 +#endif +#endif + +#ifndef SCN_HAS_RELAXED_CONSTEXPR +#if SCN_HAS_FEATURE(cxx_relaxed_constexpr) || \ + SCN_MSVC >= SCN_COMPILER(19, 10, 0) || \ + ((SCN_GCC >= SCN_COMPILER(6, 0, 0) || \ + SCN_INTEL >= SCN_COMPILER(17, 0, 0)) && \ + SCN_STD >= SCN_STD_14) +#define SCN_HAS_RELAXED_CONSTEXPR 1 +#else +#define SCN_HAS_RELAXED_CONSTEXPR 0 +#endif +#endif + +#if SCN_HAS_RELAXED_CONSTEXPR || SCN_DOXYGEN +#define SCN_CONSTEXPR14 constexpr +#else +#define SCN_CONSTEXPR14 inline +#endif + +// Detect string_view +#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201603 && \ + SCN_STD >= SCN_STD_17 +#define SCN_HAS_STRING_VIEW 1 +#else +#define SCN_HAS_STRING_VIEW 0 +#endif + +// Detect [[nodiscard]] +#if (SCN_HAS_CPP_ATTRIBUTE(nodiscard) && __cplusplus >= SCN_STD_17) || \ + (SCN_MSVC >= SCN_COMPILER(19, 11, 0) && SCN_MSVC_LANG >= SCN_STD_17) || \ + ((SCN_GCC >= SCN_COMPILER(7, 0, 0) || \ + SCN_INTEL >= SCN_COMPILER(18, 0, 0)) && \ + __cplusplus >= SCN_STD_17) && !SCN_DOXYGEN +#define SCN_NODISCARD [[nodiscard]] +#else +#define SCN_NODISCARD /*nodiscard*/ +#endif + +// Detect [[clang::trivial_abi]] +#if SCN_HAS_CPP_ATTRIBUTE(clang::trivial_abi) +#define SCN_TRIVIAL_ABI [[clang::trivial_abi]] +#else +#define SCN_TRIVIAL_ABI /*trivial_abi*/ +#endif + +#if defined(SCN_HEADER_ONLY) && SCN_HEADER_ONLY +#define SCN_FUNC inline +#else +#define SCN_FUNC +#endif + +// Detect + +#if defined(_GLIBCXX_RELEASE) && __cplusplus >= SCN_STD_17 +#define SCN_HAS_INTEGER_CHARCONV (_GLIBCXX_RELEASE >= 9) +#define SCN_HAS_FLOAT_CHARCONV (_GLIBCXX_RELEASE >= 11) +#elif SCN_MSVC >= SCN_COMPILER(19, 14, 0) +#define SCN_HAS_INTEGER_CHARCONV 1 +#define SCN_HAS_FLOAT_CHARCONV (SCN_MSVC >= SCN_COMPILER(19, 21, 0)) +#elif defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201606 +#define SCN_HAS_INTEGER_CHARCONV 1 +#define SCN_HAS_FLOAT_CHARCONV 1 +#endif // _GLIBCXX_RELEASE + +#ifndef SCN_HAS_INTEGER_CHARCONV +#define SCN_HAS_INTEGER_CHARCONV 0 +#define SCN_HAS_FLOAT_CHARCONV 0 +#endif + +// Detect std::launder +#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 +#define SCN_HAS_LAUNDER 1 +#else +#define SCN_HAS_LAUNDER 0 +#endif + +// Detect __assume +#if SCN_INTEL || SCN_MSVC +#define SCN_HAS_ASSUME 1 +#else +#define SCN_HAS_ASSUME 0 +#endif + +// Detect __builtin_assume +#if SCN_HAS_BUILTIN(__builtin_assume) +#define SCN_HAS_BUILTIN_ASSUME 1 +#else +#define SCN_HAS_BUILTIN_ASSUME 0 +#endif + +// Detect __builtin_unreachable +#if SCN_HAS_BUILTIN(__builtin_unreachable) || SCN_GCC_COMPAT +#define SCN_HAS_BUILTIN_UNREACHABLE 1 +#else +#define SCN_HAS_BUILTIN_UNREACHABLE 0 +#endif + +#if SCN_HAS_ASSUME +#define SCN_ASSUME(x) __assume(x) +#elif SCN_HAS_BUILTIN_ASSUME +#define SCN_ASSUME(x) __builtin_assume(x) +#elif SCN_HAS_BUILTIN_UNREACHABLE +#define SCN_ASSUME(x) ((x) ? static_cast(0) : __builtin_unreachable()) +#else +#define SCN_ASSUME(x) static_cast((x) ? 0 : 0) +#endif + +#if SCN_HAS_BUILTIN_UNREACHABLE +#define SCN_UNREACHABLE __builtin_unreachable() +#else +#define SCN_UNREACHABLE SCN_ASSUME(0) +#endif + +// Detect __builtin_expect +#if SCN_HAS_BUILTIN(__builtin_expect) || SCN_GCC_COMPAT +#define SCN_HAS_BUILTIN_EXPECT 1 +#else +#define SCN_HAS_BUILTIN_EXPECT 0 +#endif + +#if SCN_HAS_BUILTIN_EXPECT +#define SCN_LIKELY(x) __builtin_expect(!!(x), 1) +#define SCN_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define SCN_LIKELY(x) (x) +#define SCN_UNLIKELY(x) (x) +#endif + +#ifndef SCN_DEPRECATED + +#if (SCN_HAS_CPP_ATTRIBUTE(deprecated) && SCN_STD >= 201402L) || \ + SCN_MSVC >= SCN_COMPILER(19, 0, 0) || SCN_DOXYGEN +#define SCN_DEPRECATED [[deprecated]] +#else + +#if SCN_GCC_COMPAT +#define SCN_DEPRECATED __attribute__((deprecated)) +#elif SCN_MSVC +#define SCN_DEPRECATED __declspec(deprecated) +#else +#define SCN_DEPRECATED /* deprecated */ +#endif + +#endif + +#endif // !defined(SCN_DEPRECATED) + +// Detect concepts +#if defined(__cpp_concepts) && __cpp_concepts >= 201907L +#define SCN_HAS_CONCEPTS 1 +#else +#define SCN_HAS_CONCEPTS 0 +#endif + +// Detect ranges +#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L +#define SCN_HAS_RANGES 1 +#else +#define SCN_HAS_RANGES 0 +#endif + +// Detect char8_t +#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L +#define SCN_HAS_CHAR8 1 +#else +#define SCN_HAS_CHAR8 0 +#endif + +#define SCN_UNUSED(x) static_cast(sizeof(x)) + +#if SCN_HAS_RELAXED_CONSTEXPR +#define SCN_ASSERT(cond, msg) \ + do { \ + static_cast(SCN_LIKELY(cond)); \ + assert((cond) && msg); \ + } while (false) +#define SCN_EXPECT(cond) SCN_ASSERT(cond, "Precondition violation") +#define SCN_ENSURE(cond) SCN_ASSERT(cond, "Postcondition violation") +#else +#define SCN_ASSERT(cond, msg) SCN_UNUSED(cond) +#define SCN_EXPECT(cond) SCN_UNUSED(cond) +#define SCN_ENSURE(cond) SCN_UNUSED(cond) +#endif + +#define SCN_MOVE(x) \ + static_cast< \ + typename ::scn::detail::remove_reference \ + ::type&&>(x) +#define SCN_FWD(x) static_cast(x) +#define SCN_DECLVAL(T) static_cast(nullptr)() + +#define SCN_BEGIN_NAMESPACE inline namespace v1 { +#define SCN_END_NAMESPACE } + +#if defined(SCN_HEADER_ONLY) +#define SCN_INCLUDE_SOURCE_DEFINITIONS !SCN_HEADER_ONLY +#else +#define SCN_INCLUDE_SOURCE_DEFINITIONS 1 +#endif + +#endif // SCN_DETAIL_CONFIG_H diff --git a/src/third-party/scnlib/include/scn/detail/context.h b/src/third-party/scnlib/include/scn/detail/context.h new file mode 100644 index 0000000..5dff3b3 --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/context.h @@ -0,0 +1,126 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_CONTEXT_H +#define SCN_DETAIL_CONTEXT_H + +#include "args.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + template + class basic_context { + public: + using range_type = WrappedRange; + using iterator = typename range_type::iterator; + using sentinel = typename range_type::sentinel; + using char_type = typename range_type::char_type; + using locale_type = basic_locale_ref; + + basic_context(range_type&& r) : m_range(SCN_MOVE(r)) {} + basic_context(range_type&& r, locale_type&& loc) + : m_range(SCN_MOVE(r)), m_locale(SCN_MOVE(loc)) + { + } + + SCN_NODISCARD iterator& begin() + { + return m_range.begin(); + } + const sentinel& end() const + { + return m_range.end(); + } + + range_type& range() & noexcept + { + return m_range; + } + const range_type& range() const& noexcept + { + return m_range; + } + range_type range() && noexcept + { + return m_range; + } + + locale_type& locale() noexcept + { + return m_locale; + } + const locale_type& locale() const noexcept + { + return m_locale; + } + + private: + range_type m_range; + locale_type m_locale{}; + }; + + template + basic_context make_context(WrappedRange r) + { + return {SCN_MOVE(r)}; + } + template + basic_context make_context(WrappedRange r, LocaleRef&& loc) + { + return {SCN_MOVE(r), SCN_FWD(loc)}; + } + + template + auto get_arg(const basic_args& args, std::ptrdiff_t id) + -> expected> + { + auto a = args.get(id); + if (!a) { + return error(error::invalid_format_string, + "Argument id out of range"); + } + return a; + } + template + auto get_arg(const basic_args& args, + ParseCtx& pctx, + std::ptrdiff_t id) -> expected> + { + return pctx.check_arg_id(id) ? get_arg(args, id) + : error(error::invalid_format_string, + "Argument id out of range"); + } + template + auto get_arg(const basic_args&, ParseCtx&, basic_string_view) + -> expected> + { + return error(error::invalid_format_string, "Argument id out of range"); + } + + template + auto next_arg(const basic_args& args, ParseCtx& pctx) + -> expected> + { + return get_arg(args, pctx.next_arg_id()); + } + + SCN_END_NAMESPACE +} // namespace scn + +#endif // SCN_DETAIL_CONTEXT_H diff --git a/src/third-party/scnlib/include/scn/detail/error.h b/src/third-party/scnlib/include/scn/detail/error.h new file mode 100644 index 0000000..f79e741 --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/error.h @@ -0,0 +1,136 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_ERROR_H +#define SCN_DETAIL_ERROR_H + +#include "fwd.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + /** + * Error class. + * Used as a return value for functions without a success value. + */ + class SCN_TRIVIAL_ABI error { + public: + /// Error code + enum code : char { + /// No error + good = 0, + /// EOF + end_of_range, + /// Format string was invalid + invalid_format_string, + /// Scanned value was invalid for given type. + /// e.g. a period '.' when scanning for an int + invalid_scanned_value, + /// Stream does not support the performed operation + invalid_operation, + /// Scanned value was out of range for the desired type. + /// (e.g. `>2^32` for an `uint32_t`) + value_out_of_range, + /// Invalid argument given to operation + invalid_argument, + /// Source range has invalid (utf-8 or utf-16) encoding + invalid_encoding, + /// This operation is only possible with exceptions enabled + exceptions_required, + /// The source range emitted an error. + source_error, + /// The source range emitted an error that cannot be recovered + /// from. The stream is now unusable. + unrecoverable_source_error, + + unrecoverable_internal_error, + + max_error + }; + + struct success_tag_t { + }; + static constexpr success_tag_t success_tag() noexcept + { + return {}; + } + + constexpr error() noexcept = default; + constexpr error(success_tag_t) noexcept : error() {} + constexpr error(enum code c, const char* m) noexcept + : m_msg(m), m_code(c) + { + } + + /// Evaluated to true if there was no error + constexpr explicit operator bool() const noexcept + { + return m_code == good; + } + constexpr bool operator!() const noexcept + { + return !(operator bool()); + } + + constexpr operator enum code() const noexcept { return m_code; } + + /// Get error code + SCN_NODISCARD constexpr enum code code() const noexcept + { + return m_code; + } + SCN_NODISCARD constexpr const char* msg() const noexcept + { + return m_msg; + } + + /// Returns `true` if, after this error, the state of the given input + /// range is consistent, and thus, the range can be used for new + /// scanning operations. + SCN_NODISCARD constexpr bool is_recoverable() const noexcept + { + return !(m_code == unrecoverable_source_error || + m_code == unrecoverable_internal_error); + } + + private: + const char* m_msg{nullptr}; + enum code m_code { good }; + }; + + constexpr inline bool operator==(error a, error b) noexcept + { + return a.code() == b.code(); + } + constexpr inline bool operator!=(error a, error b) noexcept + { + return !(a == b); + } + + namespace detail { + struct error_handler { + constexpr error_handler() = default; + + void on_error(error e); + void on_error(const char* msg); + }; + } // namespace detail + + SCN_END_NAMESPACE +} // namespace scn + +#endif diff --git a/src/third-party/scnlib/include/scn/detail/file.h b/src/third-party/scnlib/include/scn/detail/file.h new file mode 100644 index 0000000..03ccff7 --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/file.h @@ -0,0 +1,568 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_FILE_H +#define SCN_DETAIL_FILE_H + +#include +#include + +#include "../util/algorithm.h" +#include "range.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace detail { + struct native_file_handle { +#if SCN_WINDOWS + using handle_type = void*; +#else + using handle_type = int; +#endif + + static native_file_handle invalid(); + + handle_type handle; + }; + + class byte_mapped_file { + public: + using iterator = const char*; + using sentinel = const char*; + + byte_mapped_file() = default; + explicit byte_mapped_file(const char* filename); + + byte_mapped_file(const byte_mapped_file&) = delete; + byte_mapped_file& operator=(const byte_mapped_file&) = delete; + + byte_mapped_file(byte_mapped_file&& o) noexcept + : m_map(exchange(o.m_map, span{})), + m_file(exchange(o.m_file, native_file_handle::invalid())) + { +#if SCN_WINDOWS + m_map_handle = + exchange(o.m_map_handle, native_file_handle::invalid()); +#endif + SCN_ENSURE(!o.valid()); + SCN_ENSURE(valid()); + } + byte_mapped_file& operator=(byte_mapped_file&& o) noexcept + { + if (valid()) { + _destruct(); + } + + m_map = exchange(o.m_map, span{}); + m_file = exchange(o.m_file, native_file_handle::invalid()); +#if SCN_WINDOWS + m_map_handle = + exchange(o.m_map_handle, native_file_handle::invalid()); +#endif + + SCN_ENSURE(!o.valid()); + SCN_ENSURE(valid()); + return *this; + } + + ~byte_mapped_file() + { + if (valid()) { + _destruct(); + } + } + + SCN_NODISCARD bool valid() const + { + return m_file.handle != native_file_handle::invalid().handle; + } + + SCN_NODISCARD iterator begin() const + { + return m_map.begin(); + } + SCN_NODISCARD sentinel end() const + { + return m_map.end(); + } + + protected: + void _destruct(); + + span m_map{}; + native_file_handle m_file{native_file_handle::invalid().handle}; +#if SCN_WINDOWS + native_file_handle m_map_handle{ + native_file_handle::invalid().handle}; +#endif + }; + } // namespace detail + + /** + * Memory-mapped file range. + * Manages the lifetime of the mapping itself. + */ + template + class basic_mapped_file : public detail::byte_mapped_file { + public: + using iterator = const CharT*; + using sentinel = const CharT*; + + /// Constructs an empty mapping + basic_mapped_file() = default; + + /// Constructs a mapping to a filename + explicit basic_mapped_file(const char* f) : detail::byte_mapped_file{f} + { + } + + SCN_NODISCARD iterator begin() const noexcept + { + // embrace the UB + return reinterpret_cast(byte_mapped_file::begin()); + } + SCN_NODISCARD sentinel end() const noexcept + { + return reinterpret_cast(byte_mapped_file::end()); + } + + SCN_NODISCARD iterator data() const noexcept + { + return begin(); + } + SCN_NODISCARD size_t size() const noexcept + { + return m_map.size() / sizeof(CharT); + } + + /// Mapping data + span buffer() const + { + return {data(), size()}; + } + + detail::range_wrapper> wrap() const noexcept + { + return basic_string_view{data(), size()}; + } + }; + + using mapped_file = basic_mapped_file; + using mapped_wfile = basic_mapped_file; + + namespace detail { + template + struct basic_file_access; + template + struct basic_file_iterator_access; + } // namespace detail + + /** + * Range mapping to a C FILE*. + * Not copyable or reconstructible. + */ + template + class basic_file { + friend struct detail::basic_file_access; + friend struct detail::basic_file_iterator_access; + + public: + class iterator { + friend struct detail::basic_file_iterator_access; + + public: + using char_type = CharT; + using value_type = expected; + using reference = value_type; + using pointer = value_type*; + using difference_type = std::ptrdiff_t; + using iterator_category = std::bidirectional_iterator_tag; + using file_type = basic_file; + + iterator() = default; + + expected operator*() const; + + iterator& operator++() + { + SCN_EXPECT(m_file); + ++m_current; + return *this; + } + iterator operator++(int) + { + iterator tmp(*this); + operator++(); + return tmp; + } + + iterator& operator--() + { + SCN_EXPECT(m_file); + SCN_EXPECT(m_current > 0); + + m_last_error = error{}; + --m_current; + + return *this; + } + iterator operator--(int) + { + iterator tmp(*this); + operator--(); + return tmp; + } + + bool operator==(const iterator& o) const; + + bool operator!=(const iterator& o) const + { + return !operator==(o); + } + + bool operator<(const iterator& o) const + { + // any valid iterator is before eof and null + if (!m_file) { + return !o.m_file; + } + if (!o.m_file) { + return !m_file; + } + SCN_EXPECT(m_file == o.m_file); + return m_current < o.m_current; + } + bool operator>(const iterator& o) const + { + return o.operator<(*this); + } + bool operator<=(const iterator& o) const + { + return !operator>(o); + } + bool operator>=(const iterator& o) const + { + return !operator<(o); + } + + void reset_begin_iterator() const noexcept + { + m_current = 0; + } + + private: + friend class basic_file; + + iterator(const file_type& f, size_t i) + : m_file{std::addressof(f)}, m_current{i} + { + } + + mutable error m_last_error{}; + const file_type* m_file{nullptr}; + mutable size_t m_current{0}; + }; + + using sentinel = iterator; + using char_type = CharT; + + /** + * Construct an empty file. + * Reading not possible: valid() is `false` + */ + basic_file() = default; + /** + * Construct from a FILE*. + * Must be a valid handle that can be read from. + */ + basic_file(FILE* f) : m_file{f} {} + + basic_file(const basic_file&) = delete; + basic_file& operator=(const basic_file&) = delete; + + basic_file(basic_file&& o) noexcept + : m_buffer(detail::exchange(o.m_buffer, {})), + m_file(detail::exchange(o.m_file, nullptr)) + { + } + basic_file& operator=(basic_file&& o) noexcept + { + if (valid()) { + sync(); + } + m_buffer = detail::exchange(o.m_buffer, {}); + m_file = detail::exchange(o.m_file, nullptr); + return *this; + } + + ~basic_file() + { + if (valid()) { + _sync_all(); + } + } + + /** + * Get the FILE* for this range. + * Only use this handle for reading sync() has been called and no + * reading operations have taken place after that. + * + * \see sync + */ + FILE* handle() const + { + return m_file; + } + + /** + * Reset the file handle. + * Calls sync(), if necessary, before resetting. + * @return The old handle + */ + FILE* set_handle(FILE* f, bool allow_sync = true) noexcept + { + auto old = m_file; + if (old && allow_sync) { + sync(); + } + m_file = f; + return old; + } + + /// Whether the file has been opened + constexpr bool valid() const noexcept + { + return m_file != nullptr; + } + + /** + * Synchronizes this file with the underlying FILE*. + * Invalidates all non-end iterators. + * File must be open. + * + * Necessary for mixing-and-matching scnlib and : + * \code{.cpp} + * scn::scan(file, ...); + * file.sync(); + * std::fscanf(file.handle(), ...); + * \endcode + * + * Necessary for synchronizing result objects: + * \code{.cpp} + * auto result = scn::scan(file, ...); + * // only result.range() can now be used for scanning + * result = scn::scan(result.range(), ...); + * // .sync() allows the original file to also be used + * file.sync(); + * result = scn::scan(file, ...); + * \endcode + */ + void sync() noexcept + { + _sync_all(); + m_buffer.clear(); + } + + iterator begin() const noexcept + { + return {*this, 0}; + } + sentinel end() const noexcept + { + return {}; + } + + span get_buffer(iterator it, + size_t max_size) const noexcept + { + if (!it.m_file) { + return {}; + } + const auto begin = + m_buffer.begin() + static_cast(it.m_current); + const auto end_diff = detail::min( + max_size, + static_cast(ranges::distance(begin, m_buffer.end()))); + return {begin, begin + static_cast(end_diff)}; + } + + private: + friend class iterator; + + expected _read_single() const; + + void _sync_all() noexcept + { + _sync_until(m_buffer.size()); + } + void _sync_until(size_t pos) noexcept; + + CharT _get_char_at(size_t i) const + { + SCN_EXPECT(valid()); + SCN_EXPECT(i < m_buffer.size()); + return m_buffer[i]; + } + + bool _is_at_end(size_t i) const + { + SCN_EXPECT(valid()); + return i >= m_buffer.size(); + } + + mutable std::basic_string m_buffer{}; + FILE* m_file{nullptr}; + }; + + using file = basic_file; + using wfile = basic_file; + + template <> + expected file::iterator::operator*() const; + template <> + expected wfile::iterator::operator*() const; + template <> + bool file::iterator::operator==(const file::iterator&) const; + template <> + bool wfile::iterator::operator==(const wfile::iterator&) const; + + template <> + expected file::_read_single() const; + template <> + expected wfile::_read_single() const; + template <> + void file::_sync_until(size_t) noexcept; + template <> + void wfile::_sync_until(size_t) noexcept; + + /** + * A child class for basic_file, handling fopen, fclose, and lifetimes with + * RAII. + */ + template + class basic_owning_file : public basic_file { + public: + using char_type = CharT; + + /// Open an empty file + basic_owning_file() = default; + /// Open a file, with fopen arguments + basic_owning_file(const char* f, const char* mode) + : basic_file(std::fopen(f, mode)) + { + } + + /// Steal ownership of a FILE* + explicit basic_owning_file(FILE* f) : basic_file(f) {} + + ~basic_owning_file() + { + if (is_open()) { + close(); + } + } + + /// fopen + bool open(const char* f, const char* mode) + { + SCN_EXPECT(!is_open()); + + auto h = std::fopen(f, mode); + if (!h) { + return false; + } + + const bool is_wide = sizeof(CharT) > 1; + auto ret = std::fwide(h, is_wide ? 1 : -1); + if ((is_wide && ret > 0) || (!is_wide && ret < 0) || ret == 0) { + this->set_handle(h); + return true; + } + return false; + } + /// Steal ownership + bool open(FILE* f) + { + SCN_EXPECT(!is_open()); + if (std::ferror(f) != 0) { + return false; + } + this->set_handle(f); + return true; + } + + /// Close file + void close() + { + SCN_EXPECT(is_open()); + this->sync(); + std::fclose(this->handle()); + this->set_handle(nullptr, false); + } + + /// Is the file open + SCN_NODISCARD bool is_open() const + { + return this->valid(); + } + }; + + using owning_file = basic_owning_file; + using owning_wfile = basic_owning_file; + + SCN_CLANG_PUSH + SCN_CLANG_IGNORE("-Wexit-time-destructors") + + // Avoid documentation issues: without this, Doxygen will think + // SCN_CLANG_PUSH is a part of the stdin_range declaration + namespace dummy { + } + + /** + * Get a reference to the global stdin range + */ + template + basic_file& stdin_range() + { + static auto f = basic_file{stdin}; + return f; + } + /** + * Get a reference to the global `char`-oriented stdin range + */ + inline file& cstdin() + { + return stdin_range(); + } + /** + * Get a reference to the global `wchar_t`-oriented stdin range + */ + inline wfile& wcstdin() + { + return stdin_range(); + } + SCN_CLANG_POP + + SCN_END_NAMESPACE +} // namespace scn + +#if defined(SCN_HEADER_ONLY) && SCN_HEADER_ONLY && !defined(SCN_FILE_CPP) +#include "file.cpp" +#endif + +#endif // SCN_DETAIL_FILE_H diff --git a/src/third-party/scnlib/include/scn/detail/fwd.h b/src/third-party/scnlib/include/scn/detail/fwd.h new file mode 100644 index 0000000..3dcebf6 --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/fwd.h @@ -0,0 +1,204 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_FWD_H +#define SCN_DETAIL_FWD_H + +#include "config.h" + +#include + +namespace scn { + SCN_BEGIN_NAMESPACE + + // args.h + + template + class basic_arg; + template + class basic_args; + template + class arg_store; + + template + struct temporary; + + // error.h + + class error; + + // locale.h + + template + class basic_locale_ref; + + // context.h + + template + class basic_context; + + // parse_context.h + + template + class basic_parse_context; + template + class basic_empty_parse_context; + + namespace detail { + template + struct parse_context_template_for_format; + } + + // reader/common.h + + template + struct scanner; + + // defined here to avoid including if the user wants to create a + // scanner for their own type + /** + * Base class for all scanners. + * User-defined scanner must derive from this type. + */ + struct parser_base { + /** + * Returns `true` if `skip_range_whitespace()` is to be called before + * scanning this value. + * + * Defaults to `true`. Is `false` for chars, code points and strings + * when using set scanning. + */ + static constexpr bool skip_preceding_whitespace() + { + return true; + } + /** + * Returns `true` if this scanner supports parsing align and fill + * specifiers from the format string, and then scanning them. + * + * Defaults to `false`, `true` for all scnlib-defined scanners. + */ + static constexpr bool support_align_and_fill() + { + return false; + } + + static SCN_CONSTEXPR14 void make_localized() {} + }; + + struct empty_parser; + struct common_parser; + struct common_parser_default; + + namespace detail { + template + struct simple_integer_scanner; + } + + // visitor.h + + template + class basic_visitor; + + // file.h + + template + class basic_mapped_file; + template + class basic_file; + template + class basic_owning_file; + + // scan.h + + template + struct span_list_wrapper; + template + struct discard_type; + + // util/array.h + + namespace detail { + template + struct array; + } + + // util/expected.h + + template + class expected; + + // util/memory.h + + namespace detail { + template + struct pointer_traits; + + template + class erased_storage; + + } // namespace detail + + // util/optional.h + + template + class optional; + + // util/small_vector.h + + namespace detail { + template + class small_vector; + } + + // util/span.h + + template + class span; + + // util/string_view.h + + template + class basic_string_view; + + // util/unique_ptr.h + + namespace detail { + template + class unique_ptr; + } + + // for SCN_MOVE + namespace detail { + template + struct remove_reference { + using type = T; + }; + template + struct remove_reference { + using type = T; + }; + template + struct remove_reference { + using type = T; + }; + } // namespace detail + + SCN_END_NAMESPACE +} // namespace scn + +#endif // SCN_DETAIL_FWD_H diff --git a/src/third-party/scnlib/include/scn/detail/locale.h b/src/third-party/scnlib/include/scn/detail/locale.h new file mode 100644 index 0000000..d4d0f8c --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/locale.h @@ -0,0 +1,595 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_LOCALE_H +#define SCN_DETAIL_LOCALE_H + +#include "../unicode/unicode.h" +#include "../util/array.h" +#include "../util/string_view.h" +#include "../util/unique_ptr.h" + +#include +#include + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace detail { + constexpr bool has_zero(uint64_t v) + { + return (v - UINT64_C(0x0101010101010101)) & ~v & + UINT64_C(0x8080808080808080); + } + + template + CharT ascii_widen(char ch); + template <> + constexpr char ascii_widen(char ch) + { + return ch; + } + template <> + constexpr wchar_t ascii_widen(char ch) + { + return static_cast(ch); + } + + // Hand write to avoid C locales and thus noticeable performance losses + inline bool is_space(char ch) noexcept + { + static constexpr detail::array lookup = { + {false, false, false, false, false, false, false, false, false, + true, true, true, true, true, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false}}; + return lookup[static_cast(static_cast(ch))]; + } + constexpr inline bool is_space(wchar_t ch) noexcept + { + return ch == 0x20 || (ch >= 0x09 && ch <= 0x0d); + } + constexpr inline bool is_space(code_point cp) noexcept + { + return cp == 0x20 || (cp >= 0x09 && cp <= 0x0d); + } + + constexpr inline bool is_digit(char ch) noexcept + { + return ch >= '0' && ch <= '9'; + } + constexpr inline bool is_digit(wchar_t ch) noexcept + { + return ch >= L'0' && ch <= L'9'; + } + constexpr inline bool is_digit(code_point cp) noexcept + { + return cp >= '0' && cp <= '9'; + } + + template + struct locale_defaults; + template <> + struct locale_defaults { + static constexpr string_view truename() + { + return {"true"}; + } + static constexpr string_view falsename() + { + return {"false"}; + } + static constexpr char decimal_point() noexcept + { + return '.'; + } + static constexpr char thousands_separator() noexcept + { + return ','; + } + }; + template <> + struct locale_defaults { + static constexpr wstring_view truename() + { + return {L"true"}; + } + static constexpr wstring_view falsename() + { + return {L"false"}; + } + static constexpr wchar_t decimal_point() noexcept + { + return L'.'; + } + static constexpr wchar_t thousands_separator() noexcept + { + return L','; + } + }; + } // namespace detail + + SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE + + SCN_CLANG_PUSH + SCN_CLANG_IGNORE("-Wpadded") + + // scn::scan: + // - no L flag -> use hard-coded defaults, akin to "C" + // locale_ref.default() -> default_locale_ref + // - L flag -> use global C++ locale + // locale_ref.localized() -> custom_locale_ref (global C++) + // scn::scan_localized: + // - no L flag -> use hard-coded defaults, akin to "C" + // locale_ref.default() -> default_locale_ref + // - L flag -> use given C++ locale + // locale_ref.localized() -> custom_locale_ref (given locale) + + namespace detail { + // constexpr locale + template + struct basic_static_locale_ref_base { + using char_type = CharT; + using string_view_type = SV; + using defaults = Def; + + static constexpr bool is_static = true; + + constexpr basic_static_locale_ref_base() = default; + + static constexpr bool is_space(char_type ch) + { + return detail::is_space(ch); + } + static constexpr bool is_digit(char_type ch) + { + return detail::is_digit(ch); + } + + static SCN_CONSTEXPR14 bool is_space(span ch) + { + SCN_EXPECT(ch.size() >= 1); + return detail::is_space(ch[0]); + } + static SCN_CONSTEXPR14 bool is_digit(span ch) + { + SCN_EXPECT(ch.size() >= 1); + return detail::is_digit(ch[0]); + } + + static constexpr char_type decimal_point() + { + return defaults::decimal_point(); + } + static constexpr char_type thousands_separator() + { + return defaults::thousands_separator(); + } + + static constexpr string_view_type truename() + { + return defaults::truename(); + } + static constexpr string_view_type falsename() + { + return defaults::falsename(); + } + }; + template + struct basic_static_locale_ref + : basic_static_locale_ref_base, + locale_defaults> { + }; + template <> + struct basic_static_locale_ref + : basic_static_locale_ref_base> { + }; + + // base class + template + class basic_locale_ref_impl_base { + public: + using char_type = CharT; + using string_type = std::basic_string; + using string_view_type = basic_string_view; + + static constexpr bool is_static = false; + + basic_locale_ref_impl_base() = default; + + basic_locale_ref_impl_base(const basic_locale_ref_impl_base&) = + default; + basic_locale_ref_impl_base(basic_locale_ref_impl_base&&) = default; + basic_locale_ref_impl_base& operator=( + const basic_locale_ref_impl_base&) = default; + basic_locale_ref_impl_base& operator=( + basic_locale_ref_impl_base&&) = default; + +#define SCN_DEFINE_LOCALE_REF_CTYPE(f) \ + bool is_##f(char_type ch) const \ + { \ + return do_is_##f(ch); \ + } \ + bool is_##f(span ch) const \ + { \ + return do_is_##f(ch); \ + } + + SCN_DEFINE_LOCALE_REF_CTYPE(space) + SCN_DEFINE_LOCALE_REF_CTYPE(digit) + // SCN_DEFINE_LOCALE_REF_CTYPE(alnum) + // SCN_DEFINE_LOCALE_REF_CTYPE(alpha) + // SCN_DEFINE_LOCALE_REF_CTYPE(blank) + // SCN_DEFINE_LOCALE_REF_CTYPE(cntrl) + // SCN_DEFINE_LOCALE_REF_CTYPE(graph) + // SCN_DEFINE_LOCALE_REF_CTYPE(lower) + // SCN_DEFINE_LOCALE_REF_CTYPE(print) + // SCN_DEFINE_LOCALE_REF_CTYPE(punct) + // SCN_DEFINE_LOCALE_REF_CTYPE(upper) + // SCN_DEFINE_LOCALE_REF_CTYPE(xdigit) +#undef SCN_DEFINE_LOCALE_REF_CTYPE + + char_type decimal_point() const + { + return do_decimal_point(); + } + char_type thousands_separator() const + { + return do_thousands_separator(); + } + + string_view_type truename() const + { + return do_truename(); + } + string_view_type falsename() const + { + return do_falsename(); + } + + protected: + ~basic_locale_ref_impl_base() = default; + + private: +#define SCN_DECLARE_LOCALE_REF_CTYPE_DO(f) \ + virtual bool do_is_##f(char_type) const = 0; \ + virtual bool do_is_##f(span) const = 0; + SCN_DECLARE_LOCALE_REF_CTYPE_DO(space) + SCN_DECLARE_LOCALE_REF_CTYPE_DO(digit) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(alnum) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(alpha) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(blank) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(cntrl) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(graph) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(lower) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(print) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(punct) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(upper) + // SCN_DECLARE_LOCALE_REF_CTYPE_DO(xdigit) +#undef SCN_DECLARE_LOCALE_REF_CTYPE_DO + + virtual char_type do_decimal_point() const = 0; + virtual char_type do_thousands_separator() const = 0; + virtual string_view_type do_truename() const = 0; + virtual string_view_type do_falsename() const = 0; + }; + + // hardcoded "C", using static_locale_ref + template + class basic_default_locale_ref final + : public basic_locale_ref_impl_base { + using base = basic_locale_ref_impl_base; + + public: + using char_type = typename base::char_type; + using string_view_type = typename base::string_view_type; + + basic_default_locale_ref() = default; + + private: + using static_type = basic_static_locale_ref; + + bool do_is_space(char_type ch) const override + { + return static_type::is_space(ch); + } + bool do_is_digit(char_type ch) const override + { + return static_type::is_digit(ch); + } + + bool do_is_space(span ch) const override + { + return static_type::is_space(ch); + } + bool do_is_digit(span ch) const override + { + return static_type::is_digit(ch); + } + + char_type do_decimal_point() const override + { + return static_type::decimal_point(); + } + char_type do_thousands_separator() const override + { + return static_type::thousands_separator(); + } + string_view_type do_truename() const override + { + return static_type::truename(); + } + string_view_type do_falsename() const override + { + return static_type::falsename(); + } + }; + + // custom + template + class basic_custom_locale_ref final + : public basic_locale_ref_impl_base { + using base = basic_locale_ref_impl_base; + + public: + using char_type = typename base::char_type; + using string_type = typename base::string_type; + using string_view_type = typename base::string_view_type; + + basic_custom_locale_ref(); + basic_custom_locale_ref(const void* locale); + + basic_custom_locale_ref(const basic_custom_locale_ref&) = delete; + basic_custom_locale_ref& operator=(const basic_custom_locale_ref&) = + delete; + + basic_custom_locale_ref(basic_custom_locale_ref&&); + basic_custom_locale_ref& operator=(basic_custom_locale_ref&&); + + ~basic_custom_locale_ref(); + + static basic_custom_locale_ref make_classic(); + + const void* get_locale() const + { + return m_locale; + } + + void convert_to_global(); + void convert_to_classic(); + + // narrow: locale multibyte -> locale wide + // wide: identity + error convert_to_wide(const CharT* from_begin, + const CharT* from_end, + const CharT*& from_next, + wchar_t* to_begin, + wchar_t* to_end, + wchar_t*& to_next) const; + expected convert_to_wide(const CharT* from_begin, + const CharT* from_end) const; + +#define SCN_DEFINE_CUSTOM_LOCALE_CTYPE(f) \ + bool is_##f(char_type) const; \ + bool is_##f(span) const; \ + bool is_##f(code_point) const; + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(alnum) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(alpha) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(blank) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(cntrl) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(graph) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(lower) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(print) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(punct) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(upper) + SCN_DEFINE_CUSTOM_LOCALE_CTYPE(xdigit) +#undef SCN_DEFINE_CUSTOM_LOCALE_CTYPE + + bool is_space(code_point) const; + using base::is_space; + + bool is_digit(code_point) const; + using base::is_digit; + + template + expected read_num(T& val, + const string_type& buf, + int base) const; + + private: + SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE + bool do_is_space(char_type ch) const override; + bool do_is_digit(char_type ch) const override; + + bool do_is_space(span ch) const override; + bool do_is_digit(span ch) const override; + SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE + + char_type do_decimal_point() const override; + char_type do_thousands_separator() const override; + string_view_type do_truename() const override; + string_view_type do_falsename() const override; + + void _initialize(); + + const void* m_locale{nullptr}; + void* m_data{nullptr}; + }; + } // namespace detail + + template + class basic_locale_ref { + public: + using char_type = CharT; + using impl_base = detail::basic_locale_ref_impl_base; + using static_type = detail::basic_static_locale_ref; + using default_type = detail::basic_default_locale_ref; + using custom_type = detail::basic_custom_locale_ref; + + // default + constexpr basic_locale_ref() = default; + // nullptr = global + constexpr basic_locale_ref(const void* p) : m_payload(p) {} + + basic_locale_ref clone() const + { + return {m_payload}; + } + + constexpr bool has_custom() const + { + return m_payload != nullptr; + } + + // hardcoded "C", constexpr, should be preferred whenever possible + constexpr static_type get_static() const + { + return {}; + } + + // hardcoded "C", not constexpr + default_type& get_default() + { + return m_default; + } + const default_type& get_default() const + { + return m_default; + } + + // global locale or given locale + custom_type& get_localized() + { + _construct_custom(); + return *m_custom; + } + const custom_type& get_localized() const + { + _construct_custom(); + return *m_custom; + } + + custom_type make_localized_classic() const + { + return custom_type::make_classic(); + } + + custom_type* get_localized_unsafe() + { + return m_custom.get(); + } + const custom_type* get_localized_unsafe() const + { + return m_custom.get(); + } + + // virtual interface + impl_base& get(bool localized) + { + if (localized) { + return get_localized(); + } + return get_default(); + } + const impl_base& get(bool localized) const + { + if (localized) { + return get_localized(); + } + return get_default(); + } + + void prepare_localized() const + { + _construct_custom(); + } + void reset_locale(const void* payload) + { + m_custom.reset(); + m_payload = payload; + _construct_custom(); + } + + private: + void _construct_custom() const + { + if (m_custom) { + // already constructed + return; + } + SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE + m_custom = detail::make_unique(m_payload); + SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE + } + + mutable detail::unique_ptr m_custom{nullptr}; + const void* m_payload{nullptr}; + default_type m_default{}; + }; + + template + basic_locale_ref make_locale_ref(const Locale& loc) + { + return {std::addressof(loc)}; + } + template + basic_locale_ref make_default_locale_ref() + { + return {}; + } + + using locale_ref = basic_locale_ref; + using wlocale_ref = basic_locale_ref; + + SCN_CLANG_POP // -Wpadded + SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE + SCN_END_NAMESPACE +} // namespace scn + +#if defined(SCN_HEADER_ONLY) && SCN_HEADER_ONLY && !defined(SCN_LOCALE_CPP) +#include "locale.cpp" +#endif + +#endif // SCN_DETAIL_LOCALE_H diff --git a/src/third-party/scnlib/include/scn/detail/parse_context.h b/src/third-party/scnlib/include/scn/detail/parse_context.h new file mode 100644 index 0000000..91d6687 --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/parse_context.h @@ -0,0 +1,581 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_PARSE_CONTEXT_H +#define SCN_DETAIL_PARSE_CONTEXT_H + +#include "../util/expected.h" +#include "locale.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace detail { + class parse_context_base { + public: + SCN_CONSTEXPR14 std::ptrdiff_t next_arg_id() + { + return m_next_arg_id >= 0 ? m_next_arg_id++ : 0; + } + SCN_CONSTEXPR14 bool check_arg_id(std::ptrdiff_t) + { + if (m_next_arg_id > 0) { + return false; + } + m_next_arg_id = -1; + return true; + } + + protected: + parse_context_base() = default; + + std::ptrdiff_t m_next_arg_id{0}; + }; + } // namespace detail + + SCN_CLANG_PUSH + SCN_CLANG_IGNORE("-Wpadded") + + template + class basic_parse_context : public detail::parse_context_base { + public: + using char_type = CharT; + using locale_type = basic_locale_ref; + using string_view_type = basic_string_view; + using iterator = typename string_view_type::iterator; + + constexpr basic_parse_context(basic_string_view f, + locale_type& loc) + : m_str(f), m_locale(loc) + { + } + + /** + * Returns `true`, if `next_char()` is a whitespace character according + * to the static locale. This means, that `skip_range_whitespace()` + * should be called on the source range. + */ + bool should_skip_ws() + { + bool skip = false; + while (*this && m_locale.get_static().is_space(next_char())) { + skip = true; + advance_char(); + } + return skip; + } + /** + * Returns `true`, if a character equal to `next_char()` should be read + * from the source range. + * + * If `*this` currently points to an escaped + * brace character `"{{"` or `"}}"`, skips the first brace, so that + * after this function is called, `next_char()` returns the character + * that should be read. + */ + bool should_read_literal() + { + const auto brace = detail::ascii_widen('{'); + if (next_char() != brace) { + if (next_char() == detail::ascii_widen('}')) { + advance_char(); + } + return true; + } + if (SCN_UNLIKELY(m_str.size() > 1 && + *(m_str.begin() + 1) == brace)) { + advance_char(); + return true; + } + return false; + } + /** + * Returns `true` if `ch` is equal to `next_char()` + */ + SCN_NODISCARD constexpr bool check_literal(char_type ch) const + { + return ch == next_char(); + } + /** + * Returns `true` if the code units contained in `ch` are equal to the + * code units starting from `pctx.begin()`. If `chars_left() < + * ch.size()`, returns `false`. + */ + SCN_NODISCARD SCN_CONSTEXPR14 bool check_literal( + span ch) const + { + if (chars_left() < ch.size()) { + return false; + } + for (size_t i = 0; i < ch.size(); ++i) { + if (ch[i] != m_str[i]) { + return false; + } + } + return true; + } + /** + * Returns `true` if `cp` is equal to the value returned by `next_cp()`. + * If `next_cp()` errored, returns that error + * (`error::invalid_encoding`). + */ + SCN_NODISCARD SCN_CONSTEXPR14 expected check_literal_cp( + code_point cp) const + { + auto next = next_cp(); + if (!next) { + return next.error(); + } + return cp == next.value(); + } + + /** + * Returns `true` if there are characters left in `*this`. + */ + constexpr bool good() const + { + return !m_str.empty(); + } + constexpr explicit operator bool() const + { + return good(); + } + + /** + * Returns the next character (= code unit) in `*this`. + * `good()` must be `true`. + */ + constexpr char_type next_char() const + { + return m_str.front(); + } + /** + * Returns the next code point in `*this`. + * If the code point is encoded incorrectly, returns + * `error::invalid_encoding`. + */ + SCN_NODISCARD SCN_CONSTEXPR14 expected next_cp() const + { + code_point cp{}; + auto it = parse_code_point(m_str.begin(), m_str.end(), cp); + if (!it) { + return it.error(); + } + return {cp}; + } + + /** + * Returns the number of chars (= code units) left in `*this`. + */ + constexpr std::size_t chars_left() const noexcept + { + return m_str.size(); + } + /** + * Returns the number of code points left in `*this`. If `*this` + * contains invalid encoding, returns `error::invalid_encoding`. + */ + SCN_NODISCARD SCN_CONSTEXPR14 expected cp_left() + const noexcept + { + auto d = code_point_distance(m_str.begin(), m_str.end()); + if (!d) { + return d.error(); + } + return {static_cast(d.value())}; + } + + /** + * Advances `*this` by `n` characters (= code units). `*this` must have + * at least `n` characters left. + */ + SCN_CONSTEXPR14 void advance_char(std::ptrdiff_t n = 1) noexcept + { + SCN_EXPECT(chars_left() >= static_cast(n)); + m_str.remove_prefix(static_cast(n)); + } + /** + * Advances `*this` by a single code point. If the code point is encoded + * incorrectly, returns `error::invalid_encoding`. + */ + SCN_NODISCARD SCN_CONSTEXPR14 error advance_cp() noexcept + { + code_point cp{}; + auto it = parse_code_point(m_str.begin(), m_str.end(), cp); + if (!it) { + return it.error(); + } + m_str.remove_prefix( + static_cast(it.value() - m_str.begin())); + return {}; + } + + /** + * Returns `true`, if `*this` has over `n` characters (= code units) + * left, so that `peek_char()` with the same `n` parameter can be + * called. + */ + constexpr bool can_peek_char(std::size_t n = 1) const noexcept + { + return chars_left() > n; + } + + /** + * Returns the character (= code unit) `n` characters past the current + * character, so that `peek_char(0)` is equivalent to `next_char()`. + * `n <= chars_left()` must be `true`. + */ + SCN_CONSTEXPR14 char_type peek_char(std::size_t n = 1) const noexcept + { + SCN_EXPECT(n <= chars_left()); + return m_str[n]; + } + /** + * Returns the code point past the current code point (`next_cp()`). + * + * If there is no code point to peek (the current code point is the last + * one in `*this`), returns `error::end_of_range`. + * If `*this` contains invalid encoding, returns + * `error::invalid_encoding`. + */ + SCN_NODISCARD SCN_CONSTEXPR14 expected peek_cp() + const noexcept + { + if (m_str.size() < 2) { + return error{error::end_of_range, + "End of format string, cannot peek"}; + } + + code_point cp{}; + auto it = parse_code_point(m_str.begin(), m_str.end(), cp); + if (!it) { + return it.error(); + } + if (it.value() == m_str.end()) { + return error{error::end_of_range, + "End of format string, cannot peek"}; + } + + it = parse_code_point(it.value(), m_str.end(), cp); + if (!it) { + return it.error(); + } + return {cp}; + } + + SCN_CONSTEXPR14 iterator begin() const noexcept + { + return m_str.begin(); + } + SCN_CONSTEXPR14 iterator end() const noexcept + { + return m_str.end(); + } + + /** + * Returns `true`, if `next_char() == '{'` + */ + SCN_CONSTEXPR14 bool check_arg_begin() const + { + SCN_EXPECT(good()); + return next_char() == detail::ascii_widen('{'); + } + /** + * Returns `true`, if `next_char() == '}'` + */ + SCN_CONSTEXPR14 bool check_arg_end() const + { + SCN_EXPECT(good()); + return next_char() == detail::ascii_widen('}'); + } + + using parse_context_base::check_arg_id; + SCN_CONSTEXPR14 void check_arg_id(basic_string_view) {} + + SCN_CONSTEXPR14 void arg_begin() const noexcept {} + SCN_CONSTEXPR14 void arg_end() const noexcept {} + + SCN_CONSTEXPR14 void arg_handled() const noexcept {} + + const locale_type& locale() const + { + return m_locale; + } + + /** + * Parse `*this` using `s` + */ + template + error parse(Scanner& s) + { + return s.parse(*this); + } + + bool has_arg_id() + { + SCN_EXPECT(good()); + if (m_str.size() == 1) { + return true; + } + if (m_str[1] == detail::ascii_widen('}')) { + advance_char(); + return false; + } + if (m_str[1] == detail::ascii_widen(':')) { + advance_char(2); + return false; + } + return true; + } + expected parse_arg_id() + { + SCN_EXPECT(good()); + advance_char(); + if (SCN_UNLIKELY(!good())) { + return error(error::invalid_format_string, + "Unexpected end of format argument"); + } + auto it = m_str.begin(); + for (std::ptrdiff_t i = 0; good(); ++i, (void)advance_char()) { + if (check_arg_end()) { + return string_view_type{ + it, + static_cast(i)}; + } + if (next_char() == detail::ascii_widen(':')) { + advance_char(); + return string_view_type{ + it, + static_cast(i)}; + } + } + return error(error::invalid_format_string, + "Unexpected end of format argument"); + } + + private: + string_view_type m_str; + locale_type& m_locale; + }; + + template + class basic_empty_parse_context : public detail::parse_context_base { + public: + using char_type = CharT; + using locale_type = basic_locale_ref; + using string_view_type = basic_string_view; + + constexpr basic_empty_parse_context(int args, + locale_type& loc, + bool localized = false) + : m_locale(loc), m_args_left(args), m_localized(localized) + { + } + + SCN_CONSTEXPR14 bool should_skip_ws() + { + if (m_should_skip_ws) { + m_should_skip_ws = false; + return true; + } + return false; + } + constexpr bool should_read_literal() const + { + return false; + } + constexpr bool check_literal(char_type) const + { + return false; + } + constexpr bool check_literal(span) const + { + return false; + } + constexpr bool check_literal_cp(code_point) const + { + return false; + } + + constexpr bool good() const + { + return m_args_left > 0; + } + constexpr explicit operator bool() const + { + return good(); + } + + SCN_CONSTEXPR14 void advance_char(std::ptrdiff_t = 1) const noexcept {} + SCN_CONSTEXPR14 error advance_cp() const noexcept + { + return {}; + } + + char_type next_char() const + { + SCN_EXPECT(false); + SCN_UNREACHABLE; + } + expected> next_cp() const + { + SCN_EXPECT(false); + SCN_UNREACHABLE; + } + + std::size_t chars_left() const noexcept + { + SCN_EXPECT(false); + SCN_UNREACHABLE; + } + std::size_t cp_left() const noexcept + { + SCN_EXPECT(false); + SCN_UNREACHABLE; + } + + constexpr bool can_peek_char() const noexcept + { + return false; + } + constexpr bool can_peek_cp() const noexcept + { + return false; + } + + char_type peek_char(std::ptrdiff_t = 1) const noexcept + { + SCN_EXPECT(false); + SCN_UNREACHABLE; + } + expected peek_cp() const noexcept + { + SCN_EXPECT(false); + SCN_UNREACHABLE; + } + + constexpr bool check_arg_begin() const + { + return true; + } + constexpr bool check_arg_end() const + { + return true; + } + + using parse_context_base::check_arg_id; + SCN_CONSTEXPR14 void check_arg_id(basic_string_view) {} + + SCN_CONSTEXPR14 void arg_begin() const noexcept {} + SCN_CONSTEXPR14 void arg_end() const noexcept {} + + SCN_CONSTEXPR14 void arg_handled() + { + m_should_skip_ws = true; + --m_args_left; + } + + const locale_type& locale() const + { + return m_locale; + } + + template + SCN_CONSTEXPR14 error parse(Scanner& s) const + { + if (m_localized) { + s.make_localized(); + } + return {}; + } + + constexpr bool has_arg_id() const + { + return false; + } + SCN_CONSTEXPR14 expected parse_arg_id() const + { + SCN_EXPECT(good()); + return string_view_type{}; + } + + void reset_args_left(int n) + { + m_args_left = n; + parse_context_base::m_next_arg_id = 0; + m_should_skip_ws = false; + } + + private: + locale_type& m_locale; + int m_args_left; + bool m_localized; + bool m_should_skip_ws{false}; + }; + + namespace detail { + template + basic_parse_context make_parse_context_impl( + basic_string_view f, + basic_locale_ref& loc, + bool) + { + return {f, loc}; + } + template + basic_empty_parse_context make_parse_context_impl( + int i, + basic_locale_ref& loc, + bool localized) + { + return {i, loc, localized}; + } + + template + struct parse_context_template_for_format> { + template + using type = basic_parse_context; + }; + template <> + struct parse_context_template_for_format { + template + using type = basic_empty_parse_context; + }; + + template + auto make_parse_context(F f, + basic_locale_ref& locale, + bool localized) + -> decltype(make_parse_context_impl(f, locale, localized)) + { + return make_parse_context_impl(f, locale, localized); + } + } // namespace detail + + template + auto make_parse_context(F f, basic_locale_ref& locale) + -> decltype(detail::make_parse_context_impl(f, locale, false)) + { + return detail::make_parse_context_impl(f, locale, false); + } + + SCN_CLANG_POP // -Wpadded + + SCN_END_NAMESPACE +} // namespace scn + +#endif // SCN_DETAIL_PARSE_CONTEXT_H diff --git a/src/third-party/scnlib/include/scn/detail/range.h b/src/third-party/scnlib/include/scn/detail/range.h new file mode 100644 index 0000000..5b8802f --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/range.h @@ -0,0 +1,598 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_RANGE_H +#define SCN_DETAIL_RANGE_H + +#include "../ranges/ranges.h" +#include "../util/algorithm.h" +#include "../util/memory.h" +#include "error.h" +#include "vectored.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace detail { + namespace _reset_begin_iterator { + struct fn { + private: + template + static auto impl(Iterator& it, priority_tag<1>) noexcept( + noexcept(it.reset_begin_iterator())) + -> decltype(it.reset_begin_iterator()) + { + return it.reset_begin_iterator(); + } + + template + static void impl(Iterator&, size_t, priority_tag<0>) noexcept + { + } + + public: + template + auto operator()(Iterator& it) const + noexcept(noexcept(fn::impl(it, priority_tag<1>{}))) + -> decltype(fn::impl(it, priority_tag<1>{})) + { + return fn::impl(it, priority_tag<1>{}); + } + }; + } // namespace _reset_begin_iterator + namespace { + static constexpr auto& reset_begin_iterator = + static_const::value; + } + + template + struct extract_char_type; + template + struct extract_char_type< + Iterator, + typename std::enable_if>::value>::type> { + using type = polyfill_2a::iter_value_t; + }; + template + struct extract_char_type< + Iterator, + void_t< + typename std::enable_if>::value>::type, + typename polyfill_2a::iter_value_t::success_type>> { + using type = + typename polyfill_2a::iter_value_t::success_type; + }; + + template + struct is_direct_impl + : std::is_integral> { + }; + + template + struct reconstruct_tag { + }; + + template < + typename Range, + typename Iterator, + typename Sentinel, + typename = typename std::enable_if< + std::is_constructible::value>::type> + Range reconstruct(reconstruct_tag, Iterator begin, Sentinel end) + { + return {begin, end}; + } +#if SCN_HAS_STRING_VIEW + // std::string_view is not reconstructible pre-C++20 + template + std::basic_string_view reconstruct( + reconstruct_tag>, + Iterator begin, + Sentinel end) + { + // On MSVC, string_view can't even be constructed from its + // iterators! + return {::scn::detail::to_address(begin), + static_cast(ranges::distance(begin, end))}; + } +#endif // SCN_HAS_STRING_VIEW + + template + struct range_wrapper_storage; + template + struct range_wrapper_storage { + using type = remove_cvref_t; + using range_type = const type&; + + const type* value{nullptr}; + + range_wrapper_storage() = default; + range_wrapper_storage(const type& v, dummy_type) + : value(std::addressof(v)) + { + } + + const type& get() const& noexcept + { + return *value; + } + type&& get() && noexcept + { + return *value; + } + }; + template + struct range_wrapper_storage { + using range_type = T; + + T value{}; + + range_wrapper_storage() = default; + template + range_wrapper_storage(U&& v, dummy_type) : value(SCN_FWD(v)) + { + } + + const T& get() const& noexcept + { + return value; + } + T&& get() && noexcept + { + return value; + } + }; + + template + using _range_wrapper_marker = typename T::range_wrapper_marker; + + template + struct _has_range_wrapper_marker + : custom_ranges::detail::exists<_range_wrapper_marker, T> { + }; + + /** + * Wraps a source range for more consistent behavior + */ + template + class range_wrapper { + public: + using range_type = Range; + using range_nocvref_type = remove_cvref_t; + using iterator = ranges::iterator_t; + using sentinel = ranges::sentinel_t; + using char_type = typename extract_char_type::type; + using difference_type = + ranges::range_difference_t; + using storage_type = + range_wrapper_storage::value>; + using storage_range_type = typename storage_type::range_type; + + using range_wrapper_marker = void; + + template < + typename R, + typename = typename std::enable_if< + !_has_range_wrapper_marker>::value>::type> + range_wrapper(R&& r) + : m_range(SCN_FWD(r), dummy_type{}), + m_begin(ranges::cbegin(m_range.get())) + { + } + + range_wrapper(const range_wrapper& o) : m_range(o.m_range) + { + const auto n = + ranges::distance(o.begin_underlying(), o.m_begin); + m_begin = ranges::cbegin(m_range.get()); + ranges::advance(m_begin, n); + m_read = o.m_read; + } + range_wrapper& operator=(const range_wrapper& o) + { + const auto n = + ranges::distance(o.begin_underlying(), o.m_begin); + m_range = o.m_range; + m_begin = ranges::cbegin(m_range.get()); + ranges::advance(m_begin, n); + m_read = o.m_read; + return *this; + } + + range_wrapper(range_wrapper&& o) noexcept + { + const auto n = + ranges::distance(o.begin_underlying(), o.m_begin); + m_range = SCN_MOVE(o.m_range); + m_begin = ranges::cbegin(m_range.get()); + ranges::advance(m_begin, n); + m_read = exchange(o.m_read, 0); + } + range_wrapper& operator=(range_wrapper&& o) noexcept + { + reset_to_rollback_point(); + + const auto n = + ranges::distance(o.begin_underlying(), o.m_begin); + m_range = SCN_MOVE(o.m_range); + m_begin = ranges::cbegin(m_range.get()); + ranges::advance(m_begin, n); + m_read = exchange(o.m_read, 0); + return *this; + } + + ~range_wrapper() = default; + + iterator begin() const noexcept + { + return m_begin; + } + SCN_GCC_PUSH + SCN_GCC_IGNORE("-Wnoexcept") + sentinel end() const noexcept( + noexcept(ranges::end(SCN_DECLVAL(const storage_type&).get()))) + { + return ranges::end(m_range.get()); + } + SCN_GCC_POP + + struct dummy { + }; + + /** + * Returns `true` if `begin() == end()`. + */ + bool empty() const + { + return begin() == end(); + } + + /** + * Advance the begin iterator by `n` characters. + */ + iterator advance(difference_type n = 1) noexcept + { + SCN_EXPECT(_advance_check( + n, std::integral_constant{})); + m_read += n; + ranges::advance(m_begin, n); + return m_begin; + } + + /// @{ + /** + * Advance the begin iterator, until it's equal to `it`. + * Assumes that `it` is reachable by repeatedly incrementing begin, + * will hang otherwise. + */ + template )>::type* = nullptr> + void advance_to(iterator it) noexcept + { + const auto diff = ranges::distance(m_begin, it); + m_read += diff; + m_begin = it; + } + template )>::type* = nullptr> + void advance_to(iterator it) noexcept + { + while (m_begin != it) { + ++m_read; + ++m_begin; + } + } + /// @} + + /** + * Returns the begin iterator of the underlying source range, is not + * necessarily equal to `begin()`. + */ + iterator begin_underlying() const noexcept(noexcept( + ranges::cbegin(SCN_DECLVAL(const range_nocvref_type&)))) + { + return ranges::cbegin(m_range.get()); + } + + /** + * Returns the underlying source range. + * Note that `range_underlying().begin()` may not be equal to + * `begin()`. + */ + const range_type& range_underlying() const noexcept + { + return m_range.get(); + } + + /** + * Returns a pointer to the beginning of the range. + * `*this` must be contiguous. + */ + template )>::type* = nullptr> + auto data() const + noexcept(noexcept(*SCN_DECLVAL(ranges::iterator_t))) + -> decltype(std::addressof( + *SCN_DECLVAL(ranges::iterator_t))) + { + return std::addressof(*m_begin); + } + SCN_GCC_PUSH + SCN_GCC_IGNORE("-Wnoexcept") + /** + * Returns `end() - begin()`. + * `*this` must be sized. + */ + template )>::type* = nullptr> + auto size() const noexcept(noexcept( + ranges::distance(SCN_DECLVAL(ranges::iterator_t), + SCN_DECLVAL(ranges::sentinel_t)))) + -> decltype(ranges::distance( + SCN_DECLVAL(ranges::iterator_t), + SCN_DECLVAL(ranges::sentinel_t))) + { + return ranges::distance(m_begin, end()); + } + SCN_GCC_POP + struct dummy2 { + }; + + template ::value>::type* = nullptr> + span get_buffer_and_advance( + size_t max_size = std::numeric_limits::max()) + { + auto buf = get_buffer(m_range.get(), begin(), max_size); + if (buf.size() == 0) { + return buf; + } + advance(buf.ssize()); + return buf; + } + + /** + * Reset `begin()` to the rollback point, as if by repeatedly + * calling `operator--()` on the begin iterator. + * + * Returns `error::unrecoverable_source_error` on failure. + * + * \see set_rollback_point() + */ + error reset_to_rollback_point() + { + for (; m_read != 0; --m_read) { + --m_begin; + if (m_begin == end()) { + return {error::unrecoverable_source_error, + "Putback failed"}; + } + } + return {}; + } + /** + * Sets the rollback point equal to the current `begin()` iterator. + * + * \see reset_to_rollback_point() + */ + void set_rollback_point() + { + m_read = 0; + } + + void reset_begin_iterator() + { + detail::reset_begin_iterator(m_begin); + } + + /** + * Construct a new source range from `begin()` and `end()`, and wrap + * it in a new `range_wrapper`. + */ + template + auto reconstruct_and_rewrap() && -> range_wrapper + { + auto reconstructed = + reconstruct(reconstruct_tag{}, begin(), end()); + return {SCN_MOVE(reconstructed)}; + } + + /** + * `true` if `value_type` is a character type (`char` or `wchar_t`) + * `false` if it's an `expected` containing a character + */ + static constexpr bool is_direct = + is_direct_impl::value; + // can call .data() and memcpy + /** + * `true` if `this->data()` can be called, and `memcpy` can be + * performed on it. + */ + static constexpr bool is_contiguous = + SCN_CHECK_CONCEPT(ranges::contiguous_range); + /** + * `true` if the range provides a way to access a contiguous buffer + * on it (`detail::get_buffer()`), which may not provide the entire + * source data, e.g. a `span` of `span`s (vectored I/O). + */ + static constexpr bool provides_buffer_access = + provides_buffer_access_impl::value; + + private: + template + bool _advance_check(std::ptrdiff_t n, std::true_type) + { + SCN_CLANG_PUSH + SCN_CLANG_IGNORE("-Wzero-as-null-pointer-constant") + return m_begin + n <= end(); + SCN_CLANG_POP + } + template + bool _advance_check(std::ptrdiff_t, std::false_type) + { + return true; + } + + storage_type m_range; + iterator m_begin; + mutable difference_type m_read{0}; + }; + + namespace _wrap { + struct fn { + private: + template + static range_wrapper impl(const range_wrapper& r, + priority_tag<4>) noexcept + { + return r; + } + template + static range_wrapper impl(range_wrapper&& r, + priority_tag<4>) noexcept + { + return SCN_MOVE(r); + } + + template + static auto impl(Range&& r, priority_tag<3>) noexcept( + noexcept(SCN_FWD(r).wrap())) -> decltype(SCN_FWD(r).wrap()) + { + return SCN_FWD(r).wrap(); + } + + template + static auto impl(CharT (&str)[N], priority_tag<2>) noexcept + -> range_wrapper< + basic_string_view::type>> + { + return { + basic_string_view::type>( + str, str + N - 1)}; + } + + template + static auto impl( + const std::basic_string, + Allocator>& str, + priority_tag<2>) noexcept + -> range_wrapper> + { + return {basic_string_view{str.data(), str.size()}}; + } + template + static auto impl( + std::basic_string, + Allocator>&& str, + priority_tag<2>) noexcept(std:: + is_nothrow_move_constructible< + decltype(str)>::value) + -> range_wrapper, + Allocator>> + { + return {SCN_MOVE(str)}; + } + +#if SCN_HAS_STRING_VIEW + template + static auto impl(const std::basic_string_view& str, + priority_tag<1>) noexcept + -> range_wrapper> + { + return {basic_string_view{str.data(), str.size()}}; + } +#endif + template ::type> + static auto impl(span s, priority_tag<2>) noexcept + -> range_wrapper> + { + return {basic_string_view{s.data(), s.size()}}; + } + + template )>::type> + static auto impl(Range r, priority_tag<1>) noexcept + -> range_wrapper + { + return {r}; + } + + template + static auto impl(const Range& r, priority_tag<0>) noexcept + -> range_wrapper + { + static_assert(SCN_CHECK_CONCEPT(ranges::range), + "Input needs to be a Range"); + return {r}; + } + template ::value>::type> + static auto impl(Range&& r, priority_tag<0>) noexcept + -> range_wrapper + { + static_assert(SCN_CHECK_CONCEPT(ranges::range), + "Input needs to be a Range"); + return {SCN_MOVE(r)}; + } + + public: + template + auto operator()(Range&& r) const + noexcept(noexcept(fn::impl(SCN_FWD(r), priority_tag<4>{}))) + -> decltype(fn::impl(SCN_FWD(r), priority_tag<4>{})) + { + return fn::impl(SCN_FWD(r), priority_tag<4>{}); + } + }; + } // namespace _wrap + } // namespace detail + + namespace { + /** + * Create a `range_wrapper` for any supported source range. + */ + static constexpr auto& wrap = + detail::static_const::value; + } // namespace + + template + struct range_wrapper_for { + using type = decltype(wrap(SCN_DECLVAL(Range))); + }; + template + using range_wrapper_for_t = typename range_wrapper_for::type; + + SCN_END_NAMESPACE +} // namespace scn + +#endif // SCN_DETAIL_RANGE_H diff --git a/src/third-party/scnlib/include/scn/detail/result.h b/src/third-party/scnlib/include/scn/detail/result.h new file mode 100644 index 0000000..6e5170d --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/result.h @@ -0,0 +1,595 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_RESULT_H +#define SCN_DETAIL_RESULT_H + +#include "../util/expected.h" +#include "error.h" +#include "range.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + /** + * Base class for the result type returned by most scanning functions + * (except for \ref scan_value). \ref scn::detail::scan_result_base inherits + * either from this class or \ref expected. + */ + struct wrapped_error { + wrapped_error() = default; + wrapped_error(::scn::error e) : err(e) {} + + /// Get underlying error + SCN_NODISCARD ::scn::error error() const + { + return err; + } + + /// Did the operation succeed -- true means success + explicit operator bool() const + { + return err.operator bool(); + } + + ::scn::error err{}; + }; + + namespace detail { + template + class scan_result_base_wrapper : public Base { + public: + scan_result_base_wrapper(Base&& b) : Base(SCN_MOVE(b)) {} + + protected: + void set_base(const Base& b) + { + static_cast(*this) = b; + } + void set_base(Base&& b) + { + static_cast(*this) = SCN_MOVE(b); + } + }; + + SCN_CLANG_PUSH + SCN_CLANG_IGNORE("-Wdocumentation-unknown-command") + + /// @{ + + /** + * Type returned by scanning functions. + * Contains an error (inherits from it: for \ref error, that's \ref + * wrapped_error; with \ref scan_value, inherits from \ref expected), + * and the leftover range after scanning. + * + * The leftover range may reference the range given to the scanning + * function. Please take the necessary measures to make sure that the + * original range outlives the leftover range. Alternatively, if + * possible for your specific range type, call the \ref reconstruct() + * member function to get a new, independent range. + */ + template + class scan_result_base : public scan_result_base_wrapper { + public: + using wrapped_range_type = WrappedRange; + using base_type = scan_result_base_wrapper; + + using range_type = typename wrapped_range_type::range_type; + using iterator = typename wrapped_range_type::iterator; + using sentinel = typename wrapped_range_type::sentinel; + using char_type = typename wrapped_range_type::char_type; + + scan_result_base(Base&& b, wrapped_range_type&& r) + : base_type(SCN_MOVE(b)), m_range(SCN_MOVE(r)) + { + } + + /// Beginning of the leftover range + iterator begin() const noexcept + { + return m_range.begin(); + } + SCN_GCC_PUSH + SCN_GCC_IGNORE("-Wnoexcept") + // Mitigate problem where Doxygen would think that SCN_GCC_PUSH was + // a part of the definition of end() + public: + /// End of the leftover range + sentinel end() const + noexcept(noexcept(SCN_DECLVAL(wrapped_range_type).end())) + { + return m_range.end(); + } + + /// Whether the leftover range is empty + bool empty() const + noexcept(noexcept(SCN_DECLVAL(wrapped_range_type).end())) + { + return begin() == end(); + } + SCN_GCC_POP + // See above at SCN_GCC_PUSH + public: + /// A subrange pointing to the leftover range + ranges::subrange subrange() const + { + return {begin(), end()}; + } + + /** + * Leftover range. + * If the leftover range is used to scan a new value, this member + * function should be used. + * + * \see range_wrapper + */ + wrapped_range_type& range() & + { + return m_range; + } + /// \copydoc range() + const wrapped_range_type& range() const& + { + return m_range; + } + /// \copydoc range() + wrapped_range_type range() && + { + return SCN_MOVE(m_range); + } + + /** + * \defgroup range_as_range Contiguous leftover range convertors + * + * These member functions enable more convenient use of the + * leftover range for non-scnlib use cases. The range must be + * contiguous. The leftover range is not advanced, and can still be + * used. + * + * @{ + */ + + /** + * \ingroup range_as_range + * Return a view into the leftover range as a \c string_view. + * Operations done to the leftover range after a call to this may + * cause issues with iterator invalidation. The returned range will + * reference to the leftover range, so be wary of + * use-after-free-problems. + */ + template < + typename R = wrapped_range_type, + typename = typename std::enable_if::type> + basic_string_view range_as_string_view() const + { + return {m_range.data(), + static_cast(m_range.size())}; + } + /** + * \ingroup range_as_range + * Return a view into the leftover range as a \c span. + * Operations done to the leftover range after a call to this may + * cause issues with iterator invalidation. The returned range will + * reference to the leftover range, so be wary of + * use-after-free-problems. + */ + template < + typename R = wrapped_range_type, + typename = typename std::enable_if::type> + span range_as_span() const + { + return {m_range.data(), + static_cast(m_range.size())}; + } + /** + * \ingroup range_as_range + * Return the leftover range as a string. The contents are copied + * into the string, so using this will not lead to lifetime issues. + */ + template < + typename R = wrapped_range_type, + typename = typename std::enable_if::type> + std::basic_string range_as_string() const + { + return {m_range.data(), + static_cast(m_range.size())}; + } + /// @} + + protected: + wrapped_range_type m_range; + + private: + /// \publicsection + + /** + * Reconstructs a range of the original type, independent of the + * leftover range, beginning from \ref begin and ending in \ref end. + * + * Compiles only if range is reconstructible. + */ + template + R reconstruct() const; + }; + + template + class intermediary_scan_result + : public scan_result_base { + public: + using base_type = scan_result_base; + + intermediary_scan_result(Base&& b, WrappedRange&& r) + : base_type(SCN_MOVE(b), SCN_MOVE(r)) + { + } + + template + void reconstruct() const + { + static_assert( + dependent_false::value, + "Cannot call .reconstruct() on intermediary_scan_result. " + "Assign this value to a previous result value returned by " + "a scanning function or make_result (type: " + "reconstructed_scan_result or " + "non_reconstructed_scan_result) "); + } + }; + template + class reconstructed_scan_result + : public intermediary_scan_result { + public: + using unwrapped_range_type = typename WrappedRange::range_type; + using base_type = intermediary_scan_result; + + reconstructed_scan_result(Base&& b, WrappedRange&& r) + : base_type(SCN_MOVE(b), SCN_MOVE(r)) + { + } + + reconstructed_scan_result& operator=( + const intermediary_scan_result& other) + { + this->set_base(other); + this->m_range = other.range(); + return *this; + } + reconstructed_scan_result& operator=( + intermediary_scan_result&& other) + { + this->set_base(other); + this->m_range = other.range(); + return *this; + } + + unwrapped_range_type reconstruct() const + { + return this->range().range_underlying(); + } + }; + template + class non_reconstructed_scan_result + : public intermediary_scan_result { + public: + using unwrapped_range_type = UnwrappedRange; + using base_type = intermediary_scan_result; + + non_reconstructed_scan_result(Base&& b, WrappedRange&& r) + : base_type(SCN_MOVE(b), SCN_MOVE(r)) + { + } + + non_reconstructed_scan_result& operator=( + const intermediary_scan_result& other) + { + this->set_base(other); + this->m_range = other.range(); + return *this; + } + non_reconstructed_scan_result& operator=( + intermediary_scan_result&& other) + { + this->set_base(other); + this->m_range = other.range(); + return *this; + } + + template + R reconstruct() const + { + return ::scn::detail::reconstruct(reconstruct_tag{}, + this->begin(), this->end()); + } + }; + + /// @} + + // -Wdocumentation-unknown-command + SCN_CLANG_PUSH + + template + struct range_tag { + }; + + namespace _wrap_result { + struct fn { + private: + // Range = range_wrapper& + template + static auto impl(Error e, + range_tag&>, + range_wrapper&& range, + priority_tag<5>) noexcept + -> intermediary_scan_result, Error> + { + return {SCN_MOVE(e), SCN_MOVE(range)}; + } + // Range = const range_wrapper& + template + static auto impl(Error e, + range_tag&>, + range_wrapper&& range, + priority_tag<5>) noexcept + -> intermediary_scan_result, Error> + { + return {SCN_MOVE(e), SCN_MOVE(range)}; + } + // Range = range_wrapper&& + template + static auto impl(Error e, + range_tag>, + range_wrapper&& range, + priority_tag<5>) noexcept + -> intermediary_scan_result, Error> + { + return {SCN_MOVE(e), SCN_MOVE(range)}; + } + + // Range = range_wrapper& + template + static auto impl(Error e, + range_tag&>, + range_wrapper&& range, + priority_tag<4>) noexcept + -> intermediary_scan_result, Error> + { + return {SCN_MOVE(e), SCN_MOVE(range)}; + } + // Range = const range_wrapper& + template + static auto impl(Error e, + range_tag&>, + range_wrapper&& range, + priority_tag<4>) noexcept + -> intermediary_scan_result, Error> + { + return {SCN_MOVE(e), SCN_MOVE(range)}; + } + // Range = range_wrapper&& + template + static auto impl(Error e, + range_tag>, + range_wrapper&& range, + priority_tag<4>) noexcept + -> intermediary_scan_result, Error> + { + return {SCN_MOVE(e), SCN_MOVE(range)}; + } + + // string literals are wonky + template > + static auto impl( + Error e, + range_tag, + range_wrapper>&& range, + priority_tag<3>) noexcept + -> reconstructed_scan_result< + range_wrapper>, + Error> + { + return {SCN_MOVE(e), SCN_MOVE(range) + .template reconstruct_and_rewrap< + basic_string_view>()}; + } + + // (const) InputRange&: View + Reconstructible + // wrapped + template ::type, + typename = typename std::enable_if)>::type> + static auto impl(Error e, + range_tag, + range_wrapper&& range, + priority_tag<2>) noexcept + -> reconstructed_scan_result< + decltype(SCN_MOVE(range) + .template reconstruct_and_rewrap< + InputRangeNoConst>()), + Error> + { + return {SCN_MOVE(e), SCN_MOVE(range) + .template reconstruct_and_rewrap< + InputRangeNoConst>()}; + } + + // (const) InputRange&: other + // wrapped + template + static auto impl(Error e, + range_tag, + range_wrapper&& range, + priority_tag<1>) noexcept + -> non_reconstructed_scan_result< + range_wrapper, + typename std::remove_const::type, + Error> + { + return {SCN_MOVE(e), SCN_MOVE(range)}; + } + + // InputRange&&: View + Reconstructible + // wrapped + template ::type, + typename = typename std::enable_if)>::type> + static auto impl(Error e, + range_tag, + range_wrapper&& range, + priority_tag<1>) noexcept + -> reconstructed_scan_result< + decltype(SCN_MOVE(range) + .template reconstruct_and_rewrap< + InputRangeNoConst>()), + Error> + { + return {SCN_MOVE(e), SCN_MOVE(range) + .template reconstruct_and_rewrap< + InputRangeNoConst>()}; + } + + // InputRange&&: other + // wrapped + template + static auto impl(Error e, + range_tag, + range_wrapper&& range, + priority_tag<0>) noexcept + -> non_reconstructed_scan_result< + range_wrapper, + typename std::remove_const::type, + Error> + { + return {SCN_MOVE(e), SCN_MOVE(range)}; + } + +#if 0 + // InputRange&& + // wrapped + template ::type> + static auto impl(Error e, + range_tag, + range_wrapper&& range, + priority_tag<0>) noexcept + -> reconstructed_scan_result, Error> + { + return {SCN_MOVE(e), + SCN_MOVE(range) + .template rewrap_and_reconstruct()}; + } +#endif + + public: + template + auto operator()(Error e, + range_tag tag, + range_wrapper&& range) const + noexcept(noexcept(impl(SCN_MOVE(e), + tag, + SCN_MOVE(range), + priority_tag<5>{}))) + -> decltype(impl(SCN_MOVE(e), + tag, + SCN_MOVE(range), + priority_tag<5>{})) + { + static_assert(SCN_CHECK_CONCEPT(ranges::range), + "Input needs to be a Range"); + return impl(SCN_MOVE(e), tag, SCN_MOVE(range), + priority_tag<5>{}); + } + }; + } // namespace _wrap_result + namespace { + static constexpr auto& wrap_result = + static_const<_wrap_result::fn>::value; + } + + template + struct result_type_for { + using type = + decltype(wrap_result(SCN_DECLVAL(Error &&), + SCN_DECLVAL(range_tag), + SCN_DECLVAL(WrappedRange&&))); + }; + template + using result_type_for_t = + typename result_type_for::type; + } // namespace detail + + /** + * Create a result object for range \c Range. + * Useful if one wishes to scan from the same range in a loop. + * + * \code{.cpp} + * auto source = ...; + * auto result = make_result(source); + * // scan until failure (no more `int`s, or EOF) + * while (result) { + * int i; + * result = scn::scan(result.range(), "{}", i); + * // use i + * } + * // see result for why we exited the loop + * \endcode + * + * \c Error template parameter can be used to customize the error type for + * the result object. By default, it's \ref wrapped_error, which is what + * most of the scanning functions use. For \c scan_value, use \c + * expected: + * + * \code{.cpp} + * auto result = make_result>(source); + * while (result) { + * result = scn::scan_value(result.range(), "{}"); + * // use result.value() + * } + * \endcode + */ + template + auto make_result(Range&& r) + -> detail::result_type_for_t> + { + return detail::wrap_result(Error{}, detail::range_tag{}, + wrap(r)); + } + + SCN_END_NAMESPACE +} // namespace scn + +#endif // SCN_DETAIL_RESULT_H diff --git a/src/third-party/scnlib/include/scn/detail/vectored.h b/src/third-party/scnlib/include/scn/detail/vectored.h new file mode 100644 index 0000000..f5c3868 --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/vectored.h @@ -0,0 +1,166 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_VECTORED_H +#define SCN_DETAIL_VECTORED_H + +#include "../ranges/util.h" +#include "../util/math.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace detail { + namespace _get_buffer { + struct fn { + private: + template + static It _get_end(It begin, It end, size_t max_size) + { + return begin + + min(max_size, static_cast( + ranges::distance(begin, end))); + } + + template + static SCN_CONSTEXPR14 + span::type> + impl(span> s, + typename span::iterator begin, + size_t max_size, + priority_tag<3>) noexcept + { + auto buf_it = s.begin(); + for (; buf_it != s.end(); ++buf_it) { + if (begin >= buf_it->begin() && begin < buf_it->end()) { + break; + } + if (begin == buf_it->end()) { + ++buf_it; + begin = buf_it->begin(); + break; + } + } + if (buf_it == s.end()) { + return {}; + } + return {begin, _get_end(begin, buf_it->end(), max_size)}; + } + + template < + typename Range, + typename std::enable_if)>::type* = nullptr> + static SCN_CONSTEXPR14 span>::type> + impl(const Range& s, + ranges::iterator_t begin, + size_t max_size, + priority_tag<2>) noexcept + { + auto b = ranges::begin(s); + auto e = ranges::end(s); + return {to_address(begin), + _get_end(to_address(begin), + to_address_safe(e, b, e), max_size)}; + } + + template + static auto impl( + const Range& r, + It begin, + size_t max_size, + priority_tag<1>) noexcept(noexcept(r.get_buffer(begin, + max_size))) + -> decltype(r.get_buffer(begin, max_size)) + { + return r.get_buffer(begin, max_size); + } + + template + static auto impl( + const Range& r, + It begin, + size_t max_size, + priority_tag<0>) noexcept(noexcept(get_buffer(r, + begin, + max_size))) + -> decltype(get_buffer(r, begin, max_size)) + { + return get_buffer(r, begin, max_size); + } + + public: + template + SCN_CONSTEXPR14 auto operator()(const Range& r, + It begin, + size_t max_size) const + noexcept(noexcept( + fn::impl(r, begin, max_size, priority_tag<3>{}))) + -> decltype(fn::impl(r, + begin, + max_size, + priority_tag<3>{})) + { + return fn::impl(r, begin, max_size, priority_tag<3>{}); + } + + template + SCN_CONSTEXPR14 auto operator()(const Range& r, It begin) const + noexcept( + noexcept(fn::impl(r, + begin, + std::numeric_limits::max(), + priority_tag<3>{}))) + -> decltype(fn::impl(r, + begin, + std::numeric_limits::max(), + priority_tag<3>{})) + { + return fn::impl(r, begin, + std::numeric_limits::max(), + priority_tag<3>{}); + } + }; + } // namespace _get_buffer + + namespace { + static constexpr auto& get_buffer = + detail::static_const<_get_buffer::fn>::value; + } // namespace + + struct provides_buffer_access_concept { + template + auto _test_requires(const Range& r, Iterator begin) + -> decltype(scn::detail::valid_expr( + ::scn::detail::get_buffer(r, begin))); + }; + template + struct provides_buffer_access_impl + : std::integral_constant< + bool, + ::scn::custom_ranges::detail::_requires< + provides_buffer_access_concept, + Range, + ::scn::ranges::iterator_t>::value> { + }; + } // namespace detail + + SCN_END_NAMESPACE +} // namespace scn + +#endif diff --git a/src/third-party/scnlib/include/scn/detail/visitor.h b/src/third-party/scnlib/include/scn/detail/visitor.h new file mode 100644 index 0000000..e88e2f7 --- /dev/null +++ b/src/third-party/scnlib/include/scn/detail/visitor.h @@ -0,0 +1,248 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_DETAIL_VISITOR_H +#define SCN_DETAIL_VISITOR_H + +#include "../reader/reader.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + template + class basic_visitor { + public: + using context_type = Context; + using char_type = typename Context::char_type; + using arg_type = basic_arg; + + basic_visitor(Context& ctx, ParseCtx& pctx) + : m_ctx(std::addressof(ctx)), m_pctx(std::addressof(pctx)) + { + } + + template + auto operator()(T&& val) -> error + { + return visit(SCN_FWD(val), detail::priority_tag<1>{}); + } + + private: + auto visit(code_point& val, detail::priority_tag<1>) -> error + { + return detail::visitor_boilerplate( + val, *m_ctx, *m_pctx); + } + auto visit(span& val, detail::priority_tag<1>) -> error + { + return detail::visitor_boilerplate( + val, *m_ctx, *m_pctx); + } + auto visit(bool& val, detail::priority_tag<1>) -> error + { + return detail::visitor_boilerplate( + val, *m_ctx, *m_pctx); + } + +#define SCN_VISIT_INT(T) \ + error visit(T& val, detail::priority_tag<0>) \ + { \ + return detail::visitor_boilerplate>( \ + val, *m_ctx, *m_pctx); \ + } + SCN_VISIT_INT(signed char) + SCN_VISIT_INT(short) + SCN_VISIT_INT(int) + SCN_VISIT_INT(long) + SCN_VISIT_INT(long long) + SCN_VISIT_INT(unsigned char) + SCN_VISIT_INT(unsigned short) + SCN_VISIT_INT(unsigned int) + SCN_VISIT_INT(unsigned long) + SCN_VISIT_INT(unsigned long long) + SCN_VISIT_INT(char_type) +#undef SCN_VISIT_INT + +#define SCN_VISIT_FLOAT(T) \ + error visit(T& val, detail::priority_tag<1>) \ + { \ + return detail::visitor_boilerplate>( \ + val, *m_ctx, *m_pctx); \ + } + SCN_VISIT_FLOAT(float) + SCN_VISIT_FLOAT(double) + SCN_VISIT_FLOAT(long double) +#undef SCN_VISIT_FLOAT + + auto visit(std::basic_string& val, detail::priority_tag<1>) + -> error + { + return detail::visitor_boilerplate( + val, *m_ctx, *m_pctx); + } + auto visit(basic_string_view& val, detail::priority_tag<1>) + -> error + { + return detail::visitor_boilerplate( + val, *m_ctx, *m_pctx); + } + auto visit(typename arg_type::handle val, detail::priority_tag<1>) + -> error + { + return val.scan(*m_ctx, *m_pctx); + } + [[noreturn]] auto visit(detail::monostate, detail::priority_tag<0>) + -> error + { + SCN_UNREACHABLE; + } + + Context* m_ctx; + ParseCtx* m_pctx; + }; + + template + error visit(Context& ctx, + ParseCtx& pctx, + basic_args args) + { + using char_type = typename Context::char_type; + using arg_type = basic_arg; + auto arg = arg_type{}; + + while (pctx) { + if (pctx.should_skip_ws()) { + // Skip whitespace from format string and from stream + // EOF is not an error + auto ret = skip_range_whitespace(ctx, false); + if (SCN_UNLIKELY(!ret)) { + if (ret == error::end_of_range) { + break; + } + SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE + auto rb = ctx.range().reset_to_rollback_point(); + if (!rb) { + return rb; + } + return ret; + } + // Don't advance pctx, should_skip_ws() does it for us + continue; + } + + // Non-brace character, or + // Brace followed by another brace, meaning a literal '{' + if (pctx.should_read_literal()) { + if (SCN_UNLIKELY(!pctx)) { + return {error::invalid_format_string, + "Unexpected end of format string"}; + } + // Check for any non-specifier {foo} characters + alignas(typename Context::char_type) unsigned char buf[4] = {0}; + auto ret = read_code_point(ctx.range(), make_span(buf, 4)); + SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE + if (!ret || !pctx.check_literal(ret.value().chars)) { + auto rb = ctx.range().reset_to_rollback_point(); + if (!rb) { + // Failed rollback + return rb; + } + if (!ret) { + // Failed read + return ret.error(); + } + + // Mismatching characters in scan string and stream + return {error::invalid_scanned_value, + "Expected character from format string not " + "found in the stream"}; + } + // Bump pctx to next char + if (!pctx.advance_cp()) { + pctx.advance_char(); + } + } + else { + // Scan argument + auto arg_wrapped = [&]() -> expected { + if (!pctx.has_arg_id()) { + return next_arg(args, pctx); + } + auto id_wrapped = pctx.parse_arg_id(); + if (!id_wrapped) { + return id_wrapped.error(); + } + auto id = id_wrapped.value(); + SCN_ENSURE(!id.empty()); + if (ctx.locale().get_static().is_digit(id.front())) { + auto s = + detail::simple_integer_scanner{}; + std::ptrdiff_t i{0}; + auto span = make_span(id.data(), id.size()); + SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE + auto ret = s.scan(span, i, 10); + SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE + if (!ret || ret.value() != span.end()) { + return error(error::invalid_format_string, + "Failed to parse argument id from " + "format string"); + } + return get_arg(args, pctx, i); + } + return get_arg(args, pctx, id); + }(); + if (!arg_wrapped) { + return arg_wrapped.error(); + } + arg = arg_wrapped.value(); + SCN_ENSURE(arg); + if (!pctx) { + return {error::invalid_format_string, + "Unexpected end of format argument"}; + } + auto ret = visit_arg( + basic_visitor(ctx, pctx), arg); + if (!ret) { + auto rb = ctx.range().reset_to_rollback_point(); + if (!rb) { + return rb; + } + return ret; + } + // Handle next arg and bump pctx + pctx.arg_handled(); + if (pctx) { + auto e = pctx.advance_cp(); + if (!e) { + return e; + } + } + } + } + if (pctx) { + // Format string not exhausted + return {error::invalid_format_string, + "Format string not exhausted"}; + } + ctx.range().set_rollback_point(); + return {}; + } + + SCN_END_NAMESPACE +} // namespace scn + +#endif // SCN_DETAIL_VISITOR_H diff --git a/src/third-party/scnlib/include/scn/fwd.h b/src/third-party/scnlib/include/scn/fwd.h new file mode 100644 index 0000000..e91a258 --- /dev/null +++ b/src/third-party/scnlib/include/scn/fwd.h @@ -0,0 +1,23 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_FWD_H +#define SCN_FWD_H + +#include "detail/fwd.h" + +#endif // SCN_FWD_H diff --git a/src/third-party/scnlib/include/scn/istream.h b/src/third-party/scnlib/include/scn/istream.h new file mode 100644 index 0000000..acb2774 --- /dev/null +++ b/src/third-party/scnlib/include/scn/istream.h @@ -0,0 +1,23 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_ISTREAM_H +#define SCN_ISTREAM_H + +#include "scan/istream.h" + +#endif // SCN_ISTREAM_H diff --git a/src/third-party/scnlib/include/scn/ranges/custom_impl.h b/src/third-party/scnlib/include/scn/ranges/custom_impl.h new file mode 100644 index 0000000..86d73d5 --- /dev/null +++ b/src/third-party/scnlib/include/scn/ranges/custom_impl.h @@ -0,0 +1,1632 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib +// +// The contents of this file are adapted from NanoRange. +// https://github.com/tcbrindle/NanoRange +// Copyright (c) 2018 Tristan Brindle +// Distributed under the Boost Software License, Version 1.0 + +#ifndef SCN_RANGES_CUSTOM_IMPL_H +#define SCN_RANGES_CUSTOM_IMPL_H + +#include "util.h" + +#include "../util/string_view.h" + +#include +#include + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace custom_ranges { + // iterator_category is span.h + + template + struct iterator_category; + + namespace detail { + template + struct iterator_category { + }; + template + struct iterator_category + : std::enable_if::value, + contiguous_iterator_tag> { + }; + template + struct iterator_category : iterator_category { + }; + template + struct iterator_category< + T, + detail::void_t> { + using type = typename T::iterator_category; + }; + } // namespace detail + + template + struct iterator_category : detail::iterator_category { + }; + template + using iterator_category_t = typename iterator_category::type; + + template + using iter_reference_t = decltype(*SCN_DECLVAL(T&)); + + // iter_difference_t + template + struct incrementable_traits; + + namespace detail { + struct empty { + }; + + template + struct with_difference_type { + using difference_type = T; + }; + template + struct incrementable_traits_helper { + }; + + template <> + struct incrementable_traits_helper { + }; + template + struct incrementable_traits_helper + : std::conditional::value, + with_difference_type, + empty>::type { + }; + template + struct incrementable_traits_helper + : incrementable_traits::type> { + }; + + template + struct has_member_difference_type : std::false_type { + }; + template + struct has_member_difference_type< + T, + detail::void_t> : std::true_type { + }; + + template + struct incrementable_traits_helper< + T, + typename std::enable_if< + has_member_difference_type::value>::type> { + using difference_type = typename T::difference_type; + }; + template + struct incrementable_traits_helper< + T, + typename std::enable_if< + !std::is_pointer::value && + !has_member_difference_type::value && + std::is_integral::value>:: + type> + : with_difference_type::type> { + }; + } // namespace detail + + template + struct incrementable_traits : detail::incrementable_traits_helper { + }; + + template + using iter_difference_t = + typename incrementable_traits::difference_type; + + // iter_value_t + template + struct readable_traits; + + namespace detail { + template + struct with_value_type { + using value_type = T; + }; + template + struct readable_traits_helper { + }; + + template + struct readable_traits_helper + : std::conditional< + std::is_object::value, + with_value_type::type>, + empty>::type { + }; + + template + struct readable_traits_helper< + I, + typename std::enable_if::value>::type> + : readable_traits::type> { + }; + + template + struct readable_traits_helper< + const I, + typename std::enable_if::value>::type> + : readable_traits::type> { + }; + + template + struct member_value_type + : std::conditional::value, + with_value_type, + empty>::type { + }; + + template + struct _member_element_type + : std::conditional< + std::is_object::value, + with_value_type::type>, + empty>::type { + }; + + template + using member_value_type_t = typename T::value_type; + + template + struct has_member_value_type : exists { + }; + + template + using member_element_type_t = typename T::element_type; + + template + struct has_member_element_type : exists { + }; + + template + struct readable_traits_helper< + T, + typename std::enable_if< + has_member_value_type::value && + !has_member_element_type::value>::type> + : member_value_type { + }; + + template + struct readable_traits_helper< + T, + typename std::enable_if::value && + !has_member_value_type::value>::type> + : _member_element_type { + }; + + template + struct readable_traits_helper< + T, + typename std::enable_if< + has_member_element_type::value && + has_member_value_type::value>::type> { + }; + } // namespace detail + + template + struct readable_traits : detail::readable_traits_helper { + }; + + template + using iter_value_t = typename readable_traits::value_type; + + // sentinel_for + namespace detail { + struct sentinel_for_concept { + template + auto _test_requires(S s, I i) + -> decltype(scn::detail::valid_expr(*i, i == s, i != s)); + }; + } // namespace detail + template + struct sentinel_for + : std::integral_constant< + bool, + std::is_default_constructible::value && + std::is_copy_constructible::value && + detail::_requires:: + value> { + }; + + // sized_sentinel_for + namespace detail { + struct sized_sentinel_for_concept { + template + auto _test_requires(const S& s, const I& i) -> decltype( + detail::requires_expr< + std::is_same>::value>{}, + detail::requires_expr< + std::is_same>::value>{}); + }; + } // namespace detail + template + struct sized_sentinel_for + : std::integral_constant< + bool, + detail::_requires:: + value && + sentinel_for::value> { + }; + template + struct sized_sentinel_for : std::false_type { + }; + template + struct sized_sentinel_for : std::false_type { + }; + template <> + struct sized_sentinel_for : std::false_type { + }; + + // begin + namespace _begin { + template + void begin(T&&) = delete; + template + void begin(std::initializer_list&&) = delete; + + struct fn { + private: + template + static SCN_CONSTEXPR14 void impl(T(&&)[N], + detail::priority_tag<3>) = + delete; + + template + static SCN_CONSTEXPR14 auto impl( + T (&t)[N], + detail::priority_tag<3>) noexcept -> decltype((t) + 0) + { + return (t) + 0; + } + + template + static SCN_CONSTEXPR14 auto impl( + basic_string_view sv, + detail::priority_tag<2>) noexcept -> decltype(sv.begin()) + { + return sv.begin(); + } + + template + static SCN_CONSTEXPR14 auto + impl(T& t, detail::priority_tag<1>) noexcept(noexcept( + ::scn::custom_ranges::detail::decay_copy(t.begin()))) + -> decltype(::scn::custom_ranges::detail::decay_copy( + t.begin())) + { + return ::scn::custom_ranges::detail::decay_copy(t.begin()); + } + + template + static SCN_CONSTEXPR14 auto + impl(T&& t, detail::priority_tag<0>) noexcept( + noexcept(::scn::custom_ranges::detail::decay_copy( + begin(SCN_FWD(t))))) + -> decltype(::scn::custom_ranges::detail::decay_copy( + begin(SCN_FWD(t)))) + { + return ::scn::custom_ranges::detail::decay_copy( + begin(SCN_FWD(t))); + } + + public: + template + SCN_CONSTEXPR14 auto operator()(T&& t) const noexcept( + noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<3>{}))) + -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<3>{})) + { + return fn::impl(SCN_FWD(t), detail::priority_tag<3>{}); + } + }; + } // namespace _begin + namespace { + constexpr auto& begin = detail::static_const<_begin::fn>::value; + } + + // end + namespace _end { + template + void end(T&&) = delete; + template + void end(std::initializer_list&&) = delete; + + struct fn { + private: + template + static constexpr void impl(T(&&)[N], + detail::priority_tag<2>) = delete; + + template + static constexpr auto impl(T (&t)[N], + detail::priority_tag<2>) noexcept + -> decltype((t) + N) + { + return (t) + N; + } + + template + static constexpr auto impl(basic_string_view sv, + detail::priority_tag<2>) noexcept + -> decltype(sv.end()) + { + return sv.end(); + } + + SCN_GCC_PUSH + SCN_GCC_IGNORE("-Wnoexcept") + template + static constexpr auto + impl(T& t, detail::priority_tag<1>) noexcept( + noexcept(::scn::custom_ranges::detail::decay_copy(t.end()))) + -> decltype(::scn::custom_ranges::detail::decay_copy( + t.end())) + { + return ::scn::custom_ranges::detail::decay_copy(t.end()); + } + + template + static constexpr auto + impl(T& t, detail::priority_tag<0>) noexcept(noexcept( + ::scn::custom_ranges::detail::decay_copy(end(SCN_FWD(t))))) + -> S + { + return ::scn::custom_ranges::detail::decay_copy( + end(SCN_FWD(t))); + } + + public: + template + constexpr auto operator()(T&& t) const noexcept( + noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<2>{}))) + -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<2>{})) + { + return fn::impl(SCN_FWD(t), detail::priority_tag<2>{}); + } + SCN_GCC_POP + }; + } // namespace _end + namespace { + constexpr auto& end = detail::static_const<_end::fn>::value; + } + + // cbegin + namespace _cbegin { + struct fn { + template + constexpr auto operator()(const T& t) const + noexcept(noexcept(::scn::custom_ranges::begin(t))) + -> decltype(::scn::custom_ranges::begin(t)) + { + return ::scn::custom_ranges::begin(t); + } + + template + constexpr auto operator()(const T&& t) const noexcept(noexcept( + ::scn::custom_ranges::begin(static_cast(t)))) + -> decltype(::scn::custom_ranges::begin( + static_cast(t))) + { + return ::scn::custom_ranges::begin( + static_cast(t)); + } + }; + } // namespace _cbegin + namespace { + constexpr auto& cbegin = detail::static_const<_cbegin::fn>::value; + } + + // cend + namespace _cend { + struct fn { + template + constexpr auto operator()(const T& t) const + noexcept(noexcept(::scn::custom_ranges::end(t))) + -> decltype(::scn::custom_ranges::end(t)) + { + return ::scn::custom_ranges::end(t); + } + + template + constexpr auto operator()(const T&& t) const noexcept(noexcept( + ::scn::custom_ranges::end(static_cast(t)))) + -> decltype(::scn::custom_ranges::end( + static_cast(t))) + { + return ::scn::custom_ranges::end(static_cast(t)); + } + }; + } // namespace _cend + namespace { + constexpr auto& cend = detail::static_const<_cend::fn>::value; + } + + // range + namespace detail { + struct range_impl_concept { + template + auto _test_requires(T&& t) + -> decltype(::scn::custom_ranges::begin(SCN_FWD(t)), + ::scn::custom_ranges::end(SCN_FWD(t))); + }; + template + struct range_impl : _requires { + }; + struct range_concept { + template + static auto test(long) -> std::false_type; + template + static auto test(int) -> + typename std::enable_if::value, + std::true_type>::type; + }; + } // namespace detail + template + struct range : decltype(detail::range_concept::test(0)) { + }; + + template + struct forwarding_range + : std::integral_constant::value && + detail::range_impl::value> { + }; + + // typedefs + template + using iterator_t = + typename std::enable_if::value, + decltype(::scn::custom_ranges::begin( + SCN_DECLVAL(R&)))>::type; + template + using sentinel_t = + typename std::enable_if::value, + decltype(::scn::custom_ranges::end( + SCN_DECLVAL(R&)))>::type; + template + using range_difference_t = + typename std::enable_if::value, + iter_difference_t>>::type; + template + using range_value_t = + typename std::enable_if::value, + iter_value_t>>::type; + template + using range_reference_t = + typename std::enable_if::value, + iter_reference_t>>::type; + + // view + struct view_base { + }; + + namespace detail { + template + struct is_std_non_view : std::false_type { + }; + template + struct is_std_non_view> : std::true_type { + }; + template + struct enable_view_helper + : std::conditional< + std::is_base_of::value, + std::true_type, + typename std::conditional< + is_std_non_view::value, + std::false_type, + typename std::conditional< + range::value && range::value, + std::is_same, + range_reference_t>, + std::true_type>::type>::type>::type { + }; + template + struct view_impl + : std::integral_constant< + bool, + std::is_copy_constructible::value && + std::is_default_constructible::value && + detail::enable_view_helper::value> { + }; + } // namespace detail + template + struct view : std::conditional::value, + detail::view_impl, + std::false_type>::type { + }; + + // data + template + struct _is_object_pointer + : std::integral_constant< + bool, + std::is_pointer

::value && + std::is_object>::value> { + }; + + namespace _data { + struct fn { + private: + template + static constexpr auto impl( + std::basic_string& str, + detail::priority_tag<2>) noexcept -> typename std:: + basic_string::pointer + { + return std::addressof(*str.begin()); + } + template + static constexpr auto impl( + const std::basic_string& str, + detail::priority_tag<2>) noexcept -> typename std:: + basic_string::const_pointer + { + return std::addressof(*str.begin()); + } + template + static constexpr auto impl( + std::basic_string&& str, + detail::priority_tag<2>) noexcept -> typename std:: + basic_string::pointer + { + return std::addressof(*str.begin()); + } + + template + static constexpr auto + impl(T& t, detail::priority_tag<1>) noexcept(noexcept( + ::scn::custom_ranges::detail::decay_copy(t.data()))) -> + typename std::enable_if<_is_object_pointer::value, + D>::type + { + return ::scn::custom_ranges::detail::decay_copy(t.data()); + } + + template + static constexpr auto + impl(T&& t, detail::priority_tag<0>) noexcept( + noexcept(::scn::custom_ranges::begin(SCN_FWD(t)))) -> + typename std::enable_if< + _is_object_pointer::value, + decltype(::scn::custom_ranges::begin(SCN_FWD(t)))>::type + { + return ::scn::custom_ranges::begin(SCN_FWD(t)); + } + + public: + template + constexpr auto operator()(T&& t) const noexcept( + noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<2>{}))) + -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<2>{})) + { + return fn::impl(SCN_FWD(t), detail::priority_tag<2>{}); + } + }; + } // namespace _data + namespace { + constexpr auto& data = detail::static_const<_data::fn>::value; + } + + // size + template + struct disable_sized_range : std::false_type { + }; + + namespace _size { + template + void size(T&&) = delete; + template + void size(T&) = delete; + + struct fn { + private: + template + static constexpr std::size_t impl( + const T(&&)[N], + detail::priority_tag<3>) noexcept + { + return N; + } + + template + static constexpr std::size_t impl( + const T (&)[N], + detail::priority_tag<3>) noexcept + { + return N; + } + + template + static constexpr auto + impl(T&& t, detail::priority_tag<2>) noexcept( + noexcept(::scn::custom_ranges::detail::decay_copy( + SCN_FWD(t).size()))) -> + typename std::enable_if< + std::is_integral::value && + !disable_sized_range< + detail::remove_cvref_t>::value, + I>::type + { + return ::scn::custom_ranges::detail::decay_copy( + SCN_FWD(t).size()); + } + + template + static constexpr auto + impl(T&& t, detail::priority_tag<1>) noexcept(noexcept( + ::scn::custom_ranges::detail::decay_copy(size(SCN_FWD(t))))) + -> typename std::enable_if< + std::is_integral::value && + !disable_sized_range< + detail::remove_cvref_t>::value, + I>::type + { + return ::scn::custom_ranges::detail::decay_copy( + size(SCN_FWD(t))); + } + + template + static constexpr auto + impl(T&& t, detail::priority_tag<0>) noexcept( + noexcept(::scn::custom_ranges::detail::decay_copy( + ::scn::custom_ranges::end(t) - + ::scn::custom_ranges::begin(t)))) -> + typename std::enable_if< + !std::is_array>::value, + D>::type + { + return ::scn::custom_ranges::detail::decay_copy( + ::scn::custom_ranges::end(t) - + ::scn::custom_ranges::begin(t)); + } + + public: + template + constexpr auto operator()(T&& t) const noexcept( + noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<3>{}))) + -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<3>{})) + { + return fn::impl(SCN_FWD(t), detail::priority_tag<3>{}); + } + }; + } // namespace _size + namespace { + constexpr auto& size = detail::static_const<_size::fn>::value; + } + + // empty + namespace _empty_ns { + struct fn { + private: + template + static constexpr auto + impl(T&& t, detail::priority_tag<2>) noexcept( + noexcept((bool(SCN_FWD(t).empty())))) + -> decltype((bool(SCN_FWD(t).empty()))) + { + return bool((SCN_FWD(t).empty())); + } + template + static constexpr auto + impl(T&& t, detail::priority_tag<1>) noexcept( + noexcept(::scn::custom_ranges::size(SCN_FWD(t)) == 0)) + -> decltype(::scn::custom_ranges::size(SCN_FWD(t)) == 0) + { + return ::scn::custom_ranges::size(SCN_FWD(t)) == 0; + } + + template + static constexpr auto + impl(T&& t, detail::priority_tag<0>) noexcept( + noexcept(::scn::custom_ranges::begin(t) == + ::scn::custom_ranges::end(t))) + -> decltype(::scn::custom_ranges::begin(t) == + ::scn::custom_ranges::end(t)) + { + return ::scn::custom_ranges::begin(t) == + ::scn::custom_ranges::end(t); + } + + public: + template + constexpr auto operator()(T&& t) const noexcept( + noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<2>{}))) + -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<2>{})) + { + return fn::impl(SCN_FWD(t), detail::priority_tag<2>{}); + } + }; + } // namespace _empty_ns + namespace { + constexpr auto& empty = detail::static_const<_empty_ns::fn>::value; + } + + // sized_range + namespace detail { + struct sized_range_concept { + template + auto _test_requires(T& t) + -> decltype(::scn::custom_ranges::size(t)); + }; + } // namespace detail + template + struct sized_range + : std::integral_constant< + bool, + range::value && + !disable_sized_range>::value && + detail::_requires::value> { + }; + + // contiguous_range + namespace detail { + struct contiguous_range_concept { + template + static auto test(long) -> std::false_type; + template + static auto test(int) -> typename std::enable_if< + _requires::value, + std::true_type>::type; + + template + auto _test_requires(T& t) + -> decltype(requires_expr>::type>::value>{}); + }; + } // namespace detail + template + struct contiguous_range + : decltype(detail::contiguous_range_concept::test(0)) { + }; + + // subrange + template + class view_interface : public view_base { + static_assert(std::is_class::value, ""); + static_assert( + std::is_same::type>::value, + ""); + + private: + SCN_CONSTEXPR14 D& derived() noexcept + { + return static_cast(*this); + } + constexpr D& derived() const noexcept + { + return static_cast(*this); + } + + public: + SCN_NODISCARD SCN_CONSTEXPR14 bool empty() + { + return ::scn::custom_ranges::begin(derived()) == + ::scn::custom_ranges::end(derived()); + } + SCN_NODISCARD constexpr bool empty() const + { + return ::scn::custom_ranges::begin(derived()) == + ::scn::custom_ranges::end(derived()); + } + + template + SCN_CONSTEXPR14 explicit operator bool() + { + return !::scn::custom_ranges::empty(derived()); + } + template + constexpr explicit operator bool() const + { + return !::scn::custom_ranges::empty(derived()); + } + + template ::value>::type* = nullptr> + auto data() -> decltype(std::addressof( + *::scn::custom_ranges::begin(static_cast(*this)))) + { + return ::scn::custom_ranges::empty(derived()) + ? nullptr + : std::addressof( + *::scn::custom_ranges::begin(derived())); + } + template ::value>::type* = nullptr> + auto data() const -> decltype(std::addressof( + *::scn::custom_ranges::begin(static_cast(*this)))) + { + return ::scn::custom_ranges::empty(derived()) + ? nullptr + : std::addressof( + *::scn::custom_ranges::begin(derived())); + } + + template ::value && + sized_sentinel_for, iterator_t>:: + value>::type* = nullptr> + SCN_CONSTEXPR14 auto size() + -> decltype(::scn::custom_ranges::end(static_cast(*this)) - + ::scn::custom_ranges::begin(static_cast(*this))) + { + return ::scn::custom_ranges::end(derived()) - + ::scn::custom_ranges::begin(derived()); + } + + template < + typename R = D, + typename std::enable_if< + range::value && + sized_sentinel_for, + iterator_t>::value>::type* = + nullptr> + constexpr auto size() const + -> decltype(::scn::custom_ranges::end( + static_cast(*this)) - + ::scn::custom_ranges::begin( + static_cast(*this))) + { + return ::scn::custom_ranges::end(derived()) - + ::scn::custom_ranges::begin(derived()); + } + }; + + enum class subrange_kind : bool { unsized, sized }; + + namespace detail { + template + struct default_subrange_kind + : std::integral_constant::value + ? subrange_kind::sized + : subrange_kind::unsized> { + }; + } // namespace detail + + namespace _subrange { + template ::value> + class subrange; + } // namespace _subrange + + using _subrange::subrange; + + namespace detail { + struct pair_like_concept { + template + static auto test(long) -> std::false_type; + template ::type> + static auto test(int) -> typename std::enable_if< + _requires::value, + std::true_type>::type; + + template + auto _test_requires(T t) -> decltype( + requires_expr< + std::is_base_of, + std::tuple_size>::value>{}, + std::declval::type>>(), + std::declval::type>>(), + requires_expr(t)), + const std::tuple_element<0, T>&>::value>{}, + requires_expr(t)), + const std::tuple_element<1, T>&>::value>{}); + }; + template + struct pair_like + : std::integral_constant< + bool, + !std::is_reference::value && + decltype(pair_like_concept::test(0))::value> { + }; + + struct pair_like_convertible_to_concept { + template + auto _test_requires(T&& t) -> decltype( + requires_expr< + std::is_convertible(SCN_FWD(t))), + U>::value>{}, + requires_expr< + std::is_convertible(SCN_FWD(t))), + V>::value>{}); + }; + template + struct pair_like_convertible_to + : std::integral_constant< + bool, + !range::value && + pair_like< + typename std::remove_reference::type>::value && + _requires:: + value> { + }; + template + struct pair_like_convertible_from + : std::integral_constant< + bool, + !range::value && + pair_like< + typename std::remove_reference::type>::value && + std::is_constructible::value> { + }; + + struct iterator_sentinel_pair_concept { + template + static auto test(long) -> std::false_type; + template + static auto test(int) -> typename std::enable_if< + !range::value && pair_like::value && + sentinel_for< + typename std::tuple_element<1, T>::type, + typename std::tuple_element<0, T>::type>::value, + std::true_type>::type; + }; + template + struct iterator_sentinel_pair + : decltype(iterator_sentinel_pair_concept::test(0)) { + }; + + template + struct subrange_data { + constexpr subrange_data() = default; + constexpr subrange_data(I&& b, S&& e) + : begin(SCN_MOVE(b)), end(SCN_MOVE(e)) + { + } + template + constexpr subrange_data( + I&& b, + S&& e, + typename std::enable_if>::type) + : begin(SCN_MOVE(b)), end(SCN_MOVE(e)) + { + } + + constexpr iter_difference_t get_size() const + { + return distance(begin, end); + } + + I begin{}; + S end{}; + }; + + template + struct subrange_data { + constexpr subrange_data() = default; + constexpr subrange_data(I&& b, S&& e, iter_difference_t s) + : begin(SCN_MOVE(b)), end(SCN_MOVE(e)), size(s) + { + } + + constexpr iter_difference_t get_size() const + { + return size; + } + + I begin{}; + S end{}; + iter_difference_t size{0}; + }; + + template + auto subrange_range_constructor_constraint_helper_fn(long) + -> std::false_type; + + template + auto subrange_range_constructor_constraint_helper_fn(int) -> + typename std::enable_if< + forwarding_range::value && + std::is_convertible, I>::value && + std::is_convertible, S>::value, + std::true_type>::type; + + template + struct subrange_range_constructor_constraint_helper + : decltype(subrange_range_constructor_constraint_helper_fn( + 0)) { + }; + + template + constexpr subrange_kind subrange_deduction_guide_helper() + { + return (sized_range::value || + sized_sentinel_for, iterator_t>::value) + ? subrange_kind::sized + : subrange_kind::unsized; + } + + template + struct not_same_as : std::integral_constant< + bool, + !std::is_same, + remove_cvref_t>::value> { + }; + } // namespace detail + + namespace _subrange { + template + class subrange : public view_interface> { + static_assert(sentinel_for::value, ""); + static_assert(K == subrange_kind::sized || + !sized_sentinel_for::value, + ""); + + static constexpr bool _store_size = + K == subrange_kind::sized && + !sized_sentinel_for::value; + + public: + using iterator = I; + using sentinel = S; + + subrange() = default; + + template ::type* = nullptr> + SCN_CONSTEXPR14 subrange(I i, S s) + : m_data{SCN_MOVE(i), SCN_MOVE(s)} + { + } + template ::type* = nullptr> + SCN_CONSTEXPR14 subrange( + I i, + S s, + typename std::enable_if>::type n) + : m_data{SCN_MOVE(i), SCN_MOVE(s), n} + { + } + + constexpr I begin() const noexcept + { + return m_data.begin; + } + + constexpr S end() const noexcept + { + return m_data.end; + } + + SCN_NODISCARD constexpr bool empty() const noexcept + { + return m_data.begin == m_data.end; + } + + template ::type* = nullptr> + constexpr iter_difference_t size() const noexcept + { + return m_data.get_size(); + } + + private: + detail::subrange_data m_data{}; + }; + + template + I begin(subrange&& r) noexcept + { + return r.begin(); + } + template + S end(subrange&& r) noexcept + { + return r.end(); + } + } // namespace _subrange + + namespace detail { + template + struct subrange_get_impl; + template <> + struct subrange_get_impl<0> { + template + static auto get(const subrange& s) + -> decltype(s.begin()) + { + return s.begin(); + } + }; + template <> + struct subrange_get_impl<1> { + template + static auto get(const subrange& s) -> decltype(s.end()) + { + return s.end(); + } + }; + } // namespace detail + + template ::type* = nullptr> + auto get(const subrange& s) + -> decltype(detail::subrange_get_impl::get(s)) + { + return detail::subrange_get_impl::get(s); + } + + // reconstructible_range + template + struct pair_reconstructible_range + : std::integral_constant< + bool, + range::value && + forwarding_range< + typename std::remove_reference::type>::value && + std::is_constructible, sentinel_t>:: + value> { + }; + template + struct reconstructible_range + : std::integral_constant< + bool, + range::value && + forwarding_range< + typename std::remove_reference::type>::value && + std::is_constructible< + R, + subrange, sentinel_t>>::value> { + }; + } // namespace custom_ranges + + namespace polyfill_2a { + // bidir iterator + namespace detail { + struct bidirectional_iterator_concept { + template + auto _test_requires(I i) + -> decltype(custom_ranges::detail::requires_expr< + std::is_same::value>{}); + template + static auto test(long) -> std::false_type; + template + static auto test(int) -> typename std::enable_if< + std::is_base_of< + custom_ranges::bidirectional_iterator_tag, + custom_ranges::iterator_category_t>::value && + custom_ranges::detail:: + _requires::value, + std::true_type>::type; + }; + } // namespace detail + template + struct bidirectional_iterator + : decltype(detail::bidirectional_iterator_concept::test(0)) { + }; + + // random access iterator + namespace detail { + struct random_access_iterator_concept { + template + auto _test_requires(I i, + const I j, + const custom_ranges::iter_difference_t n) + -> decltype(valid_expr( + j + n, + custom_ranges::detail::requires_expr< + std::is_same::value>{}, + n + j, +#ifndef _MSC_VER + custom_ranges::detail::requires_expr< + std::is_same::value>{}, +#endif + j - n, + custom_ranges::detail::requires_expr< + std::is_same::value>{}, + j[n], + custom_ranges::detail::requires_expr>::value>{}, + custom_ranges::detail::requires_expr< + std::is_convertible::value>{})); + template + static auto test(long) -> std::false_type; + template + static auto test(int) -> typename std::enable_if< + bidirectional_iterator::value && + std::is_base_of< + custom_ranges::random_access_iterator_tag, + custom_ranges::iterator_category_t>::value && + custom_ranges::sized_sentinel_for::value && + custom_ranges::detail:: + _requires::value, + std::true_type>::type; + }; + } // namespace detail + template + struct random_access_iterator + : decltype(detail::random_access_iterator_concept::test(0)) { + }; + } // namespace polyfill_2a + + namespace custom_ranges { + // advance + namespace _advance { + struct fn { + private: + template + static constexpr T abs(T t) + { + return t < T{0} ? -t : t; + } + + template < + typename R, + typename std::enable_if::value>::type* = nullptr> + static SCN_CONSTEXPR14 void impl(R& r, iter_difference_t n) + { + r += n; + } + + template < + typename I, + typename std::enable_if< + polyfill_2a::bidirectional_iterator::value && + !polyfill_2a::random_access_iterator::value>::type* = + nullptr> + static SCN_CONSTEXPR14 void impl(I& i, iter_difference_t n) + { + constexpr auto zero = iter_difference_t{0}; + + if (n > zero) { + while (n-- > zero) { + ++i; + } + } + else { + while (n++ < zero) { + --i; + } + } + } + + template < + typename I, + typename std::enable_if< + !polyfill_2a::bidirectional_iterator::value>::type* = + nullptr> + static SCN_CONSTEXPR14 void impl(I& i, iter_difference_t n) + { + while (n-- > iter_difference_t{0}) { + ++i; + } + } + + template < + typename I, + typename S, + typename std::enable_if< + std::is_assignable::value>::type* = nullptr> + static SCN_CONSTEXPR14 void impl(I& i, + S bound, + detail::priority_tag<2>) + { + i = SCN_MOVE(bound); + } + + template ::value>::type* = nullptr> + static SCN_CONSTEXPR14 void impl(I& i, + S bound, + detail::priority_tag<1>) + { + fn::impl(i, bound - i); + } + + template + static SCN_CONSTEXPR14 void impl(I& i, + S bound, + detail::priority_tag<0>) + { + while (i != bound) { + ++i; + } + } + + template ::value>::type* = nullptr> + static SCN_CONSTEXPR14 auto impl(I& i, + iter_difference_t n, + S bound) + -> iter_difference_t + { + if (fn::abs(n) >= fn::abs(bound - i)) { + auto dist = bound - i; + fn::impl(i, bound, detail::priority_tag<2>{}); + return dist; + } + else { + fn::impl(i, n); + return n; + } + } + + template < + typename I, + typename S, + typename std::enable_if< + polyfill_2a::bidirectional_iterator::value && + !sized_sentinel_for::value>::type* = nullptr> + static SCN_CONSTEXPR14 auto impl(I& i, + iter_difference_t n, + S bound) + -> iter_difference_t + { + constexpr iter_difference_t zero{0}; + iter_difference_t counter{0}; + + if (n < zero) { + do { + --i; + --counter; + } while (++n < zero && i != bound); + } + else { + while (n-- > zero && i != bound) { + ++i; + ++counter; + } + } + + return counter; + } + + template < + typename I, + typename S, + typename std::enable_if< + !polyfill_2a::bidirectional_iterator::value && + !sized_sentinel_for::value>::type* = nullptr> + static SCN_CONSTEXPR14 auto impl(I& i, + iter_difference_t n, + S bound) + -> iter_difference_t + { + constexpr iter_difference_t zero{0}; + iter_difference_t counter{0}; + + while (n-- > zero && i != bound) { + ++i; + ++counter; + } + + return counter; + } + + public: + template + SCN_CONSTEXPR14 void operator()(I& i, + iter_difference_t n) const + { + fn::impl(i, n); + } + + template ::value>::type* = nullptr> + SCN_CONSTEXPR14 void operator()(I& i, S bound) const + { + fn::impl(i, bound, detail::priority_tag<2>{}); + } + + template ::value>::type* = nullptr> + SCN_CONSTEXPR14 iter_difference_t + operator()(I& i, iter_difference_t n, S bound) const + { + return n - fn::impl(i, n, bound); + } + }; + } // namespace _advance + namespace { + constexpr auto& advance = detail::static_const<_advance::fn>::value; + } + + // distance + SCN_GCC_PUSH + SCN_GCC_IGNORE("-Wnoexcept") + namespace _distance { + struct fn { + private: + template + static SCN_CONSTEXPR14 auto impl(I i, + S s) noexcept(noexcept(s - i)) + -> typename std::enable_if::value, + iter_difference_t>::type + { + return s - i; + } + + template + static SCN_CONSTEXPR14 auto impl(I i, S s) noexcept( + noexcept(i != s, ++i, ++SCN_DECLVAL(iter_difference_t&))) + -> typename std::enable_if::value, + iter_difference_t>::type + { + iter_difference_t counter{0}; + while (i != s) { + ++i; + ++counter; + } + return counter; + } + + template + static SCN_CONSTEXPR14 auto impl(R&& r) noexcept( + noexcept(::scn::custom_ranges::size(r))) -> + typename std::enable_if< + sized_range::value, + iter_difference_t>>::type + { + return static_cast>>( + ::scn::custom_ranges::size(r)); + } + + template + static SCN_CONSTEXPR14 auto impl(R&& r) noexcept( + noexcept(fn::impl(::scn::custom_ranges::begin(r), + ::scn::custom_ranges::end(r)))) -> + typename std::enable_if< + !sized_range::value, + iter_difference_t>>::type + { + return fn::impl(::scn::custom_ranges::begin(r), + ::scn::custom_ranges::end(r)); + } + + public: + template + SCN_CONSTEXPR14 auto operator()(I first, S last) const + noexcept(noexcept(fn::impl(SCN_MOVE(first), + SCN_MOVE(last)))) -> + typename std::enable_if::value, + iter_difference_t>::type + { + return fn::impl(SCN_MOVE(first), SCN_MOVE(last)); + } + + template + SCN_CONSTEXPR14 auto operator()(R&& r) const + noexcept(noexcept(fn::impl(SCN_FWD(r)))) -> + typename std::enable_if< + range::value, + iter_difference_t>>::type + { + return fn::impl(SCN_FWD(r)); + } + }; + } // namespace _distance + namespace { + constexpr auto& distance = + detail::static_const<_distance::fn>::value; + } + SCN_GCC_POP // -Wnoexcept + } // namespace custom_ranges + + namespace polyfill_2a { + template + using iter_value_t = ::scn::custom_ranges::iter_value_t; + template + using iter_reference_t = ::scn::custom_ranges::iter_reference_t; + template + using iter_difference_t = ::scn::custom_ranges::iter_difference_t; + } // namespace polyfill_2a + + SCN_END_NAMESPACE +} // namespace scn + +namespace std { + template + struct tuple_size<::scn::custom_ranges::subrange> + : public integral_constant { + }; + + template + struct tuple_element<0, ::scn::custom_ranges::subrange> { + using type = I; + }; + template + struct tuple_element<1, ::scn::custom_ranges::subrange> { + using type = S; + }; + + using ::scn::custom_ranges::get; +} // namespace std + +#define SCN_CHECK_CONCEPT(C) C::value + +#endif // SCN_RANGES_CUSTOM_IMPL_H diff --git a/src/third-party/scnlib/include/scn/ranges/ranges.h b/src/third-party/scnlib/include/scn/ranges/ranges.h new file mode 100644 index 0000000..aa70f50 --- /dev/null +++ b/src/third-party/scnlib/include/scn/ranges/ranges.h @@ -0,0 +1,49 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_RANGES_RANGES_H +#define SCN_RANGES_RANGES_H + +#include "../detail/config.h" + +#ifndef SCN_USE_STD_RANGES + +#if SCN_HAS_CONCEPTS && SCN_HAS_RANGES +#define SCN_USE_STD_RANGES 1 +#else +#define SCN_USE_STD_RANGES 0 +#endif + +#endif // !defined(SCN_USE_STD_RANGES) + +#if SCN_USE_STD_RANGES +#include "std_impl.h" +#define SCN_RANGES_NAMESPACE ::scn::std_ranges +#else +#include "custom_impl.h" +#define SCN_RANGES_NAMESPACE ::scn::custom_ranges +#endif + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace ranges = SCN_RANGES_NAMESPACE; + + SCN_END_NAMESPACE +} // namespace scn + +#endif // SCN_RANGES_RANGES_H diff --git a/src/third-party/scnlib/include/scn/ranges/std_impl.h b/src/third-party/scnlib/include/scn/ranges/std_impl.h new file mode 100644 index 0000000..abc3422 --- /dev/null +++ b/src/third-party/scnlib/include/scn/ranges/std_impl.h @@ -0,0 +1,67 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_RANGES_STD_IMPL_H +#define SCN_RANGES_STD_IMPL_H + +#include "../detail/config.h" + +#if SCN_HAS_CONCEPTS && SCN_HAS_RANGES + +SCN_GCC_PUSH +SCN_GCC_IGNORE("-Wnoexcept") +#include +#include +SCN_GCC_POP + +#include "util.h" + +#include "../util/string_view.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace std_ranges = ::std::ranges; + + namespace polyfill_2a { + template + using iter_value_t = ::std::iter_value_t; + template + using iter_reference_t = ::std::iter_reference_t; + template + using iter_difference_t = ::std::iter_difference_t; + + template + concept bidirectional_iterator = std::bidirectional_iterator; + template + concept random_access_iterator = std::random_access_iterator; + } // namespace polyfill_2a + + SCN_END_NAMESPACE +} // namespace scn + +namespace std::ranges { + template + inline constexpr bool enable_view<::scn::basic_string_view> = true; + template + inline constexpr bool enable_view<::scn::span> = true; +} // namespace std + +#define SCN_CHECK_CONCEPT(C) C +#endif + +#endif // SCN_RANGES_STD_IMPL_H diff --git a/src/third-party/scnlib/include/scn/ranges/util.h b/src/third-party/scnlib/include/scn/ranges/util.h new file mode 100644 index 0000000..d5954d1 --- /dev/null +++ b/src/third-party/scnlib/include/scn/ranges/util.h @@ -0,0 +1,419 @@ +// Copyright 2017 Elias Kosunen +// +// 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 +// +// https://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. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib +// +// The contents of this file are adapted from NanoRange. +// https://github.com/tcbrindle/NanoRange +// Copyright (c) 2018 Tristan Brindle +// Distributed under the Boost Software License, Version 1.0 + +#ifndef SCN_RANGES_UTIL_H +#define SCN_RANGES_UTIL_H + +#include "../util/meta.h" + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace custom_ranges { + namespace detail { + template + using priority_tag = ::scn::detail::priority_tag; + + template + using void_t = ::scn::detail::void_t; + + template + using static_const = ::scn::detail::static_const; + + template + using remove_cvref_t = ::scn::detail::remove_cvref_t; + + template + constexpr typename std::decay::type decay_copy(T&& t) noexcept( + noexcept(static_cast::type>(SCN_FWD(t)))) + { + return SCN_FWD(t); + } + + struct nonesuch { + nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch& operator=(const nonesuch&) = delete; + ~nonesuch() = delete; + }; + + template + class Trait, + typename... Args> + struct test { + using type = nonesuch; + }; + + template