diff --git a/glm/detail/func_integer.inl b/glm/detail/func_integer.inl index b254d253..738a2ace 100644 --- a/glm/detail/func_integer.inl +++ b/glm/detail/func_integer.inl @@ -45,9 +45,7 @@ namespace detail template GLM_FUNC_QUALIFIER T mask(T Bits) { - GLM_STATIC_ASSERT(!std::numeric_limits::is_signed, "'Bits' type must be unsigned"); - - return ~((~static_cast(0)) << Bits); + return Bits >= sizeof(T) * 8 ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); } template @@ -189,8 +187,7 @@ namespace detail { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldExtract' only accept integer inputs"); - T const Mask = static_cast(detail::mask(detail::make_unsigned::type(Bits))); - return (Value >> static_cast(Offset)) & static_cast(Mask); + return (Value >> static_cast(Offset)) & static_cast(detail::mask(Bits)); } // bitfieldInsert @@ -205,7 +202,7 @@ namespace detail { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); - T Mask = static_cast(detail::mask(detail::make_unsigned::type(Bits)) << Offset); + T const Mask = static_cast(detail::mask(Bits) << Offset); return (Base & ~Mask) | (Insert & Mask); } diff --git a/glm/gtc/bitfield.inl b/glm/gtc/bitfield.inl index 13feafc1..0cbf3d2b 100644 --- a/glm/gtc/bitfield.inl +++ b/glm/gtc/bitfield.inl @@ -250,7 +250,7 @@ namespace detail { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); - return ~((~static_cast(0)) << Bits); + return Bits >= sizeof(genIUType) * 8 ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); } template class vecIUType> @@ -258,7 +258,7 @@ namespace detail { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); - return ~((~static_cast(0)) << v); + return detail::functor1::call(mask, v); } template diff --git a/test/core/core_func_integer.cpp b/test/core/core_func_integer.cpp index 68a135d5..2d241c92 100644 --- a/test/core/core_func_integer.cpp +++ b/test/core/core_func_integer.cpp @@ -37,8 +37,8 @@ namespace bitfieldInsert typeU32 const Data32[] = { - {0x00000000, 0xffffffff, 0, 31, 0x7fffffff}, {0x00000000, 0xffffffff, 0, 32, 0xffffffff}, + {0x00000000, 0xffffffff, 0, 31, 0x7fffffff}, {0x00000000, 0xffffffff, 0, 0, 0x00000000}, {0xff000000, 0x0000ff00, 8, 8, 0xff00ff00}, {0xffff0000, 0x0000ffff, 16, 16, 0x00000000}, diff --git a/test/gtc/gtc_bitfield.cpp b/test/gtc/gtc_bitfield.cpp index 2763e874..6c112a26 100644 --- a/test/gtc/gtc_bitfield.cpp +++ b/test/gtc/gtc_bitfield.cpp @@ -33,7 +33,20 @@ namespace mask inline int mask_mix(int Bits) { - return Bits >= 32 ? 0xffffffff : (static_cast(1) << Bits) - static_cast(1); + return Bits >= sizeof(int) * 8 ? 0xffffffff : (static_cast(1) << Bits) - static_cast(1); + } + + inline int mask_half(int Bits) + { + // We do the shift in two steps because 1 << 32 on an int is undefined. + + int const Half = Bits >> 1; + int const Fill = ~0; + int const ShiftHaft = (Fill << Half); + int const Rest = Bits - Half; + int const Reversed = ShiftHaft << Rest; + + return ~Reversed; } inline int mask_loop(int Bits) @@ -86,15 +99,26 @@ namespace mask std::clock_t Timestamp5 = std::clock(); + { + std::vector Mask; + Mask.resize(Count); + for(int i = 0; i < Count; ++i) + Mask[i] = mask_half(i % 32); + } + + std::clock_t Timestamp6 = std::clock(); + std::clock_t TimeMix = Timestamp2 - Timestamp1; std::clock_t TimeLoop = Timestamp3 - Timestamp2; std::clock_t TimeDefault = Timestamp4 - Timestamp3; std::clock_t TimeZero = Timestamp5 - Timestamp4; + std::clock_t TimeHalf = Timestamp6 - Timestamp5; printf("mask[mix]: %d\n", static_cast(TimeMix)); printf("mask[loop]: %d\n", static_cast(TimeLoop)); printf("mask[default]: %d\n", static_cast(TimeDefault)); printf("mask[zero]: %d\n", static_cast(TimeZero)); + printf("mask[half]: %d\n", static_cast(TimeHalf)); return TimeDefault < TimeLoop ? 0 : 1; } @@ -112,19 +136,25 @@ namespace mask }; int Error(0); - +/* mask_zero is sadly not a correct code for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) { int Result = mask_zero(Data[i].Value); Error += Data[i].Return == Result ? 0 : 1; } - +*/ for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) { int Result = mask_mix(Data[i].Value); Error += Data[i].Return == Result ? 0 : 1; } + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = mask_half(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) { int Result = mask_loop(Data[i].Value);