Initial commit

parents
cmake_minimum_required(VERSION 3.10)
project(functor)
set(CMAKE_CXX_STANDARD 17)
add_executable(functor
main.cpp
functor.hpp)
#pragma once
#include <cstddef>
#include <utility>
template<typename>
class functor;
template<typename Result, typename... Args>
class functor<Result(Args...)> final
{
static constexpr std::size_t buffer_size = 64;
public:
functor(Result(*fptr)(Args...)) noexcept
{
create_from_function(fptr);
}
template<typename Callable, typename = std::enable_if_t<!std::is_function_v<Callable>>>
functor(Callable &&callable) noexcept
{
create_from_callable(std::forward<Callable>(callable));
}
functor& operator=(Result(*fptr)(Args...)) noexcept
{
create_from_function(fptr);
return *this;
}
template<typename Callable, typename = std::enable_if_t<!std::is_function_v<Callable>>>
functor& operator=(Callable &&callable) noexcept
{
create_from_callable(std::forward<Callable>(callable));
return *this;
}
Result operator()(Args... args)
{
return (this->*call_invoker_)(args...);
}
private:
char buffer_[buffer_size];
Result (functor::*call_invoker_)(Args...) = nullptr;
void create_from_function(Result(*fptr)(Args...)) noexcept
{
*reinterpret_cast<Result(**)(Args...)>(&buffer_) = fptr;
call_invoker_ = &functor::call_function;
}
template<typename Callable>
void create_from_callable(Callable &&callable) noexcept
{
using _ut = union {
void *vptr;
Result (Callable::*cptr)(Args...) const;
};
auto call_helper = new (buffer_) _ut;
call_helper->cptr = &Callable::operator();
new (buffer_ + sizeof(void*)) Callable{std::forward<Callable>(callable)};
call_invoker_ = &functor::call_callable;
}
Result call_function(Args... args)
{
auto func = *reinterpret_cast<Result(**)(Args...)>(&buffer_);
return func(args...);
}
Result call_callable(Args... args)
{
void *this_ = buffer_ + sizeof(void*);
return (*reinterpret_cast<Result(**)(void*, Args...)>(&buffer_))(this_, args...);
}
};
#include "functor.hpp"
#include <iostream>
int f(int n)
{
asm("nop");
return n + 1;
}
int main()
{
int n = 0;
for (int i = 0; i < 1'000'000; ++i) {
functor<int(int)> fn = f;
n = fn(n);
fn = [](int n) {
asm("nop");
return n + 1;
};
n = fn(n);
int m = 12;
fn = [&m](int n) {
asm("nop");
return n + m + 1;
};
n = fn(n);
}
std::cout << "n = " << n << std::endl;
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment