#ifndef ATOMIC_H
#define ATOMIC_H

#if PLATFORM_WINDOWS

FORCE_INLINE i32 atomic_i32_eval(struct atomic_i32 *x) { return (i32)_InterlockedOr((volatile long *)&x->_v, 0); }
FORCE_INLINE i32 atomic_i32_inc_eval(struct atomic_i32 *x) { return (i32)_InterlockedIncrement((volatile long *)&x->_v); }
FORCE_INLINE i32 atomic_i32_dec_eval(struct atomic_i32 *x) { return (i32)_InterlockedDecrement((volatile long *)&x->_v); }
FORCE_INLINE i32 atomic_i32_eval_add(struct atomic_i32 *x, i32 a) { return (i32)_InterlockedExchangeAdd((volatile long *)&x->_v, a); }
FORCE_INLINE i32 atomic_i32_eval_exchange(struct atomic_i32 *x, i32 e) { return (i32)_InterlockedExchange((volatile long *)&x->_v, e); }
FORCE_INLINE i32 atomic_i32_eval_compare_exchange(struct atomic_i32 *x, i32 c, i32 e) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, e, c); }
FORCE_INLINE volatile i32 *atomic_i32_raw(struct atomic_i32 *x) { return &x->_v; }

FORCE_INLINE i64 atomic_i64_eval(struct atomic_i64 *x) { return (i64)_InterlockedOr64(&x->_v, 0); }
FORCE_INLINE i64 atomic_i64_inc_eval(struct atomic_i64 *x) { return (i64)_InterlockedIncrement64(&x->_v); }
FORCE_INLINE i64 atomic_i64_dec_eval(struct atomic_i64 *x) { return (i64)_InterlockedDecrement64(&x->_v); }
FORCE_INLINE i64 atomic_i64_eval_add(struct atomic_i64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); }
FORCE_INLINE i64 atomic_i64_eval_exchange(struct atomic_i64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); }
FORCE_INLINE i64 atomic_i64_eval_compare_exchange(struct atomic_i64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); }
FORCE_INLINE volatile i64 *atomic_i64_raw(struct atomic_i64 *x) { return &x->_v; }

FORCE_INLINE u32 atomic_u32_eval(struct atomic_u32 *x) { return (u32)_InterlockedExchangeAdd((volatile long *)&x->_v, 0); }
FORCE_INLINE u32 atomic_u32_inc_eval(struct atomic_u32 *x) { return (u32)_InterlockedIncrement((volatile long *)&x->_v); }
FORCE_INLINE u32 atomic_u32_dec_eval(struct atomic_u32 *x) { return (u32)_InterlockedDecrement((volatile long *)&x->_v); }
FORCE_INLINE u32 atomic_u32_eval_add(struct atomic_u32 *x, u32 a) { return (u32)_InterlockedExchangeAdd((volatile long *)&x->_v, (long)a); }
FORCE_INLINE u32 atomic_u32_eval_exchange(struct atomic_u32 *x, u32 e) { return (u32)_InterlockedExchange((volatile long *)&x->_v, (long)e); }
FORCE_INLINE u32 atomic_u32_eval_compare_exchange(struct atomic_u32 *x, u32 c, u32 e) { return (u32)_InterlockedCompareExchange((volatile long *)&x->_v, (long)e, (long)c); }
FORCE_INLINE volatile u32 *atomic_u32_raw(struct atomic_u32 *x) { return &x->_v; }

FORCE_INLINE u64 atomic_u64_eval(struct atomic_u64 *x) { return (u64)_InterlockedOr64((volatile i64 *)&x->_v, 0); }
FORCE_INLINE u64 atomic_u64_inc_eval(struct atomic_u64 *x) { return (u64)_InterlockedIncrement64((volatile i64 *)&x->_v); }
FORCE_INLINE u64 atomic_u64_dec_eval(struct atomic_u64 *x) { return (u64)_InterlockedDecrement64((volatile i64 *)&x->_v); }
FORCE_INLINE u64 atomic_u64_eval_add(struct atomic_u64 *x, u64 a) { return (u64)_InterlockedExchangeAdd64((volatile i64 *)&x->_v, (i64)a); }
FORCE_INLINE u64 atomic_u64_eval_exchange(struct atomic_u64 *x, u64 e) { return (u64)_InterlockedExchange64((volatile i64 *)&x->_v, (i64)e); }
FORCE_INLINE u64 atomic_u64_eval_compare_exchange(struct atomic_u64 *x, u64 c, u64 e) { return (u64)_InterlockedCompareExchange64((volatile i64 *)&x->_v, (i64)e, (i64)c); }
FORCE_INLINE volatile u64 *atomic_u64_raw(struct atomic_u64 *x) { return &x->_v; }

FORCE_INLINE void *atomic_ptr_eval(struct atomic_ptr *x) { return (void *)_InterlockedOr64((volatile i64 *)&x->_v, 0); }
FORCE_INLINE void *atomic_ptr_eval_compare_exchange(struct atomic_ptr *x, void *c, void *e) { return (void *)_InterlockedCompareExchange64((volatile i64 *)&x->_v, (i64)e, (i64)c); }
FORCE_INLINE volatile void **atomic_ptr_raw(struct atomic_ptr *x) { return &x->_v; }

#else
# error "Atomics not implemented"
#endif

#endif
