0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 10:12:39 +01:00

ircd::spirit: Add custom function object interposition (for clang).

This commit is contained in:
Jason Volk 2020-11-25 16:29:44 -08:00
parent 910dafbb85
commit 3132f85f9a
2 changed files with 158 additions and 9 deletions

View file

@ -27,17 +27,9 @@
#include <boost/config.hpp>
#include <boost/function.hpp>
#include "function.h"
#pragma GCC visibility push (internal)
// 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.
namespace boost::spirit
{
using std::function;
}
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/iterator.hpp>
#include <boost/fusion/adapted.hpp>

View file

@ -0,0 +1,157 @@
// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
//
// 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<class prototype>
struct function;
template<class R,
class... args>
struct function<R (args...)>;
}
template<class R,
class... args>
class [[clang::internal_linkage]]
boost::spirit::function<R (args...)>
{
size_t s
{
0UL
};
R (*f)(const void *const &, args...)
{
nullptr
};
std::unique_ptr<char, decltype(&std::free)> 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<class binder>
[[clang::internal_linkage]]
function &operator=(binder) noexcept;
function() = default;
function(const function &);
function(function &&) noexcept = default;
~function() noexcept = default;
};
template<class R,
class... args>
boost::spirit::function<R (args...)>::function(const function &o)
:s{o.s}
,f{o.f}
,o
{
this->s?
ircd::aligned_alloc(8, this->s):
std::unique_ptr<char, decltype(&std::free)>
{
nullptr, std::free
}
}
{
memcpy(this->o.get(), o.o.get(), this->s);
}
template<class R,
class... args>
template<class binder>
[[clang::reinitializes]]
boost::spirit::function<R (args...)> &
boost::spirit::function<R (args...)>::operator=(binder o)
noexcept
{
this->s = sizeof(binder);
this->o = ircd::aligned_alloc(8, this->s);
this->f = [](const void *const &o, args&&... a)
{
const auto &object
{
*reinterpret_cast<const binder *>(o)
};
return object(std::forward<args>(a)...);
};
new (this->o.get()) binder
{
std::move(o)
};
return *this;
}
template<class R,
class... args>
[[gnu::always_inline, gnu::artificial]]
inline decltype(auto)
boost::spirit::function<R (args...)>::operator()(args&&... a)
{
assert(bool(*this));
const auto o
{
std::addressof(*this->o)
};
return this->f(o, std::forward<args>(a)...);
}
template<class R,
class... args>
[[gnu::always_inline, gnu::artificial]]
inline decltype(auto)
boost::spirit::function<R (args...)>::operator()(args&&... a)
const
{
assert(bool(*this));
const auto o
{
std::addressof(*this->o)
};
return this->f(o, std::forward<args>(a)...);
}
#pragma GCC visibility pop
#endif