@@ -170,6 +170,78 @@ public:
170170 return GetBinContent (indices);
171171 }
172172
173+ // / Set the content of a single bin.
174+ // /
175+ // / \code
176+ // / ROOT::Experimental::RHistEngine<int> hist({/* two dimensions */});
177+ // / std::array<ROOT::Experimental::RBinIndex, 2> indices = {3, 5};
178+ // / int value = /* ... */;
179+ // / hist.SetBinContent(indices, value);
180+ // / \endcode
181+ // /
182+ // / \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
183+ // / values. See also the class documentation of RBinIndex.
184+ // /
185+ // / Throws an exception if the number of indices does not match the axis configuration or the bin is not found.
186+ // /
187+ // / \param[in] indices the array of indices for each axis
188+ // / \param[in] value the new value of the bin content
189+ // / \par See also
190+ // / the \ref SetBinContent(const A &... args) const "variadic function template overload" accepting arguments
191+ // / directly
192+ template <std::size_t N, typename V>
193+ void SetBinContent (const std::array<RBinIndex, N> &indices, const V &value)
194+ {
195+ // We could rely on RAxes::ComputeGlobalIndex to check the number of arguments, but its exception message might
196+ // be confusing for users.
197+ if (N != GetNDimensions ()) {
198+ throw std::invalid_argument (" invalid number of indices passed to SetBinContent" );
199+ }
200+ RLinearizedIndex index = fAxes .ComputeGlobalIndex (indices);
201+ if (!index.fValid ) {
202+ throw std::invalid_argument (" bin not found in SetBinContent" );
203+ }
204+ assert (index.fIndex < fBinContents .size ());
205+ // To allow conversion, we have to accept value with a template type V to capture any argument. Otherwise it would
206+ // select the variadic function template...
207+ fBinContents [index.fIndex ] = value;
208+ }
209+
210+ private:
211+ template <typename ... A, std::size_t ... I>
212+ void SetBinContentImpl (const std::tuple<A...> &args, std::index_sequence<I...>)
213+ {
214+ std::array<RBinIndex, sizeof ...(A) - 1 > indices{std::get<I>(args)...};
215+ SetBinContent (indices, std::get<sizeof ...(A) - 1 >(args));
216+ }
217+
218+ public:
219+ // / Set the content of a single bin.
220+ // /
221+ // / \code
222+ // / ROOT::Experimental::RHistEngine<int> hist({/* two dimensions */});
223+ // / int value = /* ... */;
224+ // / hist.SetBinContent(ROOT::Experimental::RBinIndex(3), ROOT::Experimental::RBinIndex(5), value);
225+ // / // ... or construct the RBinIndex arguments implicitly from integers:
226+ // / hist.SetBinContent(3, 5, value);
227+ // / \endcode
228+ // /
229+ // / \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
230+ // / values. See also the class documentation of RBinIndex.
231+ // /
232+ // / Throws an exception if the number of arguments does not match the axis configuration or the bin is not found.
233+ // /
234+ // / \param[in] args the arguments for each axis and the new value of the bin content
235+ // / \par See also
236+ // / the \ref SetBinContent(const std::array<RBinIndex, N> &indices, const V &value) const "function overload"
237+ // / accepting `std::array`
238+ template <typename ... A>
239+ void SetBinContent (const A &...args)
240+ {
241+ auto t = std::forward_as_tuple (args...);
242+ SetBinContentImpl (t, std::make_index_sequence<sizeof ...(A) - 1 >());
243+ }
244+
173245 // / Add all bin contents of another histogram.
174246 // /
175247 // / Throws an exception if the axes configurations are not identical.
0 commit comments