Skip to content

Commit 43e7ffd

Browse files
authored
Merge pull request #45756 from Dr15Jones/wrapperConcepts
Use C++ concepts to deduce data product attributes
2 parents 4552c8e + 1599014 commit 43e7ffd

File tree

7 files changed

+44
-178
lines changed

7 files changed

+44
-178
lines changed

DataFormats/Common/interface/Wrapper.h

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,38 +108,55 @@ namespace edm {
108108

109109
template <typename T>
110110
inline bool Wrapper<T>::isMergeable_() const {
111-
return detail::getHasMergeFunction<T>()();
111+
if constexpr (requires(T& a, T const& b) { a.mergeProduct(b); }) {
112+
return true;
113+
}
114+
return false;
112115
}
113116

114117
template <typename T>
115118
inline bool Wrapper<T>::mergeProduct_(WrapperBase const* newProduct) {
116119
Wrapper<T> const* wrappedNewProduct = dynamic_cast<Wrapper<T> const*>(newProduct);
117120
assert(wrappedNewProduct != nullptr);
118-
return detail::doMergeProduct<T>()(obj, wrappedNewProduct->obj);
121+
if constexpr (requires(T& a, T const& b) { a.mergeProduct(b); }) {
122+
return obj.mergeProduct(wrappedNewProduct->obj);
123+
}
124+
return true;
119125
}
120126

121127
template <typename T>
122128
inline bool Wrapper<T>::hasIsProductEqual_() const {
123-
return detail::getHasIsProductEqual<T>()();
129+
if constexpr (requires(T& a, T const& b) { a.isProductEqual(b); }) {
130+
return true;
131+
}
132+
return false;
124133
}
125134

126135
template <typename T>
127136
inline bool Wrapper<T>::isProductEqual_(WrapperBase const* newProduct) const {
128137
Wrapper<T> const* wrappedNewProduct = dynamic_cast<Wrapper<T> const*>(newProduct);
129138
assert(wrappedNewProduct != nullptr);
130-
return detail::doIsProductEqual<T>()(obj, wrappedNewProduct->obj);
139+
if constexpr (requires(T& a, T const& b) { a.isProductEqual(b); }) {
140+
return obj.isProductEqual(wrappedNewProduct->obj);
141+
}
142+
return true;
131143
}
132144

133145
template <typename T>
134146
inline bool Wrapper<T>::hasSwap_() const {
135-
return detail::getHasSwapFunction<T>()();
147+
if constexpr (requires(T& a, T& b) { a.swap(b); }) {
148+
return true;
149+
}
150+
return false;
136151
}
137152

138153
template <typename T>
139154
inline void Wrapper<T>::swapProduct_(WrapperBase* newProduct) {
140155
Wrapper<T>* wrappedNewProduct = dynamic_cast<Wrapper<T>*>(newProduct);
141156
assert(wrappedNewProduct != nullptr);
142-
detail::doSwapProduct<T>()(obj, wrappedNewProduct->obj);
157+
if constexpr (requires(T& a, T& b) { a.swap(b); }) {
158+
obj.swap(wrappedNewProduct->obj);
159+
}
143160
}
144161

145162
namespace soa {

DataFormats/Common/interface/WrapperDetail.h

Lines changed: 0 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -86,119 +86,6 @@ namespace edm {
8686
std::type_info const& operator()() { return typeid(T); }
8787
};
8888

89-
// bool isMergeable_() will return true if T::mergeProduct(T const&) is declared and false otherwise
90-
// bool mergeProduct_(WrapperBase const*) will merge products if T::mergeProduct(T const&) is defined
91-
// Definitions for the following struct and function templates are not needed; we only require the declarations.
92-
template <typename T, bool (T::*)(T const&)>
93-
struct mergeProduct_function;
94-
template <typename T>
95-
static yes_tag has_mergeProduct(mergeProduct_function<T, &T::mergeProduct>* dummy);
96-
template <typename T>
97-
static no_tag has_mergeProduct(...);
98-
99-
template <typename T>
100-
struct has_mergeProduct_function {
101-
static constexpr bool value = std::is_same<decltype(has_mergeProduct<T>(nullptr)), yes_tag>::value;
102-
};
103-
104-
template <typename T, bool = has_mergeProduct_function<T>::value>
105-
struct getHasMergeFunction;
106-
template <typename T>
107-
struct getHasMergeFunction<T, true> {
108-
bool operator()() { return true; }
109-
};
110-
template <typename T>
111-
struct getHasMergeFunction<T, false> {
112-
bool operator()() { return false; }
113-
};
114-
template <typename T, bool = has_mergeProduct_function<T>::value>
115-
struct doMergeProduct;
116-
template <typename T>
117-
struct doMergeProduct<T, true> {
118-
bool operator()(T& thisProduct, T const& newProduct) { return thisProduct.mergeProduct(newProduct); }
119-
};
120-
template <typename T>
121-
struct doMergeProduct<T, false> {
122-
bool operator()(T& thisProduct, T const& newProduct) {
123-
return true; // Should never be called
124-
}
125-
};
126-
127-
// bool hasIsProductEqual_() will return true if T::isProductEqual(T const&) const is declared and false otherwise
128-
// bool isProductEqual _(WrapperBase const*) will call T::isProductEqual(T const&) if it is defined
129-
// Definitions for the following struct and function templates are not needed; we only require the declarations.
130-
template <typename T, bool (T::*)(T const&) const>
131-
struct isProductEqual_function;
132-
template <typename T>
133-
static yes_tag has_isProductEqual(isProductEqual_function<T, &T::isProductEqual>* dummy);
134-
template <typename T>
135-
static no_tag has_isProductEqual(...);
136-
137-
template <typename T>
138-
struct has_isProductEqual_function {
139-
static constexpr bool value = std::is_same<decltype(has_isProductEqual<T>(nullptr)), yes_tag>::value;
140-
};
141-
142-
template <typename T, bool = has_isProductEqual_function<T>::value>
143-
struct getHasIsProductEqual;
144-
template <typename T>
145-
struct getHasIsProductEqual<T, true> {
146-
bool operator()() { return true; }
147-
};
148-
template <typename T>
149-
struct getHasIsProductEqual<T, false> {
150-
bool operator()() { return false; }
151-
};
152-
template <typename T, bool = has_isProductEqual_function<T>::value>
153-
struct doIsProductEqual;
154-
template <typename T>
155-
struct doIsProductEqual<T, true> {
156-
bool operator()(T const& thisProduct, T const& newProduct) { return thisProduct.isProductEqual(newProduct); }
157-
};
158-
template <typename T>
159-
struct doIsProductEqual<T, false> {
160-
bool operator()(T const& thisProduct, T const& newProduct) {
161-
return true; // Should never be called
162-
}
163-
};
164-
165-
// bool hasSwap_() will return true if T::swap(T&) is declared and false otherwise
166-
// void swapProduct_() will call T::swap(T&) if it is defined otherwise it does nothing
167-
// Definitions for the following struct and function templates are not needed; we only require the declarations.
168-
template <typename T, void (T::*)(T&)>
169-
struct swap_function;
170-
template <typename T>
171-
static yes_tag has_swap(swap_function<T, &T::swap>* dummy);
172-
template <typename T>
173-
static no_tag has_swap(...);
174-
175-
template <typename T>
176-
struct has_swap_function {
177-
static constexpr bool value = std::is_same<decltype(has_swap<T>(nullptr)), yes_tag>::value;
178-
};
179-
180-
template <typename T, bool = has_swap_function<T>::value>
181-
struct getHasSwapFunction;
182-
template <typename T>
183-
struct getHasSwapFunction<T, true> {
184-
bool operator()() { return true; }
185-
};
186-
template <typename T>
187-
struct getHasSwapFunction<T, false> {
188-
bool operator()() { return false; }
189-
};
190-
template <typename T, bool = has_swap_function<T>::value>
191-
struct doSwapProduct;
192-
template <typename T>
193-
struct doSwapProduct<T, true> {
194-
void operator()(T& thisProduct, T& newProduct) { thisProduct.swap(newProduct); }
195-
};
196-
template <typename T>
197-
struct doSwapProduct<T, false> {
198-
void operator()(T&, T&) {
199-
return; // Should never be called
200-
}
201-
};
20289
} // namespace detail
20390
} // namespace edm
20491
#endif

FWCore/Framework/interface/Event.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,7 @@ namespace edm {
374374
OrphanHandle<PROD> Event::putImpl(EDPutToken::value_type index, std::unique_ptr<PROD> product) {
375375
// The following will call post_insert if T has such a function,
376376
// and do nothing if T has no such function.
377-
std::conditional_t<detail::has_postinsert<PROD>::value, DoPostInsert<PROD>, DoNotPostInsert<PROD>> maybe_inserter;
378-
maybe_inserter(product.get());
377+
detail::do_post_insert_if_available(*product.get());
379378

380379
assert(index < putProducts().size());
381380

@@ -456,8 +455,7 @@ namespace edm {
456455

457456
// The following will call post_insert if T has such a function,
458457
// and do nothing if T has no such function.
459-
std::conditional_t<detail::has_postinsert<PROD>::value, DoPostInsert<PROD>, DoNotPostInsert<PROD>> maybe_inserter;
460-
maybe_inserter(&(wp->bareProduct()));
458+
detail::do_post_insert_if_available(wp->bareProduct());
461459

462460
PROD const* prod = wp->product();
463461

FWCore/Framework/interface/LuminosityBlock.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,7 @@ namespace edm {
192192
void LuminosityBlock::putImpl(EDPutToken::value_type index, std::unique_ptr<PROD> product) {
193193
// The following will call post_insert if T has such a function,
194194
// and do nothing if T has no such function.
195-
std::conditional_t<detail::has_postinsert<PROD>::value, DoPostInsert<PROD>, DoNotPostInsert<PROD>> maybe_inserter;
196-
maybe_inserter(product.get());
195+
detail::do_post_insert_if_available(*product.get());
197196

198197
assert(index < putProducts().size());
199198

@@ -271,8 +270,7 @@ namespace edm {
271270

272271
// The following will call post_insert if T has such a function,
273272
// and do nothing if T has no such function.
274-
std::conditional_t<detail::has_postinsert<PROD>::value, DoPostInsert<PROD>, DoNotPostInsert<PROD>> maybe_inserter;
275-
maybe_inserter(&(wp->bareProduct()));
273+
detail::do_post_insert_if_available(wp->bareProduct());
276274

277275
putProducts()[index] = std::move(wp);
278276
}

FWCore/Framework/interface/PrincipalGetAdapter.h

Lines changed: 13 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ namespace edm {
215215
unsigned int processBlockIndex(std::string const& processName) const;
216216

217217
private:
218+
template <typename T>
219+
static constexpr bool hasMergeProductFunction() {
220+
if constexpr (requires(T& a, T const& b) { a.mergeProduct(b); }) {
221+
return true;
222+
}
223+
return false;
224+
}
218225
// Is this an Event, a LuminosityBlock, or a Run.
219226
BranchType const& branchType() const;
220227

@@ -254,59 +261,22 @@ namespace edm {
254261
// PrincipalGetAdapter::put member template.
255262
//
256263

257-
// has_postinsert is a metafunction of one argument, the type T. As
258-
// with many metafunctions, it is implemented as a class with a data
259-
// member 'value', which contains the value 'returned' by the
260-
// metafunction.
261-
//
262-
// has_postinsert<T>::value is 'true' if T has the post_insert
263-
// member function (with the right signature), and 'false' if T has
264-
// no such member function.
265-
266264
namespace detail {
267-
using no_tag = std::false_type; // type indicating FALSE
268-
using yes_tag = std::true_type; // type indicating TRUE
269-
270-
// Definitions forthe following struct and function templates are
271-
// not needed; we only require the declarations.
272-
template <typename T, void (T::*)()>
273-
struct postinsert_function;
274-
template <typename T>
275-
no_tag has_postinsert_helper(...);
276-
template <typename T>
277-
yes_tag has_postinsert_helper(postinsert_function<T, &T::post_insert>* p);
278-
279265
template <typename T>
280-
struct has_postinsert {
281-
static constexpr bool value = std::is_same<decltype(has_postinsert_helper<T>(nullptr)), yes_tag>::value &&
282-
!std::is_base_of<DoNotSortUponInsertion, T>::value;
283-
};
284-
266+
void do_post_insert_if_available(T& iProduct) {
267+
if constexpr (not std::derived_from<T, DoNotSortUponInsertion> and requires(T& p) { p.post_insert(); }) {
268+
iProduct.post_insert();
269+
}
270+
}
285271
} // namespace detail
286272

287-
//------------------------------------------------------------
288-
289-
// The following function objects are used by Event::put, under the
290-
// control of a metafunction if, to either call the given object's
291-
// post_insert function (if it has one), or to do nothing (if it
292-
// does not have a post_insert function).
293-
template <typename T>
294-
struct DoPostInsert {
295-
void operator()(T* p) const { p->post_insert(); }
296-
};
297-
298-
template <typename T>
299-
struct DoNotPostInsert {
300-
void operator()(T*) const {}
301-
};
302-
303273
// Implementation of PrincipalGetAdapter member templates. See PrincipalGetAdapter.cc for the
304274
// implementation of non-template members.
305275
//
306276

307277
template <typename PROD>
308278
inline bool PrincipalGetAdapter::checkIfComplete() const {
309-
return isComplete() || !detail::has_mergeProduct_function<PROD>::value;
279+
return isComplete() || !hasMergeProductFunction<PROD>();
310280
}
311281

312282
} // namespace edm

FWCore/Framework/interface/ProcessBlock.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,7 @@ namespace edm {
191191
void ProcessBlock::putImpl(EDPutToken::value_type index, std::unique_ptr<PROD> product) {
192192
// The following will call post_insert if T has such a function,
193193
// and do nothing if T has no such function.
194-
std::conditional_t<detail::has_postinsert<PROD>::value, DoPostInsert<PROD>, DoNotPostInsert<PROD>> maybe_inserter;
195-
maybe_inserter(product.get());
194+
detail::do_post_insert_if_available(*product.get());
196195

197196
assert(index < putProducts().size());
198197

@@ -208,8 +207,7 @@ namespace edm {
208207

209208
// The following will call post_insert if T has such a function,
210209
// and do nothing if T has no such function.
211-
std::conditional_t<detail::has_postinsert<PROD>::value, DoPostInsert<PROD>, DoNotPostInsert<PROD>> maybe_inserter;
212-
maybe_inserter(&(wp->bareProduct()));
210+
detail::do_post_insert_if_available(wp->bareProduct());
213211

214212
putProducts()[index] = std::move(wp);
215213
}

FWCore/Framework/interface/Run.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,7 @@ namespace edm {
193193
void Run::putImpl(EDPutToken::value_type index, std::unique_ptr<PROD> product) {
194194
// The following will call post_insert if T has such a function,
195195
// and do nothing if T has no such function.
196-
std::conditional_t<detail::has_postinsert<PROD>::value, DoPostInsert<PROD>, DoNotPostInsert<PROD>> maybe_inserter;
197-
maybe_inserter(product.get());
196+
detail::do_post_insert_if_available(*product.get());
198197

199198
assert(index < putProducts().size());
200199

@@ -270,8 +269,7 @@ namespace edm {
270269

271270
// The following will call post_insert if T has such a function,
272271
// and do nothing if T has no such function.
273-
std::conditional_t<detail::has_postinsert<PROD>::value, DoPostInsert<PROD>, DoNotPostInsert<PROD>> maybe_inserter;
274-
maybe_inserter(&(wp->bareProduct()));
272+
detail::do_post_insert_if_available(wp->bareProduct());
275273

276274
putProducts()[index] = std::move(wp);
277275
}

0 commit comments

Comments
 (0)