diff --git a/glm/detail/func_integer.inl b/glm/detail/func_integer.inl index ccdb5641..b254d253 100644 --- a/glm/detail/func_integer.inl +++ b/glm/detail/func_integer.inl @@ -42,9 +42,12 @@ namespace glm{ namespace detail { - GLM_FUNC_QUALIFIER int mask(int Bits) + template + GLM_FUNC_QUALIFIER T mask(T Bits) { - return Bits >= 32 ? 0xffffffff : (static_cast(1) << Bits) - static_cast(1); + GLM_STATIC_ASSERT(!std::numeric_limits::is_signed, "'Bits' type must be unsigned"); + + return ~((~static_cast(0)) << Bits); } template @@ -186,7 +189,7 @@ namespace detail { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldExtract' only accept integer inputs"); - int const Mask = detail::mask(Bits); + T const Mask = static_cast(detail::mask(detail::make_unsigned::type(Bits))); return (Value >> static_cast(Offset)) & static_cast(Mask); } @@ -202,7 +205,7 @@ namespace detail { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); - T Mask = static_cast(detail::mask(Bits) << Offset); + T Mask = static_cast(detail::mask(detail::make_unsigned::type(Bits)) << Offset); return (Base & ~Mask) | (Insert & Mask); } diff --git a/glm/gtc/integer.hpp b/glm/gtc/integer.hpp index fb8b5660..9818cd6c 100644 --- a/glm/gtc/integer.hpp +++ b/glm/gtc/integer.hpp @@ -55,58 +55,6 @@ namespace glm /// @addtogroup gtc_integer /// @{ - /// Return true if the value is a power of two number. - /// - /// @see gtc_integer - template - GLM_FUNC_DECL bool isPowerOfTwo(genIUType Value); - - /// Return true if the value is a power of two number. - /// - /// @see gtc_integer - template class vecType> - GLM_FUNC_DECL vecType isPowerOfTwo(vecType const & value); - - /// Return the power of two number which value is just higher the input value, - /// round up to a power of two. - /// - /// @see gtc_integer - template - GLM_FUNC_DECL genIUType ceilPowerOfTwo(genIUType Value); - - /// Return the power of two number which value is just higher the input value, - /// round up to a power of two. - /// - /// @see gtc_integer - template class vecType> - GLM_FUNC_DECL vecType ceilPowerOfTwo(vecType const & value); - - /// Return the power of two number which value is just lower the input value, - /// round down to a power of two. - /// - /// @see gtc_integer - template - GLM_FUNC_DECL genIUType floorPowerOfTwo(genIUType Value); - - /// Return the power of two number which value is just lower the input value, - /// round down to a power of two. - /// - /// @see gtc_integer - template class vecType> - GLM_FUNC_DECL vecType floorPowerOfTwo(vecType const & value); - - /// Return the power of two number which value is the closet to the input value. - /// - /// @see gtc_integer - template - GLM_FUNC_DECL genIUType roundPowerOfTwo(genIUType Value); - - /// Return the power of two number which value is the closet to the input value. - /// - /// @see gtc_integer - template class vecType> - GLM_FUNC_DECL vecType roundPowerOfTwo(vecType const & value); - /// @} } //namespace glm diff --git a/glm/gtc/integer.inl b/glm/gtc/integer.inl index b06dca44..3af245b8 100644 --- a/glm/gtc/integer.inl +++ b/glm/gtc/integer.inl @@ -29,131 +29,8 @@ namespace glm{ namespace detail { - template class vecType, bool compute = false> - struct compute_ceilShift - { - GLM_FUNC_QUALIFIER static vecType call(vecType const & v, T) - { - return v; - } - }; - template class vecType> - struct compute_ceilShift - { - GLM_FUNC_QUALIFIER static vecType call(vecType const & v, T Shift) - { - return v | (v >> Shift); - } - }; - - template class vecType, bool isSigned = true> - struct compute_ceilPowerOfTwo - { - GLM_FUNC_QUALIFIER static vecType call(vecType const & x) - { - GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); - - vecType const Sign(sign(x)); - - vecType v(abs(x)); - - v = v - static_cast(1); - v = v | (v >> static_cast(1)); - v = v | (v >> static_cast(2)); - v = v | (v >> static_cast(4)); - v = compute_ceilShift= 2>::call(v, 8); - v = compute_ceilShift= 4>::call(v, 16); - v = compute_ceilShift= 8>::call(v, 32); - return (v + static_cast(1)) * Sign; - } - }; - - template class vecType> - struct compute_ceilPowerOfTwo - { - GLM_FUNC_QUALIFIER static vecType call(vecType const & x) - { - GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); - - vecType v(x); - - v = v - static_cast(1); - v = v | (v >> static_cast(1)); - v = v | (v >> static_cast(2)); - v = v | (v >> static_cast(4)); - v = compute_ceilShift= 2>::call(v, 8); - v = compute_ceilShift= 4>::call(v, 16); - v = compute_ceilShift= 8>::call(v, 32); - return v + static_cast(1); - } - }; }//namespace detail - //////////////// - // isPowerOfTwo - template - GLM_FUNC_QUALIFIER bool isPowerOfTwo(genType Value) - { - genType const Result = glm::abs(Value); - return !(Result & (Result - 1)); - } - - template class vecType> - GLM_FUNC_QUALIFIER vecType isPowerOfTwo(vecType const & Value) - { - vecType const Result(abs(Value)); - return equal(Result & (Result - 1), vecType(0)); - } - - ////////////////// - // ceilPowerOfTwo - - template - GLM_FUNC_QUALIFIER genType ceilPowerOfTwo(genType value) - { - return detail::compute_ceilPowerOfTwo::is_signed>::call(tvec1(value)).x; - } - - template class vecType> - GLM_FUNC_QUALIFIER vecType ceilPowerOfTwo(vecType const & v) - { - return detail::compute_ceilPowerOfTwo::is_signed>::call(v); - } - - /////////////////// - // floorPowerOfTwo - - template - GLM_FUNC_QUALIFIER genType floorPowerOfTwo(genType value) - { - return isPowerOfTwo(value) ? value : highestBitValue(value); - } - - template class vecType> - GLM_FUNC_QUALIFIER vecType floorPowerOfTwo(vecType const & v) - { - return detail::functor1::call(floorPowerOfTwo, v); - } - - /////////////////// - // roundPowerOfTwo - - template - GLM_FUNC_QUALIFIER genType roundPowerOfTwo(genType value) - { - if(isPowerOfTwo(value)) - return value; - - genType const prev = highestBitValue(value); - genType const next = prev << 1; - return (next - value) < (value - prev) ? next : prev; - } - - template class vecType> - GLM_FUNC_QUALIFIER vecType roundPowerOfTwo(vecType const & v) - { - return detail::functor1::call(roundPowerOfTwo, v); - } }//namespace glm diff --git a/glm/gtc/round.inl b/glm/gtc/round.inl index bc911ee6..a0981764 100644 --- a/glm/gtc/round.inl +++ b/glm/gtc/round.inl @@ -289,8 +289,8 @@ namespace detail /////////////////// // roundPowerOfTwo - template - GLM_FUNC_QUALIFIER genType roundPowerOfTwo(genType value) + template + GLM_FUNC_QUALIFIER genIUType roundPowerOfTwo(genIUType value) { if(isPowerOfTwo(value)) return value; diff --git a/test/core/core_func_integer_bit_count.cpp b/test/core/core_func_integer_bit_count.cpp index cc21b275..3082f5e7 100644 --- a/test/core/core_func_integer_bit_count.cpp +++ b/test/core/core_func_integer_bit_count.cpp @@ -174,7 +174,7 @@ int main() 0x55555555,16, 0xAAAAAAAA, 16, 0xFF000000,8, 0xC0C0C0C0,8, 0x0FFFFFF0,24, 0x80000000,1, 0xFFFFFFFF,32}; - std::size_t const Count = 10000000; + std::size_t const Count = 1000000; n = sizeof(test)/4; diff --git a/test/gtc/gtc_integer.cpp b/test/gtc/gtc_integer.cpp index e336b35c..4d5eeee3 100644 --- a/test/gtc/gtc_integer.cpp +++ b/test/gtc/gtc_integer.cpp @@ -8,277 +8,11 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// #include -#include -#include -#include -#include -#include - -namespace isPowerOfTwo -{ - template - struct type - { - genType Value; - bool Return; - }; - - int test_int16() - { - type const Data[] = - { - {0x0001, true}, - {0x0002, true}, - {0x0004, true}, - {0x0080, true}, - {0x0000, true}, - {0x0003, false} - }; - - int Error(0); - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - bool Result = glm::isPowerOfTwo(Data[i].Value); - Error += Data[i].Return == Result ? 0 : 1; - } - - return Error; - } - - int test_uint16() - { - type const Data[] = - { - {0x0001, true}, - {0x0002, true}, - {0x0004, true}, - {0x0000, true}, - {0x0000, true}, - {0x0003, false} - }; - - int Error(0); - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - bool Result = glm::isPowerOfTwo(Data[i].Value); - Error += Data[i].Return == Result ? 0 : 1; - } - - return Error; - } - - int test_int32() - { - type const Data[] = - { - {0x00000001, true}, - {0x00000002, true}, - {0x00000004, true}, - {0x0000000f, false}, - {0x00000000, true}, - {0x00000003, false} - }; - - int Error(0); - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - bool Result = glm::isPowerOfTwo(Data[i].Value); - Error += Data[i].Return == Result ? 0 : 1; - } - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - glm::bvec1 Result = glm::isPowerOfTwo(glm::ivec1(Data[i].Value)); - Error += glm::all(glm::equal(glm::bvec1(Data[i].Return), Result)) ? 0 : 1; - } - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - glm::bvec2 Result = glm::isPowerOfTwo(glm::ivec2(Data[i].Value)); - Error += glm::all(glm::equal(glm::bvec2(Data[i].Return), Result)) ? 0 : 1; - } - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - glm::bvec3 Result = glm::isPowerOfTwo(glm::ivec3(Data[i].Value)); - Error += glm::all(glm::equal(glm::bvec3(Data[i].Return), Result)) ? 0 : 1; - } - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - glm::bvec4 Result = glm::isPowerOfTwo(glm::ivec4(Data[i].Value)); - Error += glm::all(glm::equal(glm::bvec4(Data[i].Return), Result)) ? 0 : 1; - } - - return Error; - } - - int test_uint32() - { - type const Data[] = - { - {0x00000001, true}, - {0x00000002, true}, - {0x00000004, true}, - {0x80000000, true}, - {0x00000000, true}, - {0x00000003, false} - }; - - int Error(0); - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - bool Result = glm::isPowerOfTwo(Data[i].Value); - Error += Data[i].Return == Result ? 0 : 1; - } - - return Error; - } - - int test() - { - int Error(0); - - Error += test_int16(); - Error += test_uint16(); - Error += test_int32(); - Error += test_uint32(); - - return Error; - } -}//isPowerOfTwo - -namespace ceilPowerOfTwo -{ - template - GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value) - { - genIUType tmp = Value; - genIUType result = genIUType(0); - while(tmp) - { - result = (tmp & (~tmp + 1)); // grab lowest bit - tmp &= ~result; // clear lowest bit - } - return result; - } - - template - GLM_FUNC_QUALIFIER genType ceilPowerOfTwo_loop(genType value) - { - return glm::isPowerOfTwo(value) ? value : highestBitValue(value) << 1; - } - - template - struct type - { - genType Value; - genType Return; - }; - - int test_int32() - { - type const Data[] = - { - {0x0000ffff, 0x00010000}, - {-3, -4}, - {-8, -8}, - {0x00000001, 0x00000001}, - {0x00000002, 0x00000002}, - {0x00000004, 0x00000004}, - {0x00000007, 0x00000008}, - {0x0000fff0, 0x00010000}, - {0x0000f000, 0x00010000}, - {0x08000000, 0x08000000}, - {0x00000000, 0x00000000}, - {0x00000003, 0x00000004} - }; - - int Error(0); - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - glm::int32 Result = glm::ceilPowerOfTwo(Data[i].Value); - Error += Data[i].Return == Result ? 0 : 1; - } - - return Error; - } - - int test_uint32() - { - type const Data[] = - { - {0x00000001, 0x00000001}, - {0x00000002, 0x00000002}, - {0x00000004, 0x00000004}, - {0x00000007, 0x00000008}, - {0x0000ffff, 0x00010000}, - {0x0000fff0, 0x00010000}, - {0x0000f000, 0x00010000}, - {0x80000000, 0x80000000}, - {0x00000000, 0x00000000}, - {0x00000003, 0x00000004} - }; - - int Error(0); - - for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) - { - glm::uint32 Result = glm::ceilPowerOfTwo(Data[i].Value); - Error += Data[i].Return == Result ? 0 : 1; - } - - return Error; - } - - int perf() - { - int Error(0); - - std::vector v; - v.resize(100000000); - - std::clock_t Timestramp0 = std::clock(); - - for(glm::uint32 i = 0, n = static_cast(v.size()); i < n; ++i) - v[i] = ceilPowerOfTwo_loop(i); - - std::clock_t Timestramp1 = std::clock(); - - for(glm::uint32 i = 0, n = static_cast(v.size()); i < n; ++i) - v[i] = glm::ceilPowerOfTwo(i); - - std::clock_t Timestramp2 = std::clock(); - - std::printf("ceilPowerOfTwo_loop: %d clocks\n", static_cast(Timestramp1 - Timestramp0)); - std::printf("glm::ceilPowerOfTwo: %d clocks\n", static_cast(Timestramp2 - Timestramp1)); - - return Error; - } - - int test() - { - int Error(0); - - Error += test_int32(); - Error += test_uint32(); - - return Error; - } -}//namespace ceilPowerOfTwo int main() { - int Error(0); + int Error = 0; - Error += isPowerOfTwo::test(); - Error += ceilPowerOfTwo::test(); - Error += ceilPowerOfTwo::perf(); return Error; } diff --git a/test/gtc/gtc_round.cpp b/test/gtc/gtc_round.cpp index d5af5ed6..1550e7ac 100644 --- a/test/gtc/gtc_round.cpp +++ b/test/gtc/gtc_round.cpp @@ -29,11 +29,277 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include +#include +#include +#include +#include + +namespace isPowerOfTwo +{ + template + struct type + { + genType Value; + bool Return; + }; + + int test_int16() + { + type const Data[] = + { + {0x0001, true}, + {0x0002, true}, + {0x0004, true}, + {0x0080, true}, + {0x0000, true}, + {0x0003, false} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_uint16() + { + type const Data[] = + { + {0x0001, true}, + {0x0002, true}, + {0x0004, true}, + {0x0000, true}, + {0x0000, true}, + {0x0003, false} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_int32() + { + type const Data[] = + { + {0x00000001, true}, + {0x00000002, true}, + {0x00000004, true}, + {0x0000000f, false}, + {0x00000000, true}, + {0x00000003, false} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::bvec1 Result = glm::isPowerOfTwo(glm::ivec1(Data[i].Value)); + Error += glm::all(glm::equal(glm::bvec1(Data[i].Return), Result)) ? 0 : 1; + } + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::bvec2 Result = glm::isPowerOfTwo(glm::ivec2(Data[i].Value)); + Error += glm::all(glm::equal(glm::bvec2(Data[i].Return), Result)) ? 0 : 1; + } + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::bvec3 Result = glm::isPowerOfTwo(glm::ivec3(Data[i].Value)); + Error += glm::all(glm::equal(glm::bvec3(Data[i].Return), Result)) ? 0 : 1; + } + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::bvec4 Result = glm::isPowerOfTwo(glm::ivec4(Data[i].Value)); + Error += glm::all(glm::equal(glm::bvec4(Data[i].Return), Result)) ? 0 : 1; + } + + return Error; + } + + int test_uint32() + { + type const Data[] = + { + {0x00000001, true}, + {0x00000002, true}, + {0x00000004, true}, + {0x80000000, true}, + {0x00000000, true}, + {0x00000003, false} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error(0); + + Error += test_int16(); + Error += test_uint16(); + Error += test_int32(); + Error += test_uint32(); + + return Error; + } +}//isPowerOfTwo + +namespace ceilPowerOfTwo +{ + template + GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value) + { + genIUType tmp = Value; + genIUType result = genIUType(0); + while(tmp) + { + result = (tmp & (~tmp + 1)); // grab lowest bit + tmp &= ~result; // clear lowest bit + } + return result; + } + + template + GLM_FUNC_QUALIFIER genType ceilPowerOfTwo_loop(genType value) + { + return glm::isPowerOfTwo(value) ? value : highestBitValue(value) << 1; + } + + template + struct type + { + genType Value; + genType Return; + }; + + int test_int32() + { + type const Data[] = + { + {0x0000ffff, 0x00010000}, + {-3, -4}, + {-8, -8}, + {0x00000001, 0x00000001}, + {0x00000002, 0x00000002}, + {0x00000004, 0x00000004}, + {0x00000007, 0x00000008}, + {0x0000fff0, 0x00010000}, + {0x0000f000, 0x00010000}, + {0x08000000, 0x08000000}, + {0x00000000, 0x00000000}, + {0x00000003, 0x00000004} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::int32 Result = glm::ceilPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_uint32() + { + type const Data[] = + { + {0x00000001, 0x00000001}, + {0x00000002, 0x00000002}, + {0x00000004, 0x00000004}, + {0x00000007, 0x00000008}, + {0x0000ffff, 0x00010000}, + {0x0000fff0, 0x00010000}, + {0x0000f000, 0x00010000}, + {0x80000000, 0x80000000}, + {0x00000000, 0x00000000}, + {0x00000003, 0x00000004} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::uint32 Result = glm::ceilPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int perf() + { + int Error(0); + + std::vector v; + v.resize(100000000); + + std::clock_t Timestramp0 = std::clock(); + + for(glm::uint32 i = 0, n = static_cast(v.size()); i < n; ++i) + v[i] = ceilPowerOfTwo_loop(i); + + std::clock_t Timestramp1 = std::clock(); + + for(glm::uint32 i = 0, n = static_cast(v.size()); i < n; ++i) + v[i] = glm::ceilPowerOfTwo(i); + + std::clock_t Timestramp2 = std::clock(); + + std::printf("ceilPowerOfTwo_loop: %d clocks\n", static_cast(Timestramp1 - Timestramp0)); + std::printf("glm::ceilPowerOfTwo: %d clocks\n", static_cast(Timestramp2 - Timestramp1)); + + return Error; + } + + int test() + { + int Error(0); + + Error += test_int32(); + Error += test_uint32(); + + return Error; + } +}//namespace ceilPowerOfTwo int main() { - int Error = 0; + int Error(0); + Error += isPowerOfTwo::test(); + Error += ceilPowerOfTwo::test(); + Error += ceilPowerOfTwo::perf(); return Error; }