22
33#include < type_traits>
44
5+ // User-defined weight type with a single double, but can be much more complicated
6+ struct UserWeight {
7+ double fWeight = 0 ;
8+ };
9+
510// User-defined bin content type consisting of a single double, but can be much more complicated.
611struct User {
712 double fValue = 0 ;
@@ -25,6 +30,12 @@ struct User {
2530 return *this ;
2631 }
2732
33+ User &operator +=(const UserWeight &w)
34+ {
35+ fValue += w.fWeight ;
36+ return *this ;
37+ }
38+
2839 User &operator +=(const User &rhs)
2940 {
3041 fValue += rhs.fValue ;
@@ -41,6 +52,8 @@ struct User {
4152
4253 void AtomicAdd (double w) { ROOT::Experimental::Internal::AtomicAdd (&fValue , w); }
4354
55+ void AtomicAdd (const UserWeight &w) { ROOT::Experimental::Internal::AtomicAdd (&fValue , w.fWeight ); }
56+
4457 void AtomicAdd (const User &rhs) { ROOT::Experimental::Internal::AtomicAdd (&fValue , rhs.fValue ); }
4558};
4659
@@ -149,6 +162,28 @@ TEST(RHistEngineUser, FillWeight)
149162 EXPECT_EQ (engine.GetBinContent (indices).fValue , 0.9 );
150163}
151164
165+ TEST (RHistEngineUser, FillUserWeight)
166+ {
167+ // Weighted filling with user-defined weight uses operator+=(const UserWeight &)
168+ static constexpr std::size_t Bins = 20 ;
169+ const RRegularAxis axis (Bins, {0 , Bins});
170+ RHistEngine<User> engine ({axis});
171+
172+ // Must use overload accepting std::tuple
173+ engine.Fill (std::make_tuple (9.5 ), UserWeight{0.9 });
174+
175+ EXPECT_EQ (engine.GetBinContent (RBinIndex (9 )).fValue , 0.9 );
176+ }
177+
178+ TEST (RHistEngineUser, FillUserWeightInvalidNumberOfArguments)
179+ {
180+ static constexpr std::size_t Bins = 20 ;
181+ const RRegularAxis axis (Bins, {0 , Bins});
182+ RHistEngine<User> engine ({axis});
183+
184+ EXPECT_THROW (engine.Fill (std::make_tuple (8.5 , 9.5 ), UserWeight{0.9 }), std::invalid_argument);
185+ }
186+
152187TEST (RHistEngineUser, FillAtomic)
153188{
154189 // Unweighted filling with atomic instructions uses AtomicInc
@@ -166,7 +201,7 @@ TEST(RHistEngineUser, FillAtomic)
166201
167202TEST (RHistEngineUser, FillAtomicWeight)
168203{
169- // Weighted filling with atomic instructions uses AtomicAdd
204+ // Weighted filling with atomic instructions uses AtomicAdd(double)
170205 static constexpr std::size_t Bins = 20 ;
171206 const RRegularAxis axis (Bins, {0 , Bins});
172207 RHistEngine<User> engine ({axis});
@@ -179,6 +214,28 @@ TEST(RHistEngineUser, FillAtomicWeight)
179214 EXPECT_EQ (engine.GetBinContent (indices).fValue , 0.9 );
180215}
181216
217+ TEST (RHistEngineUser, FillAtomicUserWeight)
218+ {
219+ // Weighted filling with user-defined weight and atomic instructions uses AtomicAdd(const UserWeight &)
220+ static constexpr std::size_t Bins = 20 ;
221+ const RRegularAxis axis (Bins, {0 , Bins});
222+ RHistEngine<User> engine ({axis});
223+
224+ // Must use overload accepting std::tuple
225+ engine.FillAtomic (std::make_tuple (9.5 ), UserWeight{0.9 });
226+
227+ EXPECT_EQ (engine.GetBinContent (RBinIndex (9 )).fValue , 0.9 );
228+ }
229+
230+ TEST (RHistEngineUser, FillAtomicUserWeightInvalidNumberOfArguments)
231+ {
232+ static constexpr std::size_t Bins = 20 ;
233+ const RRegularAxis axis (Bins, {0 , Bins});
234+ RHistEngine<User> engine ({axis});
235+
236+ EXPECT_THROW (engine.FillAtomic (std::make_tuple (8.5 , 9.5 ), UserWeight{0.9 }), std::invalid_argument);
237+ }
238+
182239TEST (RHistEngineUser, Scale)
183240{
184241 // Scaling uses operator+=(double)
0 commit comments