// The Construct // // Copyright (C) The Construct Developers, Authors & Contributors // Copyright (C) 2016-2020 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_FUNCTION_H // This all prevents spirit grammar rules from generating a very large and/or // deep call-graph where rules compose together with indirect calls and thunks // through boost::function -- this is higly inefficient as the grammar's logic // ends up being a fraction of the generated code and the rest is invocation // related overhead since lots of optimizations become inhibited. // Spirit uses `boost::function` by default, but since it's in boost:: it // declares as `function`. We can immediately do a lot better by simply // dropping in `std::function` as said `function` instead. However, this does // not go far enough for most cases so we maximize optimization with a bespoke // function object. // Our optimized function object is built in ircd::spirit so as to not // interpose itself by default; see below for controlling conditions. namespace ircd::spirit { template class function; template class function; } // Fuse-box controlling spirit::qi parsers. namespace boost::spirit::qi { #if defined(__clang__) using ircd::spirit::function; #else using std::function; #endif } // Fusebox controlling spirit::karma generators. namespace boost::spirit::karma { #if defined(__clang__) using ircd::spirit::function; #else using std::function; #endif } /// Internal optimized function object. template class [[clang::internal_linkage]] ircd::spirit::function { R (*f)(void *, args...) { nullptr }; void *t { nullptr }; template static R handler(void *, args...); public: explicit operator bool() const noexcept; R operator()(args...) const; template function &operator=(T *const t) & noexcept; template function(T *const t) noexcept; function(const function &, void *const &) noexcept; function() = default; function(function &&) = default; function(const function &) = delete; function &operator=(function &&) = default; function &operator=(const function &) = delete; ~function() noexcept = default; }; template inline ircd::spirit::function::function(const function &f, void *const &t) noexcept :f{f.f} ,t{t} {} template template inline ircd::spirit::function::function(T *const t) noexcept :f{this->handler} ,t{t} {} template template inline ircd::spirit::function & ircd::spirit::function::operator=(T *const t) & noexcept { this->f = this->handler; this->t = t; return *this; } template template [[gnu::section("text.ircd.spirit")]] inline R ircd::spirit::function::handler(void *const t, args... a) { assert(t); return static_cast(t)->operator()(a...); } template [[gnu::always_inline]] inline R ircd::spirit::function::operator()(args... a) const { assert(this->f); return this->f(this->t, a...); } template inline ircd::spirit::function::operator bool() const noexcept { assert(!f || (f && t)); return f; }