// Copyright 2017 IAR Systems AB.

#ifndef _ATOMIC_
#define _ATOMIC_

#if defined(__STDC_NO_ATOMICS__)
#error "Atomic not supported in current code model"
#endif

#ifndef _SYSTEM_BUILD
#pragma system_include
#endif

#include <cstdint>
#include <type_traits>
#include <yvals.h>
#include <xatomic.h>
// 29, Atomic operations library

namespace std
{
  template <class _T>
  struct ident
  {
    typedef _T type;
  };

  // 29.3, Order and consistency
  // enum memory_order defined in xatomic.h

  template <class _T>
  _T kill_dependency(_T __y) noexcept
  {
    return __y;
  }

  // 29.4, Lock-free property
  // atomic lock-free macros defined in xatomic.h

  // 29.5, Atomic types
  template <class _T, typename _E = void>
  struct atomic;

  // 29.6.1, General operations on atomic types
  template <typename _T>
  inline bool atomic_is_lock_free(const volatile atomic<_T> *__pa) noexcept
  {
    return __pa->is_lock_free();
  }
  template <typename _T>
  inline bool atomic_is_lock_free(const atomic<_T> *__pa) noexcept
  {
    return __pa->is_lock_free();
  }
  template <typename _T>
  inline void
  atomic_init(volatile atomic<_T> *__pa, typename ident<_T>::type __v) noexcept
  {
    __pa->_init(__v);
  }
  template <typename _T>
  inline void
  atomic_init(atomic<_T> *__pa, typename ident<_T>::type __v) noexcept
  {
    __pa->_init(__v);
  }

  template <typename _T>
  inline void atomic_store(volatile atomic<_T> *__pa,
                           typename ident<_T>::type __v) noexcept
  {
    __pa->store(__v);
  }
  template <typename _T>
  inline void
  atomic_store(atomic<_T> *__pa, typename ident<_T>::type __v) noexcept
  {
    __pa->store(__v);
  }
  template <typename _T>
  inline void atomic_store_explicit(volatile atomic<_T> *__pa,
                                    typename ident<_T>::type __v,
                                    memory_order __mo) noexcept
  {
    __pa->store(__v, __mo);
  }
  template <typename _T>
  inline void
  atomic_store_explicit(atomic<_T> *__pa, typename ident<_T>::type __v,
                        memory_order __mo) noexcept
  {
    __pa->store(__v, __mo);
  }

  template <typename _T>
  inline _T atomic_load(const volatile atomic<_T> *__pa) noexcept
  {
    return __pa->load();
  }
  template <typename _T>
  inline _T atomic_load(const atomic<_T> *__pa) noexcept
  {
    return __pa->load();
  }
  template <typename _T>
  inline _T atomic_load_explicit(const volatile atomic<_T> *__pa,
                                 memory_order __mo) noexcept
  {
    return __pa->load(__mo);
  }
  template <typename _T>
  inline _T
  atomic_load_explicit(const atomic<_T> *__pa, memory_order __mo) noexcept
  {
    return __pa->load(__mo);
  }
  template <typename _T>
  inline _T atomic_exchange(volatile atomic<_T> *__pa,
                            typename ident<_T>::type __v) noexcept
  {
    return __pa->exchange(__v);
  }
  template <typename _T>
  inline _T
  atomic_exchange(atomic<_T> *__pa, typename ident<_T>::type __v) noexcept
  {
    return __pa->exchange(__v);
  }
  template <typename _T>
  inline _T atomic_exchange_explicit(volatile atomic<_T> *__pa,
                                     typename ident<_T>::type __v,
                                     memory_order __mo) noexcept
  {
    return __pa->exchange(__v, __mo);
  }
  template <typename _T>
  inline _T
  atomic_exchange_explicit(atomic<_T> *__pa, typename ident<_T>::type __v,
                           memory_order __mo) noexcept
  {
    return __pa->exchange(__v, __mo);
  }
  template <typename _T>
  inline bool
  atomic_compare_exchange_weak(volatile atomic<_T> *__pa, _T *__exp,
                               typename ident<_T>::type __des) noexcept
  {
    return __pa->compare_exchange_weak(*__exp, __des);
  }
  template <typename _T>
  inline bool
  atomic_compare_exchange_weak(atomic<_T> *__pa, _T *__exp,
                               typename ident<_T>::type __des) noexcept
  {
    return __pa->compare_exchange_weak(*__exp, __des);
  }
  template <typename _T>
  inline bool
  atomic_compare_exchange_strong(volatile atomic<_T> *__pa, _T *__exp,
                                 typename ident<_T>::type __des) noexcept
  {
    return __pa->compare_exchange_strong(*__exp, __des);
  }
  template <typename _T>
  inline bool
  atomic_compare_exchange_strong(atomic<_T> *__pa, _T *__exp,
                                 typename ident<_T>::type __des) noexcept
  {
    return __pa->compare_exchange_strong(*__exp, __des);
  }
  template <typename _T>
  inline bool
  atomic_compare_exchange_weak_explicit(volatile atomic<_T> *__pa, _T *__exp,
                                        typename ident<_T>::type __des,
                                        memory_order __mos,
                                        memory_order __mof) noexcept
  {
    return __pa->compare_exchange_weak(*__exp, __des, __mos, __mof);
  }
  template <typename _T>
  inline bool
  atomic_compare_exchange_weak_explicit(atomic<_T> *__pa, _T *__exp,
                                        typename ident<_T>::type __des,
                                        memory_order __mos,
                                        memory_order __mof) noexcept
  {
    return __pa->compare_exchange_weak(*__exp, __des, __mos, __mof);
  }
  template <typename _T>
  inline bool
  atomic_compare_exchange_strong_explicit(volatile atomic<_T> *__pa, _T *__exp,
                                          typename ident<_T>::type __des,
                                          memory_order __mos,
                                          memory_order __mof) noexcept
  {
    return __pa->compare_exchange_strong(*__exp, __des, __mos, __mof);
  }
  template <typename _T>
  inline bool
  atomic_compare_exchange_strong_explicit(atomic<_T> *__pa, _T *__exp,
                                          typename ident<_T>::type __des,
                                          memory_order __mos,
                                          memory_order __mof) noexcept
  {
    return __pa->compare_exchange_strong(*__exp, __des, __mos, __mof);
  }

  // 29.6.2, Templated operations on atomic types
  template <typename _T>
  inline _T atomic_fetch_add(volatile atomic<_T> *__pa,
                             typename atomic<_T>::difference_type __v) noexcept
  {
    return __pa->fetch_add(__v);
  }
  template <typename _T>
  inline _T
  atomic_fetch_add(atomic<_T> *__pa, typename atomic<_T>::difference_type __v) noexcept
  {
    return __pa->fetch_add(__v);
  }
  template <typename _T>
  inline _T atomic_fetch_add_explicit(volatile atomic<_T> *__pa,
                                      typename atomic<_T>::difference_type __v,
                                      memory_order __mo) noexcept
  {
    return __pa->fetch_add(__v, __mo);
  }
  template <typename _T>
  inline _T
  atomic_fetch_add_explicit(atomic<_T> *__pa, typename atomic<_T>::difference_type __v,
                            memory_order __mo) noexcept
  {
    return __pa->fetch_add(__v, __mo);
  }
  template <typename _T>
  inline _T atomic_fetch_sub(volatile atomic<_T> *__pa,
                             typename atomic<_T>::difference_type __v) noexcept
  {
    return __pa->fetch_sub(__v);
  }
  template <typename _T>
  inline _T
  atomic_fetch_sub(atomic<_T> *__pa, typename atomic<_T>::difference_type __v) noexcept
  {
    return __pa->fetch_sub(__v);
  }
  template <typename _T>
  inline _T atomic_fetch_sub_explicit(volatile atomic<_T> *__pa,
                                      typename atomic<_T>::difference_type __v,
                                      memory_order __mo) noexcept
  {
    return __pa->fetch_sub(__v, __mo);
  }
  template <typename _T>
  inline _T
  atomic_fetch_sub_explicit(atomic<_T> *__pa, typename atomic<_T>::difference_type __v,
                            memory_order __mo) noexcept
  {
    return __pa->fetch_sub(__v, __mo);
  }
  template <typename _T>
  inline _T atomic_fetch_and(volatile atomic<_T> *__pa,
                             typename ident<_T>::type __v) noexcept
  {
    return __pa->fetch_and(__v);
  }
  template <typename _T>
  inline _T
  atomic_fetch_and(atomic<_T> *__pa, typename ident<_T>::type __v) noexcept
  {
    return __pa->fetch_and(__v);
  }
  template <typename _T>
  inline _T atomic_fetch_and_explicit(volatile atomic<_T> *__pa,
                                      typename ident<_T>::type __v,
                                      memory_order __mo) noexcept
  {
    return __pa->fetch_and(__v, __mo);
  }
  template <typename _T>
  inline _T
  atomic_fetch_and_explicit(atomic<_T> *__pa, typename ident<_T>::type __v,
                            memory_order __mo) noexcept
  {
    return __pa->fetch_and(__v, __mo);
  }
  template <typename _T>
  inline _T atomic_fetch_or(volatile atomic<_T> *__pa,
                            typename ident<_T>::type __v) noexcept
  {
    return __pa->fetch_or(__v);
  }
  template <typename _T>
  inline _T
  atomic_fetch_or(atomic<_T> *__pa, typename ident<_T>::type __v) noexcept
  {
    return __pa->fetch_or(__v);
  }
  template <typename _T>
  inline _T atomic_fetch_or_explicit(volatile atomic<_T> *__pa,
                                     typename ident<_T>::type __v,
                                     memory_order __mo) noexcept
  {
    return __pa->fetch_or(__v, __mo);
  }
  template <typename _T>
  inline _T
  atomic_fetch_or_explicit(atomic<_T> *__pa, typename ident<_T>::type __v,
                           memory_order __mo) noexcept
  {
    return __pa->fetch_or(__v, __mo);
  }
  template <typename _T>
  inline _T atomic_fetch_xor(volatile atomic<_T> *__pa,
                             typename ident<_T>::type __v) noexcept
  {
    return __pa->fetch_xor(__v);
  }
  template <typename _T>
  inline _T
  atomic_fetch_xor(atomic<_T> *__pa, typename ident<_T>::type __v) noexcept
  {
    return __pa->fetch_xor(__v);
  }
  template <typename _T>
  inline _T atomic_fetch_xor_explicit(volatile atomic<_T> *__pa,
                                      typename ident<_T>::type __v,
                                      memory_order __mo) noexcept
  {
    return __pa->fetch_xor(__v, __mo);
  }
  template <typename _T>
  inline _T
  atomic_fetch_xor_explicit(atomic<_T> *__pa, typename ident<_T>::type __v,
                            memory_order __mo) noexcept
  {
    return __pa->fetch_xor(__v, __mo);
  }

  // 29.6.4, Partial specializations for pointers


  // 29.6.5, Initialization
  #define ATOMIC_VAR_INIT(__value) { __value }

  // 29.7, Flag type and operations
  struct atomic_flag;
  bool atomic_flag_test_and_set(volatile atomic_flag *__paf) noexcept;
  bool atomic_flag_test_and_set(atomic_flag *__paf) noexcept;
  bool atomic_flag_test_and_set_explicit(volatile atomic_flag *__paf,
                                         memory_order __mo) noexcept;
  bool atomic_flag_test_and_set_explicit(atomic_flag *__paf,
                                         memory_order __mo) noexcept;
  void atomic_flag_clear(volatile atomic_flag *__paf) noexcept;
  void atomic_flag_clear(atomic_flag *__paf) noexcept;
  void atomic_flag_clear_explicit(volatile atomic_flag *__paf,
                                  memory_order __mo) noexcept;
  void
  atomic_flag_clear_explicit(atomic_flag *__paf, memory_order __mo) noexcept;

  // 29.8, Fences
  inline void atomic_thread_fence(memory_order __mo) noexcept 
  { 
    __iar_atomic_thread_fence(__mo); 
  }
  inline void atomic_signal_fence(memory_order __mo) noexcept 
  { 
    __iar_atomic_signal_fence(__mo); 
  }

  template <class _T, class _E>
  struct atomic
  {
  private:
    typedef _T __base_type;
    typedef _Atomic __base_type __atomic_type;
    __atomic_type _M_a;

    static_assert(std::is_trivially_copyable<_T>::value,
                  "Base type for atomic<> must be trivially copyable");

  public:
    typedef _T value_type;
    
    atomic() noexcept = default;
    ~atomic() = default;

    constexpr atomic(__base_type __v) noexcept : _M_a(__v) {}

    atomic(const atomic &) = delete;
    atomic &operator=(const atomic &) = delete;
    atomic &operator=(const atomic &) volatile = delete;

    inline __base_type operator=(__base_type __v) volatile noexcept
    {
      store(__v);
      return __v;
    }
    inline __base_type operator=(__base_type __v) noexcept
    {
      store(__v);
      return __v;
    }

    inline operator __base_type() const volatile noexcept { return load(); }
    inline operator __base_type() const noexcept { return load(); }

    inline bool is_lock_free() const volatile noexcept
    {
      return __iar_atomic_is_lock_free(sizeof(__atomic_type),
                                       __alignof__(_M_a));
    }
    inline bool is_lock_free() const noexcept
    {
      return __iar_atomic_is_lock_free(sizeof(__atomic_type),
                                       __alignof__(_M_a));
    }

    static constexpr bool is_always_lock_free =
                                 __iar_atomic_is_lock_free(sizeof(__atomic_type),
                                                           __alignof__(_M_a));

    inline constexpr void _init(__base_type __v) volatile noexcept
    {
      __iar_atomic_init(&_M_a, __v);
    }
    inline constexpr void _init(__base_type __v) noexcept
    {
      __iar_atomic_init(&_M_a, __v);
    }
    inline void
    store(__base_type __v,
          memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      __iar_atomic_store(&_M_a, __v, __mo);
    }
    inline void
    store(__base_type __v, memory_order __mo = memory_order_seq_cst) noexcept
    {
      __iar_atomic_store(&_M_a, __v, __mo);
    }
    inline __base_type
    load(memory_order __mo = memory_order_seq_cst) const volatile noexcept
    {
      return __iar_atomic_load(&_M_a, __mo);
    }
    inline __base_type
    load(memory_order __mo = memory_order_seq_cst) const noexcept
    {
      return __iar_atomic_load(&_M_a, __mo);
    }
    inline __base_type
    exchange(__base_type __v,
             memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_exchange(&_M_a, __v, __mo);
    }
    inline __base_type
    exchange(__base_type __v,
             memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_exchange(&_M_a, __v, __mo);
    }
    inline bool compare_exchange_weak(__base_type &exp, __base_type des,
                                      memory_order __mos,
                                      memory_order __mof) volatile noexcept
    {
      return __iar_atomic_compare_exchange_weak(&_M_a, &exp, des, __mos,
                                                __mof);
    }
    inline bool
    compare_exchange_weak(__base_type &exp, __base_type des,
                          memory_order __mos, memory_order __mof) noexcept
    {
      return __iar_atomic_compare_exchange_weak(&_M_a, &exp, des, __mos,
                                                __mof);
    }
    inline bool compare_exchange_strong(__base_type &exp, __base_type des,
                                        memory_order __mos,
                                        memory_order __mof) volatile noexcept
    {
      return __iar_atomic_compare_exchange_strong(&_M_a, &exp, des, __mos,
                                                  __mof);
    }
    inline bool
    compare_exchange_strong(__base_type &exp, __base_type des,
                            memory_order __mos, memory_order __mof) noexcept
    {
      return __iar_atomic_compare_exchange_strong(&_M_a, &exp, des, __mos,
                                                  __mof);
    }
    inline bool compare_exchange_weak(__base_type &exp, __base_type des,
                                      memory_order __mo
                                      = memory_order_seq_cst) volatile noexcept
    {
      return compare_exchange_weak(exp, des, __mo, __mo);
    }
    inline bool
    compare_exchange_weak(__base_type &exp, __base_type des,
                          memory_order __mo = memory_order_seq_cst) noexcept
    {
      return compare_exchange_weak(exp, des, __mo, __mo);
    }
    inline bool
    compare_exchange_strong(__base_type &exp, __base_type des,
                            memory_order __mo
                            = memory_order_seq_cst) volatile noexcept
    {
      return compare_exchange_strong(exp, des, __mo, __mo);
    }
    inline bool
    compare_exchange_strong(__base_type &exp, __base_type des,
                            memory_order __mo = memory_order_seq_cst) noexcept
    {
      return compare_exchange_strong(exp, des, __mo, __mo);
    }
  };

  template <typename _Ti>
  struct atomic<_Ti,
                typename std::enable_if<std::is_integral<_Ti>::value>::type>
  {
  private:
    typedef _Ti __integral_type;
    typedef _Atomic _Ti __atomic_integral_type;
    __atomic_integral_type _M_ai;

  public:
    typedef _Ti value_type;
    typedef _Ti difference_type;
    
    atomic() noexcept = default;
    constexpr atomic(__integral_type __i) noexcept : _M_ai(__i) {}
    atomic(const atomic &) = delete;
    atomic &operator=(const atomic &) = delete;
    atomic &operator=(const atomic &) volatile = delete;

    inline __integral_type operator=(__integral_type __i) volatile noexcept
    {
      store(__i);
      return __i;
    }
    inline __integral_type operator=(__integral_type __i) noexcept
    {
      store(__i);
      return __i;
    }
    inline __integral_type operator++(int)volatile noexcept
    {
      return fetch_add(1);
    }
    inline __integral_type operator++(int)noexcept { return fetch_add(1); }
    inline __integral_type operator--(int)volatile noexcept
    {
      return fetch_sub(1);
    }
    inline __integral_type operator--(int)noexcept { return fetch_sub(1); }
    inline __integral_type operator++() volatile noexcept
    {
      return __iar_atomic_add_fetch(&_M_ai, 1, memory_order_seq_cst);
    }
    inline __integral_type operator++() noexcept
    {
      return __iar_atomic_add_fetch(&_M_ai, 1, memory_order_seq_cst);
    }
    inline __integral_type operator--() volatile noexcept
    {
      return __iar_atomic_sub_fetch(&_M_ai, 1, memory_order_seq_cst);
    }
    inline __integral_type operator--() noexcept
    {
      return __iar_atomic_sub_fetch(&_M_ai, 1, memory_order_seq_cst);
    }
    inline __integral_type operator+=(__integral_type __i) volatile noexcept
    {
      return __iar_atomic_add_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator+=(__integral_type __i) noexcept
    {
      return __iar_atomic_add_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator-=(__integral_type __i) volatile noexcept
    {
      return __iar_atomic_sub_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator-=(__integral_type __i) noexcept
    {
      return __iar_atomic_sub_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator&=(__integral_type __i) volatile noexcept
    {
      return __iar_atomic_and_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator&=(__integral_type __i) noexcept
    {
      return __iar_atomic_and_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator|=(__integral_type __i) volatile noexcept
    {
      return __iar_atomic_or_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator|=(__integral_type __i) noexcept
    {
      return __iar_atomic_or_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator^=(__integral_type __i) volatile noexcept
    {
      return __iar_atomic_xor_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline __integral_type operator^=(__integral_type __i) noexcept
    {
      return __iar_atomic_xor_fetch(&_M_ai, __i, memory_order_seq_cst);
    }
    inline bool is_lock_free() const volatile noexcept
    {
      return __iar_atomic_is_lock_free(sizeof(__atomic_integral_type),
                                       __alignof__(_M_ai));
    }
    inline bool is_lock_free() const noexcept
    {
      return __iar_atomic_is_lock_free(sizeof(__atomic_integral_type),
                                       __alignof__(_M_ai));
    }

    static constexpr bool is_always_lock_free =
                        __iar_atomic_is_lock_free(sizeof(__atomic_integral_type),
                                                  __alignof__(_M_ai));

    inline constexpr void _init(__integral_type __v) volatile noexcept
    {
      __iar_atomic_init(&_M_ai, __v);
    }
    inline constexpr void _init(__integral_type __v) noexcept
    {
      __iar_atomic_init(&_M_ai, __v);
    }
    inline void
    store(__integral_type __i,
          memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      __iar_atomic_store(&_M_ai, __i, __mo);
    }
    inline void store(__integral_type __i,
                      memory_order __mo = memory_order_seq_cst) noexcept
    {
      __iar_atomic_store(&_M_ai, __i, __mo);
    }
    inline __integral_type
    load(memory_order __mo = memory_order_seq_cst) const volatile noexcept
    {
      return __iar_atomic_load(&_M_ai, __mo);
    }
    inline __integral_type
    load(memory_order __mo = memory_order_seq_cst) const noexcept
    {
      return __iar_atomic_load(&_M_ai, __mo);
    }

    inline operator __integral_type() const volatile noexcept
    {
      return load();
    }
    inline operator __integral_type() const noexcept { return load(); }

    inline __integral_type
    exchange(__integral_type __i,
             memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_exchange(&_M_ai, __i, __mo);
    }
    inline __integral_type
    exchange(__integral_type __i,
             memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_exchange(&_M_ai, __i, __mo);
    }

    inline bool
    compare_exchange_weak(__integral_type &__exp, __integral_type __des,
                          memory_order __mos,
                          memory_order __mof) volatile noexcept
    {
      return __iar_atomic_compare_exchange_weak(&_M_ai, &__exp, __des, __mos,
                                                __mof);
    }
    inline bool
    compare_exchange_weak(__integral_type &__exp, __integral_type __des,
                          memory_order __mos, memory_order __mof) noexcept
    {
      return __iar_atomic_compare_exchange_weak(&_M_ai, &__exp, __des, __mos,
                                                __mof);
    }
    inline bool
    compare_exchange_strong(__integral_type &__exp, __integral_type __des,
                            memory_order __mos,
                            memory_order __mof) volatile noexcept
    {
      return __iar_atomic_compare_exchange_strong(&_M_ai, &__exp, __des, __mos,
                                                  __mof);
    }
    inline bool
    compare_exchange_strong(__integral_type &__exp, __integral_type __des,
                            memory_order __mos, memory_order __mof) noexcept
    {
      return __iar_atomic_compare_exchange_strong(&_M_ai, &__exp, __des, __mos,
                                                  __mof);
    }
    inline bool
    compare_exchange_weak(__integral_type &__exp, __integral_type __des,
                          memory_order __mo
                          = memory_order_seq_cst) volatile noexcept
    {
      return compare_exchange_weak(__exp, __des, __mo, __mo);
    }
    inline bool
    compare_exchange_weak(__integral_type &__exp, __integral_type __des,
                          memory_order __mo = memory_order_seq_cst) noexcept
    {
      return compare_exchange_weak(__exp, __des, __mo, __mo);
    }
    inline bool
    compare_exchange_strong(__integral_type &__exp, __integral_type __des,
                            memory_order __mo
                            = memory_order_seq_cst) volatile noexcept
    {
      return compare_exchange_strong(__exp, __des, __mo, __mo);
    }
    inline bool
    compare_exchange_strong(__integral_type &__exp, __integral_type __des,
                            memory_order __mo = memory_order_seq_cst) noexcept
    {
      return compare_exchange_strong(__exp, __des, __mo, __mo);
    }
    inline __integral_type
    fetch_add(__integral_type __i,
              memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_fetch_add(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_add(__integral_type __i,
              memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_fetch_add(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_sub(__integral_type __i,
              memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_fetch_sub(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_sub(__integral_type __i,
              memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_fetch_sub(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_and(__integral_type __i,
              memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_fetch_and(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_and(__integral_type __i,
              memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_fetch_and(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_or(__integral_type __i,
             memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_fetch_or(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_or(__integral_type __i,
             memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_fetch_or(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_xor(__integral_type __i,
              memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_fetch_xor(&_M_ai, __i, __mo);
    }
    inline __integral_type
    fetch_xor(__integral_type __i,
              memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_fetch_xor(&_M_ai, __i, __mo);
    }
  };

  template <typename T, bool is_void = std::is_void<std::remove_cv_t<std::remove_pointer_t<T>>>::value>
  struct _size_of_T;

  template <typename _T> struct _size_of_T<_T, true>  { enum { value = 1}; };
  template <typename _T> struct _size_of_T<_T, false> { enum { value = sizeof(_T)}; };

  template <class _T>
  struct atomic<_T *>
  {

  private:
    typedef _T *__pointer_type;
    typedef _Atomic __pointer_type __atomic_pointer_type;
    __atomic_pointer_type _M_ap;

    constexpr ptrdiff_t _T_offset(ptrdiff_t _n) { return _n * _size_of_T<_T>::value; }
    constexpr ptrdiff_t _T_offset(ptrdiff_t _n) volatile { return _n * _size_of_T<_T>::value; }

  public:
    typedef __pointer_type value_type;
    typedef ptrdiff_t difference_type;
    
    atomic() noexcept = default;
    constexpr atomic(__pointer_type __p) noexcept : _M_ap(__p) {}
    atomic(const atomic &) = delete;
    atomic &operator=(const atomic &) = delete;
    atomic &operator=(const atomic &) volatile = delete;

    inline operator __pointer_type() const volatile noexcept { return load(); }
    inline operator __pointer_type() const noexcept { return load(); }
    inline __pointer_type operator=(__pointer_type __p) volatile noexcept
    {
      store(__p);
      return __p;
    }
    inline __pointer_type operator=(__pointer_type __p) noexcept
    {
      store(__p);
      return __p;
    }
    inline __pointer_type operator++(int)volatile noexcept
    {
      return fetch_add(1);
    }
    inline __pointer_type operator++(int)noexcept { return fetch_add(1); }
    inline __pointer_type operator--(int)volatile noexcept
    {
      return fetch_sub(1);
    }
    inline __pointer_type operator--(int)noexcept { return fetch_sub(1); }
    inline __pointer_type operator++() volatile noexcept
    {
      return __add_fetch(1);
    }
    inline __pointer_type operator++() noexcept { return __add_fetch(1); }
    inline __pointer_type operator--() volatile noexcept
    {
      return __sub_fetch(1);
    }
    inline __pointer_type operator--() noexcept { return __sub_fetch(1); }
    inline __pointer_type operator+=(ptrdiff_t __pd) volatile noexcept
    {
      return __add_fetch(__pd);
    }
    inline __pointer_type operator+=(ptrdiff_t __pd) noexcept
    {
      return __add_fetch(__pd);
    }
    inline __pointer_type operator-=(ptrdiff_t __pd) volatile noexcept
    {
      return __sub_fetch(__pd);
    }
    inline __pointer_type operator-=(ptrdiff_t __pd) noexcept
    {
      return __sub_fetch(__pd);
    }

    inline bool is_lock_free() const volatile noexcept
    {
      return __iar_atomic_is_lock_free(sizeof(__atomic_pointer_type),
                                       __alignof__(_M_ap));
    }
    inline bool is_lock_free() const noexcept
    {
      return __iar_atomic_is_lock_free(sizeof(__atomic_pointer_type),
                                       __alignof__(_M_ap));
    }

    static constexpr bool is_always_lock_free =
                         __iar_atomic_is_lock_free(sizeof(__atomic_pointer_type),
                                                   __alignof__(_M_ap));

    inline constexpr void _init(__pointer_type __v) volatile noexcept
    {
      __iar_atomic_init(&_M_ap, __v);
    }
    inline constexpr void _init(__pointer_type __v) noexcept
    {
      __iar_atomic_init(&_M_ap, __v);
    }
    inline void
    store(__pointer_type __p,
          memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      __iar_atomic_store(&_M_ap, __p, __mo);
    }
    inline void store(__pointer_type __p,
                      memory_order __mo = memory_order_seq_cst) noexcept
    {
      __iar_atomic_store(&_M_ap, __p, __mo);
    }
    inline __pointer_type
    load(memory_order __mo = memory_order_seq_cst) const volatile noexcept
    {
      return __iar_atomic_load(&_M_ap, __mo);
    }
    inline __pointer_type
    load(memory_order __mo = memory_order_seq_cst) const noexcept
    {
      return __iar_atomic_load(&_M_ap, __mo);
    }
    inline __pointer_type
    exchange(__pointer_type __p,
             memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_exchange(&_M_ap, __p, __mo);
    }
    inline __pointer_type
    exchange(__pointer_type __p,
             memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_exchange(&_M_ap, __p, __mo);
    }
    inline bool compare_exchange_weak(__pointer_type &__exp,
                                      __pointer_type __des, memory_order __mos,
                                      memory_order __mof) volatile noexcept
    {
      return __iar_atomic_compare_exchange_weak(&_M_ap, &__exp, __des, __mos,
                                                __mof);
    }
    inline bool
    compare_exchange_weak(__pointer_type &__exp, __pointer_type __des,
                          memory_order __mos, memory_order __mof) noexcept
    {
      return __iar_atomic_compare_exchange_weak(&_M_ap, &__exp, __des, __mos,
                                                __mof);
    }
    inline bool
    compare_exchange_strong(__pointer_type &__exp, __pointer_type __des,
                            memory_order __mos,
                            memory_order __mof) volatile noexcept
    {
      return __iar_atomic_compare_exchange_strong(&_M_ap, &__exp, __des, __mos,
                                                  __mof);
    }
    inline bool
    compare_exchange_strong(__pointer_type &__exp, __pointer_type __des,
                            memory_order __mos, memory_order __mof) noexcept
    {
      return __iar_atomic_compare_exchange_strong(&_M_ap, &__exp, __des, __mos,
                                                  __mof);
    }
    inline bool
    compare_exchange_weak(__pointer_type &__exp, __pointer_type __des,
                          memory_order __mo
                          = memory_order_seq_cst) volatile noexcept
    {
      return compare_exchange_weak(__exp, __des, __mo, __mo);
    }
    inline bool
    compare_exchange_weak(__pointer_type &__exp, __pointer_type __des,
                          memory_order __mo = memory_order_seq_cst) noexcept
    {
      return compare_exchange_weak(__exp, __des, __mo, __mo);
    }
    inline bool
    compare_exchange_strong(__pointer_type &__exp, __pointer_type __des,
                            memory_order __mo
                            = memory_order_seq_cst) volatile noexcept
    {
      return compare_exchange_strong(__exp, __des, __mo, __mo);
    }
    inline bool
    compare_exchange_strong(__pointer_type &__exp, __pointer_type __des,
                            memory_order __mo = memory_order_seq_cst) noexcept
    {
      return compare_exchange_strong(__exp, __des, __mo, __mo);
    }
    inline __pointer_type
    fetch_add(ptrdiff_t __pd,
              memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_fetch_add(&_M_ap, _T_offset(__pd), __mo);
    }
    inline __pointer_type
    fetch_add(ptrdiff_t __pd,
              memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_fetch_add(&_M_ap, _T_offset(__pd), __mo);
    }
    inline __pointer_type
    fetch_sub(ptrdiff_t __pd,
              memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_fetch_sub(&_M_ap, _T_offset(__pd), __mo);
    }
    inline __pointer_type
    fetch_sub(ptrdiff_t __pd,
              memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_fetch_sub(&_M_ap, _T_offset(__pd), __mo);
    }

    inline __pointer_type
    __add_fetch(ptrdiff_t __pd,
                memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_add_fetch(&_M_ap, _T_offset(__pd), __mo);
    }
    inline __pointer_type
    __add_fetch(ptrdiff_t __pd,
                memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_add_fetch(&_M_ap, _T_offset(__pd), __mo);
    }
    inline __pointer_type
    __sub_fetch(ptrdiff_t __pd,
                memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_sub_fetch(&_M_ap, _T_offset(__pd), __mo);
    }
    inline __pointer_type
    __sub_fetch(ptrdiff_t __pd,
                memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_sub_fetch(&_M_ap, _T_offset(__pd), __mo);
    }
  };

  typedef struct atomic_flag
  {
  private:
    __iar_atomic_flag _M_b;

  public:
    inline bool
    test_and_set(memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      return __iar_atomic_flag_test_and_set(&_M_b, __mo);
    }
    inline bool test_and_set(memory_order __mo = memory_order_seq_cst) noexcept
    {
      return __iar_atomic_flag_test_and_set(&_M_b, __mo);
    }
    inline void
    clear(memory_order __mo = memory_order_seq_cst) volatile noexcept
    {
      __iar_atomic_flag_clear(&_M_b, __mo);
    }
    inline void clear(memory_order __mo = memory_order_seq_cst) noexcept
    {
      __iar_atomic_flag_clear(&_M_b, __mo);
    }
    atomic_flag() noexcept = default;
    constexpr atomic_flag(bool __b) noexcept : _M_b(__b) {}
    atomic_flag(const atomic_flag &) = delete;
    atomic_flag &operator=(const atomic_flag &) = delete;
    atomic_flag &operator=(const atomic_flag &) volatile = delete;
  } atomic_flag;

  #define ATOMIC_FLAG_INIT  { false }

  inline bool atomic_flag_test_and_set(volatile atomic_flag *__paf) noexcept
  {
    return __paf->test_and_set();
  }
  inline bool atomic_flag_test_and_set(atomic_flag *__paf) noexcept
  {
    return __paf->test_and_set();
  }
  inline bool atomic_flag_test_and_set_explicit(volatile atomic_flag *__paf,
                                                memory_order __mo) noexcept
  {
    return __paf->test_and_set(__mo);
  }
  inline bool atomic_flag_test_and_set_explicit(atomic_flag *__paf,
                                                memory_order __mo) noexcept
  {
    return __paf->test_and_set(__mo);
  }
  inline void atomic_flag_clear(volatile atomic_flag *__paf) noexcept
  {
    __paf->clear();
  }
  inline void atomic_flag_clear(atomic_flag *__paf) noexcept
  {
    __paf->clear();
  }
  inline void atomic_flag_clear_explicit(volatile atomic_flag *__paf,
                                         memory_order __mo) noexcept
  {
    __paf->clear(__mo);
  }
  inline void
  atomic_flag_clear_explicit(atomic_flag *__paf, memory_order __mo) noexcept
  {
    __paf->clear(__mo);
  }

  typedef atomic<bool> atomic_bool;
  typedef atomic<int8_t> atomic_int8_t;
  typedef atomic<uint8_t> atomic_uint8_t;
  typedef atomic<int16_t> atomic_int16_t;
  typedef atomic<uint16_t> atomic_uint16_t;
  typedef atomic<int32_t> atomic_int32_t;
  typedef atomic<uint32_t> atomic_uint32_t;
  typedef atomic<int64_t> atomic_int64_t;
  typedef atomic<uint64_t> atomic_uint64_t;

  typedef atomic<int_least8_t> atomic_int_least8_t;
  typedef atomic<uint_least8_t> atomic_uint_least8_t;
  typedef atomic<int_least16_t> atomic_int_least16_t;
  typedef atomic<uint_least16_t> atomic_uint_least16_t;
  typedef atomic<int_least32_t> atomic_int_least32_t;
  typedef atomic<uint_least32_t> atomic_uint_least32_t;
  typedef atomic<int_least64_t> atomic_int_least64_t;
  typedef atomic<uint_least64_t> atomic_uint_least64_t;

  typedef atomic<int_fast8_t> atomic_int_fast8_t;
  typedef atomic<uint_fast8_t> atomic_uint_fast8_t;
  typedef atomic<int_fast16_t> atomic_int_fast16_t;
  typedef atomic<uint_fast16_t> atomic_uint_fast16_t;
  typedef atomic<int_fast32_t> atomic_int_fast32_t;
  typedef atomic<uint_fast32_t> atomic_uint_fast32_t;
  typedef atomic<int_fast64_t> atomic_int_fast64_t;
  typedef atomic<uint_fast64_t> atomic_uint_fast64_t;

  typedef atomic<intptr_t> atomic_intptr_t;
  typedef atomic<uintptr_t> atomic_uintptr_t;

  typedef atomic<size_t> atomic_size_t;
  typedef atomic<ptrdiff_t> atomic_ptrdiff_t;

  typedef atomic<intmax_t> atomic_intmax_t;
  typedef atomic<uintmax_t> atomic_uintmax_t;

  typedef atomic<char> atomic_char;
  typedef atomic<signed char> atomic_schar;
  typedef atomic<unsigned char> atomic_uchar;

  typedef atomic<char16_t> atomic_char16_t;
  typedef atomic<char32_t> atomic_char32_t;

  typedef atomic<wchar_t> atomic_wchar_t;

  typedef atomic<short> atomic_short;
  typedef atomic<unsigned short> atomic_ushort;

  typedef atomic<int> atomic_int;
  typedef atomic<unsigned int> atomic_uint;

  typedef atomic<long> atomic_long;
  typedef atomic<unsigned long> atomic_ulong;

  typedef atomic<long long> atomic_llong;
  typedef atomic<unsigned long long> atomic_ullong;
}

#endif // _ATOMIC_
