diff --git a/glm/detail/_vectorize.hpp b/glm/detail/_vectorize.hpp index ba7fd85c..1fcaec31 100644 --- a/glm/detail/_vectorize.hpp +++ b/glm/detail/_vectorize.hpp @@ -119,5 +119,44 @@ namespace detail return vec<4, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b), Func(a.w, b)); } }; + + template + struct functor2_vec_int {}; + + template + struct functor2_vec_int<1, T, Q> + { + GLM_FUNC_QUALIFIER static vec<1, int, Q> call(int (*Func) (T x, int y), vec<1, T, Q> const& a, vec<1, int, Q> const& b) + { + return vec<1, int, Q>(Func(a.x, b.x)); + } + }; + + template + struct functor2_vec_int<2, T, Q> + { + GLM_FUNC_QUALIFIER static vec<2, int, Q> call(int (*Func) (T x, int y), vec<2, T, Q> const& a, vec<2, int, Q> const& b) + { + return vec<2, int, Q>(Func(a.x, b.x), Func(a.y, b.y)); + } + }; + + template + struct functor2_vec_int<3, T, Q> + { + GLM_FUNC_QUALIFIER static vec<3, int, Q> call(int (*Func) (T x, int y), vec<3, T, Q> const& a, vec<3, int, Q> const& b) + { + return vec<3, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); + } + }; + + template + struct functor2_vec_int<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(int (*Func) (T x, int y), vec<4, T, Q> const& a, vec<4, int, Q> const& b) + { + return vec<4, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); + } + }; }//namespace detail }//namespace glm diff --git a/glm/ext/scalar_integer.hpp b/glm/ext/scalar_integer.hpp index 7e11c764..34e9eb86 100644 --- a/glm/ext/scalar_integer.hpp +++ b/glm/ext/scalar_integer.hpp @@ -30,24 +30,28 @@ namespace glm /// @{ /// Return true if the value is a power of two number. + /// + /// @see ext_scalar_integer template GLM_FUNC_DECL bool isPowerOfTwo(genIUType v); /// Return the power of two number which value is just higher the input value, /// round up to a power of two. + /// + /// @see ext_scalar_integer template GLM_FUNC_DECL genIUType nextPowerOfTwo(genIUType v); /// Return the power of two number which value is just lower the input value, /// round down to a power of two. /// - /// @see gtc_round + /// @see ext_scalar_integer template GLM_FUNC_DECL genIUType prevPowerOfTwo(genIUType v); /// Return true if the 'Value' is a multiple of 'Multiple'. /// - /// @see gtc_round + /// @see ext_scalar_integer template GLM_FUNC_DECL bool isMultiple(genIUType v, genIUType Multiple); @@ -58,7 +62,7 @@ namespace glm /// @param v Source value to which is applied the function /// @param Multiple Must be a null or positive value /// - /// @see gtc_round + /// @see ext_scalar_integer template GLM_FUNC_DECL genIUType nextMultiple(genIUType v, genIUType Multiple); @@ -69,10 +73,20 @@ namespace glm /// @param v Source value to which is applied the function /// @param Multiple Must be a null or positive value /// - /// @see gtc_round + /// @see ext_scalar_integer template GLM_FUNC_DECL genIUType prevMultiple(genIUType v, genIUType Multiple); + /// Returns the bit number of the Nth significant bit set to + /// 1 in the binary representation of value. + /// If value bitcount is less than the Nth significant bit, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL int findNSB(genIUType x, int significantBitCount); + /// @} } //namespace glm diff --git a/glm/ext/scalar_integer.inl b/glm/ext/scalar_integer.inl index 45233e4a..4adea6b5 100644 --- a/glm/ext/scalar_integer.inl +++ b/glm/ext/scalar_integer.inl @@ -204,4 +204,40 @@ namespace detail return detail::compute_floorMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); } + + template + GLM_FUNC_QUALIFIER int findNSB(genIUType x, int significantBitCount) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findNSB' only accept integer inputs"); + + if(bitCount(x) < significantBitCount) + return -1; + + genIUType const One = static_cast(1); + int bitPos = 0; + + genIUType key = x; + int nBitCount = significantBitCount; + int Step = sizeof(x) * 8 / 2; + while (key > One) + { + genIUType Mask = static_cast((One << Step) - One); + genIUType currentKey = key & Mask; + int currentBitCount = bitCount(currentKey); + if (nBitCount > currentBitCount) + { + nBitCount -= currentBitCount; + bitPos += Step; + key >>= static_cast(Step); + } + else + { + key = key & Mask; + } + + Step >>= 1; + } + + return static_cast(bitPos); + } }//namespace glm diff --git a/glm/ext/vector_integer.hpp b/glm/ext/vector_integer.hpp index d7ada3c0..d54409da 100644 --- a/glm/ext/vector_integer.hpp +++ b/glm/ext/vector_integer.hpp @@ -31,8 +31,10 @@ namespace glm /// Return true if the value is a power of two number. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec isPowerOfTwo(vec const& v); @@ -40,8 +42,10 @@ namespace glm /// round up to a power of two. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec nextPowerOfTwo(vec const& v); @@ -49,71 +53,96 @@ namespace glm /// round down to a power of two. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec prevPowerOfTwo(vec const& v); /// Return true if the 'Value' is a multiple of 'Multiple'. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec isMultiple(vec const& v, T Multiple); /// Return true if the 'Value' is a multiple of 'Multiple'. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec isMultiple(vec const& v, vec const& Multiple); /// Higher multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec nextMultiple(vec const& v, T Multiple); /// Higher multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec nextMultiple(vec const& v, vec const& Multiple); /// Lower multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec prevMultiple(vec const& v, T Multiple); /// Lower multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector - /// @tparam T Floating-point or integer scalar types + /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer template GLM_FUNC_DECL vec prevMultiple(vec const& v, vec const& Multiple); + /// Returns the bit number of the Nth significant bit set to + /// 1 in the binary representation of value. + /// If value bitcount is less than the Nth significant bit, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec findNSB(vec const& Source, vec SignificantBitCount); + /// @} } //namespace glm diff --git a/glm/ext/vector_integer.inl b/glm/ext/vector_integer.inl index c60e68a4..939ff5e2 100644 --- a/glm/ext/vector_integer.inl +++ b/glm/ext/vector_integer.inl @@ -74,4 +74,12 @@ namespace glm return detail::functor2::call(prevMultiple, Source, Multiple); } + + template + GLM_FUNC_QUALIFIER vec findNSB(vec const& Source, vec SignificantBitCount) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findNSB' only accept integer inputs"); + + return detail::functor2_vec_int::call(findNSB, Source, SignificantBitCount); + } }//namespace glm diff --git a/test/ext/ext_scalar_integer.cpp b/test/ext/ext_scalar_integer.cpp index a51a6d8e..41d67673 100644 --- a/test/ext/ext_scalar_integer.cpp +++ b/test/ext/ext_scalar_integer.cpp @@ -600,9 +600,68 @@ namespace nextMultiple } }//namespace nextMultiple +namespace findNSB +{ + template + struct type + { + T Source; + int SignificantBitCount; + int Return; + }; + + template + int run() + { + type const Data[] = + { + { 0x00, 1,-1 }, + { 0x01, 2,-1 }, + { 0x02, 2,-1 }, + { 0x06, 3,-1 }, + { 0x01, 1, 0 }, + { 0x03, 1, 0 }, + { 0x03, 2, 1 }, + { 0x07, 2, 1 }, + { 0x05, 2, 2 }, + { 0x0D, 2, 2 } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + int const Result0 = glm::findNSB(Data[i].Source, Data[i].SignificantBitCount); + Error += Data[i].Return == Result0 ? 0 : 1; + assert(!Error); + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += run(); + Error += run(); + Error += run(); + Error += run(); +/* + Error += run(); + Error += run(); + Error += run(); + Error += run(); +*/ + return Error; + } +}//namespace findNSB + int main() { - int Error(0); + int Error = 0; + + Error += findNSB::test(); Error += isPowerOfTwo::test(); Error += prevPowerOfTwo::test(); diff --git a/test/ext/ext_vector_integer.cpp b/test/ext/ext_vector_integer.cpp index d1739c84..5974841c 100644 --- a/test/ext/ext_vector_integer.cpp +++ b/test/ext/ext_vector_integer.cpp @@ -444,6 +444,74 @@ namespace nextMultiple } }//namespace nextMultiple +namespace findNSB +{ + template + struct type + { + T Source; + int SignificantBitCount; + int Return; + }; + + template + int run() + { + type const Data[] = + { + { 0x00, 1,-1 }, + { 0x01, 2,-1 }, + { 0x02, 2,-1 }, + { 0x06, 3,-1 }, + { 0x01, 1, 0 }, + { 0x03, 1, 0 }, + { 0x03, 2, 1 }, + { 0x07, 2, 1 }, + { 0x05, 2, 2 }, + { 0x0D, 2, 2 } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::vec const Result0 = glm::findNSB(glm::vec(Data[i].Source), glm::vec(Data[i].SignificantBitCount)); + Error += glm::vec(Data[i].Return) == Result0 ? 0 : 1; + assert(!Error); + } + + return Error; + } + + int test() + { + int Error = 0; +/* + Error += run<1, glm::uint8>(); + Error += run<2, glm::uint8>(); + Error += run<3, glm::uint8>(); + Error += run<4, glm::uint8>(); + + Error += run<1, glm::uint16>(); + Error += run<2, glm::uint16>(); + Error += run<3, glm::uint16>(); + Error += run<4, glm::uint16>(); + + Error += run<1, glm::uint32>(); + Error += run<2, glm::uint32>(); + Error += run<3, glm::uint32>(); +*/ + Error += run<4, glm::uint32>(); +/* + Error += run<1, glm::uint64>(); + Error += run<2, glm::uint64>(); + Error += run<3, glm::uint64>(); + Error += run<4, glm::uint64>(); +*/ + return Error; + } +}//namespace findNSB + int main() { int Error = 0; @@ -453,6 +521,7 @@ int main() Error += nextPowerOfTwo::test(); Error += prevMultiple::test(); Error += nextMultiple::test(); + Error += findNSB::test(); return Error; }