#include "pch.h"
#include "System/Threading/Interlocked.h"

#if defined(_WIN32)
#include <windows.h>
#include <intrin.h>
#endif

namespace DotNetDupe {
    namespace System {
        namespace Threading {

            long InterlockedInternal::Increment32(volatile long* location) {
#if defined(_WIN32)
                return _InterlockedIncrement(location);
#else
                return __sync_add_and_fetch(location, 1);
#endif
            }
            long InterlockedInternal::Decrement32(volatile long* location) {
#if defined(_WIN32)
                return _InterlockedDecrement(location);
#else
                return __sync_sub_and_fetch(location, 1);
#endif
            }
            long InterlockedInternal::Add32(volatile long* location, long value) {
#if defined(_WIN32)
                return _InterlockedExchangeAdd(location, value) + value;
#else
                return __sync_add_and_fetch(location, value);
#endif
            }
            long InterlockedInternal::Exchange32(volatile long* location, long value) {
#if defined(_WIN32)
                return _InterlockedExchange(location, value);
#else
                return __sync_lock_test_and_set(location, value);
#endif
            }
            long InterlockedInternal::CompareExchange32(volatile long* location, long value, long comparand) {
#if defined(_WIN32)
                return _InterlockedCompareExchange(location, value, comparand);
#else
                return __sync_val_compare_and_swap(location, comparand, value);
#endif
            }

            long long InterlockedInternal::Increment64(volatile long long* location) {
#if defined(_WIN32)
#if defined(_M_IX86)
                long long oldVal, newVal;
                do {
                    oldVal = *location;
                    newVal = oldVal + 1;
                } while (_InterlockedCompareExchange64(location, newVal, oldVal) != oldVal);
                return newVal;
#else
                return _InterlockedIncrement64(location);
#endif
#else
                return __sync_add_and_fetch(location, 1);
#endif
            }
            long long InterlockedInternal::Decrement64(volatile long long* location) {
#if defined(_WIN32)
#if defined(_M_IX86)
                long long oldVal, newVal;
                do {
                    oldVal = *location;
                    newVal = oldVal - 1;
                } while (_InterlockedCompareExchange64(location, newVal, oldVal) != oldVal);
                return newVal;
#else
                return _InterlockedDecrement64(location);
#endif
#else
                return __sync_sub_and_fetch(location, 1);
#endif
            }
            long long InterlockedInternal::Add64(volatile long long* location, long long value) {
#if defined(_WIN32)
#if defined(_M_IX86)
                long long oldVal, newVal;
                do {
                    oldVal = *location;
                    newVal = oldVal + value;
                } while (_InterlockedCompareExchange64(location, newVal, oldVal) != oldVal);
                return newVal;
#else
                return _InterlockedExchangeAdd64(location, value) + value;
#endif
#else
                return __sync_add_and_fetch(location, value);
#endif
            }
            long long InterlockedInternal::Exchange64(volatile long long* location, long long value) {
#if defined(_WIN32)
#if defined(_M_IX86)
                long long oldVal;
                do {
                    oldVal = *location;
                } while (_InterlockedCompareExchange64(location, value, oldVal) != oldVal);
                return oldVal;
#else
                return _InterlockedExchange64(location, value);
#endif
#else
                return __sync_lock_test_and_set(location, value);
#endif
            }
            long long InterlockedInternal::CompareExchange64(volatile long long* location, long long value, long long comparand) {
#if defined(_WIN32)
                return _InterlockedCompareExchange64(location, value, comparand);
#else
                return __sync_val_compare_and_swap(location, comparand, value);
#endif
            }
        }
    }
}

Generated by OpenCppCoverage (Version: 0.9.9.0)