| @@ -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 <typename T> struct DiffTypeHelper { typedef T Type; }; | |||
| template <typename T> struct DiffTypeHelper<T*> { typedef std::ptrdiff_t Type; }; | |||
| } | |||
| #endif | |||
| #if JUCE_ATOMIC_AVAILABLE | |||
| //============================================================================== | |||
| /** | |||
| A simple wrapper around std::atomic. | |||
| */ | |||
| template <typename Type> | |||
| struct Atomic | |||
| { | |||
| typedef typename AtomicHelpers::DiffTypeHelper<Type>::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<Type>::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<Type>& operator= (const Atomic& other) noexcept | |||
| { | |||
| value = other.value.load(); | |||
| return *this; | |||
| } | |||
| /** Copies another value into this one (atomically). */ | |||
| Atomic<Type>& 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<Type> 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 <typename Type> 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 <typename Type> | |||
| class Atomic : public AtomicBase<Type> | |||
| { | |||
| public: | |||
| /** Resulting type when subtracting the underlying Type. */ | |||
| typedef typename AtomicBase<Type>::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<Type> (initialValue) {} | |||
| /** Copies another value (atomically). */ | |||
| inline Atomic (const Atomic& other) noexcept : AtomicBase<Type> (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<Type>::get(); } | |||
| /** Copies another value into this one (atomically). */ | |||
| inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase<Type>::operator= (other); return *this; } | |||
| /** Copies another value into this one (atomically). */ | |||
| inline Atomic& operator= (const Type newValue) noexcept { AtomicBase<Type>::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<Type>::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<Type>::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<Type>::compareAndSetValue (newValue, valueToCompare); } | |||
| /** Implements a memory read/write barrier. */ | |||
| static inline void memoryBarrier() noexcept { AtomicBase<Type>::memoryBarrier (); } | |||
| }; | |||
| #ifndef DOXYGEN | |||
| //============================================================================== | |||
| // Internal implementation follows | |||
| //============================================================================== | |||
| template <typename Type> | |||
| class AtomicBase | |||
| { | |||
| public: | |||
| typedef typename AtomicHelpers::DiffTypeHelper<Type>::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<Type>& 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 <typename Dest, typename Source> | |||
| 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 <Type, int32> (value); } | |||
| static inline Type castFrom64Bit (int64 value) noexcept { return castTo <Type, int64> (value); } | |||
| static inline int32 castTo32Bit (Type value) noexcept { return castTo <int32, Type> (value); } | |||
| static inline int64 castTo64Bit (Type value) noexcept { return castTo <int64, Type> (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 <typename ValueType> | |||
| 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 <typename PointerType> | |||
| inline PointerType* negateValue (PointerType* n) noexcept | |||
| { | |||
| return reinterpret_cast<PointerType*> (-reinterpret_cast<pointer_sized_int> (n)); | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| // Specialisation for void* which does not include the pointer arithmetic | |||
| template <> | |||
| class Atomic<void*> : public AtomicBase<void*> | |||
| { | |||
| public: | |||
| inline Atomic() noexcept {} | |||
| inline explicit Atomic (void* const initialValue) noexcept : AtomicBase<void*> (initialValue) {} | |||
| inline Atomic (const Atomic<void*>& other) noexcept : AtomicBase<void*> (other) {} | |||
| inline void* get() const noexcept { return AtomicBase<void*>::get(); } | |||
| inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase<void*>::operator= (other); return *this; } | |||
| inline Atomic& operator= (void* const newValue) noexcept { AtomicBase<void*>::operator= (newValue); return *this; } | |||
| inline void set (void* newValue) noexcept { exchange (newValue); } | |||
| inline void* exchange (void* v) noexcept { return AtomicBase<void*>::exchange (v); } | |||
| inline bool compareAndSetBool (void* newValue, void* valueToCompare) noexcept { return AtomicBase<void*>::compareAndSetBool (newValue, valueToCompare); } | |||
| inline void* compareAndSetValue (void* newValue, void* valueToCompare) noexcept { return AtomicBase<void*>::compareAndSetValue (newValue, valueToCompare); } | |||
| static inline void memoryBarrier() noexcept { AtomicBase<void*>::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 <typename Type> | |||
| struct AtomicIncrementDecrement | |||
| { | |||
| static inline Type inc (AtomicBase<Type>& 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<Type>& 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 <typename Type> | |||
| struct AtomicIncrementDecrement<Type*> | |||
| { | |||
| static inline Type* inc (Atomic<Type*>& a) noexcept { return a.operator+= (1); } | |||
| static inline Type* dec (Atomic<Type*>& a) noexcept { return a.operator-= (1); } | |||
| }; | |||
| //============================================================================== | |||
| template <typename Type> | |||
| inline Type AtomicBase<Type>::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 <typename Type> | |||
| inline Type AtomicBase<Type>::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 <typename Type> | |||
| inline Type Atomic<Type>::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<Type>::value) | |||
| : (Type) OSAtomicAdd64Barrier ((int64_t) amount, (volatile int64_t*) &AtomicBase<Type>::value); | |||
| #elif JUCE_ATOMICS_GCC | |||
| return (Type) __sync_add_and_fetch (& (AtomicBase<Type>::value), amount); | |||
| #endif | |||
| } | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::operator-= (const DiffType amountToSubtract) noexcept | |||
| { | |||
| return operator+= (AtomicBase<Type>::negateValue (amountToSubtract)); | |||
| } | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::operator++() noexcept { return AtomicIncrementDecrement<Type>::inc (*this); } | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::operator--() noexcept { return AtomicIncrementDecrement<Type>::dec (*this); } | |||
| template <typename Type> | |||
| inline bool AtomicBase<Type>::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 <typename Type> | |||
| inline Type AtomicBase<Type>::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 <typename Type> | |||
| inline void AtomicBase<Type>::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 <typename T> struct DiffTypeHelper { typedef T Type; }; | |||
| template <typename T> struct DiffTypeHelper<T*> { typedef std::ptrdiff_t Type; }; | |||
| } | |||
| #endif | |||
| #if JUCE_ATOMIC_AVAILABLE | |||
| //============================================================================== | |||
| /** | |||
| A simple wrapper around std::atomic. | |||
| */ | |||
| template <typename Type> | |||
| struct Atomic | |||
| { | |||
| typedef typename AtomicHelpers::DiffTypeHelper<Type>::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<Type>::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<Type>& operator= (const Atomic& other) noexcept | |||
| { | |||
| value = other.value.load(); | |||
| return *this; | |||
| } | |||
| /** Copies another value into this one (atomically). */ | |||
| Atomic<Type>& 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<Type> 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 <typename Type> 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 <typename Type> | |||
| class Atomic : public AtomicBase<Type> | |||
| { | |||
| public: | |||
| /** Resulting type when subtracting the underlying Type. */ | |||
| typedef typename AtomicBase<Type>::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<Type> (initialValue) {} | |||
| /** Copies another value (atomically). */ | |||
| inline Atomic (const Atomic& other) noexcept : AtomicBase<Type> (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<Type>::get(); } | |||
| /** Copies another value into this one (atomically). */ | |||
| inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase<Type>::operator= (other); return *this; } | |||
| /** Copies another value into this one (atomically). */ | |||
| inline Atomic& operator= (const Type newValue) noexcept { AtomicBase<Type>::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<Type>::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<Type>::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<Type>::compareAndSetValue (newValue, valueToCompare); } | |||
| /** Implements a memory read/write barrier. */ | |||
| static inline void memoryBarrier() noexcept { AtomicBase<Type>::memoryBarrier (); } | |||
| }; | |||
| #ifndef DOXYGEN | |||
| //============================================================================== | |||
| // Internal implementation follows | |||
| //============================================================================== | |||
| template <typename Type> | |||
| class AtomicBase | |||
| { | |||
| public: | |||
| typedef typename AtomicHelpers::DiffTypeHelper<Type>::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<Type>& 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 <typename Dest, typename Source> | |||
| 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 <Type, int32> (value); } | |||
| static inline Type castFrom64Bit (int64 value) noexcept { return castTo <Type, int64> (value); } | |||
| static inline int32 castTo32Bit (Type value) noexcept { return castTo <int32, Type> (value); } | |||
| static inline int64 castTo64Bit (Type value) noexcept { return castTo <int64, Type> (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 <typename ValueType> | |||
| 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 <typename PointerType> | |||
| inline PointerType* negateValue (PointerType* n) noexcept | |||
| { | |||
| return reinterpret_cast<PointerType*> (-reinterpret_cast<pointer_sized_int> (n)); | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| // Specialisation for void* which does not include the pointer arithmetic | |||
| template <> | |||
| class Atomic<void*> : public AtomicBase<void*> | |||
| { | |||
| public: | |||
| inline Atomic() noexcept {} | |||
| inline explicit Atomic (void* const initialValue) noexcept : AtomicBase<void*> (initialValue) {} | |||
| inline Atomic (const Atomic<void*>& other) noexcept : AtomicBase<void*> (other) {} | |||
| inline void* get() const noexcept { return AtomicBase<void*>::get(); } | |||
| inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase<void*>::operator= (other); return *this; } | |||
| inline Atomic& operator= (void* const newValue) noexcept { AtomicBase<void*>::operator= (newValue); return *this; } | |||
| inline void set (void* newValue) noexcept { exchange (newValue); } | |||
| inline void* exchange (void* v) noexcept { return AtomicBase<void*>::exchange (v); } | |||
| inline bool compareAndSetBool (void* newValue, void* valueToCompare) noexcept { return AtomicBase<void*>::compareAndSetBool (newValue, valueToCompare); } | |||
| inline void* compareAndSetValue (void* newValue, void* valueToCompare) noexcept { return AtomicBase<void*>::compareAndSetValue (newValue, valueToCompare); } | |||
| static inline void memoryBarrier() noexcept { AtomicBase<void*>::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 <typename Type> | |||
| struct AtomicIncrementDecrement | |||
| { | |||
| static inline Type inc (AtomicBase<Type>& 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<Type>& 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 <typename Type> | |||
| struct AtomicIncrementDecrement<Type*> | |||
| { | |||
| static inline Type* inc (Atomic<Type*>& a) noexcept { return a.operator+= (1); } | |||
| static inline Type* dec (Atomic<Type*>& a) noexcept { return a.operator-= (1); } | |||
| }; | |||
| //============================================================================== | |||
| template <typename Type> | |||
| inline Type AtomicBase<Type>::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 <typename Type> | |||
| inline Type AtomicBase<Type>::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 <typename Type> | |||
| inline Type Atomic<Type>::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<Type>::value) | |||
| : (Type) OSAtomicAdd64Barrier ((int64_t) amount, (volatile int64_t*) &AtomicBase<Type>::value); | |||
| #elif JUCE_ATOMICS_GCC | |||
| return (Type) __sync_add_and_fetch (& (AtomicBase<Type>::value), amount); | |||
| #endif | |||
| } | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::operator-= (const DiffType amountToSubtract) noexcept | |||
| { | |||
| return operator+= (AtomicBase<Type>::negateValue (amountToSubtract)); | |||
| } | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::operator++() noexcept { return AtomicIncrementDecrement<Type>::inc (*this); } | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::operator--() noexcept { return AtomicIncrementDecrement<Type>::dec (*this); } | |||
| template <typename Type> | |||
| inline bool AtomicBase<Type>::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 <typename Type> | |||
| inline Type AtomicBase<Type>::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 <typename Type> | |||
| inline void AtomicBase<Type>::memoryBarrier() noexcept | |||
| { | |||
| #if JUCE_ATOMICS_MAC_LEGACY | |||
| OSMemoryBarrier(); | |||
| #elif JUCE_ATOMICS_GCC | |||
| __sync_synchronize(); | |||
| #endif | |||
| } | |||
| #endif | |||
| #endif | |||
| } // namespace juce | |||