// The Construct // // Copyright (C) The Construct Developers, Authors & Contributors // Copyright (C) 2016-2022 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_SPIRIT_KARMA_RULE_H #if defined(__clang__) /// Custom reimplementation/interposition of the qi::rule template by /// specializing the `char *` iterator, which is common to our generators. /// /// See: qi_rule.h /// template struct boost::spirit::karma::rule :proto::extends < typename proto::terminal const>>::type ,rule > ,generator> { using Iterator = char *; using iterator_type = Iterator; using properties = mpl::int_; using this_type = rule; using reference_ = reference; using terminal = typename proto::terminal::type; using base_type = proto::extends; using template_params = mpl::vector; using output_iterator = detail::output_iterator; using locals_type = typename spirit::detail::extract_locals::type; using delimiter_type = typename spirit::detail::extract_component::type; using encoding_type = typename spirit::detail::extract_encoding::type; using sig_type = typename spirit::detail::extract_sig::type; using attr_type = typename spirit::detail::attr_from_sig::type; using attr_reference_type = const attr_type &; using parameter_types = typename spirit::detail::params_from_sig::type; using parameter_types_size = typename fusion::result_of::size::type; using context_type = context, locals_type>; using function_prototype = bool (output_iterator &, context_type &, const delimiter_type &); using function_type = function; using encoding_modifier_type = typename mpl::if_ < is_same, unused_type, tag::char_code >::type; template struct attribute { using type = attr_type; }; static constexpr const auto ¶ms_size { parameter_types_size::value }; private: BOOST_STATIC_ASSERT_MSG ( !is_reference::value && !is_const::value, "Const/reference qualifiers on Karma rule attribute are meaningless" ); template static decltype(auto) define(Expr&& expr, mpl::false_) { BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr); } template [[warn_unused_result]] static decltype(auto) define(Expr&& expr, mpl::true_) { return detail::bind_generator ( compile(std::forward(expr), encoding_modifier_type()) ); } template static decltype(auto) create(Expr&& expr) { return define ( std::forward(expr), traits::matches() ); } static constexpr const size_t buf_sz { 512 - 32 // offsetof buf }; function_type func; const char *_name; size_t _size; [[clang::loader_uninitialized]] char buf alignas(32) [buf_sz]; public: using parameterized_subject_type = const rule; const rule &get_parameterized_subject() const { return *this; } reference_ alias() const noexcept { return reference_(*this); } std::string_view name() const { return _name; } template info what(Context&) const noexcept { return info(std::string()); } template bool generate(output_iterator&, C&, const D &, const A &) const; template bool generate(output_iterator&, C&, const D &, const A &, const P &) const; #include template rule(const Expr &expr, const char *const name = "") noexcept; template explicit rule(const rule &o, const char *const name) noexcept; rule(const rule &o) :rule(o, o._name) {} rule() = delete; rule(rule &&o) = delete; rule& operator=(rule &&) = delete; rule& operator=(const rule &) = delete; ~rule() noexcept = default; }; template template inline boost::spirit::karma::rule::rule(const Expr &expr, const char *const name) noexcept :base_type(terminal::make(reference_(*this))) ,func(new (buf) decltype(create(expr)) (create(expr))) ,_name(name) ,_size(sizeof(decltype(create(expr)))) { /// If this assertion has tripped first ensure you are not copying /// an instance of this rule, otherwise see the comment on buf_sz. static_assert ( sizeof(decltype(create(expr))) <= buf_sz, "Instance buffer is insufficient for the binder object." ); } template template inline boost::spirit::karma::rule::rule(const rule &o, const char *const name) noexcept :base_type(terminal::make(reference_(*this))) ,func(o.func, buf) ,_name(name) ,_size(o._size) { assert(_size <= buf_sz); memcpy(buf, o.buf, _size); } template template inline bool boost::spirit::karma::rule::generate(output_iterator &sink, Context &, const Delimiter &delim, const Attribute &attr) const { using transform = traits::transform_attribute; typename transform::type attr_(transform::pre(attr)); context_type context(attr_); assume(bool(func)); const auto ret { func(sink, context, delim) }; if constexpr(is_same::value) if(ret) karma::delimit_out(sink, delim); return ret; } template template inline bool boost::spirit::karma::rule::generate(output_iterator &sink, Context &caller_context, const Delimiter &delim, const Attribute &attr, const Params ¶ms) const { typedef traits::transform_attribute transform; typename transform::type attr_ = transform::pre(attr); context_type context(attr_, params, caller_context); assume(bool(func)); const auto ret { func(sink, context, delim) }; if constexpr(is_same::value) if(ret) karma::delimit_out(sink, delim); return ret; } #endif defined(__clang__)