From 364a061b8790afbf3fa60fddbdafd99e200d7dd6 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Thu, 27 May 2004 00:08:52 +0000 Subject: [PATCH] add enum_add template --- stepmania/src/RageUtil.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/stepmania/src/RageUtil.h b/stepmania/src/RageUtil.h index fb24208ad9..01ef437248 100644 --- a/stepmania/src/RageUtil.h +++ b/stepmania/src/RageUtil.h @@ -121,6 +121,37 @@ inline float froundf( const float f, const float fRoundInterval ) return int( (f + fRoundInterval/2)/fRoundInterval ) * fRoundInterval; } +/* + * Safely add an integer to an enum. + * + * This is illegal: + * + * ((int&)val) += iAmt; + * + * It breaks aliasing rules; the compiler is allowed to assume that "val" doesn't + * change (unless it's declared volatile), and in some cases, you'll end up getting + * old values for "val" following the add. (What's probably really happening is + * that the memory location is being added to, but the value is stored in a register, + * and breaking aliasing rules mean the compiler doesn't know that the register + * value is invalid.) + * + * Always do these conversions through a union. + */ +template +static inline void enum_add( T &val, int iAmt ) +{ + union conv + { + T value; + int i; + conv( T v ):value(v) { } + }; + + conv c( val ); + c.i += iAmt; + val = c.value; +} + // Move val toward other_val by to_move. void fapproach( float& val, float other_val, float to_move );