// 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_BOOST_FUNCTION_H #if !defined(__clang__) #pragma GCC visibility push (internal) namespace boost::spirit { // Spirit uses `boost::function` by default, but since it's in boost:: it // simply declares as `function`. We can do a lot better by dropping in // `std::function` instead. using std::function; } #pragma GCC visibility pop #endif #if defined(__clang__) #pragma GCC visibility push (internal) namespace boost::spirit { template struct function; template struct function; } template class [[clang::internal_linkage]] boost::spirit::function { size_t s { 0UL }; R (*f)(const void *const &, args...) { nullptr }; std::unique_ptr o { nullptr, std::free }; public: explicit operator bool() const noexcept { assert(f); assert(o); return true; } decltype(auto) operator()(args&&...) const; decltype(auto) operator()(args&&...); template [[clang::internal_linkage]] function &operator=(binder) noexcept; function() = default; function(const function &); function(function &&) noexcept = default; ~function() noexcept = default; }; template boost::spirit::function::function(const function &o) :s{o.s} ,f{o.f} ,o { this->s? ircd::aligned_alloc(64, this->s): std::unique_ptr { nullptr, std::free } } { memcpy(this->o.get(), o.o.get(), this->s); } template template [[clang::reinitializes]] boost::spirit::function & boost::spirit::function::operator=(binder o) noexcept { constexpr auto alignment { std::max(std::alignment_of::value, 64UL) }; this->s = sizeof(binder); this->o = ircd::aligned_alloc(alignment, this->s); this->f = [](const void *const &o, args&&... a) { const auto &object { *reinterpret_cast(o) }; return object(std::forward(a)...); }; new (this->o.get()) binder { std::move(o) }; return *this; } template [[gnu::always_inline, gnu::artificial]] inline decltype(auto) boost::spirit::function::operator()(args&&... a) { assert(bool(*this)); const auto o { std::addressof(*this->o) }; return this->f(o, std::forward(a)...); } template [[gnu::always_inline, gnu::artificial]] inline decltype(auto) boost::spirit::function::operator()(args&&... a) const { assert(bool(*this)); const auto o { std::addressof(*this->o) }; return this->f(o, std::forward(a)...); } #pragma GCC visibility pop #endif