summaryrefslogtreecommitdiffstats
path: root/src/third-party/scnlib/include/scn/detail/args.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/third-party/scnlib/include/scn/detail/args.h')
-rw-r--r--src/third-party/scnlib/include/scn/detail/args.h619
1 files changed, 619 insertions, 0 deletions
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 <string>
+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 <typename T>
+ 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<char> buffer(32, '\0');
+ * auto result = scn::scan("123", "{}", scn::temp(scn::make_span(buffer)));
+ * // buffer == "123"
+ * \endcode
+ */
+ template <typename T,
+ typename std::enable_if<
+ !std::is_lvalue_reference<T>::value>::type* = nullptr>
+ temporary<T> 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 <typename Context, typename ParseCtx, typename T>
+ error scan_custom_arg(void* arg, Context& ctx, ParseCtx& pctx) noexcept
+ {
+ return visitor_boilerplate<scanner<T>>(*static_cast<T*>(arg), ctx,
+ pctx);
+ }
+
+ struct monostate {
+ };
+
+ template <typename Ctx>
+ struct ctx_tag {
+ };
+ template <typename ParseCtx>
+ struct parse_ctx_tag {
+ };
+
+ class value {
+ public:
+ constexpr value() noexcept : m_empty{} {}
+
+ template <typename T>
+ explicit SCN_CONSTEXPR14 value(T& val) noexcept
+ : m_value(std::addressof(val))
+ {
+ }
+
+ template <typename Ctx, typename ParseCtx, typename T>
+ value(ctx_tag<Ctx>, parse_ctx_tag<ParseCtx>, T& val) noexcept
+ : m_custom(
+ custom_value{std::addressof(val),
+ reinterpret_cast<void (*)()>(
+ &scan_custom_arg<Ctx, ParseCtx, T>)})
+ {
+ }
+
+ template <typename T>
+ SCN_CONSTEXPR14 T& get_as() noexcept
+ {
+ return *static_cast<T*>(m_value);
+ }
+ template <typename T>
+ constexpr const T& get_as() const noexcept
+ {
+ return *static_cast<const T*>(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 <typename CharT, typename T, type Type>
+ struct init {
+ T* val;
+ static const type type_tag = Type;
+
+ constexpr init(T& v) : val(std::addressof(v)) {}
+ template <typename Ctx, typename ParseCtx>
+ SCN_CONSTEXPR14 value get()
+ {
+ SCN_EXPECT(val != nullptr);
+ return value{*val};
+ }
+ };
+ template <typename CharT, typename T>
+ struct init<CharT, T, custom_type> {
+ T* val;
+ static const type type_tag = custom_type;
+
+ constexpr init(T& v) : val(std::addressof(v)) {}
+ template <typename Ctx, typename ParseCtx>
+ SCN_CONSTEXPR14 value get()
+ {
+ SCN_EXPECT(val != nullptr);
+ return {ctx_tag<Ctx>{}, parse_ctx_tag<ParseCtx>{}, *val};
+ }
+ };
+
+ template <typename Context,
+ typename ParseCtx,
+ typename T,
+ typename CharT = typename Context::char_type>
+ SCN_CONSTEXPR14 basic_arg<CharT> make_arg(T& value) noexcept;
+
+#define SCN_MAKE_VALUE(Tag, Type) \
+ template <typename CharT> \
+ constexpr init<CharT, Type, Tag> 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<CharT>)
+ SCN_MAKE_VALUE(string_type, std::basic_string<CharT>)
+ SCN_MAKE_VALUE(string_view_type, basic_string_view<CharT>)
+
+ template <typename CharT>
+ constexpr init<CharT, CharT, char_type> make_value(
+ CharT& val,
+ priority_tag<1>) noexcept
+ {
+ return val;
+ }
+
+ template <typename CharT, typename T>
+ constexpr inline auto make_value(T& val, priority_tag<0>) noexcept
+ -> init<CharT, T, custom_type>
+ {
+ 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 <typename CharT>
+ class SCN_TRIVIAL_ABI basic_arg {
+ public:
+ using char_type = CharT;
+
+ class handle {
+ public:
+ explicit handle(detail::custom_value custom) : m_custom(custom) {}
+
+ template <typename Context, typename ParseCtx>
+ error scan(Context& ctx, ParseCtx& pctx)
+ {
+ return reinterpret_cast<error (*)(void*, Context&, ParseCtx&)>(
+ 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 <typename Ctx, typename ParseCtx, typename T, typename C>
+ friend SCN_CONSTEXPR14 basic_arg<C> detail::make_arg(T& value) noexcept;
+
+ template <typename C, typename Visitor>
+ friend SCN_CONSTEXPR14 error visit_arg(Visitor&& vis,
+ basic_arg<C>& arg);
+
+ friend class basic_args<CharT>;
+
+ detail::value m_value;
+ detail::type m_type{detail::none_type};
+ };
+
+ SCN_CLANG_POP
+
+ template <typename CharT, typename Visitor>
+ SCN_CONSTEXPR14 error visit_arg(Visitor&& vis, basic_arg<CharT>& arg)
+ {
+ switch (arg.m_type) {
+ case detail::none_type:
+ break;
+
+ case detail::schar_type:
+ return vis(arg.m_value.template get_as<signed char>());
+ case detail::short_type:
+ return vis(arg.m_value.template get_as<short>());
+ case detail::int_type:
+ return vis(arg.m_value.template get_as<int>());
+ case detail::long_type:
+ return vis(arg.m_value.template get_as<long>());
+ case detail::long_long_type:
+ return vis(arg.m_value.template get_as<long long>());
+
+ case detail::uchar_type:
+ return vis(arg.m_value.template get_as<unsigned char>());
+ case detail::ushort_type:
+ return vis(arg.m_value.template get_as<unsigned short>());
+ case detail::uint_type:
+ return vis(arg.m_value.template get_as<unsigned int>());
+ case detail::ulong_type:
+ return vis(arg.m_value.template get_as<unsigned long>());
+ case detail::ulong_long_type:
+ return vis(arg.m_value.template get_as<unsigned long long>());
+
+ case detail::bool_type:
+ return vis(arg.m_value.template get_as<bool>());
+ case detail::char_type:
+ return vis(arg.m_value.template get_as<CharT>());
+ case detail::code_point_type:
+ return vis(arg.m_value.template get_as<code_point>());
+
+ case detail::float_type:
+ return vis(arg.m_value.template get_as<float>());
+ case detail::double_type:
+ return vis(arg.m_value.template get_as<double>());
+ case detail::long_double_type:
+ return vis(arg.m_value.template get_as<long double>());
+
+ case detail::buffer_type:
+ return vis(arg.m_value.template get_as<span<CharT>>());
+ case detail::string_type:
+ return vis(
+ arg.m_value.template get_as<std::basic_string<CharT>>());
+ case detail::string_view_type:
+ return vis(
+ arg.m_value.template get_as<basic_string_view<CharT>>());
+
+ case detail::custom_type:
+ return vis(typename basic_arg<CharT>::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 <typename CharT, typename T>
+ struct get_type {
+ using value_type = decltype(make_value<CharT>(
+ SCN_DECLVAL(typename std::remove_reference<
+ typename std::remove_cv<T>::type>::type&),
+ SCN_DECLVAL(priority_tag<1>)));
+ static const type value = value_type::type_tag;
+ };
+
+ template <typename CharT>
+ constexpr size_t get_types()
+ {
+ return 0;
+ }
+ template <typename CharT, typename Arg, typename... Args>
+ constexpr size_t get_types()
+ {
+ return static_cast<size_t>(get_type<CharT, Arg>::value) |
+ (get_types<CharT, Args...>() << 5);
+ }
+
+ template <typename Context,
+ typename ParseCtx,
+ typename T,
+ typename CharT>
+ SCN_CONSTEXPR14 basic_arg<CharT> make_arg(T& value) noexcept
+ {
+ basic_arg<CharT> arg;
+ arg.m_type = get_type<CharT, T>::value;
+ arg.m_value = make_value<CharT>(value, priority_tag<1>{})
+ .template get<Context, ParseCtx>();
+ return arg;
+ }
+
+ template <bool Packed,
+ typename Context,
+ typename ParseCtx,
+ typename T,
+ typename CharT = typename Context::char_type>
+ inline auto make_arg(T& v) ->
+ typename std::enable_if<Packed, value>::type
+ {
+ return make_value<CharT>(v, priority_tag<1>{})
+ .template get<Context, ParseCtx>();
+ }
+ template <bool Packed, typename Context, typename ParseCtx, typename T>
+ inline auto make_arg(T& v) -> typename std::
+ enable_if<!Packed, basic_arg<typename Context::char_type>>::type
+ {
+ return make_arg<Context, ParseCtx>(v);
+ }
+ } // namespace detail
+
+ template <typename CharT, typename... Args>
+ 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<CharT>;
+
+ static constexpr size_t get_types()
+ {
+ return is_packed ? detail::get_types<CharT, Args...>()
+ : detail::is_unpacked_bit | num_args;
+ }
+
+ public:
+ static constexpr size_t types = get_types();
+ using arg_type = basic_arg<CharT>;
+
+ using value_type =
+ typename std::conditional<is_packed, detail::value, arg_type>::type;
+ static constexpr size_t data_size =
+ num_args + (is_packed && num_args != 0 ? 0 : 1);
+
+ template <typename Ctx, typename ParseCtx>
+ SCN_CONSTEXPR14 arg_store(detail::ctx_tag<Ctx>,
+ detail::parse_ctx_tag<ParseCtx>,
+ Args&... a) noexcept
+ : m_data{{detail::make_arg<is_packed, Ctx, ParseCtx>(a)...}}
+ {
+ }
+
+ SCN_CONSTEXPR14 span<value_type> data() noexcept
+ {
+ return make_span(m_data.data(),
+ static_cast<std::ptrdiff_t>(m_data.size()));
+ }
+
+ private:
+ detail::array<value_type, data_size> m_data;
+ };
+
+ template <typename Context, typename ParseCtx, typename... Args>
+ arg_store<typename Context::char_type, Args...> make_args(Args&... args)
+ {
+ return {detail::ctx_tag<Context>(), detail::parse_ctx_tag<ParseCtx>(),
+ args...};
+ }
+ template <typename WrappedRange,
+ typename Format,
+ typename... Args,
+ typename CharT = typename WrappedRange::char_type>
+ arg_store<CharT, Args...> make_args_for(WrappedRange&,
+ Format,
+ Args&... args)
+ {
+ using context_type = basic_context<WrappedRange>;
+ using parse_context_type =
+ typename detail::parse_context_template_for_format<
+ Format>::template type<typename context_type::char_type>;
+ return {detail::ctx_tag<context_type>(),
+ detail::parse_ctx_tag<parse_context_type>(), args...};
+ }
+
+ template <typename CharT>
+ class basic_args {
+ public:
+ using arg_type = basic_arg<CharT>;
+
+ constexpr basic_args() noexcept = default;
+
+ template <typename... Args>
+ SCN_CONSTEXPR14 basic_args(arg_store<CharT, Args...>& store) noexcept
+ : m_types(store.types)
+ {
+ set_data(store.m_data.data());
+ }
+
+ SCN_CONSTEXPR14 basic_args(span<arg_type> 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<size_t>(i) <
+ (m_types &
+ ~static_cast<size_t>(detail::is_unpacked_bit));
+ }
+ return type(i) != detail::none_type;
+ }
+
+ SCN_NODISCARD constexpr size_t max_size() const noexcept
+ {
+ return is_packed()
+ ? static_cast<size_t>(detail::max_packed_args)
+ : m_types &
+ ~static_cast<size_t>(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<size_t>(i) * detail::packed_arg_bitsize;
+ return static_cast<typename detail::type>(
+ (static_cast<size_t>(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<std::ptrdiff_t>(max_size());
+ if (SCN_LIKELY(i < num_args)) {
+ arg = m_args[i];
+ }
+ return arg;
+ }
+
+ SCN_EXPECT(m_values);
+ if (SCN_UNLIKELY(
+ i > static_cast<std::ptrdiff_t>(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