mimic++ v9.2.1
Loading...
Searching...
No Matches
Facade.hpp
Go to the documentation of this file.
1// Copyright Dominic (DNKpp) Koepke 2024 - 2025.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef MIMICPP_FACADE_HPP
7#define MIMICPP_FACADE_HPP
8
9#pragma once
10
11#include "mimic++/Fwd.hpp"
12#include "mimic++/Mock.hpp"
17
18#ifndef MIMICPP_DETAIL_IS_MODULE
19 #include <cstddef>
20 #include <iterator>
21 #include <tuple>
22 #include <type_traits>
23 #include <utility>
24#endif
25
26namespace mimicpp
27{
72}
73
74namespace mimicpp::facade::detail
75{
76 // * the generated facade implementation - lambda
77 // * the generated facade implementation
78 inline constexpr std::size_t facadeBaseCallDepth{2u};
79
80 template <typename Self>
81 [[nodiscard]]
82 StringT generate_member_target_name(StringViewT const functionName)
83 {
84 StringStreamT ss{};
85 mimicpp::print_type<Self>(std::ostreambuf_iterator{ss});
86 ss << "::" << functionName;
87
88 return std::move(ss).str();
89 }
90
91 template <typename Signature, typename Target>
92 [[nodiscard]]
93 constexpr auto&& forward_for(Target& target) noexcept
94 {
95 using ref = std::conditional_t<
97 Target&&,
98 Target&>;
99
100 return static_cast<ref>(target);
101 }
102
103 // * detail::apply::lambda
104 // * detail::apply
105 inline constexpr std::size_t applyCallDepth{2u};
106
114 template <typename Signature, typename... Args>
115 constexpr decltype(auto) apply(auto& target, std::tuple<Args...>&& args)
116 {
117 return [&]<std::size_t... indices>([[maybe_unused]] std::index_sequence<indices...> const) -> decltype(auto) {
118 return forward_for<Signature>(target)(
119 std::forward<Args>(std::get<indices>(args))...);
120 }(std::index_sequence_for<Args...>{});
121 }
122}
123
125{
126 template <template <typename...> typename TargetTemplate>
128 {
129 static constexpr bool is_member{true};
130
131 template <typename... Signatures>
132 using target_type = TargetTemplate<Signatures...>;
133
134 template <typename Signature, typename... Args>
135 static constexpr decltype(auto) invoke(
136 auto& target,
137 [[maybe_unused]] auto* const self,
138 std::tuple<Args...>&& args)
139 {
140 return detail::apply<Signature>(target, std::move(args));
141 }
142
143 template <typename Self>
144 [[nodiscard]]
145 static MIMICPP_DETAIL_CONSTEXPR_STRING MockSettings make_settings([[maybe_unused]] Self const* const self, StringViewT const functionName)
146 {
147 constexpr std::size_t skip = 1u + detail::facadeBaseCallDepth + detail::applyCallDepth;
148
149 return MockSettings{
150 .name = detail::generate_member_target_name<Self>(functionName),
151 .stacktraceSkip = skip};
152 }
153 };
154
156
157 template <typename Self, template <typename...> typename TargetTemplate>
159 {
160 static constexpr bool is_member{true};
161
162 template <typename Signature, bool isConst = Constness::as_const == signature_const_qualification_v<Signature>>
164 Signature,
165 std::conditional_t<isConst, Self const*, Self*>>;
166
167 template <typename... Signatures>
168 using target_type = TargetTemplate<prepend_this<Signatures>...>;
169
170 template <typename Signature, typename... Args>
171 static constexpr decltype(auto) invoke(auto& target, auto* const self, std::tuple<Args...>&& args)
172 {
173 return detail::apply<Signature>(
174 target,
175 std::tuple_cat(std::make_tuple(self), std::move(args)));
176 }
177
178 [[nodiscard]]
179 static MIMICPP_DETAIL_CONSTEXPR_STRING MockSettings make_settings([[maybe_unused]] auto const* const self, StringViewT const functionName)
180 {
181 constexpr std::size_t skip = 1u + detail::facadeBaseCallDepth + detail::applyCallDepth;
182
183 return MockSettings{
184 .name = detail::generate_member_target_name<Self>(functionName),
185 .stacktraceSkip = skip};
186 }
187 };
188
189 template <typename Self>
191}
192
193// These symbols are called from within "exported" macros and must thus be visible to the caller.
194MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::facade::detail
195{
196 template <typename Traits>
197 inline constexpr bool is_member_v = false;
198
199 template <typename Traits>
200 requires requires { Traits::is_member; }
201 inline constexpr bool is_member_v<Traits>{Traits::is_member};
202
203 template <auto specText>
204 struct apply_normalized_specs
205 {
206 private:
207 struct spec_info
208 {
209 bool hasConst{false};
210 ValueCategory refQualifier = ValueCategory::any;
211 bool hasNoexcept{false};
212 };
213
214 [[nodiscard]]
215 static consteval auto evaluate_specs()
216 {
217 auto const end = std::ranges::end(specText);
218 auto const find_token_begin = [&](auto const first) noexcept {
219 // LCOV_EXCL_START
220 // For whatever reason, marking this lambda as `consteval` does not compile...
221 constexpr auto is_space = [](char const c) noexcept {
222 return ' ' == c || '\t' == c;
223 };
224
225 return std::ranges::find_if_not(first, end, is_space);
226 // LCOV_EXCL_STOP
227 };
228
229 spec_info result{};
230 for (auto tokenBegin = find_token_begin(std::ranges::begin(specText));
231 tokenBegin != end;
232 tokenBegin = find_token_begin(tokenBegin))
233 {
234 tokenBegin = ('&' == *tokenBegin)
235 ? parse_ref_specifier(tokenBegin, end, result)
236 : parse_keyword_specifier(tokenBegin, end, result);
237 }
238
239 return result;
240 }
241
242 template <typename Iter>
243 [[nodiscard]]
244 static consteval Iter parse_ref_specifier(Iter first, auto const end, spec_info& out_info)
245 {
246 MIMICPP_ASSERT(first != end, "First must point to the first `&` character.");
247 MIMICPP_ASSERT(out_info.refQualifier == ValueCategory::any, "Ref-qualifier already set.");
248
249 if (++first != end
250 && '&' == *first)
251 {
252 ++first;
253 out_info.refQualifier = ValueCategory::rvalue;
254 }
255 else
256 {
257 out_info.refQualifier = ValueCategory::lvalue;
258 }
259
260 return first;
261 }
262
263 template <typename Iter>
264 [[nodiscard]]
265 static consteval Iter parse_keyword_specifier(Iter first, auto const end, spec_info& out_info)
266 {
267 MIMICPP_ASSERT(first != end, "First must point to the first keyword character.");
268
269 constexpr auto is_keyword_continue = [](char const c) noexcept {
270 // LCOV_EXCL_START
271 // For whatever reason, marking this lambda as `consteval` does not compile...
272 return ('a' <= c && c <= 'z')
273 || ('A' <= c && c <= 'Z');
274 // LCOV_EXCL_STOP
275 };
276
277 auto const tokenEnd = std::ranges::find_if_not(first + 1u, end, is_keyword_continue);
278 std::string_view const token{first, tokenEnd};
279 if (constexpr std::string_view constKeyword{"const"};
280 constKeyword == token)
281 {
282 MIMICPP_ASSERT(!out_info.hasConst, "Const-qualifier already set.");
283 out_info.hasConst = true;
284 }
285 else if (constexpr std::string_view noexceptKeyword{"noexcept"};
286 noexceptKeyword == token)
287 {
288 MIMICPP_ASSERT(!out_info.hasNoexcept, "Noexcept-qualifier already set.");
289 out_info.hasNoexcept = true;
290 }
291 else if (constexpr std::string_view overrideKeyword{"override"}, finalKeyword{"final"};
292 overrideKeyword != token && finalKeyword != token)
293 {
294 throw "Invalid spec";
295 }
296
297 return tokenEnd;
298 }
299
300 static constexpr auto info = evaluate_specs();
301
302 public:
303 template <typename Signature>
304 [[nodiscard]]
305 static consteval auto evaluate() noexcept
306 {
307 using sig_maybe_ref = std::conditional_t<
308 ValueCategory::lvalue == info.refQualifier,
310 std::conditional_t<
311 ValueCategory::rvalue == info.refQualifier,
313 Signature>>;
314
315 using sig_maybe_const = std::conditional_t<
316 info.hasConst,
318 sig_maybe_ref>;
319
320 using sig_maybe_noexcept = std::conditional_t<
321 info.hasNoexcept,
323 sig_maybe_const>;
324
325 return std::type_identity<sig_maybe_noexcept>{};
326 }
327
328 template <typename Signature>
329 using type = decltype(evaluate<Signature>())::type;
330 };
331
332 template <typename RawSignature, auto specText>
333 using apply_normalized_specs_t = apply_normalized_specs<specText>::template type<RawSignature>;
334}
335
336#endif
#define MIMICPP_DETAIL_CONSTEXPR_STRING
Definition Config.hpp:60
#define MIMICPP_ASSERT(condition, msg)
Definition Config.hpp:51
#define MIMICPP_DETAIL_MODULE_EXPORT
Definition Config.hpp:19
Definition Mock.hpp:35
constexpr printing::PrintTypeFn< T > print_type
Functional object, converting the given type to its textual representation.
Definition PrintType.hpp:478
typename signature_add_const_qualifier< Signature >::type signature_add_const_qualifier_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:150
typename signature_add_lvalue_ref_qualifier< Signature >::type signature_add_lvalue_ref_qualifier_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:166
typename signature_add_noexcept< Signature >::type signature_add_noexcept_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:54
typename signature_add_rvalue_ref_qualifier< Signature >::type signature_add_rvalue_ref_qualifier_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:182
typename signature_prepend_param< Signature, T >::type signature_prepend_param_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:311
constexpr ValueCategory signature_ref_qualification_v
Convenience constant, exposing the value member of the actual type-trait.
Definition Fwd.hpp:262
Definition Facade.hpp:75
basic_as_member_with_this< Self, Mock > mock_as_member_with_this
Definition Facade.hpp:190
basic_as_member< Mock > mock_as_member
Definition Facade.hpp:155
auto constexpr is_space
Definition NameLexer.hpp:28
Definition Call.hpp:24
ValueCategory
Definition Fwd.hpp:34
@ any
Definition Fwd.hpp:37
@ lvalue
Definition Fwd.hpp:35
@ rvalue
Definition Fwd.hpp:36
std::basic_ostringstream< CharT, CharTraitsT > StringStreamT
Definition Format.hpp:35
std::basic_string_view< CharT, CharTraitsT > StringViewT
Definition Fwd.hpp:392
std::basic_string< CharT, CharTraitsT > StringT
Definition Fwd.hpp:391
static constexpr bool is_member
Definition Facade.hpp:160
static MIMICPP_DETAIL_CONSTEXPR_STRING MockSettings make_settings(auto const *const self, StringViewT const functionName)
Definition Facade.hpp:179
TargetTemplate< prepend_this< Signatures >... > target_type
Definition Facade.hpp:168
signature_prepend_param_t< Signature, std::conditional_t< isConst, Self const *, Self * > > prepend_this
Definition Facade.hpp:163
static constexpr decltype(auto) invoke(auto &target, auto *const self, std::tuple< Args... > &&args)
Definition Facade.hpp:171
Definition Facade.hpp:128
static constexpr bool is_member
Definition Facade.hpp:129
static constexpr decltype(auto) invoke(auto &target, auto *const self, std::tuple< Args... > &&args)
Definition Facade.hpp:135
TargetTemplate< Signatures... > target_type
Definition Facade.hpp:132
static MIMICPP_DETAIL_CONSTEXPR_STRING MockSettings make_settings(Self const *const self, StringViewT const functionName)
Definition Facade.hpp:145