#pragma once

// Crossplatform interlocked functions


/** Atomic compare and exchange operation
    @param destination          A pointer to the destination value
    @param value                The value to store in the destination, if the old value is equal to comparand
    @param comparand            Value to compare with the destination
    @return                     True, if previous value of destination was equal with comparand, and exchange was made.
*/
//bool InterlockedBoolCompareExchange(volatile long *destination, long value, long comparand);

/** Atomic exchange operation
    @param destination          A pointer to the destination value
    @param value                The value to store in the destination
    @return                     True, if previous value of destination was equal with new value
*/
//bool InterlockedBoolExchange(volatile long *destination, long value);


#ifdef WIN32
#include <malloc.h>
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x500
#endif
#include <intrin.h>
#pragma intrinsic (_InterlockedExchange)

#define InterlockedBoolCompareExchange(A,B,C) (_InterlockedCompareExchange(A,B,C) == (C))
#define InterlockedBoolExchange(A,B) (_InterlockedExchange(A,B) == (B))

#else  // crossplatform

#include <stdint.h>
#include <assert.h>
#include <stdlib.h>

#include <sched.h>
#define SwitchToThread() sched_yield()
  #if defined(__APPLE__) && defined(__MACH__)
   #ifdef __LP64__
        #define InterlockedIncrement(A) (long)OSAtomicIncrement64((volatile int64_t *)A)
        #define InterlockedDecrement(A) (long)OSAtomicDecrement64((volatile int64_t *)A)
   #else
        #define InterlockedIncrement(A) (long)OSAtomicIncrement32((volatile int32_t *)A)
        #define InterlockedDecrement(A) (long)OSAtomicDecrement32((volatile int32_t *)A)
 #endif
        #include <libkern/OSAtomic.h>
        #define InterlockedBoolCompareExchange(A,B,C) OSAtomicCompareAndSwapLong(C,B,(volatile long *)A)
        // The implementation below for Mac OS is NOT equal the Windows or Linux one!
        // It only tests and set 7-th bit at reference pointer
        #define InterlockedBoolExchange(A,B) OSAtomicTestAndSet(8,(volatile uint32_t *)A)
  #else  // linux and similar
        #include <malloc.h>
        #define InterlockedBoolCompareExchange(A,B,C) __sync_bool_compare_and_swap(A,C,B)
        #define _InterlockedExchange(A,B) (long)__sync_lock_test_and_set(A,B)
        #define InterlockedBoolExchange(A,B) (_InterlockedExchange(A,B) == (B))
        #define InterlockedIncrement(A) (long)__sync_add_and_fetch(A, 1L)  
        #define InterlockedDecrement(A) (long)__sync_sub_and_fetch(A, 1L)  
  #endif

#endif

