From e6ae3f7aa7e49944775e7802d2bf9e6aa8783ca4 Mon Sep 17 00:00:00 2001 From: jules Date: Wed, 20 Sep 2017 13:57:30 +0100 Subject: [PATCH] Fixed a problem in a static assert in Atomic. --- modules/juce_core/memory/juce_Atomic.h | 954 ++++++++++++------------- 1 file changed, 477 insertions(+), 477 deletions(-) diff --git a/modules/juce_core/memory/juce_Atomic.h b/modules/juce_core/memory/juce_Atomic.h index 353ca2a0d5..dd15c9893f 100644 --- a/modules/juce_core/memory/juce_Atomic.h +++ b/modules/juce_core/memory/juce_Atomic.h @@ -1,477 +1,477 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#ifndef DOXYGEN - namespace AtomicHelpers - { - template struct DiffTypeHelper { typedef T Type; }; - template struct DiffTypeHelper { typedef std::ptrdiff_t Type; }; - } -#endif - -#if JUCE_ATOMIC_AVAILABLE - //============================================================================== - /** - A simple wrapper around std::atomic. - */ - template - struct Atomic - { - typedef typename AtomicHelpers::DiffTypeHelper::Type DiffType; - - /** Creates a new value, initialised to zero. */ - Atomic() noexcept : value (0) {} - - /** Creates a new value, with a given initial value. */ - Atomic (const Type initialValue) noexcept : value (initialValue) {} - - /** Copies another value (atomically). */ - Atomic (const Atomic& other) noexcept : value (other.get()) {} - - /** Destructor. */ - ~Atomic() noexcept - { - #if __cpp_lib_atomic_is_always_lock_free - static_assert (std::atomic::is_always_lock_free(), - "This class can only be used for lock-free types"); - #endif - } - - /** Atomically reads and returns the current value. */ - Type get() const noexcept { return value.load(); } - - /** Atomically sets the current value. */ - void set (Type newValue) noexcept { value = newValue; } - - /** Atomically sets the current value, returning the value that was replaced. */ - Type exchange (Type newValue) noexcept { return value.exchange (newValue); } - - /** Atomically compares this value with a target value, and if it is equal, sets - this to be equal to a new value. - - This operation is the atomic equivalent of doing this: - @code - bool compareAndSetBool (Type newValue, Type valueToCompare) - { - if (get() == valueToCompare) - { - set (newValue); - return true; - } - - return false; - } - @endcode - - Internally, this method calls std::atomic::compare_exchange_strong with - memory_order_seq_cst (the strictest std::memory_order). - - @returns true if the comparison was true and the value was replaced; false if - the comparison failed and the value was left unchanged. - @see compareAndSetValue - */ - bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept - { - return value.compare_exchange_strong (valueToCompare, newValue); - } - - /** Copies another value into this one (atomically). */ - Atomic& operator= (const Atomic& other) noexcept - { - value = other.value.load(); - return *this; - } - - /** Copies another value into this one (atomically). */ - Atomic& operator= (const Type newValue) noexcept - { - value = newValue; - return *this; - } - - /** Atomically adds a number to this value, returning the new value. */ - Type operator+= (DiffType amountToAdd) noexcept { return value += amountToAdd; } - - /** Atomically subtracts a number from this value, returning the new value. */ - Type operator-= (DiffType amountToSubtract) noexcept { return value -= amountToSubtract; } - - /** Atomically increments this value, returning the new value. */ - Type operator++() noexcept { return ++value; } - - /** Atomically decrements this value, returning the new value. */ - Type operator--() noexcept { return --value; } - - /** Implements a memory read/write barrier. - - Internally this calls std::atomic_thread_fence with - memory_order_seq_cst (the strictest std::memory_order). - */ - void memoryBarrier() noexcept { atomic_thread_fence (std::memory_order_seq_cst); } - - /** The std::atomic object that this class operates on. */ - std::atomic value; - - //============================================================================== - #ifndef DOXYGEN - // This method has been deprecated as there is no equivalent method in std::atomic. - JUCE_DEPRECATED (Type compareAndSetValue (Type, Type) noexcept); - #endif - }; - -#else - - #ifndef DOXYGEN - template class AtomicBase; - #endif - - //============================================================================== - /** - Simple class to hold a primitive value and perform atomic operations on it. - - The type used must be a 32 or 64 bit primitive, like an int, pointer, etc. - There are methods to perform most of the basic atomic operations. - */ - template - class Atomic : public AtomicBase - { - public: - /** Resulting type when subtracting the underlying Type. */ - typedef typename AtomicBase::DiffType DiffType; - - /** Creates a new value, initialised to zero. */ - inline Atomic() noexcept {} - - /** Creates a new value, with a given initial value. */ - inline explicit Atomic (const Type initialValue) noexcept : AtomicBase (initialValue) {} - - /** Copies another value (atomically). */ - inline Atomic (const Atomic& other) noexcept : AtomicBase (other) {} - - /** Destructor. */ - inline ~Atomic() noexcept - { - static_assert (sizeof (Type) == 4 || sizeof (Type) == 8, - "Atomic can only be used for types which are 32 or 64 bits in size"); - } - - /** Atomically reads and returns the current value. */ - inline Type get() const noexcept { return AtomicBase::get(); } - - /** Copies another value into this one (atomically). */ - inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase::operator= (other); return *this; } - - /** Copies another value into this one (atomically). */ - inline Atomic& operator= (const Type newValue) noexcept { AtomicBase::operator= (newValue); return *this; } - - /** Atomically sets the current value. */ - inline void set (Type newValue) noexcept { exchange (newValue); } - - /** Atomically sets the current value, returning the value that was replaced. */ - inline Type exchange (Type v) noexcept { return AtomicBase::exchange (v); } - - /** Atomically adds a number to this value, returning the new value. */ - Type operator+= (DiffType amountToAdd) noexcept; - - /** Atomically subtracts a number from this value, returning the new value. */ - Type operator-= (DiffType amountToSubtract) noexcept; - - /** Atomically increments this value, returning the new value. */ - Type operator++() noexcept; - - /** Atomically decrements this value, returning the new value. */ - Type operator--() noexcept; - - /** Atomically compares this value with a target value, and if it is equal, sets - this to be equal to a new value. - - This operation is the atomic equivalent of doing this: - @code - bool compareAndSetBool (Type newValue, Type valueToCompare) - { - if (get() == valueToCompare) - { - set (newValue); - return true; - } - - return false; - } - @endcode - - @returns true if the comparison was true and the value was replaced; false if - the comparison failed and the value was left unchanged. - @see compareAndSetValue - */ - inline bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept { return AtomicBase::compareAndSetBool (newValue, valueToCompare); } - - /** Atomically compares this value with a target value, and if it is equal, sets - this to be equal to a new value. - - This operation is the atomic equivalent of doing this: - @code - Type compareAndSetValue (Type newValue, Type valueToCompare) - { - Type oldValue = get(); - if (oldValue == valueToCompare) - set (newValue); - - return oldValue; - } - @endcode - - @returns the old value before it was changed. - @see compareAndSetBool - */ - inline Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept { return AtomicBase::compareAndSetValue (newValue, valueToCompare); } - - /** Implements a memory read/write barrier. */ - static inline void memoryBarrier() noexcept { AtomicBase::memoryBarrier (); } - }; - - #ifndef DOXYGEN - - //============================================================================== - // Internal implementation follows - //============================================================================== - template - class AtomicBase - { - public: - typedef typename AtomicHelpers::DiffTypeHelper::Type DiffType; - - inline AtomicBase() noexcept : value (0) {} - inline explicit AtomicBase (const Type v) noexcept : value (v) {} - inline AtomicBase (const AtomicBase& other) noexcept : value (other.get()) {} - Type get() const noexcept; - inline AtomicBase& operator= (const AtomicBase& other) noexcept { exchange (other.get()); return *this; } - inline AtomicBase& operator= (const Type newValue) noexcept { exchange (newValue); return *this; } - void set (Type newValue) noexcept { exchange (newValue); } - Type exchange (Type) noexcept; - bool compareAndSetBool (Type, Type) noexcept; - Type compareAndSetValue (Type, Type) noexcept; - static void memoryBarrier() noexcept; - - //============================================================================== - #if JUCE_64BIT - JUCE_ALIGN (8) - #else - JUCE_ALIGN (4) - #endif - - /** The raw value that this class operates on. - This is exposed publicly in case you need to manipulate it directly - for performance reasons. - */ - volatile Type value; - - protected: - template - static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; } - - static inline Type castFrom32Bit (int32 value) noexcept { return castTo (value); } - static inline Type castFrom64Bit (int64 value) noexcept { return castTo (value); } - static inline int32 castTo32Bit (Type value) noexcept { return castTo (value); } - static inline int64 castTo64Bit (Type value) noexcept { return castTo (value); } - - Type operator++ (int); // better to just use pre-increment with atomics.. - Type operator-- (int); - - /** This templated negate function will negate pointers as well as integers */ - template - inline ValueType negateValue (ValueType n) noexcept - { - return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n - : (sizeof (ValueType) == 2 ? (ValueType) -(short) n - : (sizeof (ValueType) == 4 ? (ValueType) -(int) n - : ((ValueType) -(int64) n))); - } - - /** This templated negate function will negate pointers as well as integers */ - template - inline PointerType* negateValue (PointerType* n) noexcept - { - return reinterpret_cast (-reinterpret_cast (n)); - } - }; - - //============================================================================== - // Specialisation for void* which does not include the pointer arithmetic - template <> - class Atomic : public AtomicBase - { - public: - inline Atomic() noexcept {} - inline explicit Atomic (void* const initialValue) noexcept : AtomicBase (initialValue) {} - inline Atomic (const Atomic& other) noexcept : AtomicBase (other) {} - inline void* get() const noexcept { return AtomicBase::get(); } - inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase::operator= (other); return *this; } - inline Atomic& operator= (void* const newValue) noexcept { AtomicBase::operator= (newValue); return *this; } - inline void set (void* newValue) noexcept { exchange (newValue); } - inline void* exchange (void* v) noexcept { return AtomicBase::exchange (v); } - inline bool compareAndSetBool (void* newValue, void* valueToCompare) noexcept { return AtomicBase::compareAndSetBool (newValue, valueToCompare); } - inline void* compareAndSetValue (void* newValue, void* valueToCompare) noexcept { return AtomicBase::compareAndSetValue (newValue, valueToCompare); } - static inline void memoryBarrier() noexcept { AtomicBase::memoryBarrier(); } - }; - - //============================================================================== - /* - The following code is in the header so that the atomics can be inlined where possible... - */ - #if JUCE_MAC && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)) - #define JUCE_ATOMICS_MAC_LEGACY 1 // Older OSX builds using gcc4.1 or earlier - #elif JUCE_GCC || JUCE_CLANG - #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics - #if JUCE_IOS || JUCE_ANDROID // (64-bit ops will compile but not link on these mobile OSes) - #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 - #endif - #endif - - template - struct AtomicIncrementDecrement - { - static inline Type inc (AtomicBase& a) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((volatile int32_t*) &a.value) - : (Type) OSAtomicIncrement64Barrier ((volatile int64_t*) &a.value); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (& (a.value), (Type) 1) - : (Type) __sync_add_and_fetch ((int64_t*) & (a.value), 1); - #endif - } - - static inline Type dec (AtomicBase& a) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((volatile int32_t*) &a.value) - : (Type) OSAtomicDecrement64Barrier ((volatile int64_t*) &a.value); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (& (a.value), (Type) -1) - : (Type) __sync_add_and_fetch ((int64_t*) & (a.value), -1); - #endif - } - }; - - template - struct AtomicIncrementDecrement - { - static inline Type* inc (Atomic& a) noexcept { return a.operator+= (1); } - static inline Type* dec (Atomic& a) noexcept { return a.operator-= (1); } - }; - - //============================================================================== - template - inline Type AtomicBase::get() const noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (volatile int32_t*) &value)) - : castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (volatile int64_t*) &value)); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) - : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); - #endif - } - - template - inline Type AtomicBase::exchange (const Type newValue) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY || JUCE_ATOMICS_GCC - Type currentVal = value; - while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; } - return currentVal; - #endif - } - - template - inline Type Atomic::operator+= (const DiffType amountToAdd) noexcept - { - Type amount = (Type() + amountToAdd); - - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amount), (volatile int32_t*) &AtomicBase::value) - : (Type) OSAtomicAdd64Barrier ((int64_t) amount, (volatile int64_t*) &AtomicBase::value); - #elif JUCE_ATOMICS_GCC - return (Type) __sync_add_and_fetch (& (AtomicBase::value), amount); - #endif - } - - template - inline Type Atomic::operator-= (const DiffType amountToSubtract) noexcept - { - return operator+= (AtomicBase::negateValue (amountToSubtract)); - } - - template - inline Type Atomic::operator++() noexcept { return AtomicIncrementDecrement::inc (*this); } - - template - inline Type Atomic::operator--() noexcept { return AtomicIncrementDecrement::dec (*this); } - - template - inline bool AtomicBase::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (volatile int32_t*) &value) - : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (volatile int64_t*) &value); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) - : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); - #endif - } - - template - inline Type AtomicBase::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - for (;;) // Annoying workaround for only having a bool CAS operation.. - { - if (compareAndSetBool (newValue, valueToCompare)) - return valueToCompare; - - const Type result = value; - if (result != valueToCompare) - return result; - } - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) - : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); - #endif - } - - template - inline void AtomicBase::memoryBarrier() noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - OSMemoryBarrier(); - #elif JUCE_ATOMICS_GCC - __sync_synchronize(); - #endif - } - - #endif - -#endif - -} // namespace juce +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2017 - ROLI Ltd. + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +#ifndef DOXYGEN + namespace AtomicHelpers + { + template struct DiffTypeHelper { typedef T Type; }; + template struct DiffTypeHelper { typedef std::ptrdiff_t Type; }; + } +#endif + +#if JUCE_ATOMIC_AVAILABLE + //============================================================================== + /** + A simple wrapper around std::atomic. + */ + template + struct Atomic + { + typedef typename AtomicHelpers::DiffTypeHelper::Type DiffType; + + /** Creates a new value, initialised to zero. */ + Atomic() noexcept : value (0) {} + + /** Creates a new value, with a given initial value. */ + Atomic (Type initialValue) noexcept : value (initialValue) {} + + /** Copies another value (atomically). */ + Atomic (const Atomic& other) noexcept : value (other.get()) {} + + /** Destructor. */ + ~Atomic() noexcept + { + #if __cpp_lib_atomic_is_always_lock_free + static_assert (std::atomic::is_always_lock_free, + "This class can only be used for lock-free types"); + #endif + } + + /** Atomically reads and returns the current value. */ + Type get() const noexcept { return value.load(); } + + /** Atomically sets the current value. */ + void set (Type newValue) noexcept { value = newValue; } + + /** Atomically sets the current value, returning the value that was replaced. */ + Type exchange (Type newValue) noexcept { return value.exchange (newValue); } + + /** Atomically compares this value with a target value, and if it is equal, sets + this to be equal to a new value. + + This operation is the atomic equivalent of doing this: + @code + bool compareAndSetBool (Type newValue, Type valueToCompare) + { + if (get() == valueToCompare) + { + set (newValue); + return true; + } + + return false; + } + @endcode + + Internally, this method calls std::atomic::compare_exchange_strong with + memory_order_seq_cst (the strictest std::memory_order). + + @returns true if the comparison was true and the value was replaced; false if + the comparison failed and the value was left unchanged. + @see compareAndSetValue + */ + bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept + { + return value.compare_exchange_strong (valueToCompare, newValue); + } + + /** Copies another value into this one (atomically). */ + Atomic& operator= (const Atomic& other) noexcept + { + value = other.value.load(); + return *this; + } + + /** Copies another value into this one (atomically). */ + Atomic& operator= (Type newValue) noexcept + { + value = newValue; + return *this; + } + + /** Atomically adds a number to this value, returning the new value. */ + Type operator+= (DiffType amountToAdd) noexcept { return value += amountToAdd; } + + /** Atomically subtracts a number from this value, returning the new value. */ + Type operator-= (DiffType amountToSubtract) noexcept { return value -= amountToSubtract; } + + /** Atomically increments this value, returning the new value. */ + Type operator++() noexcept { return ++value; } + + /** Atomically decrements this value, returning the new value. */ + Type operator--() noexcept { return --value; } + + /** Implements a memory read/write barrier. + + Internally this calls std::atomic_thread_fence with + memory_order_seq_cst (the strictest std::memory_order). + */ + void memoryBarrier() noexcept { atomic_thread_fence (std::memory_order_seq_cst); } + + /** The std::atomic object that this class operates on. */ + std::atomic value; + + //============================================================================== + #ifndef DOXYGEN + // This method has been deprecated as there is no equivalent method in std::atomic. + JUCE_DEPRECATED (Type compareAndSetValue (Type, Type) noexcept); + #endif + }; + +#else + + #ifndef DOXYGEN + template class AtomicBase; + #endif + + //============================================================================== + /** + Simple class to hold a primitive value and perform atomic operations on it. + + The type used must be a 32 or 64 bit primitive, like an int, pointer, etc. + There are methods to perform most of the basic atomic operations. + */ + template + class Atomic : public AtomicBase + { + public: + /** Resulting type when subtracting the underlying Type. */ + typedef typename AtomicBase::DiffType DiffType; + + /** Creates a new value, initialised to zero. */ + inline Atomic() noexcept {} + + /** Creates a new value, with a given initial value. */ + inline explicit Atomic (const Type initialValue) noexcept : AtomicBase (initialValue) {} + + /** Copies another value (atomically). */ + inline Atomic (const Atomic& other) noexcept : AtomicBase (other) {} + + /** Destructor. */ + inline ~Atomic() noexcept + { + static_assert (sizeof (Type) == 4 || sizeof (Type) == 8, + "Atomic can only be used for types which are 32 or 64 bits in size"); + } + + /** Atomically reads and returns the current value. */ + inline Type get() const noexcept { return AtomicBase::get(); } + + /** Copies another value into this one (atomically). */ + inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase::operator= (other); return *this; } + + /** Copies another value into this one (atomically). */ + inline Atomic& operator= (const Type newValue) noexcept { AtomicBase::operator= (newValue); return *this; } + + /** Atomically sets the current value. */ + inline void set (Type newValue) noexcept { exchange (newValue); } + + /** Atomically sets the current value, returning the value that was replaced. */ + inline Type exchange (Type v) noexcept { return AtomicBase::exchange (v); } + + /** Atomically adds a number to this value, returning the new value. */ + Type operator+= (DiffType amountToAdd) noexcept; + + /** Atomically subtracts a number from this value, returning the new value. */ + Type operator-= (DiffType amountToSubtract) noexcept; + + /** Atomically increments this value, returning the new value. */ + Type operator++() noexcept; + + /** Atomically decrements this value, returning the new value. */ + Type operator--() noexcept; + + /** Atomically compares this value with a target value, and if it is equal, sets + this to be equal to a new value. + + This operation is the atomic equivalent of doing this: + @code + bool compareAndSetBool (Type newValue, Type valueToCompare) + { + if (get() == valueToCompare) + { + set (newValue); + return true; + } + + return false; + } + @endcode + + @returns true if the comparison was true and the value was replaced; false if + the comparison failed and the value was left unchanged. + @see compareAndSetValue + */ + inline bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept { return AtomicBase::compareAndSetBool (newValue, valueToCompare); } + + /** Atomically compares this value with a target value, and if it is equal, sets + this to be equal to a new value. + + This operation is the atomic equivalent of doing this: + @code + Type compareAndSetValue (Type newValue, Type valueToCompare) + { + Type oldValue = get(); + if (oldValue == valueToCompare) + set (newValue); + + return oldValue; + } + @endcode + + @returns the old value before it was changed. + @see compareAndSetBool + */ + inline Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept { return AtomicBase::compareAndSetValue (newValue, valueToCompare); } + + /** Implements a memory read/write barrier. */ + static inline void memoryBarrier() noexcept { AtomicBase::memoryBarrier (); } + }; + + #ifndef DOXYGEN + + //============================================================================== + // Internal implementation follows + //============================================================================== + template + class AtomicBase + { + public: + typedef typename AtomicHelpers::DiffTypeHelper::Type DiffType; + + inline AtomicBase() noexcept : value (0) {} + inline explicit AtomicBase (const Type v) noexcept : value (v) {} + inline AtomicBase (const AtomicBase& other) noexcept : value (other.get()) {} + Type get() const noexcept; + inline AtomicBase& operator= (const AtomicBase& other) noexcept { exchange (other.get()); return *this; } + inline AtomicBase& operator= (const Type newValue) noexcept { exchange (newValue); return *this; } + void set (Type newValue) noexcept { exchange (newValue); } + Type exchange (Type) noexcept; + bool compareAndSetBool (Type, Type) noexcept; + Type compareAndSetValue (Type, Type) noexcept; + static void memoryBarrier() noexcept; + + //============================================================================== + #if JUCE_64BIT + JUCE_ALIGN (8) + #else + JUCE_ALIGN (4) + #endif + + /** The raw value that this class operates on. + This is exposed publicly in case you need to manipulate it directly + for performance reasons. + */ + volatile Type value; + + protected: + template + static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; } + + static inline Type castFrom32Bit (int32 value) noexcept { return castTo (value); } + static inline Type castFrom64Bit (int64 value) noexcept { return castTo (value); } + static inline int32 castTo32Bit (Type value) noexcept { return castTo (value); } + static inline int64 castTo64Bit (Type value) noexcept { return castTo (value); } + + Type operator++ (int); // better to just use pre-increment with atomics.. + Type operator-- (int); + + /** This templated negate function will negate pointers as well as integers */ + template + inline ValueType negateValue (ValueType n) noexcept + { + return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n + : (sizeof (ValueType) == 2 ? (ValueType) -(short) n + : (sizeof (ValueType) == 4 ? (ValueType) -(int) n + : ((ValueType) -(int64) n))); + } + + /** This templated negate function will negate pointers as well as integers */ + template + inline PointerType* negateValue (PointerType* n) noexcept + { + return reinterpret_cast (-reinterpret_cast (n)); + } + }; + + //============================================================================== + // Specialisation for void* which does not include the pointer arithmetic + template <> + class Atomic : public AtomicBase + { + public: + inline Atomic() noexcept {} + inline explicit Atomic (void* const initialValue) noexcept : AtomicBase (initialValue) {} + inline Atomic (const Atomic& other) noexcept : AtomicBase (other) {} + inline void* get() const noexcept { return AtomicBase::get(); } + inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase::operator= (other); return *this; } + inline Atomic& operator= (void* const newValue) noexcept { AtomicBase::operator= (newValue); return *this; } + inline void set (void* newValue) noexcept { exchange (newValue); } + inline void* exchange (void* v) noexcept { return AtomicBase::exchange (v); } + inline bool compareAndSetBool (void* newValue, void* valueToCompare) noexcept { return AtomicBase::compareAndSetBool (newValue, valueToCompare); } + inline void* compareAndSetValue (void* newValue, void* valueToCompare) noexcept { return AtomicBase::compareAndSetValue (newValue, valueToCompare); } + static inline void memoryBarrier() noexcept { AtomicBase::memoryBarrier(); } + }; + + //============================================================================== + /* + The following code is in the header so that the atomics can be inlined where possible... + */ + #if JUCE_MAC && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)) + #define JUCE_ATOMICS_MAC_LEGACY 1 // Older OSX builds using gcc4.1 or earlier + #elif JUCE_GCC || JUCE_CLANG + #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics + #if JUCE_IOS || JUCE_ANDROID // (64-bit ops will compile but not link on these mobile OSes) + #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 + #endif + #endif + + template + struct AtomicIncrementDecrement + { + static inline Type inc (AtomicBase& a) noexcept + { + #if JUCE_ATOMICS_MAC_LEGACY + return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((volatile int32_t*) &a.value) + : (Type) OSAtomicIncrement64Barrier ((volatile int64_t*) &a.value); + #elif JUCE_ATOMICS_GCC + return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (& (a.value), (Type) 1) + : (Type) __sync_add_and_fetch ((int64_t*) & (a.value), 1); + #endif + } + + static inline Type dec (AtomicBase& a) noexcept + { + #if JUCE_ATOMICS_MAC_LEGACY + return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((volatile int32_t*) &a.value) + : (Type) OSAtomicDecrement64Barrier ((volatile int64_t*) &a.value); + #elif JUCE_ATOMICS_GCC + return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (& (a.value), (Type) -1) + : (Type) __sync_add_and_fetch ((int64_t*) & (a.value), -1); + #endif + } + }; + + template + struct AtomicIncrementDecrement + { + static inline Type* inc (Atomic& a) noexcept { return a.operator+= (1); } + static inline Type* dec (Atomic& a) noexcept { return a.operator-= (1); } + }; + + //============================================================================== + template + inline Type AtomicBase::get() const noexcept + { + #if JUCE_ATOMICS_MAC_LEGACY + return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (volatile int32_t*) &value)) + : castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (volatile int64_t*) &value)); + #elif JUCE_ATOMICS_GCC + return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) + : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); + #endif + } + + template + inline Type AtomicBase::exchange (const Type newValue) noexcept + { + #if JUCE_ATOMICS_MAC_LEGACY || JUCE_ATOMICS_GCC + Type currentVal = value; + while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; } + return currentVal; + #endif + } + + template + inline Type Atomic::operator+= (const DiffType amountToAdd) noexcept + { + Type amount = (Type() + amountToAdd); + + #if JUCE_ATOMICS_MAC_LEGACY + return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amount), (volatile int32_t*) &AtomicBase::value) + : (Type) OSAtomicAdd64Barrier ((int64_t) amount, (volatile int64_t*) &AtomicBase::value); + #elif JUCE_ATOMICS_GCC + return (Type) __sync_add_and_fetch (& (AtomicBase::value), amount); + #endif + } + + template + inline Type Atomic::operator-= (const DiffType amountToSubtract) noexcept + { + return operator+= (AtomicBase::negateValue (amountToSubtract)); + } + + template + inline Type Atomic::operator++() noexcept { return AtomicIncrementDecrement::inc (*this); } + + template + inline Type Atomic::operator--() noexcept { return AtomicIncrementDecrement::dec (*this); } + + template + inline bool AtomicBase::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept + { + #if JUCE_ATOMICS_MAC_LEGACY + return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (volatile int32_t*) &value) + : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (volatile int64_t*) &value); + #elif JUCE_ATOMICS_GCC + return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) + : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); + #endif + } + + template + inline Type AtomicBase::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept + { + #if JUCE_ATOMICS_MAC_LEGACY + for (;;) // Annoying workaround for only having a bool CAS operation.. + { + if (compareAndSetBool (newValue, valueToCompare)) + return valueToCompare; + + const Type result = value; + if (result != valueToCompare) + return result; + } + #elif JUCE_ATOMICS_GCC + return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) + : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); + #endif + } + + template + inline void AtomicBase::memoryBarrier() noexcept + { + #if JUCE_ATOMICS_MAC_LEGACY + OSMemoryBarrier(); + #elif JUCE_ATOMICS_GCC + __sync_synchronize(); + #endif + } + + #endif + +#endif + +} // namespace juce