userver: userver/utils/struct_subsets.hpp Source File
Loading...
Searching...
No Matches
struct_subsets.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/struct_subsets.hpp
4/// @brief Utilities for creating a struct with a subset of fields of the
5/// original struct, with conversions between them.
6
7#include <type_traits>
8#include <utility>
9
10#include <boost/preprocessor/empty.hpp>
11#include <boost/preprocessor/seq/for_each.hpp>
12
13#include <userver/utils/forward_like.hpp>
14#include <userver/utils/impl/boost_variadic_to_seq.hpp>
15#include <userver/utils/impl/internal_tag.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace utils::impl {
20
21struct RequireSemicolon;
22
23struct NonMovable final {
24 constexpr explicit NonMovable(InternalTag) noexcept {}
25};
26
27template <typename T>
28constexpr auto IsDefinedAndAggregate() -> decltype(static_cast<void>(sizeof(T)), false) {
29 return std::is_aggregate_v<T>;
30}
31
32template <typename /*T*/, typename... Args>
33constexpr auto IsDefinedAndAggregate(Args...) -> bool {
34 return false;
35}
36
37} // namespace utils::impl
38
39USERVER_NAMESPACE_END
40
41/// @cond
42
43// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
44#define USERVER_IMPL_STRUCT_MAP(r, data, elem)
45 USERVER_NAMESPACE::utils::ForwardLike<OtherDeps, decltype(other.elem)>(other.elem),
46
47// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
48#define USERVER_IMPL_MAKE_FROM_SUPERSET(Self, ...)
49 template <typename OtherDeps>
50 static Self MakeFromSupersetImpl(OtherDeps&& other, USERVER_NAMESPACE::utils::impl::InternalTag) {
51 return {BOOST_PP_SEQ_FOR_EACH(
52 USERVER_IMPL_STRUCT_MAP,
53 BOOST_PP_EMPTY(),
54 USERVER_IMPL_VARIADIC_TO_SEQ(__VA_ARGS__)
55 )};
56 }
57
58// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
59#define USERVER_IMPL_STRUCT_SUBSET_MAP(r, data, elem)
60 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */
61 decltype(data::elem) elem;
62
63// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
64#define USERVER_IMPL_STRUCT_SUBSET_REF_MAP(r, data, elem)
65 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */
66 std::add_const_t<decltype(data::elem)>& elem;
67
68/// @endcond
69
70/// @brief Should be invoked inside a manually defined "root" struct to enable
71/// conversions from it to subset structs created by
72/// @ref USERVER_DEFINE_STRUCT_SUBSET and @ref USERVER_DEFINE_STRUCT_SUBSET_REF.
73///
74/// @hideinitializer
75// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
76#define USERVER_ALLOW_CONVERSIONS_TO_SUBSET()
77 template <
78 typename Other,
79 std::enable_if_t<USERVER_NAMESPACE::utils::impl::IsDefinedAndAggregate<Other>(), int> Enable = 0>
80 /*implicit*/ operator Other() const& {
81 return Other::MakeFromSupersetImpl(*this, USERVER_NAMESPACE::utils::impl::InternalTag{});
82 }
83
84 template <
85 typename Other,
86 std::enable_if_t<USERVER_NAMESPACE::utils::impl::IsDefinedAndAggregate<Other>(), int> Enable = 0>
87 /*implicit*/ operator Other()&& {
88 return Other::MakeFromSupersetImpl(std::move(*this), USERVER_NAMESPACE::utils::impl::InternalTag{});
89 }
90
91 friend struct USERVER_NAMESPACE::utils::impl::RequireSemicolon
92
93/// @brief Defines a struct containing a subset of data members
94/// from @a OriginalDependencies.
95///
96/// Implicit conversions (by copy and by move) are allowed from any superset
97/// struct to the @a SubsetStruct, as long as the names of the data members
98/// match, and the superset struct is either defined using
99/// @ref USERVER_DEFINE_STRUCT_SUBSET or @ref USERVER_DEFINE_STRUCT_SUBSET_REF,
100/// or it contains @ref USERVER_ALLOW_CONVERSIONS_TO_SUBSET.
101///
102/// Usage example:
103/// @snippet utils/struct_subsets_test.cpp deps definitions
104/// @snippet utils/struct_subsets_test.cpp deps usage
105///
106/// @param SubsetStruct the name of the subset struct to define
107/// @param OriginalStruct the name of the superset struct, including its
108/// namespace if needed
109/// @param ... names of the data members to copy
110///
111/// @hideinitializer
112// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
113#define USERVER_DEFINE_STRUCT_SUBSET(SubsetStruct, OriginalStruct, ...)
114 struct SubsetStruct {
115 BOOST_PP_SEQ_FOR_EACH(
116 USERVER_IMPL_STRUCT_SUBSET_MAP,
117 OriginalStruct,
118 USERVER_IMPL_VARIADIC_TO_SEQ(__VA_ARGS__)
119 )
120
121 USERVER_IMPL_MAKE_FROM_SUPERSET(SubsetStruct, __VA_ARGS__)
122
124 }
125
126/// @brief Defines a struct containing a subset of data members
127/// from @a OriginalDependencies. Appends `const&` to types of all non-reference
128/// data members.
129///
130/// Implicit conversions (by copy and by move) are allowed from any superset
131/// struct to the @a SubsetStruct, as long as the names of the data members
132/// match, and the superset struct is either defined using
133/// @ref USERVER_DEFINE_STRUCT_SUBSET or @ref USERVER_DEFINE_STRUCT_SUBSET_REF,
134/// or it contains @ref USERVER_ALLOW_CONVERSIONS_TO_SUBSET.
135///
136/// `*Ref` structs can be used for parameters of utility functions to avoid
137/// copying non-reference data members.
138///
139/// Usage example:
140/// @snippet utils/struct_subsets_test.cpp ref definitions
141/// @snippet utils/struct_subsets_test.cpp ref usage
142///
143/// @param SubsetStructRef the name of the subset struct to define, it should
144/// typically contain `*Ref` suffix to underline that it needs the original
145/// backing struct to work
146/// @param OriginalStruct the name of the superset struct, including its
147/// namespace if needed
148/// @param ... names of the data members to copy
149///
150/// @hideinitializer
151// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
152#define USERVER_DEFINE_STRUCT_SUBSET_REF(SubsetStructRef, OriginalStruct, ...)
153 struct SubsetStructRef {
154 BOOST_PP_SEQ_FOR_EACH(
155 USERVER_IMPL_STRUCT_SUBSET_REF_MAP,
156 OriginalStruct,
157 USERVER_IMPL_VARIADIC_TO_SEQ(__VA_ARGS__)
158 )
159
160 /* Protects against copying into async functions */
161 USERVER_NAMESPACE::utils::impl::NonMovable _impl_non_movable{USERVER_NAMESPACE::utils::impl::InternalTag{}};
162
163 USERVER_IMPL_MAKE_FROM_SUPERSET(SubsetStructRef, __VA_ARGS__)
164
166 }