/* Icinga 2 | (c) 2019 Icinga GmbH | GPLv2+ */ #ifndef ATOMIC_H #define ATOMIC_H #include #include #include namespace icinga { /** * Extends std::atomic with an atomic constructor. * * @ingroup base */ template class Atomic : public std::atomic { public: /** * Like std::atomic#atomic, but operates atomically * * @param desired Initial value */ inline Atomic(T desired) { this->store(desired); } /** * Like std::atomic#atomic, but operates atomically * * @param desired Initial value * @param order Initial store operation's memory order */ inline Atomic(T desired, std::memory_order order) { this->store(desired, order); } }; /** * Wraps T into a std::atomic-like interface. * * @ingroup base */ template class NotAtomic { public: inline T load() const { return m_Value; } inline void store(T desired) { m_Value = std::move(desired); } T m_Value; }; /** * Tells whether to use std::atomic or NotAtomic. * * @ingroup base */ template struct Atomicable { // Doesn't work with too old compilers. //static constexpr bool value = std::is_trivially_copyable::value && sizeof(T) <= sizeof(void*); static constexpr bool value = (std::is_fundamental::value || std::is_pointer::value) && sizeof(T) <= sizeof(void*); }; /** * Uses either std::atomic or NotAtomic depending on atomicable. * * @ingroup base */ template struct AtomicTemplate; template<> struct AtomicTemplate { template struct tmplt { typedef NotAtomic type; }; }; template<> struct AtomicTemplate { template struct tmplt { typedef std::atomic type; }; }; /** * Uses either std::atomic or NotAtomic depending on T. * * @ingroup base */ template struct EventuallyAtomic { typedef typename AtomicTemplate::value>::template tmplt::type type; }; } #endif /* ATOMIC_H */