Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RHistUtils.hxx
Go to the documentation of this file.
1/// \file
2/// \warning This file contains implementation details that will change without notice. User code should never include
3/// this header directly.
4
5#ifndef ROOT_RHistUtils
6#define ROOT_RHistUtils
7
8#include <type_traits>
9
10#ifdef _MSC_VER
11#include <intrin.h>
12#endif
13
14namespace ROOT {
15namespace Experimental {
16namespace Internal {
17
18template <typename T, typename... Ts>
19struct LastType : LastType<Ts...> {};
20template <typename T>
21struct LastType<T> {
22 using type = T;
23};
24
25#ifdef _MSC_VER
26namespace MSVC {
27template <std::size_t N>
28struct AtomicOps {};
29
30template <>
31struct AtomicOps<1> {
32 static void Load(const void *ptr, void *ret)
33 {
34 *static_cast<char *>(ret) = __iso_volatile_load8(static_cast<const char *>(ptr));
35 }
36 static void Add(void *ptr, const void *val)
37 {
38 _InterlockedExchangeAdd8(static_cast<char *>(ptr), *static_cast<const char *>(val));
39 }
40 static bool CompareExchange(void *ptr, void *expected, const void *desired)
41 {
42 // MSVC functions have the arguments reversed...
43 const char expectedVal = *static_cast<char *>(expected);
44 const char desiredVal = *static_cast<const char *>(desired);
45 const char previous = _InterlockedCompareExchange8(static_cast<char *>(ptr), desiredVal, expectedVal);
46 if (previous == expectedVal) {
47 return true;
48 }
49 *static_cast<char *>(expected) = previous;
50 return false;
51 }
52};
53
54template <>
55struct AtomicOps<2> {
56 static void Load(const void *ptr, void *ret)
57 {
58 *static_cast<short *>(ret) = __iso_volatile_load16(static_cast<const short *>(ptr));
59 }
60 static void Add(void *ptr, const void *val)
61 {
62 _InterlockedExchangeAdd16(static_cast<short *>(ptr), *static_cast<const short *>(val));
63 }
64 static bool CompareExchange(void *ptr, void *expected, const void *desired)
65 {
66 // MSVC functions have the arguments reversed...
67 const short expectedVal = *static_cast<short *>(expected);
68 const short desiredVal = *static_cast<const short *>(desired);
69 const short previous = _InterlockedCompareExchange16(static_cast<short *>(ptr), desiredVal, expectedVal);
70 if (previous == expectedVal) {
71 return true;
72 }
73 *static_cast<short *>(expected) = previous;
74 return false;
75 }
76};
77
78template <>
79struct AtomicOps<4> {
80 static void Load(const void *ptr, void *ret)
81 {
82 *static_cast<int *>(ret) = __iso_volatile_load32(static_cast<const int *>(ptr));
83 }
84 static void Add(void *ptr, const void *val)
85 {
86 _InterlockedExchangeAdd(static_cast<long *>(ptr), *static_cast<const long *>(val));
87 }
88 static bool CompareExchange(void *ptr, void *expected, const void *desired)
89 {
90 // MSVC functions have the arguments reversed...
91 const long expectedVal = *static_cast<long *>(expected);
92 const long desiredVal = *static_cast<const long *>(desired);
93 const long previous = _InterlockedCompareExchange(static_cast<long *>(ptr), desiredVal, expectedVal);
94 if (previous == expectedVal) {
95 return true;
96 }
97 *static_cast<long *>(expected) = previous;
98 return false;
99 }
100};
101
102template <>
103struct AtomicOps<8> {
104 static void Load(const void *ptr, void *ret)
105 {
106 *static_cast<__int64 *>(ret) = __iso_volatile_load64(static_cast<const __int64 *>(ptr));
107 }
108 static void Add(void *ptr, const void *val);
109 static bool CompareExchange(void *ptr, void *expected, const void *desired)
110 {
111 // MSVC functions have the arguments reversed...
112 const __int64 expectedVal = *static_cast<__int64 *>(expected);
113 const __int64 desiredVal = *static_cast<const __int64 *>(desired);
115 if (previous == expectedVal) {
116 return true;
117 }
118 *static_cast<__int64 *>(expected) = previous;
119 return false;
120 }
121};
122} // namespace MSVC
123#endif
124
125template <typename T>
126void AtomicLoad(const T *ptr, T *ret)
127{
128#ifndef _MSC_VER
130#else
131 MSVC::AtomicOps<sizeof(T)>::Load(ptr, ret);
132#endif
133}
134
135template <typename T>
137{
138#ifndef _MSC_VER
140#else
141 return MSVC::AtomicOps<sizeof(T)>::CompareExchange(ptr, expected, desired);
142#endif
143}
144
145template <typename T>
147{
148 T expected;
149 AtomicLoad(ptr, &expected);
150 T desired = expected + val;
151 while (!AtomicCompareExchange(ptr, &expected, &desired)) {
152 // expected holds the new value; try again.
153 desired = expected + val;
154 }
155}
156
157#ifdef _MSC_VER
158namespace MSVC {
159inline void AtomicOps<8>::Add(void *ptr, const void *val)
160{
161#if _WIN64
162 _InterlockedExchangeAdd64(static_cast<__int64 *>(ptr), *static_cast<const __int64 *>(val));
163#else
164 AtomicAddCompareExchangeLoop(static_cast<__int64 *>(ptr), *static_cast<const __int64 *>(val));
165#endif
166}
167} // namespace MSVC
168#endif
169
170template <typename T>
171std::enable_if_t<std::is_integral_v<T>> AtomicAdd(T *ptr, T val)
172{
173#ifndef _MSC_VER
175#else
176 MSVC::AtomicOps<sizeof(T)>::Add(ptr, &val);
177#endif
178}
179
180template <typename T>
181std::enable_if_t<std::is_floating_point_v<T>> AtomicAdd(T *ptr, T val)
182{
184}
185
186// For adding a double-precision weight to a single-precision bin content type, cast the argument once before the
187// compare-exchange loop.
188static inline void AtomicAdd(float *ptr, double val)
189{
190 AtomicAdd(ptr, static_cast<float>(val));
191}
192
193template <typename T>
194std::enable_if_t<std::is_arithmetic_v<T>> AtomicInc(T *ptr)
195{
196 AtomicAdd(ptr, static_cast<T>(1));
197}
198
199template <typename T, typename U>
200std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::AtomicAdd)>> AtomicAdd(T *ptr, const U &add)
201{
202 ptr->AtomicAdd(add);
203}
204
205template <typename T>
206std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::AtomicInc)>> AtomicInc(T *ptr)
207{
208 ptr->AtomicInc();
209}
210
211} // namespace Internal
212} // namespace Experimental
213} // namespace ROOT
214
215#endif
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
std::enable_if_t< std::is_arithmetic_v< T > > AtomicInc(T *ptr)
void AtomicLoad(const T *ptr, T *ret)
bool AtomicCompareExchange(T *ptr, T *expected, T *desired)
void AtomicAddCompareExchangeLoop(T *ptr, T val)
std::enable_if_t< std::is_integral_v< T > > AtomicAdd(T *ptr, T val)
TMatrixT< Element > & Add(TMatrixT< Element > &target, Element scalar, const TMatrixT< Element > &source)
Modify addition: target += scalar * source.