23#if defined(_MSC_VER) && \
24 (defined(_M_AMD64) || defined(_M_IX86) || defined(_M_ARM64) || defined(_M_ARM))
30#define DISPENSO_MAJOR_VERSION 1
31#define DISPENSO_MINOR_VERSION 6
32#define DISPENSO_PATCH_VERSION 2
35#if __cplusplus >= 202002L && defined(__cpp_concepts) && __cpp_concepts >= 201907L
36#define DISPENSO_HAS_CONCEPTS 1
39#define DISPENSO_HAS_CONCEPTS 0
56#if DISPENSO_HAS_CONCEPTS
57#define DISPENSO_REQUIRES(...) requires(__VA_ARGS__)
59#define DISPENSO_REQUIRES(...)
73#if __cplusplus >= 201703L
74#define DISPENSO_DEPRECATED(msg) [[deprecated(msg)]]
76#define DISPENSO_DEPRECATED(msg)
79#if defined(DISPENSO_SHARED_LIB)
82#if defined(DISPENSO_LIB_EXPORT)
83#define DISPENSO_DLL_ACCESS __declspec(dllexport)
85#define DISPENSO_DLL_ACCESS __declspec(dllimport)
88#elif defined(__clang__) || defined(__GNUC__)
89#define DISPENSO_DLL_ACCESS __attribute__((visibility("default")))
93#if !defined(DISPENSO_DLL_ACCESS)
94#define DISPENSO_DLL_ACCESS
100#if defined(__clang__)
101#define DISPENSO_NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
103#define DISPENSO_NO_THREAD_SAFETY_ANALYSIS
106using ssize_t = std::make_signed<std::size_t>::type;
108#if defined(__CUDACC__)
109#define DISPENSO_INLINE __host__ __device__ __forceinline__
110#elif defined(__clang__) || defined(__GNUC__)
111#define DISPENSO_INLINE __attribute__((always_inline)) inline
112#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
113#define DISPENSO_INLINE __forceinline
115#define DISPENSO_INLINE inline
122#if defined(__APPLE__) && defined(__arm64__)
140#define DISPENSO_CACHELINE_ALIGNED alignas(kCacheLineSize)
149#define DISPENSO_THREAD_LOCAL __declspec(thread)
150#elif defined(__GNUC__) || defined(__clang__)
151#define DISPENSO_THREAD_LOCAL __thread
153#error Supply lightweight thread-locals for this compiler. Can define to thread_local if lightweight not available
156#if (defined(__GNUC__) || defined(__clang__))
157#define DISPENSO_EXPECT(a, b) __builtin_expect(a, b)
159#define DISPENSO_EXPECT(a, b) a
163#if (defined(__GNUC__) || defined(__clang__))
164#define DO_PRAGMA(X) _Pragma(#X)
165#define DISPENSO_DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push)
166#define DISPENSO_DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop)
167#define DISPENSO_DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName)
168#if !defined(__clang__)
169#define DISPENSO_DISABLE_WARNING_ZERO_VARIADIC_MACRO_ARGUMENTS
170#define DISPENSO_DISABLE_WARNING_GLOBAL_CONSTRUCTORS
171#define DISPENSO_DISABLE_WARNING_FREE_NONHEAP_OBJECT \
172 DISPENSO_DISABLE_WARNING(-Wfree-nonheap-object)
174#define DISPENSO_DISABLE_WARNING_ZERO_VARIADIC_MACRO_ARGUMENTS \
175 DISPENSO_DISABLE_WARNING(-Wgnu-zero-variadic-macro-arguments)
176#define DISPENSO_DISABLE_WARNING_GLOBAL_CONSTRUCTORS \
177 DISPENSO_DISABLE_WARNING(-Wglobal-constructors)
178#define DISPENSO_DISABLE_WARNING_FREE_NONHEAP_OBJECT
180#elif defined(_MSC_VER)
181#define DISPENSO_DISABLE_WARNING_PUSH __pragma(warning(push))
182#define DISPENSO_DISABLE_WARNING_POP __pragma(warning(pop))
183#define DISPENSO_DISABLE_WARNING(warningNumber) __pragma(warning(disable : warningNumber))
184#define DISPENSO_DISABLE_WARNING_ZERO_VARIADIC_MACRO_ARGUMENTS
185#define DISPENSO_DISABLE_WARNING_GLOBAL_CONSTRUCTORS
186#define DISPENSO_DISABLE_WARNING_FREE_NONHEAP_OBJECT
188#define DISPENSO_DISABLE_WARNING_PUSH
189#define DISPENSO_DISABLE_WARNING_POP
190#define DISPENSO_DISABLE_WARNING_ZERO_VARIADIC_MACRO_ARGUMENTS
191#define DISPENSO_DISABLE_WARNING_GLOBAL_CONSTRUCTORS
192#define DISPENSO_DISABLE_WARNING_FREE_NONHEAP_OBJECT
213 operator const T&()
const {
225 alignas(
alignof(T))
char b[
sizeof(T)];
229struct alignas(kCacheLineSize)
AlignedAtomic :
public std::atomic<T*> {};
231inline void* alignedMalloc(
size_t bytes,
size_t alignment) {
232 alignment = std::max(alignment,
sizeof(uintptr_t));
233 char* ptr =
reinterpret_cast<char*
>(::malloc(bytes + alignment));
234 uintptr_t base =
reinterpret_cast<uintptr_t
>(ptr);
235 uintptr_t oldBase = base;
236 uintptr_t mask = alignment - 1;
240 uintptr_t* recovery =
reinterpret_cast<uintptr_t*
>(base -
sizeof(uintptr_t));
242 return reinterpret_cast<void*
>(base);
245inline void* alignedMalloc(
size_t bytes) {
246 return alignedMalloc(bytes, kCacheLineSize);
249inline void alignedFree(
void* ptr) {
253 char* p =
reinterpret_cast<char*
>(ptr);
254 uintptr_t recovered = *
reinterpret_cast<uintptr_t*
>(p -
sizeof(uintptr_t));
255 ::free(
reinterpret_cast<void*
>(recovered));
259struct AlignedFreeDeleter {
260 void operator()(T* ptr) {
262 detail::alignedFree(ptr);
266struct AlignedFreeDeleter<void> {
267 void operator()(
void* ptr) {
268 detail::alignedFree(ptr);
275struct AlignedArrayFreeDeleter {
277 void operator()(T* ptr) {
278 for (
size_t i = 0; i < count; ++i) {
281 detail::alignedFree(ptr);
288std::unique_ptr<T[], AlignedArrayFreeDeleter<T>> makeAlignedArray(
size_t n) {
289 void* raw = detail::alignedMalloc(
sizeof(T) * n,
alignof(T));
290 T* arr =
static_cast<T*
>(raw);
291 for (
size_t i = 0; i < n; ++i) {
294 return std::unique_ptr<T[], AlignedArrayFreeDeleter<T>>(arr, AlignedArrayFreeDeleter<T>{n});
298template <
typename T,
class... Args>
299std::unique_ptr<T, AlignedFreeDeleter<T>> makeAligned(Args&&... args) {
300 void* raw = detail::alignedMalloc(
sizeof(T),
alignof(T));
301 T* obj =
new (raw) T(std::forward<Args>(args)...);
302 return std::unique_ptr<T, AlignedFreeDeleter<T>>(obj);
305template <
typename T,
class... Args>
306std::shared_ptr<T> make_shared(Args&&... args) {
307 void* tv = alignedMalloc(
sizeof(T),
alignof(T));
308 T* t =
new (tv) T(std::forward<Args>(args)...);
309 return std::shared_ptr<T>(t, AlignedFreeDeleter<T>());
312inline constexpr uintptr_t alignToCacheLine(uintptr_t val) {
319#if defined __x86_64__ || defined __i386__
320inline void cpuRelax() {
321 asm volatile(
"pause" :::
"memory");
323#elif defined _MSC_VER && (defined _M_AMD64 || defined _M_IX86)
324inline void cpuRelax() {
327#elif defined __arm64__ || defined __aarch64__
328inline void cpuRelax() {
329 asm volatile(
"yield" :::
"memory");
331#elif defined _MSC_VER && (defined _M_ARM64 || defined _M_ARM)
332inline void cpuRelax() {
335#elif defined __powerpc__ || defined __POWERPC__
337inline void cpuRelax() {
338 asm volatile(
"or r27,r27,r27" :::
"memory");
341inline void cpuRelax() {
342 asm volatile(
"or 27,27,27" :::
"memory");
347inline void cpuRelax() {}
357 ssize_t transitionTaskIndex;
358 ssize_t ceilChunkSize;
361inline StaticChunking staticChunkSize(ssize_t items, ssize_t chunks) {
364 chunking.ceilChunkSize = (items + chunks - 1) / chunks;
365 ssize_t numLeft = chunking.ceilChunkSize * chunks - items;
366 chunking.transitionTaskIndex = chunks - numLeft;
376inline StaticChunking staticChunkSizeGranular(ssize_t items, ssize_t chunks, uint32_t granularity) {
378 assert(granularity >= 1);
379 if (granularity <= 1) {
380 return staticChunkSize(items, chunks);
382 assert(items %
static_cast<ssize_t
>(granularity) == 0);
385 ssize_t gUnits = items /
static_cast<ssize_t
>(granularity);
386 ssize_t ceilG = (gUnits + chunks - 1) / chunks;
387 ssize_t numLeft = ceilG * chunks - gUnits;
388 chunking.ceilChunkSize = ceilG *
static_cast<ssize_t
>(granularity);
389 chunking.transitionTaskIndex = chunks - numLeft;
detail::AlignedAtomic< T > AlignedAtomic
Cache-line aligned atomic pointer.
detail::AlignedBuffer< T > AlignedBuffer
Buffer with proper alignment for type T.
detail::StaticChunking StaticChunking
Information for statically chunking a range across threads.