Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/beast2
8 : //
9 :
10 : #ifndef BOOST_BEAST2_SERVER_ANY_LAMBDA_HPP
11 : #define BOOST_BEAST2_SERVER_ANY_LAMBDA_HPP
12 :
13 : #include <boost/beast2/detail/config.hpp>
14 :
15 : #include <cstddef>
16 : #include <cstring>
17 : #include <functional>
18 : #include <new>
19 : #include <stdexcept>
20 : #include <type_traits>
21 : #include <utility>
22 :
23 : namespace boost {
24 : namespace beast2 {
25 :
26 : namespace detail {
27 :
28 : struct A { void f(); int g() const; virtual void h(); };
29 : struct B { virtual void f(); };
30 : struct C : virtual B { void g(); };
31 :
32 : constexpr std::size_t max_size(std::size_t a, std::size_t b) noexcept
33 : {
34 : return a > b ? a : b;
35 : }
36 :
37 : constexpr std::size_t max_sizeof_mfp() noexcept
38 : {
39 : return max_size(
40 : max_size(
41 : max_size(sizeof(void (A::*)()), sizeof(int (A::*)() const)),
42 : sizeof(void (B::*)())
43 : ),
44 : sizeof(void (C::*)())
45 : );
46 : }
47 :
48 : } // detail
49 :
50 : template<class Signature>
51 : struct any_lambda; // primary template left undefined
52 :
53 : template<class R, class... Args>
54 : struct any_lambda<R(Args...)>
55 : {
56 : private:
57 : // Adjust as desired — must fit your expected lambdas
58 : static constexpr std::size_t BufferSize = detail::max_sizeof_mfp();
59 : static constexpr std::size_t BufferAlign = alignof(std::max_align_t);
60 :
61 : using InvokeFn = R(*)(void*, Args&&...);
62 : using CopyFn = void(*)(void*, const void*);
63 : using MoveFn = void(*)(void*, void*);
64 : using DestroyFn= void(*)(void*);
65 :
66 : typename std::aligned_storage<BufferSize, BufferAlign>::type buffer;
67 : InvokeFn invoke = nullptr;
68 : CopyFn copy = nullptr;
69 : MoveFn move = nullptr;
70 : DestroyFn destroy = nullptr;
71 :
72 : public:
73 : any_lambda() = default;
74 :
75 : any_lambda(std::nullptr_t) noexcept {}
76 :
77 0 : any_lambda(const any_lambda& other)
78 0 : {
79 0 : if (other.invoke)
80 : {
81 0 : invoke = other.invoke;
82 0 : copy = other.copy;
83 0 : move = other.move;
84 0 : destroy = other.destroy;
85 0 : copy(&buffer, &other.buffer);
86 : }
87 0 : }
88 :
89 : any_lambda(any_lambda&& other) noexcept
90 : {
91 : if (other.invoke)
92 : {
93 : invoke = other.invoke;
94 : copy = other.copy;
95 : move = other.move;
96 : destroy = other.destroy;
97 : move(&buffer, &other.buffer);
98 : other.reset();
99 : }
100 : }
101 :
102 : template<class F>
103 0 : any_lambda(F f)
104 0 : {
105 : static_assert(!std::is_same<any_lambda, typename std::decay<F>::type>::value,
106 : "cannot construct from self");
107 : static_assert(sizeof(F) <= BufferSize, "lambda too large for buffer");
108 : static_assert(alignof(F) <= BufferAlign, "lambda alignment too strict");
109 :
110 0 : new (&buffer) F(std::move(f));
111 :
112 0 : invoke = [](void* p, Args&&... args) -> R {
113 0 : return (*static_cast<F*>(p))(std::forward<Args>(args)...);
114 : };
115 0 : copy = [](void* dst, const void* src) {
116 0 : new (dst) F(*static_cast<const F*>(src));
117 : };
118 0 : move = [](void* dst, void* src) {
119 0 : new (dst) F(std::move(*static_cast<F*>(src)));
120 0 : static_cast<F*>(src)->~F();
121 : };
122 0 : destroy = [](void* p) { static_cast<F*>(p)->~F(); };
123 0 : }
124 :
125 : any_lambda& operator=(const any_lambda& other)
126 : {
127 : if (this != &other)
128 : {
129 : reset();
130 : if (other.invoke)
131 : {
132 : invoke = other.invoke;
133 : copy = other.copy;
134 : move = other.move;
135 : destroy = other.destroy;
136 : copy(&buffer, &other.buffer);
137 : }
138 : }
139 : return *this;
140 : }
141 :
142 : any_lambda& operator=(any_lambda&& other) noexcept
143 : {
144 : if (this != &other)
145 : {
146 : reset();
147 : if (other.invoke)
148 : {
149 : invoke = other.invoke;
150 : copy = other.copy;
151 : move = other.move;
152 : destroy = other.destroy;
153 : move(&buffer, &other.buffer);
154 : other.reset();
155 : }
156 : }
157 : return *this;
158 : }
159 :
160 0 : ~any_lambda() { reset(); }
161 :
162 0 : void reset()
163 : {
164 0 : if (destroy)
165 0 : destroy(&buffer);
166 0 : invoke = nullptr;//copy = move = destroy = nullptr;
167 0 : }
168 :
169 : explicit operator bool() const noexcept { return invoke != nullptr; }
170 :
171 0 : R operator()(Args... args) const
172 : {
173 0 : if (!invoke)
174 0 : throw std::bad_function_call();
175 0 : return invoke(const_cast<void*>(static_cast<const void*>(&buffer)),
176 0 : std::forward<Args>(args)...);
177 : }
178 : };
179 : } // beast2
180 : } // boost
181 :
182 : #endif
|