#ifndef RT_ATOMICS_H
#define RT_ATOMICS_H

/* Macros & helpers for atomic instructions */

#ifdef _MSC_VER

/* Increment and decrement return the new value */

#define rtAtomic32Inc(pa) _InterlockedIncrement((volatile long *)(pa))
#define rtAtomic64Inc(pa) _InterlockedIncrement64((volatile __int64 *)(pa))
#define rtAtomic32Dec(pa) _InterlockedDecrement((volatile long *)(pa))
#define rtAtomic64Dec(pa) _InterlockedDecrement64((volatile __int64 *)(pa))

#define rtAtomic32FetchAdd(pa, value) _InterlockedExchangeAdd((volatile long *)(pa), (LONG)(value))
#define rtAtomic64FetchAdd(pa, value)                                                              \
    _InterlockedExchangeAdd64((volatile __int64 *)(pa), (LONG)(value))

#if defined(_M_ARM) || defined(_M_ARM64)
#define rtAtomic32ExchangeAcq(_pDest, _NewVal)                                                     \
    _InterlockedExchange_acq((volatile long *)(_pDest), (_NewVal))
#define rtAtomic32ExchangeRel(_pDest, _NewVal)                                                     \
    _InterlockedExchange_rel((volatile long *)(_pDest), (_NewVal))
#define rtAtomic32CASAcq(_pDest, _NewVal, _Compare)                                                \
    _InterlockedCompareExchange_acq((volatile long *)(_pDest), (_NewVal), (_Compare))
#define rtAtomic32CASRel(_pDest, _NewVal, _Compare) _InterlockedCompareExchange_rel((volatile long *)(_pDest), (_NewVal), (_Compare
#else
/* x64/86 does not have acquire/release versions of these */
#define rtAtomic32ExchangeAcq(_pDest, _NewVal)                                                     \
    _InterlockedExchange((volatile long *)(_pDest), (_NewVal))
#define rtAtomic32ExchangeRel(_pDest, _NewVal)                                                     \
    _InterlockedExchange((volatile long *)(_pDest), (_NewVal))
#define rtAtomic32CASAcq(_pDest, _NewVal, _Compare)                                                \
    _InterlockedCompareExchange((volatile long *)(_pDest), (_NewVal), (_Compare))
#define rtAtomic32CASRel(_pDest, _NewVal, _Compare) _InterlockedCompareExchange((volatile long *)(_pDest), (_NewVal), (_Compare
#endif
#define rtAtomic32Exchange(_pDest, _NewVal)                                                        \
    _InterlockedExchange((volatile long *)(_pDest), (_NewVal))
#define rtAtomic32CAS(_pDest, _NewVal, _Compare)                                                   \
    _InterlockedCompareExchange((volatile long *)(_pDest), (_NewVal), (_Compare))

#elif defined(__GNUC__) || defined(__clang__)

#define rtAtomic32Inc(pa) __atomic_add_fetch((pa), 1, __ATOMIC_SEQ_CST)
#define rtAtomic64Inc(pa) __atomic_add_fetch((pa), 1LL, __ATOMIC_SEQ_CST)
#define rtAtomic32Dec(pa) __atomic_sub_fetch((pa), 1, __ATOMIC_SEQ_CST)
#define rtAtomic64Dec(pa) __atomic_sub_fetch((pa), 1LL, __ATOMIC_SEQ_CST)

#define rtAtomic32FetchAdd(pa, value) __atomic_fetch_add((pa), (value), __ATOMIC_SEQ_CST)
#define rtAtomic64FetchAdd(pa, value) __atomic_fetch_add((pa), (value), __ATOMIC_SEQ_CST)

/* TODO Linux versions of compare exchange
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
*/

#endif

#endif
