25#define DISPENSO_MAJOR_VERSION 1
26#define DISPENSO_MINOR_VERSION 4
27#define DISPENSO_PATCH_VERSION 1
29#if defined(DISPENSO_SHARED_LIB)
32#if defined(DISPENSO_LIB_EXPORT)
33#define DISPENSO_DLL_ACCESS __declspec(dllexport)
35#define DISPENSO_DLL_ACCESS __declspec(dllimport)
38#elif defined(__clang__) || defined(__GNUC__)
39#define DISPENSO_DLL_ACCESS __attribute__((visibility("default")))
43#if !defined(DISPENSO_DLL_ACCESS)
44#define DISPENSO_DLL_ACCESS
47using ssize_t = std::make_signed<std::size_t>::type;
49#if defined(__clang__) || defined(__GNUC__)
50#define DISPENSO_INLINE __attribute__((always_inline)) inline
51#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
52#define DISPENSO_INLINE __forceinline
54#define DISPENSO_INLINE inline
70#define DISPENSO_THREAD_LOCAL __declspec(thread)
71#elif defined(__GNUC__) || defined(__clang__)
72#define DISPENSO_THREAD_LOCAL __thread
74#error Supply lightweight thread-locals for this compiler. Can define to thread_local if lightweight not available
77#if (defined(__GNUC__) || defined(__clang__))
78#define DISPENSO_EXPECT(a, b) __builtin_expect(a, b)
80#define DISPENSO_EXPECT(a, b) a
84#if (defined(__GNUC__) || defined(__clang__))
85#define DO_PRAGMA(X) _Pragma(#X)
86#define DISPENSO_DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push)
87#define DISPENSO_DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop)
88#define DISPENSO_DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName)
89#if !defined(__clang__)
90#define DISPENSO_DISABLE_WARNING_ZERO_VARIADIC_MACRO_ARGUMENTS
91#define DISPENSO_DISABLE_WARNING_GLOBAL_CONSTRUCTORS
93#define DISPENSO_DISABLE_WARNING_ZERO_VARIADIC_MACRO_ARGUMENTS \
94 DISPENSO_DISABLE_WARNING(-Wgnu-zero-variadic-macro-arguments)
95#define DISPENSO_DISABLE_WARNING_GLOBAL_CONSTRUCTORS \
96 DISPENSO_DISABLE_WARNING(-Wglobal-constructors)
98#elif defined(_MSC_VER)
99#define DISPENSO_DISABLE_WARNING_PUSH __pragma(warning(push))
100#define DISPENSO_DISABLE_WARNING_POP __pragma(warning(pop))
101#define DISPENSO_DISABLE_WARNING(warningNumber) __pragma(warning(disable : warningNumber))
102#define DISPENSO_DISABLE_WARNING_ZERO_VARIADIC_MACRO_ARGUMENTS
103#define DISPENSO_DISABLE_WARNING_GLOBAL_CONSTRUCTORS
105#define DISPENSO_DISABLE_WARNING_PUSH
106#define DISPENSO_DISABLE_WARNING_POP
107#define DISPENSO_DISABLE_WARNING_ZERO_VARIADIC_MACRO_ARGUMENTS
108#define DISPENSO_DISABLE_WARNING_GLOBAL_CONSTRUCTORS
121 operator const T&()
const {
133 alignas(
alignof(T))
char b[
sizeof(T)];
137struct alignas(kCacheLineSize) AlignedAtomic :
public std::atomic<T*> {};
139inline void* alignedMalloc(
size_t bytes,
size_t alignment) {
140 alignment = std::max(alignment,
sizeof(uintptr_t));
141 char* ptr =
reinterpret_cast<char*
>(::malloc(bytes + alignment));
142 uintptr_t base =
reinterpret_cast<uintptr_t
>(ptr);
143 uintptr_t oldBase = base;
144 uintptr_t mask = alignment - 1;
148 uintptr_t* recovery =
reinterpret_cast<uintptr_t*
>(base -
sizeof(uintptr_t));
150 return reinterpret_cast<void*
>(base);
153inline void* alignedMalloc(
size_t bytes) {
154 return alignedMalloc(bytes, kCacheLineSize);
157inline void alignedFree(
void* ptr) {
161 char* p =
reinterpret_cast<char*
>(ptr);
162 uintptr_t recovered = *
reinterpret_cast<uintptr_t*
>(p -
sizeof(uintptr_t));
163 ::free(
reinterpret_cast<void*
>(recovered));
167struct AlignedFreeDeleter {
168 void operator()(T* ptr) {
170 detail::alignedFree(ptr);
174struct AlignedFreeDeleter<void> {
175 void operator()(
void* ptr) {
176 detail::alignedFree(ptr);
180template <
typename T,
class... Args>
181std::shared_ptr<T> make_shared(Args&&... args) {
182 void* tv = alignedMalloc(
sizeof(T),
alignof(T));
183 T* t =
new (tv) T(std::forward<Args>(args)...);
184 return std::shared_ptr<T>(t, AlignedFreeDeleter<T>());
187inline constexpr uintptr_t alignToCacheLine(uintptr_t val) {
194#if defined __x86_64__ || defined __i386__
195inline void cpuRelax() {
196 asm volatile(
"pause" :::
"memory");
198#elif defined __arm64__ || defined __aarch64__
199inline void cpuRelax() {
200 asm volatile(
"yield" :::
"memory");
202#elif defined __powerpc__ || defined __POWERPC__
204inline void cpuRelax() {
205 asm volatile(
"or r27,r27,r27" :::
"memory");
208inline void cpuRelax() {
209 asm volatile(
"or 27,27,27" :::
"memory");
214inline void cpuRelax() {}
224 ssize_t transitionTaskIndex;
225 ssize_t ceilChunkSize;
228inline StaticChunking staticChunkSize(ssize_t items, ssize_t chunks) {
231 chunking.ceilChunkSize = (items + chunks - 1) / chunks;
232 ssize_t numLeft = chunking.ceilChunkSize * chunks - items;
233 chunking.transitionTaskIndex = chunks - numLeft;
detail::AlignedBuffer< T > AlignedBuffer
Buffer with proper alignment for type T.
detail::StaticChunking StaticChunking
Information for statically chunking a range across threads.