diff options
Diffstat (limited to 'libs/ode-0.16.1/ou/include/ou/atomicflags.h')
-rw-r--r-- | libs/ode-0.16.1/ou/include/ou/atomicflags.h | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/libs/ode-0.16.1/ou/include/ou/atomicflags.h b/libs/ode-0.16.1/ou/include/ou/atomicflags.h new file mode 100644 index 0000000..58517fa --- /dev/null +++ b/libs/ode-0.16.1/ou/include/ou/atomicflags.h @@ -0,0 +1,367 @@ +/************************************************************************* + * * + * ODER's Utilities Library. Copyright (C) 2008-2019 Oleh Derevenko. * + * All rights reserved. e-mail: odar@eleks.com (change all "a" to "e") * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 3 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE-LESSER.TXT. Since LGPL is the extension of GPL * + * the text of GNU General Public License is also provided for * + * your information in file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * (3) The zlib/libpng license that is included with this library in * + * the file LICENSE-ZLIB.TXT * + * * + * This library is distributed WITHOUT ANY WARRANTY, including implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the files LICENSE.TXT and LICENSE-LESSER.TXT or LICENSE-BSD.TXT * + * or LICENSE-ZLIB.TXT for more details. * + * * + *************************************************************************/ + +#ifndef __OU_ATOMICFLAGS_H_INCLUDED +#define __OU_ATOMICFLAGS_H_INCLUDED + + +#include <ou/flagsdefines.h> +#include <ou/atomic.h> +#include <ou/assert.h> +#include <ou/namespace.h> + + +BEGIN_NAMESPACE_OU(); + + +/* + * Implementation Note: + * Modification functions are implemented as memory barriers. + * Retrieval functions are implemented as ordinary memory accesses. + * Practice proves that such approach is quite sufficient to provide + * reliable synchronization mechanisms (provided a developer has solid + * knowledge in field, of course). + */ + +class CAtomicFlags +{ +public: + _OU_INLINE _OU_CONVENTION_METHOD CAtomicFlags(): + m_aoFlagsValue(0) + { + } + + _OU_INLINE _OU_CONVENTION_METHOD CAtomicFlags(atomicord32 aoFlagsValue): + m_aoFlagsValue(aoFlagsValue) + { + } + + typedef atomicord32 value_type; + +public: + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */AssignFlagsAllValues(atomicord32 aoFlagsValue) + { + AtomicExchange(&m_aoFlagsValue, aoFlagsValue); + } + + _OU_ALWAYSINLINE atomicord32 _OU_CONVENTION_METHOD + /*atomicord32 */QueryFlagsAllValues() const + { + return m_aoFlagsValue; + } + + + // Can operate both on single flag and flag set + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */SetFlagsMaskValue(atomicord32 aoFlagsMask, bool bFlagValue) + { + if (bFlagValue) + { + AtomicOrNoResult(&m_aoFlagsValue, aoFlagsMask); + } + else + { + AtomicAndNoResult(&m_aoFlagsValue, ~aoFlagsMask); + } + } + + // Can operate both on single flag and flag set + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */SignalFlagsMaskValue(atomicord32 aoFlagsMask) + { + AtomicOrNoResult(&m_aoFlagsValue, aoFlagsMask); + } + + // Can operate both on single flag and flag set + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */DropFlagsMaskValue(atomicord32 aoFlagsMask) + { + AtomicAndNoResult(&m_aoFlagsValue, ~aoFlagsMask); + } + + + // Can operate on single flag only + // Returns previous flag value + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */ToggleSingleFlagValue(atomicord32 aoSingleFlag) + { + OU_ASSERT(OU_FLAGS_FLAG_IS_SINGLE(atomicord32, aoSingleFlag)); + + return (AtomicXor(&m_aoFlagsValue, aoSingleFlag) & aoSingleFlag) != (atomicord32)0; + } + + // Can operate on single flag only + // Returns if modification occurred + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */ModifySingleFlagValue(atomicord32 aoSingleFlag, bool bFlagValue) + { + OU_ASSERT(OU_FLAGS_FLAG_IS_SINGLE(atomicord32, aoSingleFlag)); + + return bFlagValue + ? ((AtomicOr(&m_aoFlagsValue, aoSingleFlag) & aoSingleFlag) == (atomicord32)0) + : ((AtomicAnd(&m_aoFlagsValue, ~aoSingleFlag) & aoSingleFlag) != (atomicord32)0); + } + + + // Modifies subset of flags + // Returns previous flags + _OU_ALWAYSINLINE atomicord32 _OU_CONVENTION_METHOD + /*atomicord32 */AssignFlagsByMask(atomicord32 aoFlagsMask, atomicord32 aoFlagsValue) + { + atomicord32 aoFlagsOldValue; + + do + { + aoFlagsOldValue = m_aoFlagsValue; + } + while (!AtomicCompareExchange(&m_aoFlagsValue, aoFlagsOldValue, (aoFlagsOldValue & ~aoFlagsMask) | (aoFlagsValue & aoFlagsMask))); + + return aoFlagsOldValue; + } + + // Modifies subset of flags + // Returns if modification occurred + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */AlterFlagsByMask(atomicord32 aoFlagsMask, atomicord32 aoFlagsValue) + { + atomicord32 aoFlagsOldValue; + + do + { + aoFlagsOldValue = m_aoFlagsValue; + } + while (!AtomicCompareExchange(&m_aoFlagsValue, aoFlagsOldValue, (aoFlagsOldValue & ~aoFlagsMask) | (aoFlagsValue & aoFlagsMask))); + + return ((aoFlagsOldValue ^ aoFlagsValue) & aoFlagsMask) != (atomicord32)0; + } + + + // Returns value of flag or tests for any bit in a mask + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */GetFlagsMaskValue(atomicord32 aoFlagsMask) const + { + return (m_aoFlagsValue & aoFlagsMask) != (atomicord32)0; + } + + // Returns subset of flags + _OU_ALWAYSINLINE atomicord32 _OU_CONVENTION_METHOD + /*atomicord32 */QueryFlagsByMask(atomicord32 aoFlagsMask) const + { + return (m_aoFlagsValue & aoFlagsMask); + } + +public: + // Signal only flag out of mask + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */OnlySignalSingleFlagOutOfMask(atomicord32 aoFlagsMask, atomicord32 aoSingleFlag) + { + OU_ASSERT(OU_FLAGS_FLAG_IS_SINGLE(atomicord32, aoSingleFlag)); + + bool bResult; + + atomicord32 aoFlagsOldValue; + + do + { + aoFlagsOldValue = m_aoFlagsValue; + + /* + * Implementation Note: + * 1) This function may be not a memory barrier. However that would also mean that + * no modification occurred and result is 'false'. Such behavior should be OK. + * 2) Even though second assignment to bResult is unnecessary it might yield + * better code as compiler does not need to save variable's value for the call + * to AtomicCompareExchange in this case. + */ + } + while ((bResult = !(aoFlagsOldValue & aoFlagsMask)) && !(bResult = AtomicCompareExchange(&m_aoFlagsValue, aoFlagsOldValue, aoFlagsOldValue | aoSingleFlag))); + + return bResult; + } + +public: + // Set value of flag indexed by enum + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */EnumSetEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedValue, unsigned int uiEnumeratedMaximum, bool bFlagValue) + { + OU_ASSERT(uiEnumeratedValue < uiEnumeratedMaximum && OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + SetFlagsMaskValue(aoStartingFlag << uiEnumeratedValue, bFlagValue); + } + + // Signal value of flag indexed by enum + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */EnumSignalEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedValue, unsigned int uiEnumeratedMaximum) + { + OU_ASSERT(uiEnumeratedValue < uiEnumeratedMaximum && OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + SignalFlagsMaskValue(aoStartingFlag << uiEnumeratedValue); + } + + // Drop value of flag indexed by enum + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */EnumDropEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedValue, unsigned int uiEnumeratedMaximum) + { + OU_ASSERT(uiEnumeratedValue < uiEnumeratedMaximum && OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + DropFlagsMaskValue(aoStartingFlag << uiEnumeratedValue); + } + + + // Can operate on single flag only + // Returns previous flag value + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */EnumToggleEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedValue, unsigned int uiEnumeratedMaximum) + { + OU_ASSERT(uiEnumeratedValue < uiEnumeratedMaximum && OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + return ToggleSingleFlagValue(aoStartingFlag << uiEnumeratedValue); + } + + // Can operate on single flag only + // Returns if modification occurred + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */EnumModifyEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedValue, unsigned int uiEnumeratedMaximum, bool bFlagValue) + { + OU_ASSERT(uiEnumeratedValue < uiEnumeratedMaximum && OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + return ModifySingleFlagValue(aoStartingFlag << uiEnumeratedValue, bFlagValue); + } + + + // Returns if this was the first flag signaled + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */EnumSignalFirstEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedValue, unsigned int uiEnumeratedMaximum) + { + OU_ASSERT(uiEnumeratedValue < uiEnumeratedMaximum && OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + return (AssignFlagsByMask(aoStartingFlag << uiEnumeratedValue, aoStartingFlag << uiEnumeratedValue) & OU_FLAGS_ENUMFLAGS_MASK(atomicord32, aoStartingFlag, uiEnumeratedMaximum)) == (atomicord32)0; + } + + // Returns if this was the last flag signaled + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */EnumSignalLastEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedValue, unsigned int uiEnumeratedMaximum) + { + OU_ASSERT(uiEnumeratedValue < uiEnumeratedMaximum && OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + return (AssignFlagsByMask(aoStartingFlag << uiEnumeratedValue, aoStartingFlag << uiEnumeratedValue) & OU_FLAGS_ENUMFLAGS_MASK(atomicord32, aoStartingFlag, uiEnumeratedMaximum)) == (OU_FLAGS_ENUMFLAGS_MASK(atomicord32, aoStartingFlag, uiEnumeratedMaximum) & ~(aoStartingFlag << uiEnumeratedValue)); + } + + + // Retrieve value of flag indexed by enum + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */EnumGetEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedValue, unsigned int uiEnumeratedMaximum) const + { + OU_ASSERT(uiEnumeratedValue < uiEnumeratedMaximum && OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + return GetFlagsMaskValue(aoStartingFlag << uiEnumeratedValue); + } + + // Find enum value for first flag signaled + _OU_INLINE int _OU_CONVENTION_METHOD + /*int */EnumFindFirstEnumeratedFlag(atomicord32 aoStartingFlag, unsigned int uiEnumeratedMaximum) const + { + OU_ASSERT(OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + unsigned int uiResult = 0; + + atomicord32 aoFlagsMask = aoStartingFlag; + for (; uiResult < uiEnumeratedMaximum; ++uiResult, aoFlagsMask <<= 1) + { + if (GetFlagsMaskValue(aoFlagsMask)) + { + break; + } + } + + return uiResult; + } + +public: + // Signal all flags indexed by enum + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */EnumAllSignalEnumeratedFlags(atomicord32 aoStartingFlag, unsigned int uiEnumeratedMaximum) + { + OU_ASSERT(OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + SignalFlagsMaskValue(OU_FLAGS_ENUMFLAGS_MASK(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + } + + // Drop all flags indexed by enum + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */EnumAllDropEnumeratedFlags(atomicord32 aoStartingFlag, unsigned int uiEnumeratedMaximum) + { + OU_ASSERT(OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + DropFlagsMaskValue(OU_FLAGS_ENUMFLAGS_MASK(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + } + + + // Query all flags indexed by enum + _OU_ALWAYSINLINE atomicord32 _OU_CONVENTION_METHOD + /*atomicord32 */EnumAllQueryEnumeratedFlags(atomicord32 aoStartingFlag, unsigned int uiEnumeratedMaximum) const + { + OU_ASSERT(OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + return QueryFlagsByMask(OU_FLAGS_ENUMFLAGS_MASK(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + } + + // Get if any flag indexed by enum is set + _OU_ALWAYSINLINE bool _OU_CONVENTION_METHOD + /*bool */EnumAnyGetEnumeratedFlagValue(atomicord32 aoStartingFlag, unsigned int uiEnumeratedMaximum) const + { + OU_ASSERT(OU_FLAGS_ENUMFLAGS_START_VALID(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + + return GetFlagsMaskValue(OU_FLAGS_ENUMFLAGS_MASK(atomicord32, aoStartingFlag, uiEnumeratedMaximum)); + } + +public: + // Store enumerated value in flags + _OU_ALWAYSINLINE void _OU_CONVENTION_METHOD + /*void */StoreFlagsEnumeratedValue(atomicord32 aoEnumeratedValueMask, unsigned int uiEnumeratedValueShift, unsigned int uiEnumeratedValue) + { + OU_ASSERT(OU_FLAGS_STOREENUM_VALUE_IN_MASK(atomicord32, uiEnumeratedValue, aoEnumeratedValueMask)); + + AssignFlagsByMask(aoEnumeratedValueMask << uiEnumeratedValueShift, (atomicord32)uiEnumeratedValue << uiEnumeratedValueShift); + } + + // Retrieve enumerated value from flags + _OU_ALWAYSINLINE unsigned int _OU_CONVENTION_METHOD + /*unsigned int */RetrieveFlagsEnumeratedValue(atomicord32 aoEnumeratedValueMask, unsigned int uiEnumeratedValueShift) const + { + return (unsigned int)((QueryFlagsAllValues() >> uiEnumeratedValueShift) & aoEnumeratedValueMask); + } + +private: + atomicord32 m_aoFlagsValue; +}; + + +END_NAMESPACE_OU(); + + +#endif // #ifndef __OU_ATOMICFLAGS_H_INCLUDED |