From 62e4c68907d8d33709c2c1f92a161dff00b3d5f2 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 22:01:36 +0200 Subject: Adding upstream version 0.11.2. Signed-off-by: Daniel Baumann --- src/third-party/scnlib/include/scn/detail/args.h | 619 +++++++++++++++++++++++ 1 file changed, 619 insertions(+) create mode 100644 src/third-party/scnlib/include/scn/detail/args.h (limited to 'src/third-party/scnlib/include/scn/detail/args.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 -- cgit v1.2.3