From 891fa25675e8fd71a8fd9d99612d5cec9a44aa15 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Wed, 2 Nov 2016 01:15:10 +0100 Subject: [PATCH] Add vector_cast implementation and the unit test for it. --- README.md | 3 ++ include/vectorwrapper/vector_cast.hpp | 44 +++++++++++++++++ test/unit_noconv/CMakeLists.txt | 28 +++++++++++ test/unit_noconv/sample_vector.hpp | 32 ++++++++++++ test/unit_noconv/test_conversions.cpp | 71 +++++++++++++++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 include/vectorwrapper/vector_cast.hpp create mode 100644 test/unit_noconv/CMakeLists.txt create mode 100644 test/unit_noconv/sample_vector.hpp create mode 100644 test/unit_noconv/test_conversions.cpp diff --git a/README.md b/README.md index 842ae02..7f65453 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,9 @@ You still need to type some code in order to get started using the vector wrappe ### Automated conversion ### You can assign or construct a `Vec` from a `Vec`, provided they have the same dimensions and the assignemnt operator is able to convert B's scalar type to that of A. You need to define VWR_WITH_IMPLICIT_CONVERSIONS for this to work. +### Manual conversions ### +You can convert one vector to the other using vector_cast. For example, auto b = vector_cast(a); will create a temporary of type float2 the whose elements are a static_cast'ed copy of the elements in a and assign it to b. You need to include vectorwrapper/vector_cast.hpp. + ### Access the wrapped type ### Through the `data()` method you can always obtain a ref to the wrapped type. diff --git a/include/vectorwrapper/vector_cast.hpp b/include/vectorwrapper/vector_cast.hpp new file mode 100644 index 0000000..e50bf35 --- /dev/null +++ b/include/vectorwrapper/vector_cast.hpp @@ -0,0 +1,44 @@ +/* + * Copyright 2015-2016 Michele "King_DuckZ" Santullo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef idE24EF7737A7F4882B2BF254F0A3EEC34 +#define idE24EF7737A7F4882B2BF254F0A3EEC34 + +#include + +namespace vwr { + namespace implem { + template + Vec vector_cast (const Vec& parVec, Vec*, std::index_sequence) { + static_assert( + static_cast(Vec::dimensions) == static_cast(Vec::dimensions), + "Mismatching dimensions" + ); + static_assert(sizeof...(I) == Vec::dimensions, "Mismatching index count"); + typedef typename Vec::scalar_type CastType; + + return Vec(static_cast(parVec[I])...); + } + } //namespace implem + + template + TOVec vector_cast (const Vec& parVec) { + TOVec* const to = nullptr; + return implem::vector_cast(parVec, to, std::make_index_sequence::dimensions>()); + } +} //namespace vwr + +#endif diff --git a/test/unit_noconv/CMakeLists.txt b/test/unit_noconv/CMakeLists.txt new file mode 100644 index 0000000..74ebc85 --- /dev/null +++ b/test/unit_noconv/CMakeLists.txt @@ -0,0 +1,28 @@ +project(unit_noconv CXX) + +set(warning_flags "-Wall -Wextra -Wconversion -Werror") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warning_flags}") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${warning_flags}") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${warning_flags}") + +add_executable(${PROJECT_NAME} + ${GTEST_MAIN_CPP} + test_conversions.cpp +) + +target_link_libraries(${PROJECT_NAME} + gtest +) + +target_compile_definitions(${PROJECT_NAME} + PRIVATE VWR_STATIC_CAST_RESULTS +) + +set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD_REQUIRED ON) +set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14) + +add_test( + NAME TestNoImplicitConversion + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${PROJECT_NAME} +) diff --git a/test/unit_noconv/sample_vector.hpp b/test/unit_noconv/sample_vector.hpp new file mode 100644 index 0000000..ebdf020 --- /dev/null +++ b/test/unit_noconv/sample_vector.hpp @@ -0,0 +1,32 @@ +#ifndef idD52B2591EB8240A980C5B3823D025EC1 +#define idD52B2591EB8240A980C5B3823D025EC1 + +#include "vectorwrapper/vectorwrapper.hpp" +#include + +#define SPECIALIZE_ARRAY_VECTOR(TYPE, DIM) \ + template <> \ + struct VectorWrapperInfo> { \ + enum { dimensions = DIM }; \ + typedef TYPE scalar_type; \ + typedef std::array vector_type; \ + static scalar_type& get_at (size_t parIndex, vector_type& parVector) { \ + return parVector[parIndex]; \ + } \ + } + +namespace vwr { + SPECIALIZE_ARRAY_VECTOR(float, 2); + SPECIALIZE_ARRAY_VECTOR(float, 3); + SPECIALIZE_ARRAY_VECTOR(short int, 2); + SPECIALIZE_ARRAY_VECTOR(short int, 3); + + typedef Vec> float2; + typedef Vec> float3; + typedef Vec> short2; + typedef Vec> short3; +} //namespace vwr + +#undef SPECIALIZE_ARRAY_VECTOR + +#endif diff --git a/test/unit_noconv/test_conversions.cpp b/test/unit_noconv/test_conversions.cpp new file mode 100644 index 0000000..0ecc196 --- /dev/null +++ b/test/unit_noconv/test_conversions.cpp @@ -0,0 +1,71 @@ +#include "sample_vector.hpp" +#include "vectorwrapper/vector_cast.hpp" +#include + +TEST(vwr, vector_cast) { + using namespace vwr; + + { + float2 v1(1.0f, 2.0f); + short2 v2(vector_cast(v1)); + + EXPECT_EQ(1, v2.x()); + EXPECT_EQ(2, v2.y()); + } + + { + short3 v1(3, 4, 5); + auto v2 = vector_cast(v1) / float3(2.0f); + + EXPECT_FLOAT_EQ(1.5f, v2.x()); + EXPECT_FLOAT_EQ(2.0f, v2.y()); + EXPECT_FLOAT_EQ(2.5f, v2.z()); + } + + { + short3 v1(0xAB, 0xCD, 0xEF); + short3 v2(0x12, 0x34, 0x56); + float3 v3(vector_cast(v1 + v2)); + + EXPECT_FLOAT_EQ(static_cast(0xAB + 0x12), v3.x()); + EXPECT_FLOAT_EQ(static_cast(0xCD + 0x34), v3.y()); + EXPECT_FLOAT_EQ(static_cast(0xEF + 0x56), v3.z()); + + short3 v4 = vector_cast(v3); + EXPECT_EQ(0xAB + 0x12, v4.x()); + EXPECT_EQ(0xCD + 0x34, v4.y()); + EXPECT_EQ(0xEF + 0x56, v4.z()); + } +} + +TEST(vwr, promotion_static_cast) { + using namespace vwr; + + { + short2 v1(100, 200); + auto v2 = v1 / short2(2); + EXPECT_EQ(50, v2.x()); + EXPECT_EQ(100, v2.y()); + } + + { + short2 v1(100, 200); + auto v2 = v1 * short2(2); + EXPECT_EQ(200, v2.x()); + EXPECT_EQ(400, v2.y()); + } + + { + short2 v1(100, 200); + auto v2 = v1 + short2(2); + EXPECT_EQ(102, v2.x()); + EXPECT_EQ(202, v2.y()); + } + + { + short2 v1(100, 200); + auto v2 = v1 - short2(2); + EXPECT_EQ(98, v2.x()); + EXPECT_EQ(198, v2.y()); + } +}