/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "os.h"

#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32)

// add
char interlocked_add_fetch_8(char volatile* ptr, char val) {
#ifdef _TD_GO_DLL_
  return __sync_fetch_and_add(ptr, val) + val;
#else
  return _InterlockedExchangeAdd8(ptr, val) + val;
#endif
}

short interlocked_add_fetch_16(short volatile* ptr, short val) {
#ifdef _TD_GO_DLL_
  return __sync_fetch_and_add(ptr, val) + val;
#else
  return _InterlockedExchangeAdd16(ptr, val) + val;
#endif
}

long interlocked_add_fetch_32(long volatile* ptr, long val) {
  return _InterlockedExchangeAdd(ptr, val) + val;
}

__int64 interlocked_add_fetch_64(__int64 volatile* ptr, __int64 val) {
//#ifdef _WIN64
  return InterlockedExchangeAdd64(ptr, val) + val;
//#else
//  return _InterlockedExchangeAdd(ptr, val) + val;
//#endif
}

char interlocked_and_fetch_8(char volatile* ptr, char val) {
  return _InterlockedAnd8(ptr, val) & val;
}

short interlocked_and_fetch_16(short volatile* ptr, short val) {
  return _InterlockedAnd16(ptr, val) & val;
}

long interlocked_and_fetch_32(long volatile* ptr, long val) {
  return _InterlockedAnd(ptr, val) & val;
}


__int64 interlocked_and_fetch_64(__int64 volatile* ptr, __int64 val) {
#ifndef _M_IX86
  return _InterlockedAnd64(ptr, val) & val;
#else
  __int64 old, res;
  do {
    old = *ptr;
    res = old & val;
  } while (_InterlockedCompareExchange64(ptr, res, old) != old);
  return res;
#endif
}

__int64 interlocked_fetch_and_64(__int64 volatile* ptr, __int64 val) {
#ifdef _M_IX86
  __int64 old;
  do {
    old = *ptr;
  } while (_InterlockedCompareExchange64(ptr, old & val, old) != old);
  return old;
#else
  return _InterlockedAnd64((__int64 volatile*)(ptr), (__int64)(val));
#endif
}

char interlocked_or_fetch_8(char volatile* ptr, char val) {
  return _InterlockedOr8(ptr, val) | val;
}

short interlocked_or_fetch_16(short volatile* ptr, short val) {
  return _InterlockedOr16(ptr, val) | val;
}

long interlocked_or_fetch_32(long volatile* ptr, long val) {
  return _InterlockedOr(ptr, val) | val;
}

__int64 interlocked_or_fetch_64(__int64 volatile* ptr, __int64 val) {
#ifdef _M_IX86
  __int64 old, res;
  do {
    old = *ptr;
    res = old | val;
  } while(_InterlockedCompareExchange64(ptr, res, old) != old);
  return res;
#else
  return _InterlockedOr64(ptr, val) & val;
#endif
}

__int64 interlocked_fetch_or_64(__int64 volatile* ptr, __int64 val) {
#ifdef _M_IX86
  __int64 old;
  do {
    old = *ptr;
  } while(_InterlockedCompareExchange64(ptr, old | val, old) != old);
  return old;
#else
  return _InterlockedOr64((__int64 volatile*)(ptr), (__int64)(val));
#endif
}

char interlocked_xor_fetch_8(char volatile* ptr, char val) {
  return _InterlockedXor8(ptr, val) ^ val;
}

short interlocked_xor_fetch_16(short volatile* ptr, short val) {
  return _InterlockedXor16(ptr, val) ^ val;
}

long interlocked_xor_fetch_32(long volatile* ptr, long val) {
  return _InterlockedXor(ptr, val) ^ val;
}

__int64 interlocked_xor_fetch_64(__int64 volatile* ptr, __int64 val) {
#ifdef _M_IX86
  __int64 old, res;
  do {
    old = *ptr;
    res = old ^ val;
  } while(_InterlockedCompareExchange64(ptr, res, old) != old);
  return res;
#else
  return _InterlockedXor64(ptr, val) ^ val;
#endif
}

__int64 interlocked_fetch_xor_64(__int64 volatile* ptr, __int64 val) {
#ifdef _M_IX86
  __int64 old;
  do {
    old = *ptr;
  } while (_InterlockedCompareExchange64(ptr, old ^ val, old) != old);
  return old;
#else
  return _InterlockedXor64((__int64 volatile*)(ptr), (__int64)(val));
#endif
}

#endif

#ifdef _TD_NINGSI_60
void* atomic_exchange_ptr_impl(void** ptr, void* val ) {
  void *old;
  do {
    old = *ptr;
  } while( !__sync_bool_compare_and_swap(ptr, old, val) );
  return old;
}
int8_t atomic_exchange_8_impl(int8_t* ptr, int8_t val ) {
  int8_t old;
  do {
    old = *ptr;
  } while( !__sync_bool_compare_and_swap(ptr, old, val) );
  return old;
}
int16_t atomic_exchange_16_impl(int16_t* ptr, int16_t val ) {
  int16_t old;
  do {
    old = *ptr;
  } while( !__sync_bool_compare_and_swap(ptr, old, val) );
  return old;
}
int32_t atomic_exchange_32_impl(int32_t* ptr, int32_t val ) {
  int32_t old;
  do {
    old = *ptr;
  } while( !__sync_bool_compare_and_swap(ptr, old, val) );
  return old;
}
int64_t atomic_exchange_64_impl(int64_t* ptr, int64_t val ) {
  int64_t old;
  do {
    old = *ptr;
  } while( !__sync_bool_compare_and_swap(ptr, old, val) );
  return old;
}
#endif
