diff --git a/.github/workflows/msvc-17-10.yml b/.github/workflows/msvc-17-10.yml index 843d3e2..0c54437 100644 --- a/.github/workflows/msvc-17-10.yml +++ b/.github/workflows/msvc-17-10.yml @@ -1,44 +1,44 @@ -# SPDX short identifier: BSL-1.0 - -name: msvc-17-10 -on: - push: - paths: - - '.github/**' - - 'cmake/**' - - 'cml/**' - - 'tests/**' - - 'CMakeLists.txt' - - 'CMakePresets.json' - - 'CML.cmake' - - 'vcpkg.json' - -jobs: - msvc-17-10: - name: MSVC 17.10 - runs-on: windows-2022 - steps: - - name: Install MSVC 17.10 - shell: pwsh - run: | - $vspath = 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise' - Test-Path -Path $vspath | Should -Be $true - - $vsinstaller = 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe' - Test-Path -Path $vsinstaller | Should -Be $true - - Start-Process -NoNewWindow -Wait -FilePath $vsinstaller -ArgumentList ` - 'modify', '--installPath', "`"$vspath`"", '--quiet', '--norestart', '--nocache', '--noUpdateInstaller', ` - '--add', 'Microsoft.VisualStudio.Component.VC.14.40.17.10.x86.x64' - - - uses: actions/checkout@v4 - - uses: lukka/get-cmake@latest - with: - cmakeVersion: "~3.29.0" - - uses: lukka/run-vcpkg@v11 - - uses: lukka/run-cmake@v10 - with: - configurePreset: "cml-ci-msvc17-mt-s" - configurePresetAdditionalArgs: "['-T version=14.40']" - buildPreset: "cml-ci-msvc17-mt-s-release" - testPreset: "cml-ci-msvc17-mt-s-release-test" +# SPDX short identifier: BSL-1.0 + +name: msvc-17-10 +on: + push: + paths: + - '.github/**' + - 'cmake/**' + - 'cml/**' + - 'tests/**' + - 'CMakeLists.txt' + - 'CMakePresets.json' + - 'CML.cmake' + - 'vcpkg.json' + +jobs: + msvc-17-10: + name: MSVC 17.10 + runs-on: windows-2022 + steps: + - name: Install MSVC 17.10 + shell: pwsh + run: | + $vspath = 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise' + Test-Path -Path $vspath | Should -Be $true + + $vsinstaller = 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe' + Test-Path -Path $vsinstaller | Should -Be $true + + Start-Process -NoNewWindow -Wait -FilePath $vsinstaller -ArgumentList ` + 'modify', '--installPath', "`"$vspath`"", '--quiet', '--norestart', '--nocache', '--noUpdateInstaller', ` + '--add', 'Microsoft.VisualStudio.Component.VC.14.40.17.10.x86.x64' + + - uses: actions/checkout@v4 + - uses: lukka/get-cmake@latest + with: + cmakeVersion: "~3.29.0" + - uses: lukka/run-vcpkg@v11 + - uses: lukka/run-cmake@v10 + with: + configurePreset: "cml-ci-msvc17-mt-s" + configurePresetAdditionalArgs: "['-T version=14.40']" + buildPreset: "cml-ci-msvc17-mt-s-release" + testPreset: "cml-ci-msvc17-mt-s-release-test" diff --git a/.github/workflows/msvc-clangcl-latest.yml b/.github/workflows/msvc-clangcl-latest.yml index 08cdd23..b7bdfc6 100644 --- a/.github/workflows/msvc-clangcl-latest.yml +++ b/.github/workflows/msvc-clangcl-latest.yml @@ -1,30 +1,30 @@ -# SPDX short identifier: BSL-1.0 - -name: msvc-clangcl-latest -on: - push: - paths: - - '.github/**' - - 'cmake/**' - - 'cml/**' - - 'tests/**' - - 'CMakeLists.txt' - - 'CMakePresets.json' - - 'CML.cmake' - - 'vcpkg.json' - -jobs: - msvc-clangcl-latest: - name: MSVC ClangCL Latest - runs-on: windows-2022 - steps: - - uses: actions/checkout@v4 - - uses: lukka/get-cmake@latest - with: - cmakeVersion: "~3.29.0" - - uses: lukka/run-vcpkg@v11 - - uses: lukka/run-cmake@v10 - with: - configurePreset: "cml-ci-ninja-msvc-clangcl-mt-s" - buildPreset: "cml-ci-ninja-msvc-clangcl-mt-s-release" +# SPDX short identifier: BSL-1.0 + +name: msvc-clangcl-latest +on: + push: + paths: + - '.github/**' + - 'cmake/**' + - 'cml/**' + - 'tests/**' + - 'CMakeLists.txt' + - 'CMakePresets.json' + - 'CML.cmake' + - 'vcpkg.json' + +jobs: + msvc-clangcl-latest: + name: MSVC ClangCL Latest + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + - uses: lukka/get-cmake@latest + with: + cmakeVersion: "~3.29.0" + - uses: lukka/run-vcpkg@v11 + - uses: lukka/run-cmake@v10 + with: + configurePreset: "cml-ci-ninja-msvc-clangcl-mt-s" + buildPreset: "cml-ci-ninja-msvc-clangcl-mt-s-release" testPreset: "cml-ci-ninja-msvc-clangcl-mt-s-release-test" \ No newline at end of file diff --git a/.github/workflows/msvc-latest.yml b/.github/workflows/msvc-latest.yml index fefd691..9328323 100644 --- a/.github/workflows/msvc-latest.yml +++ b/.github/workflows/msvc-latest.yml @@ -1,30 +1,30 @@ -# SPDX short identifier: BSL-1.0 - -name: msvc-latest.yml -on: - push: - paths: - - '.github/**' - - 'cmake/**' - - 'cml/**' - - 'tests/**' - - 'CMakeLists.txt' - - 'CMakePresets.json' - - 'CML.cmake' - - 'vcpkg.json' - -jobs: - msvc-latest: - name: MSVC Latest - runs-on: windows-2022 - steps: - - uses: actions/checkout@v4 - - uses: lukka/get-cmake@latest - with: - cmakeVersion: "~3.29.0" - - uses: lukka/run-vcpkg@v11 - - uses: lukka/run-cmake@v10 - with: - configurePreset: "cml-ci-ninja-msvc-mt-s" - buildPreset: "cml-ci-ninja-msvc-mt-s-release" +# SPDX short identifier: BSL-1.0 + +name: msvc-latest.yml +on: + push: + paths: + - '.github/**' + - 'cmake/**' + - 'cml/**' + - 'tests/**' + - 'CMakeLists.txt' + - 'CMakePresets.json' + - 'CML.cmake' + - 'vcpkg.json' + +jobs: + msvc-latest: + name: MSVC Latest + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + - uses: lukka/get-cmake@latest + with: + cmakeVersion: "~3.29.0" + - uses: lukka/run-vcpkg@v11 + - uses: lukka/run-cmake@v10 + with: + configurePreset: "cml-ci-ninja-msvc-mt-s" + buildPreset: "cml-ci-ninja-msvc-mt-s-release" testPreset: "cml-ci-ninja-msvc-mt-s-release-test" \ No newline at end of file diff --git a/CML.cmake b/CML.cmake index 21eef13..23d9307 100644 --- a/CML.cmake +++ b/CML.cmake @@ -1,379 +1,379 @@ -# -------------------------------------------------------------------------- -# @@COPYRIGHT@@ -# -------------------------------------------------------------------------- - -set(main_HEADERS - cml/cml.h - cml/matrix.h - cml/quaternion.h - cml/types.h - cml/util.h - cml/vector.h - cml/version.h -) - -set(common_HEADERS - cml/common/array_size_of.h - cml/common/basis_tags.h - cml/common/exception.h - cml/common/hash.h - cml/common/layout_tags.h - cml/common/memory_tags.h - cml/common/promotion.h - cml/common/size_tags.h - cml/common/storage_tags.h - cml/common/temporary.h - cml/common/traits.h - cml/common/type_util.h -) - -set(common_mpl_HEADERS - cml/common/mpl/are_convertible.h - cml/common/mpl/are_same.h - cml/common/mpl/enable_if_arithmetic.h - cml/common/mpl/enable_if_array.h - cml/common/mpl/enable_if_convertible.h - cml/common/mpl/enable_if_pointer.h - cml/common/mpl/enable_if_reshapeable.h - cml/common/mpl/enable_if_same.h - cml/common/mpl/enable_if_t.h - cml/common/mpl/if_t.h - cml/common/mpl/int_c.h - cml/common/mpl/is_reshapeable.h - cml/common/mpl/is_same_pair.h - cml/common/mpl/is_statically_polymorphic.h - cml/common/mpl/item_at.h - cml/common/mpl/plus_c.h - cml/common/mpl/rebind.h - cml/common/mpl/type_map.h - cml/common/mpl/type_table.h -) - -set(scalar_HEADERS - cml/scalar/binary_ops.h - cml/scalar/constants.h - cml/scalar/functions.h - cml/scalar/promotion.h - cml/scalar/traits.h - cml/scalar/unary_ops.h -) - -set(storage_HEADERS - cml/storage/allocated_selector.h - cml/storage/any_selector.h - cml/storage/compiled_selector.h - cml/storage/external_selector.h - cml/storage/promotion.h - cml/storage/resize.h - cml/storage/selectors.h - cml/storage/type_util.h -) - -set(vector_HEADERS - cml/vector/binary_node.h - cml/vector/binary_node.tpp - cml/vector/binary_ops.h - cml/vector/comparison.h - cml/vector/comparison.tpp - cml/vector/cross.h - cml/vector/cross_node.h - cml/vector/cross_node.tpp - cml/vector/cross_ops.h - cml/vector/dot.h - cml/vector/dot.tpp - cml/vector/dynamic.h - cml/vector/dynamic_allocated.h - cml/vector/dynamic_allocated.tpp - cml/vector/dynamic_const_external.h - cml/vector/dynamic_const_external.tpp - cml/vector/dynamic_external.h - cml/vector/dynamic_external.tpp - cml/vector/external.h - cml/vector/fixed.h - cml/vector/fixed_compiled.h - cml/vector/fixed_compiled.tpp - cml/vector/fixed_const_external.h - cml/vector/fixed_const_external.tpp - cml/vector/fixed_external.h - cml/vector/fixed_external.tpp - cml/vector/functions.h - cml/vector/functions.tpp - cml/vector/fwd.h - cml/vector/hadamard_product.h - cml/vector/ops.h - cml/vector/outer_product.h - cml/vector/outer_product_node.h - cml/vector/outer_product_node.tpp - cml/vector/outer_product_ops.h - cml/vector/perp_dot.h - cml/vector/perp_dot.tpp - cml/vector/products.h - cml/vector/promotion.h - cml/vector/readable_vector.h - cml/vector/readable_vector.tpp - cml/vector/scalar_node.h - cml/vector/scalar_node.tpp - cml/vector/scalar_ops.h - cml/vector/size_checking.h - cml/vector/size_checking.tpp - cml/vector/subvector.h - cml/vector/subvector_node.h - cml/vector/subvector_node.tpp - cml/vector/subvector_ops.h - cml/vector/subvector_ops.tpp - cml/vector/temporary.h - cml/vector/traits.h - cml/vector/triple_product.h - cml/vector/triple_product.tpp - cml/vector/types.h - cml/vector/type_util.h - cml/vector/unary_node.h - cml/vector/unary_node.tpp - cml/vector/unary_ops.h - cml/vector/vector.h - cml/vector/writable_vector.h - cml/vector/writable_vector.tpp -) - -set(vector_detail_HEADERS - cml/vector/detail/check_or_resize.h - cml/vector/detail/combined_size_of.h - cml/vector/detail/resize.h -) - -set(matrix_HEADERS - cml/matrix/array_size_of.h - cml/matrix/basis.h - cml/matrix/basis_node.h - cml/matrix/basis_node.tpp - cml/matrix/basis_ops.h - cml/matrix/binary_node.h - cml/matrix/binary_node.tpp - cml/matrix/binary_ops.h - cml/matrix/col_node.h - cml/matrix/col_node.tpp - cml/matrix/col_ops.h - cml/matrix/comparison.h - cml/matrix/comparison.tpp - cml/matrix/determinant.h - cml/matrix/determinant.tpp - cml/matrix/dynamic.h - cml/matrix/dynamic_allocated.h - cml/matrix/dynamic_allocated.tpp - cml/matrix/dynamic_external.h - cml/matrix/dynamic_external.tpp - cml/matrix/external.h - cml/matrix/fixed.h - cml/matrix/fixed_compiled.h - cml/matrix/fixed_compiled.tpp - cml/matrix/fixed_external.h - cml/matrix/fixed_external.tpp - cml/matrix/functions.h - cml/matrix/fwd.h - cml/matrix/hadamard_product.h - cml/matrix/inverse.h - cml/matrix/lu.h - cml/matrix/lu.tpp - cml/matrix/matrix.h - cml/matrix/matrix_product.h - cml/matrix/matrix_product.tpp - cml/matrix/ops.h - cml/matrix/promotion.h - cml/matrix/readable_matrix.h - cml/matrix/readable_matrix.tpp - cml/matrix/row_col.h - cml/matrix/row_node.h - cml/matrix/row_node.tpp - cml/matrix/row_ops.h - cml/matrix/scalar_node.h - cml/matrix/scalar_node.tpp - cml/matrix/scalar_ops.h - cml/matrix/size_checking.h - cml/matrix/size_checking.tpp - cml/matrix/temporary.h - cml/matrix/trace.h - cml/matrix/trace.tpp - cml/matrix/traits.h - cml/matrix/transpose.h - cml/matrix/transpose_node.h - cml/matrix/transpose_node.tpp - cml/matrix/transpose_ops.h - cml/matrix/types.h - cml/matrix/type_util.h - cml/matrix/unary_node.h - cml/matrix/unary_node.tpp - cml/matrix/unary_ops.h - cml/matrix/vector_product.h - cml/matrix/vector_product.tpp - cml/matrix/writable_matrix.h - cml/matrix/writable_matrix.tpp -) - -set(matrix_detail_HEADERS - cml/matrix/detail/apply.h - cml/matrix/detail/check_or_resize.h - cml/matrix/detail/copy.h - cml/matrix/detail/determinant.h - cml/matrix/detail/determinant.tpp - cml/matrix/detail/generate.h - cml/matrix/detail/get.h - cml/matrix/detail/inverse.h - cml/matrix/detail/lu.h - cml/matrix/detail/lu.tpp - cml/matrix/detail/resize.h - cml/matrix/detail/transpose.h -) - -set(quaternion_HEADERS - cml/quaternion/binary_node.h - cml/quaternion/binary_node.tpp - cml/quaternion/binary_ops.h - cml/quaternion/comparison.h - cml/quaternion/comparison.tpp - cml/quaternion/conjugate.h - cml/quaternion/conjugate_node.h - cml/quaternion/conjugate_node.tpp - cml/quaternion/conjugate_ops.h - cml/quaternion/conjugate_ops.tpp - cml/quaternion/cross_tags.h - cml/quaternion/dot.h - cml/quaternion/dot.tpp - cml/quaternion/fixed.h - cml/quaternion/fixed_compiled.h - cml/quaternion/fixed_compiled.tpp - cml/quaternion/functions.h - cml/quaternion/functions.tpp - cml/quaternion/fwd.h - cml/quaternion/imaginary.h - cml/quaternion/imaginary_node.h - cml/quaternion/imaginary_node.tpp - cml/quaternion/imaginary_ops.h - cml/quaternion/imaginary_ops.tpp - cml/quaternion/inverse.h - cml/quaternion/inverse_node.h - cml/quaternion/inverse_node.tpp - cml/quaternion/inverse_ops.h - cml/quaternion/inverse_ops.tpp - cml/quaternion/ops.h - cml/quaternion/order_tags.h - cml/quaternion/product.h - cml/quaternion/product.tpp - cml/quaternion/promotion.h - cml/quaternion/quaternion.h - cml/quaternion/readable_quaternion.h - cml/quaternion/readable_quaternion.tpp - cml/quaternion/scalar_node.h - cml/quaternion/scalar_node.tpp - cml/quaternion/scalar_ops.h - cml/quaternion/size_checking.h - cml/quaternion/temporary.h - cml/quaternion/traits.h - cml/quaternion/types.h - cml/quaternion/type_util.h - cml/quaternion/unary_node.h - cml/quaternion/unary_node.tpp - cml/quaternion/unary_ops.h - cml/quaternion/writable_quaternion.h - cml/quaternion/writable_quaternion.tpp -) - -set(mathlib_HEADERS - cml/mathlib/axis_order.h - cml/mathlib/constants.h - cml/mathlib/coordinate_conversion.h - cml/mathlib/coordinate_conversion.tpp - cml/mathlib/euler_order.h - cml/mathlib/frustum.h - cml/mathlib/frustum.tpp - cml/mathlib/mathlib.h - cml/mathlib/random_unit.h - cml/mathlib/random_unit.tpp -) - -set(mathlib_vector_HEADERS - cml/mathlib/vector/angle.h - cml/mathlib/vector/angle.tpp - cml/mathlib/vector/generators.h - cml/mathlib/vector/misc.h - cml/mathlib/vector/misc.tpp - cml/mathlib/vector/orthonormal.h - cml/mathlib/vector/orthonormal.tpp - cml/mathlib/vector/products.h - cml/mathlib/vector/rotation.h - cml/mathlib/vector/rotation.tpp - cml/mathlib/vector/transform.h - cml/mathlib/vector/transform.tpp -) - -set(mathlib_matrix_HEADERS - cml/mathlib/matrix/basis.h - cml/mathlib/matrix/basis.tpp - cml/mathlib/matrix/concat.h - cml/mathlib/matrix/concat.tpp - cml/mathlib/matrix/generators.h - cml/mathlib/matrix/invert.h - cml/mathlib/matrix/invert.tpp - cml/mathlib/matrix/misc.h - cml/mathlib/matrix/misc.tpp - cml/mathlib/matrix/projection.h - cml/mathlib/matrix/projection.tpp - cml/mathlib/matrix/rotation.h - cml/mathlib/matrix/rotation.tpp - cml/mathlib/matrix/scale.h - cml/mathlib/matrix/scale.tpp - cml/mathlib/matrix/size_checking.h - cml/mathlib/matrix/size_checking.tpp - cml/mathlib/matrix/temporary.h - cml/mathlib/matrix/transform.h - cml/mathlib/matrix/transform.tpp - cml/mathlib/matrix/translation.h - cml/mathlib/matrix/translation.tpp -) - -set(mathlib_quaternion_HEADERS - cml/mathlib/quaternion/basis.h - cml/mathlib/quaternion/basis.tpp - cml/mathlib/quaternion/rotation.h - cml/mathlib/quaternion/rotation.tpp -) - -set(util_HEADERS - cml/util/matrix_print.h - cml/util/matrix_print.tpp - cml/util/quaternion_print.h - cml/util/quaternion_print.tpp - cml/util/vector_hash.h - cml/util/vector_print.h - cml/util/vector_print.tpp -) - -set(all_headers - ${main_HEADERS} - ${common_HEADERS} - ${common_mpl_HEADERS} - ${scalar_HEADERS} - ${storage_HEADERS} - ${matrix_HEADERS} - ${matrix_detail_HEADERS} - ${quaternion_HEADERS} - ${util_HEADERS} - ${vector_HEADERS} - ${vector_detail_HEADERS} - ${mathlib_HEADERS} - ${mathlib_vector_HEADERS} - ${mathlib_matrix_HEADERS} - ${mathlib_quaternion_HEADERS} -) - -add_library(cml INTERFACE) -target_compile_features(cml INTERFACE - cxx_reference_qualified_functions - cxx_constexpr - cxx_defaulted_functions -) -target_include_directories(cml INTERFACE $) -target_include_directories(cml INTERFACE $/include>) - -# Setup a custom target, and use IDE groups for the headers when possible: -source_group(TREE "${CML_ROOT}/cml" FILES ${all_headers}) +# -------------------------------------------------------------------------- +# @@COPYRIGHT@@ +# -------------------------------------------------------------------------- + +set(main_HEADERS + cml/cml.h + cml/matrix.h + cml/quaternion.h + cml/types.h + cml/util.h + cml/vector.h + cml/version.h +) + +set(common_HEADERS + cml/common/array_size_of.h + cml/common/basis_tags.h + cml/common/exception.h + cml/common/hash.h + cml/common/layout_tags.h + cml/common/memory_tags.h + cml/common/promotion.h + cml/common/size_tags.h + cml/common/storage_tags.h + cml/common/temporary.h + cml/common/traits.h + cml/common/type_util.h +) + +set(common_mpl_HEADERS + cml/common/mpl/are_convertible.h + cml/common/mpl/are_same.h + cml/common/mpl/enable_if_arithmetic.h + cml/common/mpl/enable_if_array.h + cml/common/mpl/enable_if_convertible.h + cml/common/mpl/enable_if_pointer.h + cml/common/mpl/enable_if_reshapeable.h + cml/common/mpl/enable_if_same.h + cml/common/mpl/enable_if_t.h + cml/common/mpl/if_t.h + cml/common/mpl/int_c.h + cml/common/mpl/is_reshapeable.h + cml/common/mpl/is_same_pair.h + cml/common/mpl/is_statically_polymorphic.h + cml/common/mpl/item_at.h + cml/common/mpl/plus_c.h + cml/common/mpl/rebind.h + cml/common/mpl/type_map.h + cml/common/mpl/type_table.h +) + +set(scalar_HEADERS + cml/scalar/binary_ops.h + cml/scalar/constants.h + cml/scalar/functions.h + cml/scalar/promotion.h + cml/scalar/traits.h + cml/scalar/unary_ops.h +) + +set(storage_HEADERS + cml/storage/allocated_selector.h + cml/storage/any_selector.h + cml/storage/compiled_selector.h + cml/storage/external_selector.h + cml/storage/promotion.h + cml/storage/resize.h + cml/storage/selectors.h + cml/storage/type_util.h +) + +set(vector_HEADERS + cml/vector/binary_node.h + cml/vector/binary_node.tpp + cml/vector/binary_ops.h + cml/vector/comparison.h + cml/vector/comparison.tpp + cml/vector/cross.h + cml/vector/cross_node.h + cml/vector/cross_node.tpp + cml/vector/cross_ops.h + cml/vector/dot.h + cml/vector/dot.tpp + cml/vector/dynamic.h + cml/vector/dynamic_allocated.h + cml/vector/dynamic_allocated.tpp + cml/vector/dynamic_const_external.h + cml/vector/dynamic_const_external.tpp + cml/vector/dynamic_external.h + cml/vector/dynamic_external.tpp + cml/vector/external.h + cml/vector/fixed.h + cml/vector/fixed_compiled.h + cml/vector/fixed_compiled.tpp + cml/vector/fixed_const_external.h + cml/vector/fixed_const_external.tpp + cml/vector/fixed_external.h + cml/vector/fixed_external.tpp + cml/vector/functions.h + cml/vector/functions.tpp + cml/vector/fwd.h + cml/vector/hadamard_product.h + cml/vector/ops.h + cml/vector/outer_product.h + cml/vector/outer_product_node.h + cml/vector/outer_product_node.tpp + cml/vector/outer_product_ops.h + cml/vector/perp_dot.h + cml/vector/perp_dot.tpp + cml/vector/products.h + cml/vector/promotion.h + cml/vector/readable_vector.h + cml/vector/readable_vector.tpp + cml/vector/scalar_node.h + cml/vector/scalar_node.tpp + cml/vector/scalar_ops.h + cml/vector/size_checking.h + cml/vector/size_checking.tpp + cml/vector/subvector.h + cml/vector/subvector_node.h + cml/vector/subvector_node.tpp + cml/vector/subvector_ops.h + cml/vector/subvector_ops.tpp + cml/vector/temporary.h + cml/vector/traits.h + cml/vector/triple_product.h + cml/vector/triple_product.tpp + cml/vector/types.h + cml/vector/type_util.h + cml/vector/unary_node.h + cml/vector/unary_node.tpp + cml/vector/unary_ops.h + cml/vector/vector.h + cml/vector/writable_vector.h + cml/vector/writable_vector.tpp +) + +set(vector_detail_HEADERS + cml/vector/detail/check_or_resize.h + cml/vector/detail/combined_size_of.h + cml/vector/detail/resize.h +) + +set(matrix_HEADERS + cml/matrix/array_size_of.h + cml/matrix/basis.h + cml/matrix/basis_node.h + cml/matrix/basis_node.tpp + cml/matrix/basis_ops.h + cml/matrix/binary_node.h + cml/matrix/binary_node.tpp + cml/matrix/binary_ops.h + cml/matrix/col_node.h + cml/matrix/col_node.tpp + cml/matrix/col_ops.h + cml/matrix/comparison.h + cml/matrix/comparison.tpp + cml/matrix/determinant.h + cml/matrix/determinant.tpp + cml/matrix/dynamic.h + cml/matrix/dynamic_allocated.h + cml/matrix/dynamic_allocated.tpp + cml/matrix/dynamic_external.h + cml/matrix/dynamic_external.tpp + cml/matrix/external.h + cml/matrix/fixed.h + cml/matrix/fixed_compiled.h + cml/matrix/fixed_compiled.tpp + cml/matrix/fixed_external.h + cml/matrix/fixed_external.tpp + cml/matrix/functions.h + cml/matrix/fwd.h + cml/matrix/hadamard_product.h + cml/matrix/inverse.h + cml/matrix/lu.h + cml/matrix/lu.tpp + cml/matrix/matrix.h + cml/matrix/matrix_product.h + cml/matrix/matrix_product.tpp + cml/matrix/ops.h + cml/matrix/promotion.h + cml/matrix/readable_matrix.h + cml/matrix/readable_matrix.tpp + cml/matrix/row_col.h + cml/matrix/row_node.h + cml/matrix/row_node.tpp + cml/matrix/row_ops.h + cml/matrix/scalar_node.h + cml/matrix/scalar_node.tpp + cml/matrix/scalar_ops.h + cml/matrix/size_checking.h + cml/matrix/size_checking.tpp + cml/matrix/temporary.h + cml/matrix/trace.h + cml/matrix/trace.tpp + cml/matrix/traits.h + cml/matrix/transpose.h + cml/matrix/transpose_node.h + cml/matrix/transpose_node.tpp + cml/matrix/transpose_ops.h + cml/matrix/types.h + cml/matrix/type_util.h + cml/matrix/unary_node.h + cml/matrix/unary_node.tpp + cml/matrix/unary_ops.h + cml/matrix/vector_product.h + cml/matrix/vector_product.tpp + cml/matrix/writable_matrix.h + cml/matrix/writable_matrix.tpp +) + +set(matrix_detail_HEADERS + cml/matrix/detail/apply.h + cml/matrix/detail/check_or_resize.h + cml/matrix/detail/copy.h + cml/matrix/detail/determinant.h + cml/matrix/detail/determinant.tpp + cml/matrix/detail/generate.h + cml/matrix/detail/get.h + cml/matrix/detail/inverse.h + cml/matrix/detail/lu.h + cml/matrix/detail/lu.tpp + cml/matrix/detail/resize.h + cml/matrix/detail/transpose.h +) + +set(quaternion_HEADERS + cml/quaternion/binary_node.h + cml/quaternion/binary_node.tpp + cml/quaternion/binary_ops.h + cml/quaternion/comparison.h + cml/quaternion/comparison.tpp + cml/quaternion/conjugate.h + cml/quaternion/conjugate_node.h + cml/quaternion/conjugate_node.tpp + cml/quaternion/conjugate_ops.h + cml/quaternion/conjugate_ops.tpp + cml/quaternion/cross_tags.h + cml/quaternion/dot.h + cml/quaternion/dot.tpp + cml/quaternion/fixed.h + cml/quaternion/fixed_compiled.h + cml/quaternion/fixed_compiled.tpp + cml/quaternion/functions.h + cml/quaternion/functions.tpp + cml/quaternion/fwd.h + cml/quaternion/imaginary.h + cml/quaternion/imaginary_node.h + cml/quaternion/imaginary_node.tpp + cml/quaternion/imaginary_ops.h + cml/quaternion/imaginary_ops.tpp + cml/quaternion/inverse.h + cml/quaternion/inverse_node.h + cml/quaternion/inverse_node.tpp + cml/quaternion/inverse_ops.h + cml/quaternion/inverse_ops.tpp + cml/quaternion/ops.h + cml/quaternion/order_tags.h + cml/quaternion/product.h + cml/quaternion/product.tpp + cml/quaternion/promotion.h + cml/quaternion/quaternion.h + cml/quaternion/readable_quaternion.h + cml/quaternion/readable_quaternion.tpp + cml/quaternion/scalar_node.h + cml/quaternion/scalar_node.tpp + cml/quaternion/scalar_ops.h + cml/quaternion/size_checking.h + cml/quaternion/temporary.h + cml/quaternion/traits.h + cml/quaternion/types.h + cml/quaternion/type_util.h + cml/quaternion/unary_node.h + cml/quaternion/unary_node.tpp + cml/quaternion/unary_ops.h + cml/quaternion/writable_quaternion.h + cml/quaternion/writable_quaternion.tpp +) + +set(mathlib_HEADERS + cml/mathlib/axis_order.h + cml/mathlib/constants.h + cml/mathlib/coordinate_conversion.h + cml/mathlib/coordinate_conversion.tpp + cml/mathlib/euler_order.h + cml/mathlib/frustum.h + cml/mathlib/frustum.tpp + cml/mathlib/mathlib.h + cml/mathlib/random_unit.h + cml/mathlib/random_unit.tpp +) + +set(mathlib_vector_HEADERS + cml/mathlib/vector/angle.h + cml/mathlib/vector/angle.tpp + cml/mathlib/vector/generators.h + cml/mathlib/vector/misc.h + cml/mathlib/vector/misc.tpp + cml/mathlib/vector/orthonormal.h + cml/mathlib/vector/orthonormal.tpp + cml/mathlib/vector/products.h + cml/mathlib/vector/rotation.h + cml/mathlib/vector/rotation.tpp + cml/mathlib/vector/transform.h + cml/mathlib/vector/transform.tpp +) + +set(mathlib_matrix_HEADERS + cml/mathlib/matrix/basis.h + cml/mathlib/matrix/basis.tpp + cml/mathlib/matrix/concat.h + cml/mathlib/matrix/concat.tpp + cml/mathlib/matrix/generators.h + cml/mathlib/matrix/invert.h + cml/mathlib/matrix/invert.tpp + cml/mathlib/matrix/misc.h + cml/mathlib/matrix/misc.tpp + cml/mathlib/matrix/projection.h + cml/mathlib/matrix/projection.tpp + cml/mathlib/matrix/rotation.h + cml/mathlib/matrix/rotation.tpp + cml/mathlib/matrix/scale.h + cml/mathlib/matrix/scale.tpp + cml/mathlib/matrix/size_checking.h + cml/mathlib/matrix/size_checking.tpp + cml/mathlib/matrix/temporary.h + cml/mathlib/matrix/transform.h + cml/mathlib/matrix/transform.tpp + cml/mathlib/matrix/translation.h + cml/mathlib/matrix/translation.tpp +) + +set(mathlib_quaternion_HEADERS + cml/mathlib/quaternion/basis.h + cml/mathlib/quaternion/basis.tpp + cml/mathlib/quaternion/rotation.h + cml/mathlib/quaternion/rotation.tpp +) + +set(util_HEADERS + cml/util/matrix_print.h + cml/util/matrix_print.tpp + cml/util/quaternion_print.h + cml/util/quaternion_print.tpp + cml/util/vector_hash.h + cml/util/vector_print.h + cml/util/vector_print.tpp +) + +set(all_headers + ${main_HEADERS} + ${common_HEADERS} + ${common_mpl_HEADERS} + ${scalar_HEADERS} + ${storage_HEADERS} + ${matrix_HEADERS} + ${matrix_detail_HEADERS} + ${quaternion_HEADERS} + ${util_HEADERS} + ${vector_HEADERS} + ${vector_detail_HEADERS} + ${mathlib_HEADERS} + ${mathlib_vector_HEADERS} + ${mathlib_matrix_HEADERS} + ${mathlib_quaternion_HEADERS} +) + +add_library(cml INTERFACE) +target_compile_features(cml INTERFACE + cxx_reference_qualified_functions + cxx_constexpr + cxx_defaulted_functions +) +target_include_directories(cml INTERFACE $) +target_include_directories(cml INTERFACE $/include>) + +# Setup a custom target, and use IDE groups for the headers when possible: +source_group(TREE "${CML_ROOT}/cml" FILES ${all_headers}) add_custom_target(cml-dev SOURCES ${all_headers}) \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json index d19afb9..5c67160 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,255 +1,255 @@ -{ - // Core configuration presets: - "version": 7, - "configurePresets": [ - { - // Inheritable conditional to enable a configuration preset on Windows only: - "name": ".cml-windows-only", - "hidden": true, - "condition": { - "type": "allOf", - "conditions": [ - { - "lhs": "${hostSystemName}", - "type": "equals", - "rhs": "Windows" - } - ] - } - }, - { - // Inheritable conditional to enable a configuration preset on Linux only: - "name": ".cml-linux-only", - "hidden": true, - "condition": { - "type": "allOf", - "conditions": [ - { - "lhs": "${hostSystemName}", - "type": "equals", - "rhs": "Linux" - } - ] - } - }, - { - // Inheritable conditional to enable a configuration preset on Darwin (Mac OS/X) only: - "name": ".cml-macosx-only", - "hidden": true, - "condition": { - "type": "allOf", - "conditions": [ - { - "lhs": "${hostSystemName}", - "type": "equals", - "rhs": "Darwin" - } - ] - } - }, - - - { - // Standard build directory, and always target x64: - "name": ".cml-configure-defaults", - "hidden": true, - "binaryDir": "${sourceDir}/.build/${presetName}", - "architecture": { - "value": "x64", - "strategy": "external" - }, - "cacheVariables": { - "BUILD_SHARED_LIBS": { - "type": "BOOL", - "value": false - }, - "BUILD_STATIC_RUNTIME": { - "type": "BOOL", - "value": true - }, - "BUILD_TESTING": { - "type": "BOOL", - "value": true - } - } - }, - - { - // Inheritable configuration to use the system default MSVC ClangCL and the Ninja generator: - "name": ".cml-ninja-msvc-clangcl", - "hidden": true, - "inherits": [ ".cml-windows-only" ], - "generator": "Ninja Multi-Config", - "cacheVariables": { - "CMAKE_C_COMPILER": "clang-cl.exe", - "CMAKE_CXX_COMPILER": "clang-cl.exe" - } - }, - { - // Inheritable configuration to use the system default MSVC and the Ninja generator: - "name": ".cml-ninja-msvc", - "hidden": true, - "inherits": [ ".cml-windows-only" ], - "generator": "Ninja Multi-Config", - "cacheVariables": { - "CMAKE_C_COMPILER": "cl.exe", - "CMAKE_CXX_COMPILER": "cl.exe" - } - }, - { - // Inheritable configuration to use MSVC17 and MSBuild: - "name": ".cml-msvc17", - "hidden": true, - "inherits": [ ".cml-windows-only" ], - "generator": "Visual Studio 17 2022" - }, - { - // Inheritable configuration to use the system default MSVC17 with ClangCL and MSBuild: - "name": ".cml-msvc17-clangcl", - "hidden": true, - "inherits": [ ".cml-windows-only" ], - "generator": "Visual Studio 17 2022", - "toolset": "ClangCL" - }, - - { - // Preset to configure a static dev-test (IDE) build with the system default MSVC17: - "name": "cml-dev-msvc17-mt-s", - "inherits": [ ".cml-configure-defaults", ".cml-msvc17" ] - }, - { - // Preset to configure a static dev-test build (IDE) with the system default MSVC17 ClangCL: - "name": "cml-dev-msvc17-clangcl-mt-s", - "inherits": [ ".cml-configure-defaults", ".cml-msvc17-clangcl" ] - }, - - { - // Preset to configure a CI test build with Ninja Multi-Config and the system default MSVC ClangCL: - "name": "cml-ci-ninja-msvc-clangcl-mt-s", - "inherits": [ ".cml-configure-defaults", ".cml-ninja-msvc-clangcl" ] - }, - { - // Preset to configure a CI test build with Ninja Multi-Config and the system default MSVC: - "name": "cml-ci-ninja-msvc-mt-s", - "inherits": [ ".cml-configure-defaults", ".cml-ninja-msvc" ] - }, - { - // Preset to configure a CI test build with MSVC17: - "name": "cml-ci-msvc17-mt-s", - "inherits": [ ".cml-configure-defaults", ".cml-msvc17" ] - } - ], - - "buildPresets": [ - { - // Inheritable conditional to enable a build preset on Windows only: - "name": ".cml-windows-build-only", - "hidden": true, - "condition": { - "type": "allOf", - "conditions": [ - { - "lhs": "${hostSystemName}", - "type": "equals", - "rhs": "Windows" - } - ] - } - }, - { - // Inheritable conditional to enable a build preset on Linux only: - "name": ".cml-linux-build-only", - "hidden": true, - "condition": { - "type": "allOf", - "conditions": [ - { - "lhs": "${hostSystemName}", - "type": "equals", - "rhs": "Windows" - } - ] - } - }, - { - // Inheritable conditional to enable a build preset on OS/X only: - "name": ".cml-macosx-build-only", - "hidden": true, - "condition": { - "type": "allOf", - "conditions": [ - { - "lhs": "${hostSystemName}", - "type": "equals", - "rhs": "Darwin" - } - ] - } - }, - - { - // Static Ninja+MSVC release build: - "name": "cml-ci-ninja-msvc-mt-s-release", - "inherits": [ ".cml-windows-build-only" ], - "configurePreset": "cml-ci-ninja-msvc-mt-s", - "inheritConfigureEnvironment": true, - "configuration": "Release" - }, - { - // Static Ninja+ClangCl release build: - "name": "cml-ci-ninja-msvc-clangcl-mt-s-release", - "inherits": [ ".cml-windows-build-only" ], - "configurePreset": "cml-ci-ninja-msvc-clangcl-mt-s", - "inheritConfigureEnvironment": true, - "configuration": "Release" - }, - { - // Static MSVC release build: - "name": "cml-ci-msvc17-mt-s-release", - "inherits": [ ".cml-windows-build-only" ], - "configurePreset": "cml-ci-msvc17-mt-s", - "inheritConfigureEnvironment": true, - "configuration": "Release" - } - ], - - "testPresets": [ - { - // Inheritable conditional to enable a test preset on Windows only: - "name": ".cml-windows-test-only", - "hidden": true, - "condition": { - "type": "allOf", - "conditions": [ - { - "lhs": "${hostSystemName}", - "type": "equals", - "rhs": "Windows" - } - ] - } - }, - - { - "name": "cml-ci-ninja-msvc-mt-s-release-test", - "inherits": [ ".cml-windows-test-only" ], - "configurePreset": "cml-ci-ninja-msvc-mt-s", - "inheritConfigureEnvironment": true, - "configuration": "Release" - }, - { - "name": "cml-ci-ninja-msvc-clangcl-mt-s-release-test", - "inherits": [ ".cml-windows-test-only" ], - "configurePreset": "cml-ci-ninja-msvc-clangcl-mt-s", - "inheritConfigureEnvironment": true, - "configuration": "Release" - }, - { - "name": "cml-ci-msvc17-mt-s-release-test", - "inherits": [ ".cml-windows-test-only" ], - "configurePreset": "cml-ci-msvc17-mt-s", - "inheritConfigureEnvironment": true, - "configuration": "Release" - } - ] +{ + // Core configuration presets: + "version": 7, + "configurePresets": [ + { + // Inheritable conditional to enable a configuration preset on Windows only: + "name": ".cml-windows-only", + "hidden": true, + "condition": { + "type": "allOf", + "conditions": [ + { + "lhs": "${hostSystemName}", + "type": "equals", + "rhs": "Windows" + } + ] + } + }, + { + // Inheritable conditional to enable a configuration preset on Linux only: + "name": ".cml-linux-only", + "hidden": true, + "condition": { + "type": "allOf", + "conditions": [ + { + "lhs": "${hostSystemName}", + "type": "equals", + "rhs": "Linux" + } + ] + } + }, + { + // Inheritable conditional to enable a configuration preset on Darwin (Mac OS/X) only: + "name": ".cml-macosx-only", + "hidden": true, + "condition": { + "type": "allOf", + "conditions": [ + { + "lhs": "${hostSystemName}", + "type": "equals", + "rhs": "Darwin" + } + ] + } + }, + + + { + // Standard build directory, and always target x64: + "name": ".cml-configure-defaults", + "hidden": true, + "binaryDir": "${sourceDir}/.build/${presetName}", + "architecture": { + "value": "x64", + "strategy": "external" + }, + "cacheVariables": { + "BUILD_SHARED_LIBS": { + "type": "BOOL", + "value": false + }, + "BUILD_STATIC_RUNTIME": { + "type": "BOOL", + "value": true + }, + "BUILD_TESTING": { + "type": "BOOL", + "value": true + } + } + }, + + { + // Inheritable configuration to use the system default MSVC ClangCL and the Ninja generator: + "name": ".cml-ninja-msvc-clangcl", + "hidden": true, + "inherits": [ ".cml-windows-only" ], + "generator": "Ninja Multi-Config", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl.exe", + "CMAKE_CXX_COMPILER": "clang-cl.exe" + } + }, + { + // Inheritable configuration to use the system default MSVC and the Ninja generator: + "name": ".cml-ninja-msvc", + "hidden": true, + "inherits": [ ".cml-windows-only" ], + "generator": "Ninja Multi-Config", + "cacheVariables": { + "CMAKE_C_COMPILER": "cl.exe", + "CMAKE_CXX_COMPILER": "cl.exe" + } + }, + { + // Inheritable configuration to use MSVC17 and MSBuild: + "name": ".cml-msvc17", + "hidden": true, + "inherits": [ ".cml-windows-only" ], + "generator": "Visual Studio 17 2022" + }, + { + // Inheritable configuration to use the system default MSVC17 with ClangCL and MSBuild: + "name": ".cml-msvc17-clangcl", + "hidden": true, + "inherits": [ ".cml-windows-only" ], + "generator": "Visual Studio 17 2022", + "toolset": "ClangCL" + }, + + { + // Preset to configure a static dev-test (IDE) build with the system default MSVC17: + "name": "cml-dev-msvc17-mt-s", + "inherits": [ ".cml-configure-defaults", ".cml-msvc17" ] + }, + { + // Preset to configure a static dev-test build (IDE) with the system default MSVC17 ClangCL: + "name": "cml-dev-msvc17-clangcl-mt-s", + "inherits": [ ".cml-configure-defaults", ".cml-msvc17-clangcl" ] + }, + + { + // Preset to configure a CI test build with Ninja Multi-Config and the system default MSVC ClangCL: + "name": "cml-ci-ninja-msvc-clangcl-mt-s", + "inherits": [ ".cml-configure-defaults", ".cml-ninja-msvc-clangcl" ] + }, + { + // Preset to configure a CI test build with Ninja Multi-Config and the system default MSVC: + "name": "cml-ci-ninja-msvc-mt-s", + "inherits": [ ".cml-configure-defaults", ".cml-ninja-msvc" ] + }, + { + // Preset to configure a CI test build with MSVC17: + "name": "cml-ci-msvc17-mt-s", + "inherits": [ ".cml-configure-defaults", ".cml-msvc17" ] + } + ], + + "buildPresets": [ + { + // Inheritable conditional to enable a build preset on Windows only: + "name": ".cml-windows-build-only", + "hidden": true, + "condition": { + "type": "allOf", + "conditions": [ + { + "lhs": "${hostSystemName}", + "type": "equals", + "rhs": "Windows" + } + ] + } + }, + { + // Inheritable conditional to enable a build preset on Linux only: + "name": ".cml-linux-build-only", + "hidden": true, + "condition": { + "type": "allOf", + "conditions": [ + { + "lhs": "${hostSystemName}", + "type": "equals", + "rhs": "Windows" + } + ] + } + }, + { + // Inheritable conditional to enable a build preset on OS/X only: + "name": ".cml-macosx-build-only", + "hidden": true, + "condition": { + "type": "allOf", + "conditions": [ + { + "lhs": "${hostSystemName}", + "type": "equals", + "rhs": "Darwin" + } + ] + } + }, + + { + // Static Ninja+MSVC release build: + "name": "cml-ci-ninja-msvc-mt-s-release", + "inherits": [ ".cml-windows-build-only" ], + "configurePreset": "cml-ci-ninja-msvc-mt-s", + "inheritConfigureEnvironment": true, + "configuration": "Release" + }, + { + // Static Ninja+ClangCl release build: + "name": "cml-ci-ninja-msvc-clangcl-mt-s-release", + "inherits": [ ".cml-windows-build-only" ], + "configurePreset": "cml-ci-ninja-msvc-clangcl-mt-s", + "inheritConfigureEnvironment": true, + "configuration": "Release" + }, + { + // Static MSVC release build: + "name": "cml-ci-msvc17-mt-s-release", + "inherits": [ ".cml-windows-build-only" ], + "configurePreset": "cml-ci-msvc17-mt-s", + "inheritConfigureEnvironment": true, + "configuration": "Release" + } + ], + + "testPresets": [ + { + // Inheritable conditional to enable a test preset on Windows only: + "name": ".cml-windows-test-only", + "hidden": true, + "condition": { + "type": "allOf", + "conditions": [ + { + "lhs": "${hostSystemName}", + "type": "equals", + "rhs": "Windows" + } + ] + } + }, + + { + "name": "cml-ci-ninja-msvc-mt-s-release-test", + "inherits": [ ".cml-windows-test-only" ], + "configurePreset": "cml-ci-ninja-msvc-mt-s", + "inheritConfigureEnvironment": true, + "configuration": "Release" + }, + { + "name": "cml-ci-ninja-msvc-clangcl-mt-s-release-test", + "inherits": [ ".cml-windows-test-only" ], + "configurePreset": "cml-ci-ninja-msvc-clangcl-mt-s", + "inheritConfigureEnvironment": true, + "configuration": "Release" + }, + { + "name": "cml-ci-msvc17-mt-s-release-test", + "inherits": [ ".cml-windows-test-only" ], + "configurePreset": "cml-ci-msvc17-mt-s", + "inheritConfigureEnvironment": true, + "configuration": "Release" + } + ] } \ No newline at end of file diff --git a/README.md b/README.md index f1f164b..c7c41cd 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,47 @@ -[![msvc-latest](https://github.com/demianmnave/CML/actions/workflows/msvc-latest.yml/badge.svg)](https://github.com/demianmnave/CML/actions/workflows/msvc-latest.yml) -[![msvc-clangcl-latest](https://github.com/demianmnave/CML/actions/workflows/msvc-clangcl-latest.yml/badge.svg)](https://github.com/demianmnave/CML/actions/workflows/msvc-clangcl-latest.yml) -[![msvc-17-10](https://github.com/demianmnave/CML/actions/workflows/msvc-17-10.yml/badge.svg)](https://github.com/demianmnave/CML/actions/workflows/msvc-17-10.yml) - -## Configurable Math Library -For CML version 1, please see https://github.com/demianmnave/CML1. -## License -The Configurable Math Library (CML) is released under the [Boost Software -License, Version 1.0.](http://www.boost.org/LICENSE_1_0.txt). -## Using the CML -As it is header-only, it is simple enough to copy the `cml` header directory into your project and setup your build to reference it. Users of CMake 3.15+ can also leverage [`cmake --install ...`](make.org/cmake/help/v3.15/manual/cmake.1.html#install-a-project) and [`find_package(CML CONFIG)`](https://cmake.org/cmake/help/v3.15/command/find_package.html) to integrate CML into a CMake project. -## Compiler requirements -The CML requires a compiler with C++17 support. -## Building and Running Tests -### With plain CMake -To run the test suite from a command prompt using a Makefile-like generator, start in your build directory and execute: -```bash -cmake -S \ -G{generator name} -DBUILD_TESTING=On -DCMAKE_BUILD_TYPE=Release -``` -Then, to build the tests (again from your build directory): -```bash -cmake --build . --config Release -``` -You can run the full test suite from your build directory by executing: -```bash -ctest -C Release -``` -If you have multiple CPUs (e.g. 4 in this case), you can speed things up a bit using, for example: -```bash -cmake --build . --config Release -- -j4 -ctest -C Release -j4 -``` -### With CMake presets -See _CMakePresets.json_ for the default base presets, as well as the predefined configure and build presets. Note that all of the predefined configure presets generate a build system under _\/.build_/\. - -To see the available configure presets, execute: -```bash -cmake --list-presets -``` -To see the available build presets, execute: -```bash -cmake --build --list-presets -``` -To use one of the predefined configure presets, for example _cml-dev-msvc17-clangcl-mt-s_ to use the Visual Studio 2022 IDE with ClangCL: -```bash -cmake --preset=cml-dev-msvc17-clangcl-mt-s +[![msvc-latest](https://github.com/demianmnave/CML/actions/workflows/msvc-latest.yml/badge.svg)](https://github.com/demianmnave/CML/actions/workflows/msvc-latest.yml) +[![msvc-clangcl-latest](https://github.com/demianmnave/CML/actions/workflows/msvc-clangcl-latest.yml/badge.svg)](https://github.com/demianmnave/CML/actions/workflows/msvc-clangcl-latest.yml) +[![msvc-17-10](https://github.com/demianmnave/CML/actions/workflows/msvc-17-10.yml/badge.svg)](https://github.com/demianmnave/CML/actions/workflows/msvc-17-10.yml) + +## Configurable Math Library +For CML version 1, please see https://github.com/demianmnave/CML1. +## License +The Configurable Math Library (CML) is released under the [Boost Software +License, Version 1.0.](http://www.boost.org/LICENSE_1_0.txt). +## Using the CML +As it is header-only, it is simple enough to copy the `cml` header directory into your project and setup your build to reference it. Users of CMake 3.15+ can also leverage [`cmake --install ...`](make.org/cmake/help/v3.15/manual/cmake.1.html#install-a-project) and [`find_package(CML CONFIG)`](https://cmake.org/cmake/help/v3.15/command/find_package.html) to integrate CML into a CMake project. +## Compiler requirements +The CML requires a compiler with C++17 support. +## Building and Running Tests +### With plain CMake +To run the test suite from a command prompt using a Makefile-like generator, start in your build directory and execute: +```bash +cmake -S \ -G{generator name} -DBUILD_TESTING=On -DCMAKE_BUILD_TYPE=Release +``` +Then, to build the tests (again from your build directory): +```bash +cmake --build . --config Release +``` +You can run the full test suite from your build directory by executing: +```bash +ctest -C Release +``` +If you have multiple CPUs (e.g. 4 in this case), you can speed things up a bit using, for example: +```bash +cmake --build . --config Release -- -j4 +ctest -C Release -j4 +``` +### With CMake presets +See _CMakePresets.json_ for the default base presets, as well as the predefined configure and build presets. Note that all of the predefined configure presets generate a build system under _\/.build_/\. + +To see the available configure presets, execute: +```bash +cmake --list-presets +``` +To see the available build presets, execute: +```bash +cmake --build --list-presets +``` +To use one of the predefined configure presets, for example _cml-dev-msvc17-clangcl-mt-s_ to use the Visual Studio 2022 IDE with ClangCL: +```bash +cmake --preset=cml-dev-msvc17-clangcl-mt-s ``` \ No newline at end of file diff --git a/cml/cml.h b/cml/cml.h index 855223f..dcd3cd5 100644 --- a/cml/cml.h +++ b/cml/cml.h @@ -1,12 +1,12 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include diff --git a/cml/common/array_size_of.h b/cml/common/array_size_of.h index 7a4d2d3..5ef93ea 100644 --- a/cml/common/array_size_of.h +++ b/cml/common/array_size_of.h @@ -1,109 +1,109 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { -namespace detail { - -/** Helper defining a typedef @c type that is int if @c T is an integral - * type, or @c T otherwise. - */ -template struct int_if_integral -{ - using type = typename std::conditional::value, int, T>::type; -}; - -} // namespace detail - - -/** Specializable compile-time array size. */ -template struct array_size_of_c; - -/** Specializable compile-time array row count. */ -template struct array_rows_of_c; - -/** Specializable compile-time array row count. */ -template struct array_cols_of_c; - -/** Compile-time size of an array. */ -template -struct array_size_of_c::value>::type> -{ - static const int value = int(std::extent::value); -}; - -/** Compile-time size of an object implementing an array_size integral or - * enum member. - */ -template -struct array_size_of_c::type> -{ - static const int value = Array::array_size; -}; - -/** Return the size of @c array if it implements the size() method. */ -template -inline auto -array_size_of(const Array& array) -> - typename detail::int_if_integral::type -{ - using result_type = typename detail::int_if_integral::type; - return result_type(array.size()); -} - -/** Return the size of a fixed-length array. */ -template -inline int -array_size_of(const Array&, - typename std::enable_if::value>::type* = 0) -{ - return int(array_size_of_c::value); -} - -/** Compile-time size of an object implementing an array_rows integral or - * enum member. - */ -template -struct array_rows_of_c::type> -{ - static const int value = int(Array::array_rows); -}; - -/** Compile-time size of an object implementing an array_cols integral or - * enum member. - */ -template -struct array_cols_of_c::type> -{ - static const int value = int(Array::array_cols); -}; - -/** Return the number of rows of @c array if it implements the rows() - * method. - */ -template -inline auto -array_rows_of(const Array& array) -> decltype(array.rows()) -{ - return array.rows(); -} - -/** Return the number of columns @c array if it implements the cols() - * method. - */ -template -inline auto -array_cols_of(const Array& array) -> decltype(array.cols()) -{ - return array.cols(); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { +namespace detail { + +/** Helper defining a typedef @c type that is int if @c T is an integral + * type, or @c T otherwise. + */ +template struct int_if_integral +{ + using type = typename std::conditional::value, int, T>::type; +}; + +} // namespace detail + + +/** Specializable compile-time array size. */ +template struct array_size_of_c; + +/** Specializable compile-time array row count. */ +template struct array_rows_of_c; + +/** Specializable compile-time array row count. */ +template struct array_cols_of_c; + +/** Compile-time size of an array. */ +template +struct array_size_of_c::value>::type> +{ + static const int value = int(std::extent::value); +}; + +/** Compile-time size of an object implementing an array_size integral or + * enum member. + */ +template +struct array_size_of_c::type> +{ + static const int value = Array::array_size; +}; + +/** Return the size of @c array if it implements the size() method. */ +template +inline auto +array_size_of(const Array& array) -> + typename detail::int_if_integral::type +{ + using result_type = typename detail::int_if_integral::type; + return result_type(array.size()); +} + +/** Return the size of a fixed-length array. */ +template +inline int +array_size_of(const Array&, + typename std::enable_if::value>::type* = 0) +{ + return int(array_size_of_c::value); +} + +/** Compile-time size of an object implementing an array_rows integral or + * enum member. + */ +template +struct array_rows_of_c::type> +{ + static const int value = int(Array::array_rows); +}; + +/** Compile-time size of an object implementing an array_cols integral or + * enum member. + */ +template +struct array_cols_of_c::type> +{ + static const int value = int(Array::array_cols); +}; + +/** Return the number of rows of @c array if it implements the rows() + * method. + */ +template +inline auto +array_rows_of(const Array& array) -> decltype(array.rows()) +{ + return array.rows(); +} + +/** Return the number of columns @c array if it implements the cols() + * method. + */ +template +inline auto +array_cols_of(const Array& array) -> decltype(array.cols()) +{ + return array.cols(); +} + +} // namespace cml diff --git a/cml/common/basis_tags.h b/cml/common/basis_tags.h index f14868e..47384b9 100644 --- a/cml/common/basis_tags.h +++ b/cml/common/basis_tags.h @@ -1,114 +1,114 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -enum basis_kind -{ - row_basis_c = 1, - col_basis_c = 2, - any_basis_c = 3, - basis_count = 3 -}; - -/** Row basis tag. */ -struct row_basis -{ - static const basis_kind value = row_basis_c; -}; - -/** Column basis tag. */ -struct col_basis -{ - static const basis_kind value = col_basis_c; -}; - -/** Any basis tag. */ -struct any_basis -{ - static const basis_kind value = any_basis_c; -}; - -/** Detect valid basis tags. */ -template struct is_basis_tag -{ - static const bool value = std::is_same::value - || std::is_same::value - || std::is_same::value; -}; - -/** Templated helper to determine the basis tag of an expression that - * defines the basis_tag type. - */ -template struct basis_tag_of -{ - using type = typename T::basis_tag; - static_assert(is_basis_tag::value, "invalid basis tag"); -}; - -/** Convenience alias for basis_tag_of. */ -template using basis_tag_of_t = typename basis_tag_of::type; - -/** Retrieve the basis_tag of @c T via traits. */ -template struct basis_tag_trait_of -{ - using type = typename traits_of::type::basis_tag; - static_assert(is_basis_tag::value, "invalid basis tag"); -}; - -/** Convenience alias for basis_tag_trait_of. */ -template -using basis_tag_trait_of_t = typename basis_tag_trait_of::type; - -/** Helper to detect row basis types. */ -template struct is_row_basis -{ - static const bool value = std::is_same, row_basis>::value; -}; - -/** Wrapper for enable_if to detect types tagged with row_basis. */ -template -struct enable_if_row_basis : std::enable_if::value, T> -{}; - -/** Convenience alias for enable_if_row_basis. */ -template -using enable_if_row_basis_t = typename enable_if_row_basis::type; - -/** Helper to detect column basis types. */ -template struct is_col_basis -{ - static const bool value = std::is_same, col_basis>::value; -}; - -/** Wrapper for enable_if to detect types tagged with col_basis. */ -template -struct enable_if_col_basis : std::enable_if::value, T> -{}; - -/** Convenience alias for enable_if_col_basis. */ -template -using enable_if_col_basis_t = typename enable_if_col_basis::type; - -/** Helper to detect arbitrary basis types. */ -template struct is_any_basis -{ - static const bool value = std::is_same, any_basis>::value; -}; - -/** Wrapper for enable_if to detect types tagged with any_basis. */ -template -struct enable_if_any_basis : std::enable_if::value, T> -{}; - -/** Convenience alias for enable_if_any_basis. */ -template -using enable_if_any_basis_t = typename enable_if_any_basis::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +enum basis_kind +{ + row_basis_c = 1, + col_basis_c = 2, + any_basis_c = 3, + basis_count = 3 +}; + +/** Row basis tag. */ +struct row_basis +{ + static const basis_kind value = row_basis_c; +}; + +/** Column basis tag. */ +struct col_basis +{ + static const basis_kind value = col_basis_c; +}; + +/** Any basis tag. */ +struct any_basis +{ + static const basis_kind value = any_basis_c; +}; + +/** Detect valid basis tags. */ +template struct is_basis_tag +{ + static const bool value = std::is_same::value + || std::is_same::value + || std::is_same::value; +}; + +/** Templated helper to determine the basis tag of an expression that + * defines the basis_tag type. + */ +template struct basis_tag_of +{ + using type = typename T::basis_tag; + static_assert(is_basis_tag::value, "invalid basis tag"); +}; + +/** Convenience alias for basis_tag_of. */ +template using basis_tag_of_t = typename basis_tag_of::type; + +/** Retrieve the basis_tag of @c T via traits. */ +template struct basis_tag_trait_of +{ + using type = typename traits_of::type::basis_tag; + static_assert(is_basis_tag::value, "invalid basis tag"); +}; + +/** Convenience alias for basis_tag_trait_of. */ +template +using basis_tag_trait_of_t = typename basis_tag_trait_of::type; + +/** Helper to detect row basis types. */ +template struct is_row_basis +{ + static const bool value = std::is_same, row_basis>::value; +}; + +/** Wrapper for enable_if to detect types tagged with row_basis. */ +template +struct enable_if_row_basis : std::enable_if::value, T> +{}; + +/** Convenience alias for enable_if_row_basis. */ +template +using enable_if_row_basis_t = typename enable_if_row_basis::type; + +/** Helper to detect column basis types. */ +template struct is_col_basis +{ + static const bool value = std::is_same, col_basis>::value; +}; + +/** Wrapper for enable_if to detect types tagged with col_basis. */ +template +struct enable_if_col_basis : std::enable_if::value, T> +{}; + +/** Convenience alias for enable_if_col_basis. */ +template +using enable_if_col_basis_t = typename enable_if_col_basis::type; + +/** Helper to detect arbitrary basis types. */ +template struct is_any_basis +{ + static const bool value = std::is_same, any_basis>::value; +}; + +/** Wrapper for enable_if to detect types tagged with any_basis. */ +template +struct enable_if_any_basis : std::enable_if::value, T> +{}; + +/** Convenience alias for enable_if_any_basis. */ +template +using enable_if_any_basis_t = typename enable_if_any_basis::type; + +} // namespace cml diff --git a/cml/common/exception.h b/cml/common/exception.h index e6973fb..6209751 100644 --- a/cml/common/exception.h +++ b/cml/common/exception.h @@ -1,12 +1,12 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -/** Throw exception _e_ with message _msg_ if _cond_ is false. */ -#define cml_require(_cond_, _e_, _msg_) \ - if((_cond_)) { \ - } else throw _e_(_msg_) +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +/** Throw exception _e_ with message _msg_ if _cond_ is false. */ +#define cml_require(_cond_, _e_, _msg_) \ + if((_cond_)) { \ + } else throw _e_(_msg_) diff --git a/cml/common/hash.h b/cml/common/hash.h index 27dd624..63d17d3 100644 --- a/cml/common/hash.h +++ b/cml/common/hash.h @@ -1,64 +1,64 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml::detail { - -/* Adapted from boost/functional/hash/hash.hpp> */ -#if defined(_MSC_VER) -# define _HASH_ROTL32(x, r) _rotl(x, r) -#else -# define _HASH_ROTL32(x, r) ((x << r) | (x >> (32 - r))) -#endif - -template -inline void -hash_combine_impl(U32& h1, U32 k1, cml::int_c<4>) -{ - const auto c1 = UINT32_C(0xcc'9e'2d'51); - const auto c2 = UINT32_C(0x1b'87'35'93); - - k1 *= c1; - k1 = _HASH_ROTL32(k1, 15); - k1 *= c2; - - h1 ^= k1; - h1 = _HASH_ROTL32(h1, 13); - h1 = h1 * 5 + 0xe6'54'6b'64; -} - -#undef _CML_HASH_ROTL32 - -template -inline void -hash_combine_impl(U64& h, U64 k, cml::int_c<8>) -{ - const auto m = UINT64_C(0xc6'a4'a7'93'5b'd1'e9'95); - const auto r = 47; - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; - - // Completely arbitrary number, to prevent 0's - // from hashing to 0. - h += UINT64_C(0xe6'54'6b'64); -} - -template -inline void -hash_combine(UInt& h, UInt k) -{ - hash_combine_impl(h, k, cml::int_c()); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml::detail { + +/* Adapted from boost/functional/hash/hash.hpp> */ +#if defined(_MSC_VER) +# define _HASH_ROTL32(x, r) _rotl(x, r) +#else +# define _HASH_ROTL32(x, r) ((x << r) | (x >> (32 - r))) +#endif + +template +inline void +hash_combine_impl(U32& h1, U32 k1, cml::int_c<4>) +{ + const auto c1 = UINT32_C(0xcc'9e'2d'51); + const auto c2 = UINT32_C(0x1b'87'35'93); + + k1 *= c1; + k1 = _HASH_ROTL32(k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = _HASH_ROTL32(h1, 13); + h1 = h1 * 5 + 0xe6'54'6b'64; +} + +#undef _CML_HASH_ROTL32 + +template +inline void +hash_combine_impl(U64& h, U64 k, cml::int_c<8>) +{ + const auto m = UINT64_C(0xc6'a4'a7'93'5b'd1'e9'95); + const auto r = 47; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + + // Completely arbitrary number, to prevent 0's + // from hashing to 0. + h += UINT64_C(0xe6'54'6b'64); +} + +template +inline void +hash_combine(UInt& h, UInt k) +{ + hash_combine_impl(h, k, cml::int_c()); +} + +} diff --git a/cml/common/layout_tags.h b/cml/common/layout_tags.h index 2f8ac7b..6ef7a02 100644 --- a/cml/common/layout_tags.h +++ b/cml/common/layout_tags.h @@ -1,88 +1,88 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/* Forward declarations: */ -struct row_major; -struct col_major; -struct any_major; - -enum layout_kind -{ - row_major_c = 1, - col_major_c = 2, - any_major_c = 3, - layout_count = 3 -}; - -/** Row major tag. */ -struct row_major -{ - /** row_major transposes to col_major. */ - using transposed_tag = col_major; - - /** Integral identifier. */ - static const layout_kind value = row_major_c; -}; - -/** Column major tag. */ -struct col_major -{ - /** col_major transposes to row_major. */ - using transposed_tag = row_major; - - /** Integral identifier. */ - static const layout_kind value = col_major_c; -}; - -/** Arbitrary or unspecified major tag. */ -struct any_major -{ - /** any_major transposes to itself. */ - using transposed_tag = any_major; - - /** Integral identifier. */ - static const layout_kind value = any_major_c; -}; - -/** Detect valid layout tags. - * - * @note This can be specialized for user-defined layout tags. - */ -template struct is_layout_tag -{ - static const bool value = std::is_same::value - || std::is_same::value - || std::is_same::value; -}; - -/** Templated helper to determine the layout tag of an expression that - * defines the layout_tag type. - */ -template struct layout_tag_of -{ - using type = typename T::layout_tag; - static_assert(is_layout_tag::value, "invalid layout tag"); -}; - -/** Convenience alias for layout_tag_of. */ -template using layout_tag_of_t = typename layout_tag_of::type; - -/** Retrieve the layout_tag of @c T via traits. */ -template struct layout_tag_trait_of -{ - using type = typename traits_of::type::layout_tag; - static_assert(is_layout_tag::value, "invalid layout tag"); -}; - -/** Convenience alias for layout_tag_trait_of. */ -template -using layout_tag_trait_of_t = typename layout_tag_trait_of::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/* Forward declarations: */ +struct row_major; +struct col_major; +struct any_major; + +enum layout_kind +{ + row_major_c = 1, + col_major_c = 2, + any_major_c = 3, + layout_count = 3 +}; + +/** Row major tag. */ +struct row_major +{ + /** row_major transposes to col_major. */ + using transposed_tag = col_major; + + /** Integral identifier. */ + static const layout_kind value = row_major_c; +}; + +/** Column major tag. */ +struct col_major +{ + /** col_major transposes to row_major. */ + using transposed_tag = row_major; + + /** Integral identifier. */ + static const layout_kind value = col_major_c; +}; + +/** Arbitrary or unspecified major tag. */ +struct any_major +{ + /** any_major transposes to itself. */ + using transposed_tag = any_major; + + /** Integral identifier. */ + static const layout_kind value = any_major_c; +}; + +/** Detect valid layout tags. + * + * @note This can be specialized for user-defined layout tags. + */ +template struct is_layout_tag +{ + static const bool value = std::is_same::value + || std::is_same::value + || std::is_same::value; +}; + +/** Templated helper to determine the layout tag of an expression that + * defines the layout_tag type. + */ +template struct layout_tag_of +{ + using type = typename T::layout_tag; + static_assert(is_layout_tag::value, "invalid layout tag"); +}; + +/** Convenience alias for layout_tag_of. */ +template using layout_tag_of_t = typename layout_tag_of::type; + +/** Retrieve the layout_tag of @c T via traits. */ +template struct layout_tag_trait_of +{ + using type = typename traits_of::type::layout_tag; + static_assert(is_layout_tag::value, "invalid layout tag"); +}; + +/** Convenience alias for layout_tag_trait_of. */ +template +using layout_tag_trait_of_t = typename layout_tag_trait_of::type; + +} // namespace cml diff --git a/cml/common/memory_tags.h b/cml/common/memory_tags.h index bb04132..444fd8f 100644 --- a/cml/common/memory_tags.h +++ b/cml/common/memory_tags.h @@ -1,69 +1,69 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -/** Specify a type containing compile-time memory. */ -struct compiled_memory_tag -{}; - -/** Specify a type containing allocated memory. */ -struct allocated_memory_tag -{}; - -/** Specify a type containing externally referenced memory (pointer, - * reference, etc.). - */ -struct external_memory_tag -{}; - -/** Specify a type having arbitrary or unspecified memory. */ -struct any_memory_tag -{}; - -/** Detect valid memory tags. */ -template struct is_memory_tag -{ - static const bool value = std::is_same::value - || std::is_same::value - || std::is_same::value - || std::is_same::value; -}; - -/** Templated helper to determine the memory tag of an expression that - * defines the memory_tag type. - */ -template struct memory_tag_of -{ - using type = typename T::memory_tag; - static_assert(is_memory_tag::value, "invalid memory tag"); -}; - -/** Convenience alias for memory_tag_of. */ -template using memory_tag_of_t = typename memory_tag_of::type; - -/** Helper to detect compiled-memory types. */ -template struct is_compiled_memory -{ - static const bool value = - std::is_same, compiled_memory_tag>::value; -}; - -/** Helper to detect allocated-memory types. */ -template struct is_allocated_memory -{ - static const bool value = - std::is_same, allocated_memory_tag>::value; -}; - -/** Helper to detect external-memory types. */ -template struct is_external_memory -{ - static const bool value = - std::is_same, external_memory_tag>::value; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +/** Specify a type containing compile-time memory. */ +struct compiled_memory_tag +{}; + +/** Specify a type containing allocated memory. */ +struct allocated_memory_tag +{}; + +/** Specify a type containing externally referenced memory (pointer, + * reference, etc.). + */ +struct external_memory_tag +{}; + +/** Specify a type having arbitrary or unspecified memory. */ +struct any_memory_tag +{}; + +/** Detect valid memory tags. */ +template struct is_memory_tag +{ + static const bool value = std::is_same::value + || std::is_same::value + || std::is_same::value + || std::is_same::value; +}; + +/** Templated helper to determine the memory tag of an expression that + * defines the memory_tag type. + */ +template struct memory_tag_of +{ + using type = typename T::memory_tag; + static_assert(is_memory_tag::value, "invalid memory tag"); +}; + +/** Convenience alias for memory_tag_of. */ +template using memory_tag_of_t = typename memory_tag_of::type; + +/** Helper to detect compiled-memory types. */ +template struct is_compiled_memory +{ + static const bool value = + std::is_same, compiled_memory_tag>::value; +}; + +/** Helper to detect allocated-memory types. */ +template struct is_allocated_memory +{ + static const bool value = + std::is_same, allocated_memory_tag>::value; +}; + +/** Helper to detect external-memory types. */ +template struct is_external_memory +{ + static const bool value = + std::is_same, external_memory_tag>::value; +}; + +} // namespace cml diff --git a/cml/common/mpl/are_convertible.h b/cml/common/mpl/are_convertible.h index 569071d..c8347f9 100644 --- a/cml/common/mpl/are_convertible.h +++ b/cml/common/mpl/are_convertible.h @@ -1,29 +1,29 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Determine if a set of types, @c Froms, are convertible to another type, - * @c To via std::is_convertible. - */ -template struct are_convertible; - -/** Determine if @c From is convertible to @c To. */ -template -struct are_convertible : std::is_convertible -{}; - -/** Recursively determine if @c From and @c Froms are convertible to @c To. */ -template -struct are_convertible -{ - static const bool value = std::is_convertible::value - && are_convertible::value; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Determine if a set of types, @c Froms, are convertible to another type, + * @c To via std::is_convertible. + */ +template struct are_convertible; + +/** Determine if @c From is convertible to @c To. */ +template +struct are_convertible : std::is_convertible +{}; + +/** Recursively determine if @c From and @c Froms are convertible to @c To. */ +template +struct are_convertible +{ + static const bool value = std::is_convertible::value + && are_convertible::value; +}; + +} // namespace cml diff --git a/cml/common/mpl/are_same.h b/cml/common/mpl/are_same.h index cda5566..9f16660 100644 --- a/cml/common/mpl/are_same.h +++ b/cml/common/mpl/are_same.h @@ -1,29 +1,29 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Determine if a set of types, @c Froms, are the same as @c To via - * std::is_same. - */ -template struct are_same; - -/** Determine if @c From is the same as @c To. */ -template -struct are_same : std::is_same -{}; - -/** Recursively determine if @c From and @c Froms are the same as @c To. */ -template -struct are_same -{ - static const bool value = - std::is_same::value && are_same::value; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Determine if a set of types, @c Froms, are the same as @c To via + * std::is_same. + */ +template struct are_same; + +/** Determine if @c From is the same as @c To. */ +template +struct are_same : std::is_same +{}; + +/** Recursively determine if @c From and @c Froms are the same as @c To. */ +template +struct are_same +{ + static const bool value = + std::is_same::value && are_same::value; +}; + +} // namespace cml diff --git a/cml/common/mpl/enable_if_arithmetic.h b/cml/common/mpl/enable_if_arithmetic.h index dd62d43..6c1e916 100644 --- a/cml/common/mpl/enable_if_arithmetic.h +++ b/cml/common/mpl/enable_if_arithmetic.h @@ -1,22 +1,22 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Wrapper for enable_if to detect arithmetic types. @c T is tested after - * removing const, volatile, and reference qualifiers. - */ -template -struct enable_if_arithmetic : std::enable_if::value> -{}; - -/** Convenience alias for enable_if_arithmetic. */ -template -using enable_if_arithmetic_t = typename enable_if_arithmetic::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Wrapper for enable_if to detect arithmetic types. @c T is tested after + * removing const, volatile, and reference qualifiers. + */ +template +struct enable_if_arithmetic : std::enable_if::value> +{}; + +/** Convenience alias for enable_if_arithmetic. */ +template +using enable_if_arithmetic_t = typename enable_if_arithmetic::type; + +} // namespace cml diff --git a/cml/common/mpl/enable_if_array.h b/cml/common/mpl/enable_if_array.h index 18dd81d..2ac3551 100644 --- a/cml/common/mpl/enable_if_array.h +++ b/cml/common/mpl/enable_if_array.h @@ -1,24 +1,24 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Alias for std::enable_if using std::is_array to determine the - * boolean value. - */ -template -using enable_if_array = typename std::enable_if::value - && !std::is_pointer::value>; - -/** Alias for std::enable_if::type using std::is_array to determine - * the boolean value. - */ -template -using enable_if_array_t = typename enable_if_array::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Alias for std::enable_if using std::is_array to determine the + * boolean value. + */ +template +using enable_if_array = typename std::enable_if::value + && !std::is_pointer::value>; + +/** Alias for std::enable_if::type using std::is_array to determine + * the boolean value. + */ +template +using enable_if_array_t = typename enable_if_array::type; + +} // namespace cml diff --git a/cml/common/mpl/enable_if_convertible.h b/cml/common/mpl/enable_if_convertible.h index 98ff6b7..7da53cb 100644 --- a/cml/common/mpl/enable_if_convertible.h +++ b/cml/common/mpl/enable_if_convertible.h @@ -1,23 +1,23 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Convenience alias for enable_if to detect if a set of types, @c Froms, - * are convertible to @c To. - */ -template -using enable_if_convertible = - std::enable_if::value>; - -/** Convenience alias for enable_if_convertible. */ -template -using enable_if_convertible_t = - typename std::enable_if::value>::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Convenience alias for enable_if to detect if a set of types, @c Froms, + * are convertible to @c To. + */ +template +using enable_if_convertible = + std::enable_if::value>; + +/** Convenience alias for enable_if_convertible. */ +template +using enable_if_convertible_t = + typename std::enable_if::value>::type; + +} // namespace cml diff --git a/cml/common/mpl/enable_if_pointer.h b/cml/common/mpl/enable_if_pointer.h index c280849..272fb9d 100644 --- a/cml/common/mpl/enable_if_pointer.h +++ b/cml/common/mpl/enable_if_pointer.h @@ -1,24 +1,24 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Alias for std::enable_if using std::is_pointer to determine the - * boolean value. - */ -template -using enable_if_pointer = typename std::enable_if< - std::is_pointer::value && !std::is_array::value>; - -/** Alias for std::enable_if::type using std::is_pointer to determine - * the boolean value. - */ -template -using enable_if_pointer_t = typename enable_if_pointer::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Alias for std::enable_if using std::is_pointer to determine the + * boolean value. + */ +template +using enable_if_pointer = typename std::enable_if< + std::is_pointer::value && !std::is_array::value>; + +/** Alias for std::enable_if::type using std::is_pointer to determine + * the boolean value. + */ +template +using enable_if_pointer_t = typename enable_if_pointer::type; + +} // namespace cml diff --git a/cml/common/mpl/enable_if_reshapeable.h b/cml/common/mpl/enable_if_reshapeable.h index 6ae48a3..0d3bf7f 100644 --- a/cml/common/mpl/enable_if_reshapeable.h +++ b/cml/common/mpl/enable_if_reshapeable.h @@ -1,22 +1,22 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Wrapper for enable_if to detect if @c T implements resize(m,n), where m - * and n are convertible from int. - */ -template -struct enable_if_reshapeable : std::enable_if::value> -{}; - -/** Convenience alias for enable_if_reshapeable. */ -template -using enable_if_reshapeable_t = typename enable_if_reshapeable::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Wrapper for enable_if to detect if @c T implements resize(m,n), where m + * and n are convertible from int. + */ +template +struct enable_if_reshapeable : std::enable_if::value> +{}; + +/** Convenience alias for enable_if_reshapeable. */ +template +using enable_if_reshapeable_t = typename enable_if_reshapeable::type; + +} // namespace cml diff --git a/cml/common/mpl/enable_if_same.h b/cml/common/mpl/enable_if_same.h index ec24f1d..6615498 100644 --- a/cml/common/mpl/enable_if_same.h +++ b/cml/common/mpl/enable_if_same.h @@ -1,22 +1,22 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Wrapper for enable_if to detect if a set of types, @c Froms, are the - * same type as @c To. - */ -template -struct enable_if_same : std::enable_if::value> -{}; - -/** Convenience alias for enable_if_same. */ -template -using enable_if_same_t = typename enable_if_same::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Wrapper for enable_if to detect if a set of types, @c Froms, are the + * same type as @c To. + */ +template +struct enable_if_same : std::enable_if::value> +{}; + +/** Convenience alias for enable_if_same. */ +template +using enable_if_same_t = typename enable_if_same::type; + +} // namespace cml diff --git a/cml/common/mpl/enable_if_t.h b/cml/common/mpl/enable_if_t.h index 1c021ca..cc69802 100644 --- a/cml/common/mpl/enable_if_t.h +++ b/cml/common/mpl/enable_if_t.h @@ -1,18 +1,18 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Helper for enable_if. - * - * @todo use C++14 enable_if_t if available. - */ -template -using enable_if_t = typename std::enable_if::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Helper for enable_if. + * + * @todo use C++14 enable_if_t if available. + */ +template +using enable_if_t = typename std::enable_if::type; + +} // namespace cml diff --git a/cml/common/mpl/if_t.h b/cml/common/mpl/if_t.h index 4d8ca38..b24de21 100644 --- a/cml/common/mpl/if_t.h +++ b/cml/common/mpl/if_t.h @@ -1,17 +1,17 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Convenience alias to simplify conditionals. If B is true, then if_t - * takes the type of T. Otherwise, if_t takes the type of F. - */ -template -using if_t = typename std::conditional::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Convenience alias to simplify conditionals. If B is true, then if_t + * takes the type of T. Otherwise, if_t takes the type of F. + */ +template +using if_t = typename std::conditional::type; + +} // namespace cml diff --git a/cml/common/mpl/int_c.h b/cml/common/mpl/int_c.h index 77c517a..38c9c9e 100644 --- a/cml/common/mpl/int_c.h +++ b/cml/common/mpl/int_c.h @@ -1,19 +1,19 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Convenience "alias" for std::integral_constant. */ -template struct int_c : std::integral_constant -{}; - -// Note: As of now, Visual C++ (18.00) apparently can't handle the obvious -// alias when deducing function template arguments: -// template using int_c = std::integral_constant; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Convenience "alias" for std::integral_constant. */ +template struct int_c : std::integral_constant +{}; + +// Note: As of now, Visual C++ (18.00) apparently can't handle the obvious +// alias when deducing function template arguments: +// template using int_c = std::integral_constant; + +} // namespace cml diff --git a/cml/common/mpl/is_reshapeable.h b/cml/common/mpl/is_reshapeable.h index cdb471f..508defd 100644 --- a/cml/common/mpl/is_reshapeable.h +++ b/cml/common/mpl/is_reshapeable.h @@ -1,33 +1,33 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -/** Helper that defines @c type as std::true_type and @c value as true if - * @c T implements resize(m,n), where m and n are convertible from int. - */ -template struct is_reshapeable -{ - /* Overload resolution trickery to determine if T implements resize(): */ - - private: - template - static inline auto has_resize(X&&) - -> decltype(std::declval().actual().resize(0, 0), std::true_type()); - - template static inline auto has_resize(X...) -> std::false_type; - - public: - /** std::true_type if @c T has a compatible resize() method, - * std::false_type otherwise. - */ - using type = decltype(has_resize(std::declval())); - - /** true if @c T has a compatible resize() method, false otherwise. */ - static const int value = type::value; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +/** Helper that defines @c type as std::true_type and @c value as true if + * @c T implements resize(m,n), where m and n are convertible from int. + */ +template struct is_reshapeable +{ + /* Overload resolution trickery to determine if T implements resize(): */ + + private: + template + static inline auto has_resize(X&&) + -> decltype(std::declval().actual().resize(0, 0), std::true_type()); + + template static inline auto has_resize(X...) -> std::false_type; + + public: + /** std::true_type if @c T has a compatible resize() method, + * std::false_type otherwise. + */ + using type = decltype(has_resize(std::declval())); + + /** true if @c T has a compatible resize() method, false otherwise. */ + static const int value = type::value; +}; + +} // namespace cml diff --git a/cml/common/mpl/is_same_pair.h b/cml/common/mpl/is_same_pair.h index b68350e..cab1cd4 100644 --- a/cml/common/mpl/is_same_pair.h +++ b/cml/common/mpl/is_same_pair.h @@ -1,28 +1,28 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Defines @c value to true if @c is symmetrically identical to @c - * . - */ -template struct is_same_pair -{ - static const bool value = - (std::is_same::value && std::is_same::value) - || (std::is_same::value && std::is_same::value); -}; - -/** Specialization of is_same_pair for matching @c U1 and @c U2. */ -template struct is_same_pair -{ - static const bool value = - std::is_same::value && std::is_same::value; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Defines @c value to true if @c is symmetrically identical to @c + * . + */ +template struct is_same_pair +{ + static const bool value = + (std::is_same::value && std::is_same::value) + || (std::is_same::value && std::is_same::value); +}; + +/** Specialization of is_same_pair for matching @c U1 and @c U2. */ +template struct is_same_pair +{ + static const bool value = + std::is_same::value && std::is_same::value; +}; + +} // namespace cml diff --git a/cml/common/mpl/is_statically_polymorphic.h b/cml/common/mpl/is_statically_polymorphic.h index ccb8628..e25b0e1 100644 --- a/cml/common/mpl/is_statically_polymorphic.h +++ b/cml/common/mpl/is_statically_polymorphic.h @@ -1,38 +1,38 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Defines typedef @c type as std::true_type if @c T has a member function - * actual() that returns a reference type, or std::false_type otherwise. - * The static bool @c value is set to true or false to match @c type. - */ -template struct is_statically_polymorphic -{ - private: - /* SFINAE overload to deduce the return type of T::actual, if it exists. */ - template - static auto get_type_of_actual(int) -> decltype(std::declval().actual()); - - /* The default overload deduces a void return type. */ - template static auto get_type_of_actual(...) -> void; - - - public: - /* std::true_type if T::actual is a member function returning a - * reference type, std::false_type otherwise. - */ - using type = cml::if_t< - std::is_reference(0))>::value, - std::true_type, std::false_type>; - - /* True or false, depending upon 'type': */ - static const bool value = type::value; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Defines typedef @c type as std::true_type if @c T has a member function + * actual() that returns a reference type, or std::false_type otherwise. + * The static bool @c value is set to true or false to match @c type. + */ +template struct is_statically_polymorphic +{ + private: + /* SFINAE overload to deduce the return type of T::actual, if it exists. */ + template + static auto get_type_of_actual(int) -> decltype(std::declval().actual()); + + /* The default overload deduces a void return type. */ + template static auto get_type_of_actual(...) -> void; + + + public: + /* std::true_type if T::actual is a member function returning a + * reference type, std::false_type otherwise. + */ + using type = cml::if_t< + std::is_reference(0))>::value, + std::true_type, std::false_type>; + + /* True or false, depending upon 'type': */ + static const bool value = type::value; +}; + +} // namespace cml diff --git a/cml/common/mpl/item_at.h b/cml/common/mpl/item_at.h index 00b6696..dcc9cbb 100644 --- a/cml/common/mpl/item_at.h +++ b/cml/common/mpl/item_at.h @@ -1,20 +1,20 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Return item @c N of argument pack @c Args. */ -template -inline auto -item_at(Args&&... args) - -> decltype(std::get(std::forward_as_tuple(std::forward(args)...))) -{ - return std::get(std::forward_as_tuple(std::forward(args)...)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Return item @c N of argument pack @c Args. */ +template +inline auto +item_at(Args&&... args) + -> decltype(std::get(std::forward_as_tuple(std::forward(args)...))) +{ + return std::get(std::forward_as_tuple(std::forward(args)...)); +} + +} // namespace cml diff --git a/cml/common/mpl/plus_c.h b/cml/common/mpl/plus_c.h index a315e5e..365155a 100644 --- a/cml/common/mpl/plus_c.h +++ b/cml/common/mpl/plus_c.h @@ -1,19 +1,19 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -/** Helper to add two integral constants. - * - * @note This also avoids spurious VC14 "integral constant overflow" - * warnings. - */ -template struct plus_c -{ - static const int value = a + b; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +/** Helper to add two integral constants. + * + * @note This also avoids spurious VC14 "integral constant overflow" + * warnings. + */ +template struct plus_c +{ + static const int value = a + b; +}; + +} // namespace cml diff --git a/cml/common/mpl/rebind.h b/cml/common/mpl/rebind.h index 2c412aa..70c8d43 100644 --- a/cml/common/mpl/rebind.h +++ b/cml/common/mpl/rebind.h @@ -1,38 +1,38 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Helper to rebind @c T via template rebind. - * - * @note Only typed parameters are supported. - */ -template struct rebind -{ - using other = typename T::template rebind::other; -}; - -/** Convenience alias for rebind. */ -template -using rebind_t = typename rebind::other; - -/** Helper to rebind allocator @c T. - * - * @note Only typed parameters are supported. - */ -template struct rebind_alloc -{ - using traits = std::allocator_traits; - using other = typename traits::template rebind_alloc; -}; - -/** Convenience alias for rebind_alloc. */ -template -using rebind_alloc_t = typename rebind_alloc::other; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Helper to rebind @c T via template rebind. + * + * @note Only typed parameters are supported. + */ +template struct rebind +{ + using other = typename T::template rebind::other; +}; + +/** Convenience alias for rebind. */ +template +using rebind_t = typename rebind::other; + +/** Helper to rebind allocator @c T. + * + * @note Only typed parameters are supported. + */ +template struct rebind_alloc +{ + using traits = std::allocator_traits; + using other = typename traits::template rebind_alloc; +}; + +/** Convenience alias for rebind_alloc. */ +template +using rebind_alloc_t = typename rebind_alloc::other; + +} // namespace cml diff --git a/cml/common/mpl/type_map.h b/cml/common/mpl/type_map.h index 5f265cf..7a4197e 100644 --- a/cml/common/mpl/type_map.h +++ b/cml/common/mpl/type_map.h @@ -1,120 +1,120 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -#ifdef _MSC_VER -/* Disable "identifier too long" warning: */ -# pragma warning(push) -# pragma warning(disable : 4503) -#endif - -namespace cml { - -/** A bijective mapping of unique types, using a list of arbitrary items as - * the source of the mapping. Types in @c Entries must define @c first and - * @c second, where @c first and @c second are the mapped types. For - * example: - * - * @code - * template struct item { - * typedef T1 first; - * typedef T2 second; - * }; - * @endcode - */ -template class type_map -{ - public: - /** The type of @c type_map::find::type. */ - template struct result_type - { - /** The found type. Only valid if @c value is true. */ - using type = T; - - /** @c value is true if @c type is in the table, false otherwise. */ - enum - { - value = Found - }; - }; - - - public: - /** Type-compare @c T to @c Entry::first. @c value is set to the - * comparison result. - */ - template struct match - { - using first = typename Entry::first; - static const bool value = std::is_same::value; - }; - - - private: - /** The internal find<> helper. */ - template class Map, typename T, class... Rest> struct _find; - - template struct map_first - { - using first = typename E::first; - using second = typename E::second; - }; - - template struct map_second - { - using first = typename E::second; - using second = typename E::first; - }; - - - public: - /** Search the @c first type of the map entries for T. If the match is - * found, @c type is set to <@c T2, true>, where @c T2 is the @c first - * type of the matching Entry. Otherwise, @c type is set to - * . - */ - template struct find_first - { - using type = typename _find::type; - }; - - template struct find_second - { - using type = typename _find::type; - }; - - - private: - /** Match @c T to @c Entry, and recursively to @c Rest. */ - template class Map, typename T, class Entry, class... Rest> - struct _find - { - using map_type = Map; - static const bool found = match::value; - using type = cml::if_t, - typename _find::type>; - }; - - /** The not-found case. */ - template class Map, typename T> struct _find - { - using type = result_type; - }; -}; - -/** Basic implementation of a type_map entry. */ -template struct type_map_item -{ - using first = T1; - using second = T2; -}; - -} // namespace cml - -#ifdef _MSC_VER -# pragma warning(pop) -#endif +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +#ifdef _MSC_VER +/* Disable "identifier too long" warning: */ +# pragma warning(push) +# pragma warning(disable : 4503) +#endif + +namespace cml { + +/** A bijective mapping of unique types, using a list of arbitrary items as + * the source of the mapping. Types in @c Entries must define @c first and + * @c second, where @c first and @c second are the mapped types. For + * example: + * + * @code + * template struct item { + * typedef T1 first; + * typedef T2 second; + * }; + * @endcode + */ +template class type_map +{ + public: + /** The type of @c type_map::find::type. */ + template struct result_type + { + /** The found type. Only valid if @c value is true. */ + using type = T; + + /** @c value is true if @c type is in the table, false otherwise. */ + enum + { + value = Found + }; + }; + + + public: + /** Type-compare @c T to @c Entry::first. @c value is set to the + * comparison result. + */ + template struct match + { + using first = typename Entry::first; + static const bool value = std::is_same::value; + }; + + + private: + /** The internal find<> helper. */ + template class Map, typename T, class... Rest> struct _find; + + template struct map_first + { + using first = typename E::first; + using second = typename E::second; + }; + + template struct map_second + { + using first = typename E::second; + using second = typename E::first; + }; + + + public: + /** Search the @c first type of the map entries for T. If the match is + * found, @c type is set to <@c T2, true>, where @c T2 is the @c first + * type of the matching Entry. Otherwise, @c type is set to + * . + */ + template struct find_first + { + using type = typename _find::type; + }; + + template struct find_second + { + using type = typename _find::type; + }; + + + private: + /** Match @c T to @c Entry, and recursively to @c Rest. */ + template class Map, typename T, class Entry, class... Rest> + struct _find + { + using map_type = Map; + static const bool found = match::value; + using type = cml::if_t, + typename _find::type>; + }; + + /** The not-found case. */ + template class Map, typename T> struct _find + { + using type = result_type; + }; +}; + +/** Basic implementation of a type_map entry. */ +template struct type_map_item +{ + using first = T1; + using second = T2; +}; + +} // namespace cml + +#ifdef _MSC_VER +# pragma warning(pop) +#endif diff --git a/cml/common/mpl/type_table.h b/cml/common/mpl/type_table.h index 37b5f64..369e6a7 100644 --- a/cml/common/mpl/type_table.h +++ b/cml/common/mpl/type_table.h @@ -1,107 +1,107 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -#ifdef _MSC_VER -/* Disable "identifier too long" warning: */ -# pragma warning(push) -# pragma warning(disable : 4503) -#endif - -namespace cml { - -/** A symmetric mapping of type pairs to a new type, using a list of - * arbitrary items as the source of the mapping. Types in @c Entries must - * define @c first, @c second, and @c type, where @c first and @c second - * are the map-from types, and @c type is the map-to type. For example: - * - * @code - * template struct item { - * typedef T1 first; - * typedef T2 second; - * typedef T type; - * }; - * @endcode - */ -template class type_table -{ - public: - /** The type of @c type_table::find::type. */ - template struct result_type - { - /** The found type. Only valid if @c value is true. */ - using type = T; - - /** @c value is true if @c type is in the table, false otherwise. */ - enum - { - value = Found - }; - }; - - - public: - /** Type-compare <@c Ta,@c Tb> to <@c Entry::first,@c Entry::second> - * using std::is_same, ignoring order. @c value is set to the - * comparison result. - */ - template struct match - { - using first = typename Entry::first; - using second = typename Entry::second; - static const bool value = - (std::is_same::value && std::is_same::value) - || (std::is_same::value && std::is_same::value); - }; - - - private: - /** The internal find<> helper. */ - template struct _find; - - - public: - /** Search the table for type pair <@c T1, @c T2>. If the pair is - * found, @c type is set to <@c T, true>, where @c T is the mapped-to - * type. Otherwise, @c type is set to . - */ - template struct find - { - using type = typename _find::type; - }; - - - private: - /** Match <@c T1, @c T2> to @c Entry, and recursively to @c Rest. */ - template - struct _find - { - static const bool found = match::value; - using type = cml::if_t, - typename _find::type>; - }; - - /** The not-found case. */ - template struct _find - { - using type = result_type; - }; -}; - -/** Basic implementation of a type_table entry. */ -template struct type_table_item -{ - using first = T1; - using second = T2; - using type = T; -}; - -} // namespace cml - -#ifdef _MSC_VER -# pragma warning(pop) -#endif +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +#ifdef _MSC_VER +/* Disable "identifier too long" warning: */ +# pragma warning(push) +# pragma warning(disable : 4503) +#endif + +namespace cml { + +/** A symmetric mapping of type pairs to a new type, using a list of + * arbitrary items as the source of the mapping. Types in @c Entries must + * define @c first, @c second, and @c type, where @c first and @c second + * are the map-from types, and @c type is the map-to type. For example: + * + * @code + * template struct item { + * typedef T1 first; + * typedef T2 second; + * typedef T type; + * }; + * @endcode + */ +template class type_table +{ + public: + /** The type of @c type_table::find::type. */ + template struct result_type + { + /** The found type. Only valid if @c value is true. */ + using type = T; + + /** @c value is true if @c type is in the table, false otherwise. */ + enum + { + value = Found + }; + }; + + + public: + /** Type-compare <@c Ta,@c Tb> to <@c Entry::first,@c Entry::second> + * using std::is_same, ignoring order. @c value is set to the + * comparison result. + */ + template struct match + { + using first = typename Entry::first; + using second = typename Entry::second; + static const bool value = + (std::is_same::value && std::is_same::value) + || (std::is_same::value && std::is_same::value); + }; + + + private: + /** The internal find<> helper. */ + template struct _find; + + + public: + /** Search the table for type pair <@c T1, @c T2>. If the pair is + * found, @c type is set to <@c T, true>, where @c T is the mapped-to + * type. Otherwise, @c type is set to . + */ + template struct find + { + using type = typename _find::type; + }; + + + private: + /** Match <@c T1, @c T2> to @c Entry, and recursively to @c Rest. */ + template + struct _find + { + static const bool found = match::value; + using type = cml::if_t, + typename _find::type>; + }; + + /** The not-found case. */ + template struct _find + { + using type = result_type; + }; +}; + +/** Basic implementation of a type_table entry. */ +template struct type_table_item +{ + using first = T1; + using second = T2; + using type = T; +}; + +} // namespace cml + +#ifdef _MSC_VER +# pragma warning(pop) +#endif diff --git a/cml/common/promotion.h b/cml/common/promotion.h index 56b807e..d8f9c8c 100644 --- a/cml/common/promotion.h +++ b/cml/common/promotion.h @@ -1,196 +1,196 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace cml { - -/** Deduce the size tag needed to compare the size of two expressions - * having size tags @c Tag1 and @c Tag2. By default: - * - * - any_size_tag with any other tag: any_size_tag - * - fixed_size_tag with fixed_size_tag: fixed_size_tag - * - otherwise: dynamic_size_tag - */ -template struct size_check_promote -{ - static_assert(is_size_tag::value, "invalid size tag"); - static_assert(is_size_tag::value, "invalid size tag"); - - /* Promote to any_size_tag when combined with any other tag: */ - static const bool is_any = std::is_same::value - || std::is_same::value; - - /* Promote to fixed_size_tag when combining two fixed-size expressions: */ - static const bool is_fixed = std::is_same::value - && std::is_same::value; - - /* Promote to dynamic_size_tag by default if not promoting to - * any_size_tag or fixed_size_tag: - */ - using type = cml::if_t>; -}; - -/** Convenience alias for size_check_promote. */ -template -using size_check_promote_t = typename size_check_promote::type; - -/** Deduce the default size tag needed to promote the result of combining - * two expressions having size tags @c Tag1 and @c Tag2. By default: - * - * - fixed_size_tag with any other tag: fixed_size_tag - * - dynamic_size_tag with any other tag: dynamic_size_tag - * - any_size_tag with any_size_tag: any_size_tag - */ -template struct size_tag_promote -{ - static_assert(is_size_tag::value, "invalid size tag"); - static_assert(is_size_tag::value, "invalid size tag"); - - /* Fixed-size with any other tag promotes to fixed-size: */ - static const bool is_fixed = std::is_same::value - || std::is_same::value; - - /* Promote to dynamic if not promoting to fixed, and if at least one of - * the size tags is dynamic_size_tag: - */ - static const bool is_dynamic = !is_fixed - && (std::is_same::value - || std::is_same::value); - - /* Promote to any_size_tag when both are any_size_tag: */ - static const bool is_any = std::is_same::value - && std::is_same::value; - - /* Has to be one of the deduced categories: */ - static_assert(is_fixed || is_dynamic || is_any, "unexpected size tag type"); - - /* Promote to the selected tag: */ - using type = cml::if_t>; -}; - -/** Convenience alias for size_tag_promote. */ -template -using size_tag_promote_t = typename size_tag_promote::type; - -/** Deduce the default size tag needed to promote the result of combining - * two expressions @c T1 and @c T2 with traits that define the size_tag - * type. - */ -template struct size_tag_trait_promote -{ - using type = size_tag_promote_t, size_tag_trait_of_t>; -}; - -/** Convenience alias for size_tag_trait_promote. */ -template -using size_tag_trait_promote_t = typename size_tag_trait_promote::type; - -/** Deduce the default basis tag needed to promote the result of combining - * two expressions having basis tags @c Tag1 and @c Tag2. By default: - * - * - both row_basis, or row_basis with any_basis: row_basis - * - both col_basis, or col_basis with any_basis: col_basis - * - otherwise: any_basis - */ -template struct basis_tag_promote -{ - static_assert(is_basis_tag::value, "invalid basis tag"); - static_assert(is_basis_tag::value, "invalid basis tag"); - - /* True if possible to promote to row_basis: */ - static const bool is_row_basis = is_same_pair::value - || is_same_pair::value; - - /* True if possible to promote to col_basis: */ - static const bool is_col_basis = is_same_pair::value - || is_same_pair::value; - - /* At least one has to be false: */ - static_assert(!is_row_basis || !is_col_basis, "invalid basis promotion"); - - /* Promote to the selected basis, or any_basis otherwise: */ - using type = cml::if_t>; -}; - -/** Convenience alias for basis_tag_promote. */ -template -using basis_tag_promote_t = typename basis_tag_promote::type; - -/** Deduce the default basis tag needed to promote the result of combining - * two expressions @c T1 and @c T2 with traits that define the basis_tag - * type. - */ -template struct basis_tag_trait_promote -{ - using type = basis_tag_promote_t, - basis_tag_trait_of_t>; -}; - -/** Convenience alias for basis_tag_trait_promote. */ -template -using basis_tag_trait_promote_t = - typename basis_tag_trait_promote::type; - -/** Deduce the default layout tag needed to promote the result of combining - * two expressions having layout tags @c Tag1 and @c Tag2. By default: - * - * - both row_major, or row_major with any_major: row_major - * - both col_major, or col_major with any_major: col_major - * - otherwise: any_major - */ -template struct layout_tag_promote -{ - static_assert(is_layout_tag::value, "invalid layout tag"); - static_assert(is_layout_tag::value, "invalid layout tag"); - - /* True if possible to promote to row_major: */ - static const bool is_row_major = is_same_pair::value - || is_same_pair::value; - - /* True if possible to promote to col_major: */ - static const bool is_col_major = is_same_pair::value - || is_same_pair::value; - - /* At least one has to be false: */ - static_assert(!is_row_major || !is_col_major, "invalid layout promotion"); - - /* Promote to the selected layout, or any_major otherwise: */ - using type = cml::if_t>; -}; - -/** Convenience alias for layout_tag_promote. */ -template -using layout_tag_promote_t = typename layout_tag_promote::type; - -/** Deduce the default layout tag needed to promote the result of combining - * two expressions @c T1 and @c T2 with traits that define the layout_tag - * type. - */ -template struct layout_tag_trait_promote -{ - using type = layout_tag_promote_t, - layout_tag_trait_of_t>; -}; - -/** Convenience alias for layout_tag_trait_promote. */ -template -using layout_tag_trait_promote_t = - typename layout_tag_trait_promote::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace cml { + +/** Deduce the size tag needed to compare the size of two expressions + * having size tags @c Tag1 and @c Tag2. By default: + * + * - any_size_tag with any other tag: any_size_tag + * - fixed_size_tag with fixed_size_tag: fixed_size_tag + * - otherwise: dynamic_size_tag + */ +template struct size_check_promote +{ + static_assert(is_size_tag::value, "invalid size tag"); + static_assert(is_size_tag::value, "invalid size tag"); + + /* Promote to any_size_tag when combined with any other tag: */ + static const bool is_any = std::is_same::value + || std::is_same::value; + + /* Promote to fixed_size_tag when combining two fixed-size expressions: */ + static const bool is_fixed = std::is_same::value + && std::is_same::value; + + /* Promote to dynamic_size_tag by default if not promoting to + * any_size_tag or fixed_size_tag: + */ + using type = cml::if_t>; +}; + +/** Convenience alias for size_check_promote. */ +template +using size_check_promote_t = typename size_check_promote::type; + +/** Deduce the default size tag needed to promote the result of combining + * two expressions having size tags @c Tag1 and @c Tag2. By default: + * + * - fixed_size_tag with any other tag: fixed_size_tag + * - dynamic_size_tag with any other tag: dynamic_size_tag + * - any_size_tag with any_size_tag: any_size_tag + */ +template struct size_tag_promote +{ + static_assert(is_size_tag::value, "invalid size tag"); + static_assert(is_size_tag::value, "invalid size tag"); + + /* Fixed-size with any other tag promotes to fixed-size: */ + static const bool is_fixed = std::is_same::value + || std::is_same::value; + + /* Promote to dynamic if not promoting to fixed, and if at least one of + * the size tags is dynamic_size_tag: + */ + static const bool is_dynamic = !is_fixed + && (std::is_same::value + || std::is_same::value); + + /* Promote to any_size_tag when both are any_size_tag: */ + static const bool is_any = std::is_same::value + && std::is_same::value; + + /* Has to be one of the deduced categories: */ + static_assert(is_fixed || is_dynamic || is_any, "unexpected size tag type"); + + /* Promote to the selected tag: */ + using type = cml::if_t>; +}; + +/** Convenience alias for size_tag_promote. */ +template +using size_tag_promote_t = typename size_tag_promote::type; + +/** Deduce the default size tag needed to promote the result of combining + * two expressions @c T1 and @c T2 with traits that define the size_tag + * type. + */ +template struct size_tag_trait_promote +{ + using type = size_tag_promote_t, size_tag_trait_of_t>; +}; + +/** Convenience alias for size_tag_trait_promote. */ +template +using size_tag_trait_promote_t = typename size_tag_trait_promote::type; + +/** Deduce the default basis tag needed to promote the result of combining + * two expressions having basis tags @c Tag1 and @c Tag2. By default: + * + * - both row_basis, or row_basis with any_basis: row_basis + * - both col_basis, or col_basis with any_basis: col_basis + * - otherwise: any_basis + */ +template struct basis_tag_promote +{ + static_assert(is_basis_tag::value, "invalid basis tag"); + static_assert(is_basis_tag::value, "invalid basis tag"); + + /* True if possible to promote to row_basis: */ + static const bool is_row_basis = is_same_pair::value + || is_same_pair::value; + + /* True if possible to promote to col_basis: */ + static const bool is_col_basis = is_same_pair::value + || is_same_pair::value; + + /* At least one has to be false: */ + static_assert(!is_row_basis || !is_col_basis, "invalid basis promotion"); + + /* Promote to the selected basis, or any_basis otherwise: */ + using type = cml::if_t>; +}; + +/** Convenience alias for basis_tag_promote. */ +template +using basis_tag_promote_t = typename basis_tag_promote::type; + +/** Deduce the default basis tag needed to promote the result of combining + * two expressions @c T1 and @c T2 with traits that define the basis_tag + * type. + */ +template struct basis_tag_trait_promote +{ + using type = basis_tag_promote_t, + basis_tag_trait_of_t>; +}; + +/** Convenience alias for basis_tag_trait_promote. */ +template +using basis_tag_trait_promote_t = + typename basis_tag_trait_promote::type; + +/** Deduce the default layout tag needed to promote the result of combining + * two expressions having layout tags @c Tag1 and @c Tag2. By default: + * + * - both row_major, or row_major with any_major: row_major + * - both col_major, or col_major with any_major: col_major + * - otherwise: any_major + */ +template struct layout_tag_promote +{ + static_assert(is_layout_tag::value, "invalid layout tag"); + static_assert(is_layout_tag::value, "invalid layout tag"); + + /* True if possible to promote to row_major: */ + static const bool is_row_major = is_same_pair::value + || is_same_pair::value; + + /* True if possible to promote to col_major: */ + static const bool is_col_major = is_same_pair::value + || is_same_pair::value; + + /* At least one has to be false: */ + static_assert(!is_row_major || !is_col_major, "invalid layout promotion"); + + /* Promote to the selected layout, or any_major otherwise: */ + using type = cml::if_t>; +}; + +/** Convenience alias for layout_tag_promote. */ +template +using layout_tag_promote_t = typename layout_tag_promote::type; + +/** Deduce the default layout tag needed to promote the result of combining + * two expressions @c T1 and @c T2 with traits that define the layout_tag + * type. + */ +template struct layout_tag_trait_promote +{ + using type = layout_tag_promote_t, + layout_tag_trait_of_t>; +}; + +/** Convenience alias for layout_tag_trait_promote. */ +template +using layout_tag_trait_promote_t = + typename layout_tag_trait_promote::type; + +} // namespace cml diff --git a/cml/common/size_tags.h b/cml/common/size_tags.h index 5e81018..7a1c07e 100644 --- a/cml/common/size_tags.h +++ b/cml/common/size_tags.h @@ -1,121 +1,125 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Indicates a fixed-sized operand. - * - * @note Fixed-size vector types define a constant, @c array_size, - * containing the array length. - * - * @note Fixed-size matrix types define two constants, @c array_rows and @c - * array_cols, containing the number of rows and columns. - */ -struct fixed_size_tag -{}; - -/** Indicates a runtime-sized operand. - * - * @note Dynamic-size vector types define a constant, @c array_size, set to - * -1. - * - * @note Dynamic-size matrices define two constants, @c array_rows and @c - * array_cols, both set to -1. - */ -struct dynamic_size_tag -{}; - -/** Indicates that the vector or matrix type has an unspecified or - * arbitrary size tag. - */ -struct any_size_tag -{}; - -/** Detect valid size tags. - * - * @note This can be specialized for user-defined size tags. - */ -template struct is_size_tag -{ - static const bool value = std::is_same::value - || std::is_same::value - || std::is_same::value; -}; - -/** Templated helper to determine the size tag of an expression that - * defines the size_tag type. - */ -template struct size_tag_of -{ - using type = typename T::size_tag; - static_assert(is_size_tag::value, "invalid size tag"); -}; - -/** Convenience alias for size_tag_of. */ -template using size_tag_of_t = typename size_tag_of::type; - -/** Retrieve the size_tag of @c T via traits. */ -template struct size_tag_trait_of -{ - using type = typename traits_of::type::size_tag; - static_assert(is_size_tag::value, "invalid size tag"); -}; - -/** Convenience alias for size_tag_trait_of. */ -template -using size_tag_trait_of_t = typename size_tag_trait_of::type; - -/** Helper to detect fixed-size types. */ -template struct is_fixed_size -{ - static const bool value = - std::is_same, fixed_size_tag>::value; -}; - -/** Wrapper for enable_if to detect types tagged with fixed_size_tag. */ -template -struct enable_if_fixed_size : std::enable_if::value, T> -{}; - -/** Convenience alias for enable_if_fixed_size. */ -template -using enable_if_fixed_size_t = typename enable_if_fixed_size::type; - -/** Helper to detect dynamic-size types. */ -template struct is_dynamic_size -{ - static const bool value = - std::is_same, dynamic_size_tag>::value; -}; - -/** Wrapper for enable_if to detect types tagged with dynamic_size_tag. */ -template -struct enable_if_dynamic_size : std::enable_if::value, T> -{}; - -/** Convenience alias for enable_if_dynamic_size. */ -template -using enable_if_dynamic_size_t = typename enable_if_dynamic_size::type; - -/** Helper to detect any-size types. */ -template struct is_any_size -{ - static const bool value = std::is_same, any_size_tag>::value; -}; - -/** Wrapper for enable_if to detect types tagged with any_size_tag. */ -template -struct enable_if_any_size : std::enable_if::value, T> -{}; - -/** Convenience alias for enable_if_any_size. */ -template -using enable_if_any_size_t = typename enable_if_any_size::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Indicates a fixed-sized operand. + * + * @note Fixed-size vector types define a constant, @c array_size, + * containing the array length. + * + * @note Fixed-size matrix types define two constants, @c array_rows and @c + * array_cols, containing the number of rows and columns. + */ +struct fixed_size_tag +{}; + +/** Indicates a runtime-sized operand. + * + * @note Dynamic-size vector types define a constant, @c array_size, set to + * -1. + * + * @note Dynamic-size matrices define two constants, @c array_rows and @c + * array_cols, both set to -1. + */ +struct dynamic_size_tag +{}; + +/** Indicates that the vector or matrix type has an unspecified or + * arbitrary size tag. + */ +struct any_size_tag +{}; + +/** Detect valid size tags. + * + * @note This can be specialized for user-defined size tags. + */ +template struct is_size_tag +{ + static const bool value = std::is_same::value + || std::is_same::value + || std::is_same::value; +}; + +/** Templated helper to determine the size tag of an expression that + * defines the size_tag type. + */ +template struct size_tag_of +{ + using type = typename T::size_tag; + static_assert(is_size_tag::value, "invalid size tag"); +}; + +/** Convenience alias for size_tag_of. */ +template using size_tag_of_t = typename size_tag_of::type; + +/** Retrieve the size_tag of @c T via traits. */ +template struct size_tag_trait_of +{ + using type = typename traits_of::type::size_tag; + static_assert(is_size_tag::value, "invalid size tag"); +}; + +/** Convenience alias for size_tag_trait_of. */ +template +using size_tag_trait_of_t = typename size_tag_trait_of::type; + +/** Helper to detect fixed-size types. */ +template struct is_fixed_size +{ + static const bool value = + std::is_same, fixed_size_tag>::value; +}; + +/** Helper to detect fixed-size types. */ +template constexpr auto is_fixed_size_v + = is_fixed_size::value; + +/** Wrapper for enable_if to detect types tagged with fixed_size_tag. */ +template +struct enable_if_fixed_size : std::enable_if::value, T> +{}; + +/** Convenience alias for enable_if_fixed_size. */ +template +using enable_if_fixed_size_t = typename enable_if_fixed_size::type; + +/** Helper to detect dynamic-size types. */ +template struct is_dynamic_size +{ + static const bool value = + std::is_same, dynamic_size_tag>::value; +}; + +/** Wrapper for enable_if to detect types tagged with dynamic_size_tag. */ +template +struct enable_if_dynamic_size : std::enable_if::value, T> +{}; + +/** Convenience alias for enable_if_dynamic_size. */ +template +using enable_if_dynamic_size_t = typename enable_if_dynamic_size::type; + +/** Helper to detect any-size types. */ +template struct is_any_size +{ + static const bool value = std::is_same, any_size_tag>::value; +}; + +/** Wrapper for enable_if to detect types tagged with any_size_tag. */ +template +struct enable_if_any_size : std::enable_if::value, T> +{}; + +/** Convenience alias for enable_if_any_size. */ +template +using enable_if_any_size_t = typename enable_if_any_size::type; + +} // namespace cml diff --git a/cml/common/storage_tags.h b/cml/common/storage_tags.h index e5af02f..8f138d1 100644 --- a/cml/common/storage_tags.h +++ b/cml/common/storage_tags.h @@ -1,64 +1,64 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Specify vector storage types. */ -struct vector_storage_tag -{}; - -/** Specify matrix storage types. */ -struct matrix_storage_tag -{}; - -/** Specify quaternion storage types. */ -struct quaternion_storage_tag -{}; - -/** Detect valid storage tags. */ -template struct is_storage_tag -{ - static const bool value = std::is_same::value - || std::is_same::value - || std::is_same::value; -}; - -/** Templated helper to determine the storage tag of an expression that - * defines the storage_tag type. - */ -template struct storage_tag_of -{ - using type = typename T::storage_tag; - static_assert(is_storage_tag::value, "invalid storage tag"); -}; - -/** Convenience alias for storage_tag_of. */ -template using storage_tag_of_t = typename storage_tag_of::type; - -/** Helper to detect vector storage types. */ -template struct is_vector_storage -{ - static const bool value = - std::is_same, vector_storage_tag>::value; -}; - -/** Helper to detect matrix storage types. */ -template struct is_matrix_storage -{ - static const bool value = - std::is_same, matrix_storage_tag>::value; -}; - -/** Helper to detect quaternion storage types. */ -template struct is_quaternion_storage -{ - static const bool value = - std::is_same, quaternion_storage_tag>::value; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Specify vector storage types. */ +struct vector_storage_tag +{}; + +/** Specify matrix storage types. */ +struct matrix_storage_tag +{}; + +/** Specify quaternion storage types. */ +struct quaternion_storage_tag +{}; + +/** Detect valid storage tags. */ +template struct is_storage_tag +{ + static const bool value = std::is_same::value + || std::is_same::value + || std::is_same::value; +}; + +/** Templated helper to determine the storage tag of an expression that + * defines the storage_tag type. + */ +template struct storage_tag_of +{ + using type = typename T::storage_tag; + static_assert(is_storage_tag::value, "invalid storage tag"); +}; + +/** Convenience alias for storage_tag_of. */ +template using storage_tag_of_t = typename storage_tag_of::type; + +/** Helper to detect vector storage types. */ +template struct is_vector_storage +{ + static const bool value = + std::is_same, vector_storage_tag>::value; +}; + +/** Helper to detect matrix storage types. */ +template struct is_matrix_storage +{ + static const bool value = + std::is_same, matrix_storage_tag>::value; +}; + +/** Helper to detect quaternion storage types. */ +template struct is_quaternion_storage +{ + static const bool value = + std::is_same, quaternion_storage_tag>::value; +}; + +} // namespace cml diff --git a/cml/common/temporary.h b/cml/common/temporary.h index de33e8b..c3a7aa2 100644 --- a/cml/common/temporary.h +++ b/cml/common/temporary.h @@ -1,18 +1,18 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -/** Specializable struct to obtain a temporary for a specified expression - * type, possibly using SFINAE. Specializations should typedef "type" as a - * temporary for @c T. - */ -template struct temporary_of; - -/** Convenience alias for temporary_of. */ -template using temporary_of_t = typename temporary_of::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +/** Specializable struct to obtain a temporary for a specified expression + * type, possibly using SFINAE. Specializations should typedef "type" as a + * temporary for @c T. + */ +template struct temporary_of; + +/** Convenience alias for temporary_of. */ +template using temporary_of_t = typename temporary_of::type; + +} // namespace cml diff --git a/cml/common/traits.h b/cml/common/traits.h index b710204..b9bab79 100644 --- a/cml/common/traits.h +++ b/cml/common/traits.h @@ -24,10 +24,10 @@ template struct value_type_of using type = typename T::value_type; }; -/** Convenience alias for value_typet_of. */ +/** Convenience alias for value_type_of. */ template using value_type_of_t = typename value_type_of::type; -/** Retrieve the value_type of @c T via traits. +/** Retrieve the value_type of @c T via traits. * * @note This applies to CML expression types, including scalars. */ diff --git a/cml/common/type_util.h b/cml/common/type_util.h index b4888cd..7f80428 100644 --- a/cml/common/type_util.h +++ b/cml/common/type_util.h @@ -1,83 +1,83 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Remove const-volatile and reference types from @c T, but leave array and - * function pointer types alone. - */ -template struct unqualified_type -{ - using type = typename std::remove_cv::type>::type; -}; - -/** Convenience alias for unqualified_type. */ -template -using unqualified_type_t = typename cml::unqualified_type::type; - -/** Deduce the derived type of a statically polymorphic type @c T from the - * reference return type of @c T::actual, if defined. If @c T does not - * implement @c T::actual having a reference return type, then @c type is - * defined as the unqualified base type of @c T. - */ -template struct actual_type_of -{ - private: - /* Strip const, volatile, and reference from T to get the return type - * of T::actual: - */ - using naked_type = cml::unqualified_type_t; - - /* SFINAE overload to deduce the return type of T::actual, if it exists. */ - template - static auto get_naked_type_of_actual(int) - -> cml::unqualified_type_t().actual())>; - - /* The default overload deduces a void return type. */ - template static auto get_naked_type_of_actual(...) -> void; - - - public: - /* Deduce the return type of T::actual: */ - using type = cml::if_t::value, - decltype(get_naked_type_of_actual(0)), naked_type>; -}; - -/** Convenience alias for actual_type_of<>. */ -template using actual_type_of_t = typename actual_type_of::type; - -/** If @c T is a reference type, @c type is defined as a reference to the - * derived type of a statically polymorphic type @c T, or as @c T for other - * types. For example, if @c T is readable_matrix&, then @c type is S&. - * The const-ness of @c T is maintained for lvalue references. - */ -template struct actual_operand_type_of -{ - private: - static_assert(std::is_reference::value, "T is not a reference type"); - - /* Possibly const, non-reference type: */ - using base_type = typename std::remove_reference::type; - - /* Derived type of T: */ - using actual_type = actual_type_of_t; - - - public: - /* Build the reference type: */ - using type = cml::if_t::value, actual_type&&, - cml::if_t::value, const actual_type&, - actual_type&>>; -}; - -/** Convenience alias for actual_operand_type_of<>. */ -template -using actual_operand_type_of_t = typename actual_operand_type_of::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Remove const-volatile and reference types from @c T, but leave array and + * function pointer types alone. + */ +template struct unqualified_type +{ + using type = typename std::remove_cv::type>::type; +}; + +/** Convenience alias for unqualified_type. */ +template +using unqualified_type_t = typename cml::unqualified_type::type; + +/** Deduce the derived type of a statically polymorphic type @c T from the + * reference return type of @c T::actual, if defined. If @c T does not + * implement @c T::actual having a reference return type, then @c type is + * defined as the unqualified base type of @c T. + */ +template struct actual_type_of +{ + private: + /* Strip const, volatile, and reference from T to get the return type + * of T::actual: + */ + using naked_type = cml::unqualified_type_t; + + /* SFINAE overload to deduce the return type of T::actual, if it exists. */ + template + static auto get_naked_type_of_actual(int) + -> cml::unqualified_type_t().actual())>; + + /* The default overload deduces a void return type. */ + template static auto get_naked_type_of_actual(...) -> void; + + + public: + /* Deduce the return type of T::actual: */ + using type = cml::if_t::value, + decltype(get_naked_type_of_actual(0)), naked_type>; +}; + +/** Convenience alias for actual_type_of<>. */ +template using actual_type_of_t = typename actual_type_of::type; + +/** If @c T is a reference type, @c type is defined as a reference to the + * derived type of a statically polymorphic type @c T, or as @c T for other + * types. For example, if @c T is readable_matrix&, then @c type is S&. + * The const-ness of @c T is maintained for lvalue references. + */ +template struct actual_operand_type_of +{ + private: + static_assert(std::is_reference::value, "T is not a reference type"); + + /* Possibly const, non-reference type: */ + using base_type = typename std::remove_reference::type; + + /* Derived type of T: */ + using actual_type = actual_type_of_t; + + + public: + /* Build the reference type: */ + using type = cml::if_t::value, actual_type&&, + cml::if_t::value, const actual_type&, + actual_type&>>; +}; + +/** Convenience alias for actual_operand_type_of<>. */ +template +using actual_operand_type_of_t = typename actual_operand_type_of::type; + +} // namespace cml diff --git a/cml/mathlib/axis_order.h b/cml/mathlib/axis_order.h index a0f6296..e427cab 100644 --- a/cml/mathlib/axis_order.h +++ b/cml/mathlib/axis_order.h @@ -1,79 +1,79 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Specify 3D axis ordering. */ -enum axis_order -{ - axis_order_xyz = euler_order_xyz, // 0x00 [0000] - axis_order_xzy = euler_order_xzy, // 0x02 [0010] - axis_order_yzx = euler_order_yzx, // 0x04 [0100] - axis_order_yxz = euler_order_yxz, // 0x06 [0110] - axis_order_zxy = euler_order_zxy, // 0x08 [1000] - axis_order_zyx = euler_order_zyx // 0x0A [1010] -}; - -/** Specify 2D axis ordering. */ -enum axis_order2D -{ - axis_order_xy = axis_order_xyz, // 0x00 [0000] - axis_order_yx = axis_order_yxz, // 0x06 [0110] -}; - -/** For CML1 compatibility. */ -using AxisOrder = axis_order; -using AxisOrder2D = axis_order2D; - -inline void -unpack_axis_order(axis_order order, int& i, int& j, int& k, bool& odd) -{ - enum - { - ODD = 0x02, - AXIS = 0x0C - }; - - odd = ((order & ODD) == ODD); - int offset = int(odd); - i = (order & AXIS) % 3; - j = (i + 1 + offset) % 3; - k = (i + 2 - offset) % 3; -} - -inline void -unpack_axis_order2D(axis_order2D order, int& i, int& j, bool& odd) -{ - enum - { - ODD = 0x02, - AXIS = 0x0C - }; - - odd = ((order & ODD) == ODD); - int offset = int(odd); - i = (order & AXIS) % 3; - j = (i + 1 + offset) % 3; -} - -inline axis_order -pack_axis_order(int i, bool odd) -{ - return axis_order((i << 2) | (int(odd) << 1)); -} - -inline axis_order -swap_axis_order(axis_order order) -{ - int i, j, k; - bool odd; - unpack_axis_order(order, i, j, k, odd); - return pack_axis_order(j, !odd); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Specify 3D axis ordering. */ +enum axis_order +{ + axis_order_xyz = euler_order_xyz, // 0x00 [0000] + axis_order_xzy = euler_order_xzy, // 0x02 [0010] + axis_order_yzx = euler_order_yzx, // 0x04 [0100] + axis_order_yxz = euler_order_yxz, // 0x06 [0110] + axis_order_zxy = euler_order_zxy, // 0x08 [1000] + axis_order_zyx = euler_order_zyx // 0x0A [1010] +}; + +/** Specify 2D axis ordering. */ +enum axis_order2D +{ + axis_order_xy = axis_order_xyz, // 0x00 [0000] + axis_order_yx = axis_order_yxz, // 0x06 [0110] +}; + +/** For CML1 compatibility. */ +using AxisOrder = axis_order; +using AxisOrder2D = axis_order2D; + +inline void +unpack_axis_order(axis_order order, int& i, int& j, int& k, bool& odd) +{ + enum + { + ODD = 0x02, + AXIS = 0x0C + }; + + odd = ((order & ODD) == ODD); + int offset = int(odd); + i = (order & AXIS) % 3; + j = (i + 1 + offset) % 3; + k = (i + 2 - offset) % 3; +} + +inline void +unpack_axis_order2D(axis_order2D order, int& i, int& j, bool& odd) +{ + enum + { + ODD = 0x02, + AXIS = 0x0C + }; + + odd = ((order & ODD) == ODD); + int offset = int(odd); + i = (order & AXIS) % 3; + j = (i + 1 + offset) % 3; +} + +inline axis_order +pack_axis_order(int i, bool odd) +{ + return axis_order((i << 2) | (int(odd) << 1)); +} + +inline axis_order +swap_axis_order(axis_order order) +{ + int i, j, k; + bool odd; + unpack_axis_order(order, i, j, k, odd); + return pack_axis_order(j, !odd); +} + +} // namespace cml diff --git a/cml/mathlib/constants.h b/cml/mathlib/constants.h index 7577eae..25c5ed5 100644 --- a/cml/mathlib/constants.h +++ b/cml/mathlib/constants.h @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -/** Coordinate system handedness. */ -enum AxisOrientation -{ - left_handed, - right_handed -}; - -/** For CML1 compatibility. */ -using Handedness = AxisOrientation; - -/** Perspective clipping type. */ -enum ZClip -{ - z_clip_neg_one, - z_clip_zero -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +/** Coordinate system handedness. */ +enum AxisOrientation +{ + left_handed, + right_handed +}; + +/** For CML1 compatibility. */ +using Handedness = AxisOrientation; + +/** Perspective clipping type. */ +enum ZClip +{ + z_clip_neg_one, + z_clip_zero +}; + +} // namespace cml diff --git a/cml/mathlib/coordinate_conversion.h b/cml/mathlib/coordinate_conversion.h index b1be247..261ddc7 100644 --- a/cml/mathlib/coordinate_conversion.h +++ b/cml/mathlib/coordinate_conversion.h @@ -1,196 +1,196 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_coord_conversion Coordinate Conversion */ - -namespace cml { - -/** @addtogroup mathlib_coord_conversion */ -/*@{*/ - -/** Spherical conversion types. */ -enum LatitudeType -{ - latitude, - colatitude -}; - -/** For CML1 compatibility. */ -using SphericalType = LatitudeType; - -/** @addtogroup mathlib_coord_conversion_to_cartesion Conversions to Cartesian Coordinates - */ -/*@{*/ - -/** Convert 2D polar coordinates to Cartesian coordinates. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D. If @c m is fixed-size, the size is checked at compile-time. - */ -template -void polar_to_cartesian(writable_vector& v, E0 radius, E1 theta); - -/** For CML1 compatibility. */ -template -void polar_to_cartesian(E radius, E theta, writable_vector& v); - - -/** Convert 3D cylindrical coordinates to Cartesian coordinates. @c v[axis] - * is set @c height, while the other two are set to the Cartesian - * coordinates given by @c radius and @c theta. - * - * @param radius the cylinder radius. - * - * @param theta the angle around the cylinder axis to the point. - * - * @param height the distance from the cylinder base plane to the point. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c m is fixed-size, the size is checked at compile-time. - * - * @throws std::invalid_argument if @c axis is not 0, 1, or 2. - */ -template -void cylindrical_to_cartesian(writable_vector& v, int axis, E0 radius, - E1 theta, E2 height); - -/** For CML1 compatibility. */ -template -void cylindrical_to_cartesian(E radius, E theta, E height, int axis, - writable_vector& v); - - -/** Convert 3D spherical coordinates to Cartesian coordinates. - * - * @param radius the distance from the origin to the point. - * - * @param theta the inclination. - * - * @param phi the azimuth. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c m is fixed-size, the size is checked at compile-time. - * - * @throws std::invalid_argument if @c axis is not 0, 1, or 2. - */ -template -void spherical_to_cartesian(writable_vector& v, int axis, - LatitudeType type, E0 radius, E1 theta, E2 phi); - -/** For CML1 compatibility. */ -template -void spherical_to_cartesian(E radius, E theta, E phi, int axis, - LatitudeType type, writable_vector& v); - -/*@}*/ - - -/** @addtogroup mathlib_coord_conversion_from_cartesion Conversions from Cartesian Coordinates - */ -/*@{*/ - -/** Convert 2D Cartesian coordinates to polar coordinates. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D. If @c m is fixed-size, the size is checked at compile-time. - * - * @note @c theta will be 0 if @c radius < sqrt(eps), where eps is machine - * epsilon for the value_type of @c Sub. - */ -template -void cartesian_to_polar(const readable_vector& v, E0& radius, E1& theta); - -/** Convert 2D Cartesian coordinates to polar coordinates, specifying a - * zero tolerance on @c radius. - */ -template -void cartesian_to_polar(const readable_vector& v, E0& radius, E1& theta, - Tol tolerance); - - -/** Convert 3D Cartesian coordinates to cylindrical coordinates. @c height - * is set to @c v[axis], while @c radius and @c theta are computed from the - * other coordinates of @c v. - * - * @param radius the distance from the cylinder axis to @c v, measured on - * the cylinder base plane. - * - * @param theta the angle around the cylinder axis to @c v. - * - * @param height the distance from the cylinder base plane to @c v. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c m is fixed-size, the size is checked at compile-time. - * - * @throws std::invalid_argument if @c axis is not 0, 1, or 2. - * - * @note @c theta will be 0 if @c radius < sqrt(eps), where eps is machine - * epsilon for the value_type of @c Sub. - */ -template -void cartesian_to_cylindrical(const readable_vector& v, int axis, - E0& radius, E1& theta, E2& height); - -/** Convert 3D Cartesian coordinates to cylindrical coordinates, specifying - * a zero tolerance on @c radius. - */ -template -void cartesian_to_cylindrical(const readable_vector& v, int axis, - E0& radius, E1& theta, E2& height, Tol tolerance); - -/** For compatibility with CML1. */ -template -void cartesian_to_cylindrical(const readable_vector& v, E& radius, - E& theta, E& height, int axis, - E tolerance = scalar_traits::sqrt_epsilon()); - - -/** Convert 3D Cartesian coordinates to spherical coordinates. - * - * @param radius the distance from the origin to @c v. - * - * @param theta the inclination (angle from the axis base plane). - * - * @param phi the azimuth (angle around the axis). - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c m is fixed-size, the size is checked at compile-time. - * - * @throws std::invalid_argument if @c axis is not 0, 1, or 2. - * - * @note @c theta will be 0 @c v lies on @c axis. - * - * @note @c phi will be 0 if @c v lies on the base plane. - */ -template -void cartesian_to_spherical(const readable_vector& v, int axis, - LatitudeType type, E0& radius, E1& theta, E2& phi); - -/** Convert 3D Cartesian coordinates to spherical coordinates, specifying - * the zero tolerance on @c theta. - */ -template -void cartesian_to_spherical(const readable_vector& v, int axis, - LatitudeType type, E0& radius, E1& theta, E2& phi, Tol tolerance); - -/** For compatibility with CML1. */ -template -void cartesian_to_spherical(const readable_vector& v, E& radius, E& theta, - E& phi, int axis, LatitudeType type, - E tolerance = scalar_traits::sqrt_epsilon()); - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_COORDINATE_CONVERSION_TPP -#include -#undef __CML_MATHLIB_COORDINATE_CONVERSION_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_coord_conversion Coordinate Conversion */ + +namespace cml { + +/** @addtogroup mathlib_coord_conversion */ +/*@{*/ + +/** Spherical conversion types. */ +enum LatitudeType +{ + latitude, + colatitude +}; + +/** For CML1 compatibility. */ +using SphericalType = LatitudeType; + +/** @addtogroup mathlib_coord_conversion_to_cartesion Conversions to Cartesian Coordinates + */ +/*@{*/ + +/** Convert 2D polar coordinates to Cartesian coordinates. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D. If @c m is fixed-size, the size is checked at compile-time. + */ +template +void polar_to_cartesian(writable_vector& v, E0 radius, E1 theta); + +/** For CML1 compatibility. */ +template +void polar_to_cartesian(E radius, E theta, writable_vector& v); + + +/** Convert 3D cylindrical coordinates to Cartesian coordinates. @c v[axis] + * is set @c height, while the other two are set to the Cartesian + * coordinates given by @c radius and @c theta. + * + * @param radius the cylinder radius. + * + * @param theta the angle around the cylinder axis to the point. + * + * @param height the distance from the cylinder base plane to the point. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c m is fixed-size, the size is checked at compile-time. + * + * @throws std::invalid_argument if @c axis is not 0, 1, or 2. + */ +template +void cylindrical_to_cartesian(writable_vector& v, int axis, E0 radius, + E1 theta, E2 height); + +/** For CML1 compatibility. */ +template +void cylindrical_to_cartesian(E radius, E theta, E height, int axis, + writable_vector& v); + + +/** Convert 3D spherical coordinates to Cartesian coordinates. + * + * @param radius the distance from the origin to the point. + * + * @param theta the inclination. + * + * @param phi the azimuth. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c m is fixed-size, the size is checked at compile-time. + * + * @throws std::invalid_argument if @c axis is not 0, 1, or 2. + */ +template +void spherical_to_cartesian(writable_vector& v, int axis, + LatitudeType type, E0 radius, E1 theta, E2 phi); + +/** For CML1 compatibility. */ +template +void spherical_to_cartesian(E radius, E theta, E phi, int axis, + LatitudeType type, writable_vector& v); + +/*@}*/ + + +/** @addtogroup mathlib_coord_conversion_from_cartesion Conversions from Cartesian Coordinates + */ +/*@{*/ + +/** Convert 2D Cartesian coordinates to polar coordinates. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D. If @c m is fixed-size, the size is checked at compile-time. + * + * @note @c theta will be 0 if @c radius < sqrt(eps), where eps is machine + * epsilon for the value_type of @c Sub. + */ +template +void cartesian_to_polar(const readable_vector& v, E0& radius, E1& theta); + +/** Convert 2D Cartesian coordinates to polar coordinates, specifying a + * zero tolerance on @c radius. + */ +template +void cartesian_to_polar(const readable_vector& v, E0& radius, E1& theta, + Tol tolerance); + + +/** Convert 3D Cartesian coordinates to cylindrical coordinates. @c height + * is set to @c v[axis], while @c radius and @c theta are computed from the + * other coordinates of @c v. + * + * @param radius the distance from the cylinder axis to @c v, measured on + * the cylinder base plane. + * + * @param theta the angle around the cylinder axis to @c v. + * + * @param height the distance from the cylinder base plane to @c v. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c m is fixed-size, the size is checked at compile-time. + * + * @throws std::invalid_argument if @c axis is not 0, 1, or 2. + * + * @note @c theta will be 0 if @c radius < sqrt(eps), where eps is machine + * epsilon for the value_type of @c Sub. + */ +template +void cartesian_to_cylindrical(const readable_vector& v, int axis, + E0& radius, E1& theta, E2& height); + +/** Convert 3D Cartesian coordinates to cylindrical coordinates, specifying + * a zero tolerance on @c radius. + */ +template +void cartesian_to_cylindrical(const readable_vector& v, int axis, + E0& radius, E1& theta, E2& height, Tol tolerance); + +/** For compatibility with CML1. */ +template +void cartesian_to_cylindrical(const readable_vector& v, E& radius, + E& theta, E& height, int axis, + E tolerance = scalar_traits::sqrt_epsilon()); + + +/** Convert 3D Cartesian coordinates to spherical coordinates. + * + * @param radius the distance from the origin to @c v. + * + * @param theta the inclination (angle from the axis base plane). + * + * @param phi the azimuth (angle around the axis). + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c m is fixed-size, the size is checked at compile-time. + * + * @throws std::invalid_argument if @c axis is not 0, 1, or 2. + * + * @note @c theta will be 0 @c v lies on @c axis. + * + * @note @c phi will be 0 if @c v lies on the base plane. + */ +template +void cartesian_to_spherical(const readable_vector& v, int axis, + LatitudeType type, E0& radius, E1& theta, E2& phi); + +/** Convert 3D Cartesian coordinates to spherical coordinates, specifying + * the zero tolerance on @c theta. + */ +template +void cartesian_to_spherical(const readable_vector& v, int axis, + LatitudeType type, E0& radius, E1& theta, E2& phi, Tol tolerance); + +/** For compatibility with CML1. */ +template +void cartesian_to_spherical(const readable_vector& v, E& radius, E& theta, + E& phi, int axis, LatitudeType type, + E tolerance = scalar_traits::sqrt_epsilon()); + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_COORDINATE_CONVERSION_TPP +#include +#undef __CML_MATHLIB_COORDINATE_CONVERSION_TPP diff --git a/cml/mathlib/coordinate_conversion.tpp b/cml/mathlib/coordinate_conversion.tpp index e5e2924..d9957f4 100644 --- a/cml/mathlib/coordinate_conversion.tpp +++ b/cml/mathlib/coordinate_conversion.tpp @@ -1,236 +1,236 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_COORDINATE_CONVERSION_TPP -# error "mathlib/matrix/coordinate_conversion.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -/* To Cartesian: */ - -template -inline void -polar_to_cartesian(writable_vector& v, E0 radius, E1 theta) -{ - using theta_traits = scalar_traits; - - static_assert(cml::are_convertible, E0, E1>::value, - "incompatible scalar types"); - cml::check_size(v, int_c<2>()); - - v[0] = theta_traits::cos(theta) * radius; - v[1] = theta_traits::sin(theta) * radius; -} - -template -inline void -polar_to_cartesian(E radius, E theta, writable_vector& v) -{ - polar_to_cartesian(v, radius, theta); -} - -template -inline void -cylindrical_to_cartesian(writable_vector& v, int axis, E0 radius, E1 theta, - E2 height) -{ - using theta_traits = scalar_traits; - - static_assert( - cml::are_convertible, E0, E1, E2>::value, - "incompatible scalar types"); - cml_require(0 <= axis && axis <= 2, std::invalid_argument, - "axis must be 0, 1, or 2"); - cml::check_size(v, int_c<3>()); - - /* Make i = axis, and (j,k) equal to the other axis in cyclic order from - * i: - */ - int i, j, k; - cml::cyclic_permutation(axis, i, j, k); - - /* Initialize the vector: */ - v[i] = height; - v[j] = theta_traits::cos(theta) * radius; - v[k] = theta_traits::sin(theta) * radius; -} - -template -inline void -cylindrical_to_cartesian(E radius, E theta, E height, int axis, - writable_vector& v) -{ - cylindrical_to_cartesian(v, axis, radius, theta, height); -} - -template -inline void -spherical_to_cartesian(writable_vector& v, int axis, LatitudeType type, - E0 radius, E1 theta, E2 phi) -{ - using theta_traits = scalar_traits; - using phi_traits = scalar_traits; - - static_assert( - cml::are_convertible, E0, E1, E2>::value, - "incompatible scalar types"); - cml_require(0 <= axis && axis <= 2, std::invalid_argument, - "axis must be 0, 1, or 2"); - cml::check_size(v, int_c<3>()); - - if(type == latitude) phi = constants::pi_over_2() - phi; - - auto sin_phi = phi_traits::sin(phi); - auto cos_phi = phi_traits::cos(phi); - auto sin_phi_r = sin_phi * radius; - - /* Make i = axis, and (j,k) equal to the other axis in cyclic order from - * i: - */ - int i, j, k; - cml::cyclic_permutation(axis, i, j, k); - - /* Initialize the vector: */ - v[i] = cos_phi * radius; - v[j] = sin_phi_r * theta_traits::cos(theta); - v[k] = sin_phi_r * theta_traits::sin(theta); -} - -template -inline void -spherical_to_cartesian(E radius, E theta, E phi, int axis, LatitudeType type, - writable_vector& v) -{ - spherical_to_cartesian(v, axis, type, radius, theta, phi); -} - -/* From Cartesian: */ - -template -inline void -cartesian_to_polar(const readable_vector& v, E0& radius, E1& theta, - Tol tolerance) -{ - using value_type = value_type_trait_of_t; - using value_traits = scalar_traits; - - static_assert( - cml::are_convertible, E0, E1, Tol>::value, - "incompatible scalar types"); - cml::check_size(v, int_c<2>()); - - radius = v.length(); - theta = radius < tolerance ? E1(0) : E1(value_traits::atan2(v[1], v[0])); -} - -template -inline void -cartesian_to_polar(const readable_vector& v, E0& radius, E1& theta) -{ - using tolerance_type = value_type_trait_promote_t; - cartesian_to_polar(v, radius, theta, - scalar_traits::sqrt_epsilon()); -} - -template -inline void -cartesian_to_cylindrical(const readable_vector& v, int axis, E0& radius, - E1& theta, E2& height, Tol tolerance) -{ - using value_type = value_type_trait_of_t; - using value_traits = scalar_traits; - - static_assert( - cml::are_convertible, E0, E1, E2, Tol>::value, - "incompatible scalar types"); - cml_require(0 <= axis && axis <= 2, std::invalid_argument, - "axis must be 0, 1, or 2"); - cml::check_size(v, int_c<3>()); - - /* Make i = axis, and (j,k) equal to the other axis in cyclic order from - * i: - */ - int i, j, k; - cml::cyclic_permutation(axis, i, j, k); - - /* Initialize return values; */ - height = E2(v[i]); - radius = E0(cml::length(v[j], v[k])); - theta = radius < tolerance ? E1(0) : E1(value_traits::atan2(v[k], v[j])); -} - -template -inline void -cartesian_to_cylindrical(const readable_vector& v, int axis, E0& radius, - E1& theta, E2& height) -{ - using tolerance_type = value_type_trait_promote_t; - cartesian_to_cylindrical(v, axis, radius, theta, height, - scalar_traits::sqrt_epsilon()); -} - -template -inline void -cartesian_to_cylindrical(const readable_vector& v, E& radius, E& theta, - E& height, int axis, E tolerance) -{ - cartesian_to_cylindrical(v, axis, radius, theta, height, tolerance); -} - -template -inline void -cartesian_to_spherical(const readable_vector& v, int axis, - LatitudeType type, E0& radius, E1& theta, E2& phi, Tol tolerance) -{ - using value_type = value_type_trait_of_t; - using value_traits = scalar_traits; - - static_assert( - cml::are_convertible, E0, E1, E2, Tol>::value, - "incompatible scalar types"); - cml_require(0 <= axis && axis <= 2, std::invalid_argument, - "axis must be 0, 1, or 2"); - cml::check_size(v, int_c<3>()); - - /* Make i = axis, and (j,k) equal to the other axis in cyclic order from - * i: - */ - int i, j, k; - cml::cyclic_permutation(axis, i, j, k); - - auto len = cml::length(v[j], v[k]); - theta = len < tolerance ? E1(0) : E1(value_traits::atan2(v[k], v[j])); - radius = E0(cml::length(v[i], len)); - if(radius < tolerance) { - phi = E2(0); - } else { - phi = E2(value_traits::atan2(len, v[i])); - if(type == latitude) phi = constants::pi_over_2() - phi; - } -} - -template -inline void -cartesian_to_spherical(const readable_vector& v, int axis, - LatitudeType type, E0& radius, E1& theta, E2& phi) -{ - using tolerance_type = value_type_trait_promote_t; - cartesian_to_spherical(v, axis, type, radius, theta, phi, - scalar_traits::sqrt_epsilon()); -} - -template -inline void -cartesian_to_spherical(const readable_vector& v, E& radius, E& theta, - E& phi, int axis, LatitudeType type, E tolerance) -{ - cartesian_to_spherical(v, axis, type, radius, theta, phi, tolerance); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_COORDINATE_CONVERSION_TPP +# error "mathlib/matrix/coordinate_conversion.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +/* To Cartesian: */ + +template +inline void +polar_to_cartesian(writable_vector& v, E0 radius, E1 theta) +{ + using theta_traits = scalar_traits; + + static_assert(cml::are_convertible, E0, E1>::value, + "incompatible scalar types"); + cml::check_size(v, int_c<2>()); + + v[0] = theta_traits::cos(theta) * radius; + v[1] = theta_traits::sin(theta) * radius; +} + +template +inline void +polar_to_cartesian(E radius, E theta, writable_vector& v) +{ + polar_to_cartesian(v, radius, theta); +} + +template +inline void +cylindrical_to_cartesian(writable_vector& v, int axis, E0 radius, E1 theta, + E2 height) +{ + using theta_traits = scalar_traits; + + static_assert( + cml::are_convertible, E0, E1, E2>::value, + "incompatible scalar types"); + cml_require(0 <= axis && axis <= 2, std::invalid_argument, + "axis must be 0, 1, or 2"); + cml::check_size(v, int_c<3>()); + + /* Make i = axis, and (j,k) equal to the other axis in cyclic order from + * i: + */ + int i, j, k; + cml::cyclic_permutation(axis, i, j, k); + + /* Initialize the vector: */ + v[i] = height; + v[j] = theta_traits::cos(theta) * radius; + v[k] = theta_traits::sin(theta) * radius; +} + +template +inline void +cylindrical_to_cartesian(E radius, E theta, E height, int axis, + writable_vector& v) +{ + cylindrical_to_cartesian(v, axis, radius, theta, height); +} + +template +inline void +spherical_to_cartesian(writable_vector& v, int axis, LatitudeType type, + E0 radius, E1 theta, E2 phi) +{ + using theta_traits = scalar_traits; + using phi_traits = scalar_traits; + + static_assert( + cml::are_convertible, E0, E1, E2>::value, + "incompatible scalar types"); + cml_require(0 <= axis && axis <= 2, std::invalid_argument, + "axis must be 0, 1, or 2"); + cml::check_size(v, int_c<3>()); + + if(type == latitude) phi = constants::pi_over_2() - phi; + + auto sin_phi = phi_traits::sin(phi); + auto cos_phi = phi_traits::cos(phi); + auto sin_phi_r = sin_phi * radius; + + /* Make i = axis, and (j,k) equal to the other axis in cyclic order from + * i: + */ + int i, j, k; + cml::cyclic_permutation(axis, i, j, k); + + /* Initialize the vector: */ + v[i] = cos_phi * radius; + v[j] = sin_phi_r * theta_traits::cos(theta); + v[k] = sin_phi_r * theta_traits::sin(theta); +} + +template +inline void +spherical_to_cartesian(E radius, E theta, E phi, int axis, LatitudeType type, + writable_vector& v) +{ + spherical_to_cartesian(v, axis, type, radius, theta, phi); +} + +/* From Cartesian: */ + +template +inline void +cartesian_to_polar(const readable_vector& v, E0& radius, E1& theta, + Tol tolerance) +{ + using value_type = value_type_trait_of_t; + using value_traits = scalar_traits; + + static_assert( + cml::are_convertible, E0, E1, Tol>::value, + "incompatible scalar types"); + cml::check_size(v, int_c<2>()); + + radius = v.length(); + theta = radius < tolerance ? E1(0) : E1(value_traits::atan2(v[1], v[0])); +} + +template +inline void +cartesian_to_polar(const readable_vector& v, E0& radius, E1& theta) +{ + using tolerance_type = value_type_trait_promote_t; + cartesian_to_polar(v, radius, theta, + scalar_traits::sqrt_epsilon()); +} + +template +inline void +cartesian_to_cylindrical(const readable_vector& v, int axis, E0& radius, + E1& theta, E2& height, Tol tolerance) +{ + using value_type = value_type_trait_of_t; + using value_traits = scalar_traits; + + static_assert( + cml::are_convertible, E0, E1, E2, Tol>::value, + "incompatible scalar types"); + cml_require(0 <= axis && axis <= 2, std::invalid_argument, + "axis must be 0, 1, or 2"); + cml::check_size(v, int_c<3>()); + + /* Make i = axis, and (j,k) equal to the other axis in cyclic order from + * i: + */ + int i, j, k; + cml::cyclic_permutation(axis, i, j, k); + + /* Initialize return values; */ + height = E2(v[i]); + radius = E0(cml::length(v[j], v[k])); + theta = radius < tolerance ? E1(0) : E1(value_traits::atan2(v[k], v[j])); +} + +template +inline void +cartesian_to_cylindrical(const readable_vector& v, int axis, E0& radius, + E1& theta, E2& height) +{ + using tolerance_type = value_type_trait_promote_t; + cartesian_to_cylindrical(v, axis, radius, theta, height, + scalar_traits::sqrt_epsilon()); +} + +template +inline void +cartesian_to_cylindrical(const readable_vector& v, E& radius, E& theta, + E& height, int axis, E tolerance) +{ + cartesian_to_cylindrical(v, axis, radius, theta, height, tolerance); +} + +template +inline void +cartesian_to_spherical(const readable_vector& v, int axis, + LatitudeType type, E0& radius, E1& theta, E2& phi, Tol tolerance) +{ + using value_type = value_type_trait_of_t; + using value_traits = scalar_traits; + + static_assert( + cml::are_convertible, E0, E1, E2, Tol>::value, + "incompatible scalar types"); + cml_require(0 <= axis && axis <= 2, std::invalid_argument, + "axis must be 0, 1, or 2"); + cml::check_size(v, int_c<3>()); + + /* Make i = axis, and (j,k) equal to the other axis in cyclic order from + * i: + */ + int i, j, k; + cml::cyclic_permutation(axis, i, j, k); + + auto len = cml::length(v[j], v[k]); + theta = len < tolerance ? E1(0) : E1(value_traits::atan2(v[k], v[j])); + radius = E0(cml::length(v[i], len)); + if(radius < tolerance) { + phi = E2(0); + } else { + phi = E2(value_traits::atan2(len, v[i])); + if(type == latitude) phi = constants::pi_over_2() - phi; + } +} + +template +inline void +cartesian_to_spherical(const readable_vector& v, int axis, + LatitudeType type, E0& radius, E1& theta, E2& phi) +{ + using tolerance_type = value_type_trait_promote_t; + cartesian_to_spherical(v, axis, type, radius, theta, phi, + scalar_traits::sqrt_epsilon()); +} + +template +inline void +cartesian_to_spherical(const readable_vector& v, E& radius, E& theta, + E& phi, int axis, LatitudeType type, E tolerance) +{ + cartesian_to_spherical(v, axis, type, radius, theta, phi, tolerance); +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/euler_order.h b/cml/mathlib/euler_order.h index 319c495..2be4e07 100644 --- a/cml/mathlib/euler_order.h +++ b/cml/mathlib/euler_order.h @@ -1,52 +1,52 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -/** Constants for specifying the order of Euler angle computations. */ -enum euler_order -{ - euler_order_xyz, // 0x00 [0000] - euler_order_xyx, // 0x01 [0001] - euler_order_xzy, // 0x02 [0010] - euler_order_xzx, // 0x03 [0011] - euler_order_yzx, // 0x04 [0100] - euler_order_yzy, // 0x05 [0101] - euler_order_yxz, // 0x06 [0110] - euler_order_yxy, // 0x07 [0111] - euler_order_zxy, // 0x08 [1000] - euler_order_zxz, // 0x09 [1001] - euler_order_zyx, // 0x0A [1010] - euler_order_zyz // 0x0B [1011] -}; - -/** For CML1 compatibility. */ -using EulerOrder = euler_order; - -/** Unpack Euler ordering @c order as three integers in {0, 1, 2}. If @c - * odd is true, the ordering is swapped. If @c repeat is true, one axis - * appears twice in the order. - */ -inline void -unpack_euler_order(euler_order order, int& i, int& j, int& k, bool& odd, - bool& repeat) -{ - enum - { - REPEAT = 0x01, - ODD = 0x02, - AXIS = 0x0C - }; - - repeat = order & REPEAT; - odd = ((order & ODD) == ODD); - int offset = odd; - i = (order & AXIS) % 3; - j = (i + 1 + offset) % 3; - k = (i + 2 - offset) % 3; -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +/** Constants for specifying the order of Euler angle computations. */ +enum euler_order +{ + euler_order_xyz, // 0x00 [0000] + euler_order_xyx, // 0x01 [0001] + euler_order_xzy, // 0x02 [0010] + euler_order_xzx, // 0x03 [0011] + euler_order_yzx, // 0x04 [0100] + euler_order_yzy, // 0x05 [0101] + euler_order_yxz, // 0x06 [0110] + euler_order_yxy, // 0x07 [0111] + euler_order_zxy, // 0x08 [1000] + euler_order_zxz, // 0x09 [1001] + euler_order_zyx, // 0x0A [1010] + euler_order_zyz // 0x0B [1011] +}; + +/** For CML1 compatibility. */ +using EulerOrder = euler_order; + +/** Unpack Euler ordering @c order as three integers in {0, 1, 2}. If @c + * odd is true, the ordering is swapped. If @c repeat is true, one axis + * appears twice in the order. + */ +inline void +unpack_euler_order(euler_order order, int& i, int& j, int& k, bool& odd, + bool& repeat) +{ + enum + { + REPEAT = 0x01, + ODD = 0x02, + AXIS = 0x0C + }; + + repeat = order & REPEAT; + odd = ((order & ODD) == ODD); + int offset = odd; + i = (order & AXIS) % 3; + j = (i + 1 + offset) % 3; + k = (i + 2 - offset) % 3; +} + +} // namespace cml diff --git a/cml/mathlib/frustum.h b/cml/mathlib/frustum.h index d97c054..ce5b729 100644 --- a/cml/mathlib/frustum.h +++ b/cml/mathlib/frustum.h @@ -1,84 +1,84 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_frustum Frustum Functions */ - -namespace cml { - -/** @addtogroup mathlib_frustum */ -/*@{*/ - -/** Extract the planes of a frustum given modelview and projection - * matrices, and the near z-clipping range. The planes are normalized by - * default, but this can be turned off with the 'normalize' argument. - * - * The planes are in ax+by+cz+d = 0 form, and are in the order: - * left - * right - * bottom - * top - * near - * far - * - * @throws minimum_matrix_size_error at run-time if @c modelview or @c - * projection is dynamically-sized, and is not at least 4x4. The size is - * checked at compile-time for fixed-size matrices. - * - * @throws non_square_matrix_error at run-time if @c modelview or @c projection - * is dynamically-sized and non-square. The size is checked at - * compile-time for fixed-size matrices. - */ -template -void extract_frustum_planes(const readable_matrix& modelview, - const readable_matrix& projection, E planes[6][4], ZClip z_clip, - bool normalize = true); - -/** Extract the planes of a frustum from a matrix assumed to contain any - * model and view transforms, followed by a projection transform with the - * given near z-cliping range. The planes are normalized by default, but - * this can be turned off with the 'normalize' argument. - * - * The planes are in ax+by+cz+d = 0 form, and are in the order: - * left - * right - * bottom - * top - * near - * far - * - * @throws minimum_matrix_size_error at run-time if @c m is dynamically-sized, - * and is not at least 4x4. The size is checked at compile-time for - * fixed-size matrices. - */ -template -void extract_frustum_planes(const readable_matrix& m, E planes[6][4], - ZClip z_clip, bool normalize = true); - -/** Extract the near plane of a frustum given a concatenated modelview and - * projection matrix @c m and the near z-clipping range. The plane is not - * normalized. - * - * @note @c plane is in ax+by+cz+d = 0 form, and must have exactly 4 - * elements. - * - * @throws minimum_matrix_size_error at run-time if @c m is dynamically-sized, - * and is not at least 4x4. The size is checked at compile-time for - * fixed-size matrices. - */ -template -void extract_near_frustum_plane(const readable_matrix& m, Plane& plane, - ZClip z_clip); - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_FRUSTUM_TPP -#include -#undef __CML_MATHLIB_FRUSTUM_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_frustum Frustum Functions */ + +namespace cml { + +/** @addtogroup mathlib_frustum */ +/*@{*/ + +/** Extract the planes of a frustum given modelview and projection + * matrices, and the near z-clipping range. The planes are normalized by + * default, but this can be turned off with the 'normalize' argument. + * + * The planes are in ax+by+cz+d = 0 form, and are in the order: + * left + * right + * bottom + * top + * near + * far + * + * @throws minimum_matrix_size_error at run-time if @c modelview or @c + * projection is dynamically-sized, and is not at least 4x4. The size is + * checked at compile-time for fixed-size matrices. + * + * @throws non_square_matrix_error at run-time if @c modelview or @c projection + * is dynamically-sized and non-square. The size is checked at + * compile-time for fixed-size matrices. + */ +template +void extract_frustum_planes(const readable_matrix& modelview, + const readable_matrix& projection, E planes[6][4], ZClip z_clip, + bool normalize = true); + +/** Extract the planes of a frustum from a matrix assumed to contain any + * model and view transforms, followed by a projection transform with the + * given near z-cliping range. The planes are normalized by default, but + * this can be turned off with the 'normalize' argument. + * + * The planes are in ax+by+cz+d = 0 form, and are in the order: + * left + * right + * bottom + * top + * near + * far + * + * @throws minimum_matrix_size_error at run-time if @c m is dynamically-sized, + * and is not at least 4x4. The size is checked at compile-time for + * fixed-size matrices. + */ +template +void extract_frustum_planes(const readable_matrix& m, E planes[6][4], + ZClip z_clip, bool normalize = true); + +/** Extract the near plane of a frustum given a concatenated modelview and + * projection matrix @c m and the near z-clipping range. The plane is not + * normalized. + * + * @note @c plane is in ax+by+cz+d = 0 form, and must have exactly 4 + * elements. + * + * @throws minimum_matrix_size_error at run-time if @c m is dynamically-sized, + * and is not at least 4x4. The size is checked at compile-time for + * fixed-size matrices. + */ +template +void extract_near_frustum_plane(const readable_matrix& m, Plane& plane, + ZClip z_clip); + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_FRUSTUM_TPP +#include +#undef __CML_MATHLIB_FRUSTUM_TPP diff --git a/cml/mathlib/frustum.tpp b/cml/mathlib/frustum.tpp index a407b5f..64b35f2 100644 --- a/cml/mathlib/frustum.tpp +++ b/cml/mathlib/frustum.tpp @@ -1,211 +1,211 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_FRUSTUM_TPP -# error "mathlib/frustum.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -template -void -extract_frustum_planes(const readable_matrix& modelview, - const readable_matrix& projection, E planes[6][4], ZClip z_clip, - bool normalize) -{ - extract_frustum_planes(matrix_concat(modelview, projection), planes, z_clip, - normalize); -} - -template -void -extract_frustum_planes(const readable_matrix& m, E planes[6][4], - ZClip z_clip, bool normalize) -{ - static_assert(cml::are_convertible, E>::value, - "incompatible scalar types"); - - /* Near: [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */ - extract_near_frustum_plane(m, planes[4], z_clip); - /* Note: also checks that m is at least 4x4. */ - - /* Left: [03+00, 13+10, 23+20, 33+30] */ - - planes[0][0] = E(m.basis_element(0, 3) + m.basis_element(0, 0)); - planes[0][1] = E(m.basis_element(1, 3) + m.basis_element(1, 0)); - planes[0][2] = E(m.basis_element(2, 3) + m.basis_element(2, 0)); - planes[0][3] = E(m.basis_element(3, 3) + m.basis_element(3, 0)); - - /* Right: [03-00, 13-10, 23-20, 33-30] */ - - planes[1][0] = E(m.basis_element(0, 3) - m.basis_element(0, 0)); - planes[1][1] = E(m.basis_element(1, 3) - m.basis_element(1, 0)); - planes[1][2] = E(m.basis_element(2, 3) - m.basis_element(2, 0)); - planes[1][3] = E(m.basis_element(3, 3) - m.basis_element(3, 0)); - - /* Bottom: [03+01, 13+11, 23+21, 33+31] */ - - planes[2][0] = E(m.basis_element(0, 3) + m.basis_element(0, 1)); - planes[2][1] = E(m.basis_element(1, 3) + m.basis_element(1, 1)); - planes[2][2] = E(m.basis_element(2, 3) + m.basis_element(2, 1)); - planes[2][3] = E(m.basis_element(3, 3) + m.basis_element(3, 1)); - - /* Top: [03-01, 13-11, 23-21, 33-31] */ - - planes[3][0] = E(m.basis_element(0, 3) - m.basis_element(0, 1)); - planes[3][1] = E(m.basis_element(1, 3) - m.basis_element(1, 1)); - planes[3][2] = E(m.basis_element(2, 3) - m.basis_element(2, 1)); - planes[3][3] = E(m.basis_element(3, 3) - m.basis_element(3, 1)); - - /* Far: [03-02, 13-12, 23-22, 33-32] */ - - planes[5][0] = E(m.basis_element(0, 3) - m.basis_element(0, 2)); - planes[5][1] = E(m.basis_element(1, 3) - m.basis_element(1, 2)); - planes[5][2] = E(m.basis_element(2, 3) - m.basis_element(2, 2)); - planes[5][3] = E(m.basis_element(3, 3) - m.basis_element(3, 2)); - - /* Compute normalized planes: */ - if(normalize) { - for(int i = 0; i < 6; ++i) { - auto l = cml::length(planes[i][0], planes[i][1], planes[i][2]); - planes[i][0] /= l; - planes[i][1] /= l; - planes[i][2] /= l; - planes[i][3] /= l; - } - } -} - -template -void -extract_near_frustum_plane(const readable_matrix& m, Plane& plane, - ZClip z_clip) -{ - cml::check_minimum_size(m, cml::int_c<4>(), cml::int_c<4>()); - //XXX cml::check_minimum_size(plane, cml::int_c<4>()); - - /* Near: [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */ - if(z_clip == z_clip_neg_one) { - plane[0] = m.basis_element(0, 3) + m.basis_element(0, 2); - plane[1] = m.basis_element(1, 3) + m.basis_element(1, 2); - plane[2] = m.basis_element(2, 3) + m.basis_element(2, 2); - plane[3] = m.basis_element(3, 3) + m.basis_element(3, 2); - } else { // z_clip == z_clip_zero - plane[0] = m.basis_element(0, 2); - plane[1] = m.basis_element(1, 2); - plane[2] = m.basis_element(2, 2); - plane[3] = m.basis_element(3, 2); - } -} - -} // namespace cml - -#if 0 -// XXX INCOMPLETE XXX - -/* @todo: plane class, and perhaps named arguments instead of an array. */ - -namespace detail { - -/* This is currently only in support of finding the corners of a frustum. - * The input planes are assumed to have a single unique intersection, so - * no tolerance is used. - */ - -template < typename Real > vector< Real, fixed<3> > -intersect_planes(Real p1[4], Real p2[4], Real p3[4]) -{ - typedef vector< Real, fixed<3> > vector_type; - typedef typename vector_type::value_type value_type; - - vector_type n1(p1[0],p1[1],p1[2]); - vector_type n2(p2[0],p2[1],p2[2]); - vector_type n3(p3[0],p3[1],p3[2]); - - value_type d1 = -p1[3]; - value_type d2 = -p2[3]; - value_type d3 = -p3[3]; - - vector_type numer = - d1*cross(n2,n3) + d2*cross(n3,n1) + d3*cross(n1,n2); - value_type denom = triple_product(n1,n2,n3); - return numer/denom; -} - -} // namespace detail - -/* Get the corners of a frustum defined by 6 planes. The planes are in - * ax+by+cz+d = 0 form, and are in the order: - * left - * right - * bottom - * top - * near - * far - * - * The corners are in CCW order starting in the lower-left, first at the near - * plane, then at the far plane. - */ - -template < typename Real, typename E, class A > void -get_frustum_corners(Real planes[6][4], vector corners[8]) -{ - // NOTE: Prefixed with 'PLANE_' due to symbol conflict with Windows - // macros PLANE_LEFT and PLANE_RIGHT. - enum { - PLANE_LEFT, - PLANE_RIGHT, - PLANE_BOTTOM, - PLANE_TOP, - PLANE_NEAR, - PLANE_FAR - }; - - corners[0] = detail::intersect_planes( - planes[PLANE_LEFT], - planes[PLANE_BOTTOM], - planes[PLANE_NEAR] - ); - corners[1] = detail::intersect_planes( - planes[PLANE_RIGHT], - planes[PLANE_BOTTOM], - planes[PLANE_NEAR] - ); - corners[2] = detail::intersect_planes( - planes[PLANE_RIGHT], - planes[PLANE_TOP], - planes[PLANE_NEAR] - ); - corners[3] = detail::intersect_planes( - planes[PLANE_LEFT], - planes[PLANE_TOP], - planes[PLANE_NEAR] - ); - corners[4] = detail::intersect_planes( - planes[PLANE_LEFT], - planes[PLANE_BOTTOM], - planes[PLANE_FAR] - ); - corners[5] = detail::intersect_planes( - planes[PLANE_RIGHT], - planes[PLANE_BOTTOM], - planes[PLANE_FAR] - ); - corners[6] = detail::intersect_planes( - planes[PLANE_RIGHT], - planes[PLANE_TOP], - planes[PLANE_FAR] - ); - corners[7] = detail::intersect_planes( - planes[PLANE_LEFT], - planes[PLANE_TOP], - planes[PLANE_FAR] - ); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_FRUSTUM_TPP +# error "mathlib/frustum.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +template +void +extract_frustum_planes(const readable_matrix& modelview, + const readable_matrix& projection, E planes[6][4], ZClip z_clip, + bool normalize) +{ + extract_frustum_planes(matrix_concat(modelview, projection), planes, z_clip, + normalize); +} + +template +void +extract_frustum_planes(const readable_matrix& m, E planes[6][4], + ZClip z_clip, bool normalize) +{ + static_assert(cml::are_convertible, E>::value, + "incompatible scalar types"); + + /* Near: [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */ + extract_near_frustum_plane(m, planes[4], z_clip); + /* Note: also checks that m is at least 4x4. */ + + /* Left: [03+00, 13+10, 23+20, 33+30] */ + + planes[0][0] = E(m.basis_element(0, 3) + m.basis_element(0, 0)); + planes[0][1] = E(m.basis_element(1, 3) + m.basis_element(1, 0)); + planes[0][2] = E(m.basis_element(2, 3) + m.basis_element(2, 0)); + planes[0][3] = E(m.basis_element(3, 3) + m.basis_element(3, 0)); + + /* Right: [03-00, 13-10, 23-20, 33-30] */ + + planes[1][0] = E(m.basis_element(0, 3) - m.basis_element(0, 0)); + planes[1][1] = E(m.basis_element(1, 3) - m.basis_element(1, 0)); + planes[1][2] = E(m.basis_element(2, 3) - m.basis_element(2, 0)); + planes[1][3] = E(m.basis_element(3, 3) - m.basis_element(3, 0)); + + /* Bottom: [03+01, 13+11, 23+21, 33+31] */ + + planes[2][0] = E(m.basis_element(0, 3) + m.basis_element(0, 1)); + planes[2][1] = E(m.basis_element(1, 3) + m.basis_element(1, 1)); + planes[2][2] = E(m.basis_element(2, 3) + m.basis_element(2, 1)); + planes[2][3] = E(m.basis_element(3, 3) + m.basis_element(3, 1)); + + /* Top: [03-01, 13-11, 23-21, 33-31] */ + + planes[3][0] = E(m.basis_element(0, 3) - m.basis_element(0, 1)); + planes[3][1] = E(m.basis_element(1, 3) - m.basis_element(1, 1)); + planes[3][2] = E(m.basis_element(2, 3) - m.basis_element(2, 1)); + planes[3][3] = E(m.basis_element(3, 3) - m.basis_element(3, 1)); + + /* Far: [03-02, 13-12, 23-22, 33-32] */ + + planes[5][0] = E(m.basis_element(0, 3) - m.basis_element(0, 2)); + planes[5][1] = E(m.basis_element(1, 3) - m.basis_element(1, 2)); + planes[5][2] = E(m.basis_element(2, 3) - m.basis_element(2, 2)); + planes[5][3] = E(m.basis_element(3, 3) - m.basis_element(3, 2)); + + /* Compute normalized planes: */ + if(normalize) { + for(int i = 0; i < 6; ++i) { + auto l = cml::length(planes[i][0], planes[i][1], planes[i][2]); + planes[i][0] /= l; + planes[i][1] /= l; + planes[i][2] /= l; + planes[i][3] /= l; + } + } +} + +template +void +extract_near_frustum_plane(const readable_matrix& m, Plane& plane, + ZClip z_clip) +{ + cml::check_minimum_size(m, cml::int_c<4>(), cml::int_c<4>()); + //XXX cml::check_minimum_size(plane, cml::int_c<4>()); + + /* Near: [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */ + if(z_clip == z_clip_neg_one) { + plane[0] = m.basis_element(0, 3) + m.basis_element(0, 2); + plane[1] = m.basis_element(1, 3) + m.basis_element(1, 2); + plane[2] = m.basis_element(2, 3) + m.basis_element(2, 2); + plane[3] = m.basis_element(3, 3) + m.basis_element(3, 2); + } else { // z_clip == z_clip_zero + plane[0] = m.basis_element(0, 2); + plane[1] = m.basis_element(1, 2); + plane[2] = m.basis_element(2, 2); + plane[3] = m.basis_element(3, 2); + } +} + +} // namespace cml + +#if 0 +// XXX INCOMPLETE XXX + +/* @todo: plane class, and perhaps named arguments instead of an array. */ + +namespace detail { + +/* This is currently only in support of finding the corners of a frustum. + * The input planes are assumed to have a single unique intersection, so + * no tolerance is used. + */ + +template < typename Real > vector< Real, fixed<3> > +intersect_planes(Real p1[4], Real p2[4], Real p3[4]) +{ + typedef vector< Real, fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + vector_type n1(p1[0],p1[1],p1[2]); + vector_type n2(p2[0],p2[1],p2[2]); + vector_type n3(p3[0],p3[1],p3[2]); + + value_type d1 = -p1[3]; + value_type d2 = -p2[3]; + value_type d3 = -p3[3]; + + vector_type numer = + d1*cross(n2,n3) + d2*cross(n3,n1) + d3*cross(n1,n2); + value_type denom = triple_product(n1,n2,n3); + return numer/denom; +} + +} // namespace detail + +/* Get the corners of a frustum defined by 6 planes. The planes are in + * ax+by+cz+d = 0 form, and are in the order: + * left + * right + * bottom + * top + * near + * far + * + * The corners are in CCW order starting in the lower-left, first at the near + * plane, then at the far plane. + */ + +template < typename Real, typename E, class A > void +get_frustum_corners(Real planes[6][4], vector corners[8]) +{ + // NOTE: Prefixed with 'PLANE_' due to symbol conflict with Windows + // macros PLANE_LEFT and PLANE_RIGHT. + enum { + PLANE_LEFT, + PLANE_RIGHT, + PLANE_BOTTOM, + PLANE_TOP, + PLANE_NEAR, + PLANE_FAR + }; + + corners[0] = detail::intersect_planes( + planes[PLANE_LEFT], + planes[PLANE_BOTTOM], + planes[PLANE_NEAR] + ); + corners[1] = detail::intersect_planes( + planes[PLANE_RIGHT], + planes[PLANE_BOTTOM], + planes[PLANE_NEAR] + ); + corners[2] = detail::intersect_planes( + planes[PLANE_RIGHT], + planes[PLANE_TOP], + planes[PLANE_NEAR] + ); + corners[3] = detail::intersect_planes( + planes[PLANE_LEFT], + planes[PLANE_TOP], + planes[PLANE_NEAR] + ); + corners[4] = detail::intersect_planes( + planes[PLANE_LEFT], + planes[PLANE_BOTTOM], + planes[PLANE_FAR] + ); + corners[5] = detail::intersect_planes( + planes[PLANE_RIGHT], + planes[PLANE_BOTTOM], + planes[PLANE_FAR] + ); + corners[6] = detail::intersect_planes( + planes[PLANE_RIGHT], + planes[PLANE_TOP], + planes[PLANE_FAR] + ); + corners[7] = detail::intersect_planes( + planes[PLANE_LEFT], + planes[PLANE_TOP], + planes[PLANE_FAR] + ); +} + #endif \ No newline at end of file diff --git a/cml/mathlib/mathlib.h b/cml/mathlib/mathlib.h index 37b8e4f..f5feb55 100644 --- a/cml/mathlib/mathlib.h +++ b/cml/mathlib/mathlib.h @@ -1,30 +1,30 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include diff --git a/cml/mathlib/matrix/basis.h b/cml/mathlib/matrix/basis.h index f545694..61271d3 100644 --- a/cml/mathlib/matrix/basis.h +++ b/cml/mathlib/matrix/basis.h @@ -1,249 +1,249 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -/** @defgroup mathlib_matrix_basis Matrix Basis Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_basis */ -/*@{*/ - -/** @defgroup mathlib_matrix_basis_2D 2D Matrix Basis Functions */ -/*@{*/ - -/** Set the i'th basis vector of a 2D transform */ -template -inline void matrix_set_basis_vector_2D(writable_matrix& m, int i, - const readable_vector& v); - -/** Set the x basis vector of a 2D transform */ -template -inline void matrix_set_x_basis_vector_2D(writable_matrix& m, - const readable_vector& x); - -/** Set the y basis vector of a 2D transform */ -template -inline void matrix_set_y_basis_vector_2D(writable_matrix& m, - const readable_vector& y); - -/** Set the basis vectors of 2D transform @c m. */ -template -inline void matrix_set_basis_vectors_2D(writable_matrix& m, - const readable_vector& x, const readable_vector& y); - - -/** Set the i'th transposed basis vector of a 2D transform */ -template -inline void matrix_set_transposed_basis_vector_2D(writable_matrix& m, - int i, const readable_vector& v); - -/** Set the transposed x basis vector of a 2D transform */ -template -inline void matrix_set_transposed_x_basis_vector_2D(writable_matrix& m, - const readable_vector& x); - -/** Set the transposed y basis vector of a 2D transform */ -template -inline void matrix_set_transposed_y_basis_vector_2D(writable_matrix& m, - const readable_vector& y); - -/** Set the transposed basis vectors of 2D transform @c m. */ -template -inline void matrix_set_transposed_basis_vectors_2D(writable_matrix& m, - const readable_vector& x, const readable_vector& y); - - -/** Get the i'th basis vector of a 2D transform as a temporary vector. */ -template -inline auto matrix_get_basis_vector_2D(const readable_matrix& m, int i) - -> n_basis_vector_of_t; - -/** Get the x basis vector of a 2D transform as a temporary vector. */ -template -inline auto matrix_get_x_basis_vector_2D(const readable_matrix& m) - -> n_basis_vector_of_t; - -/** Get the y basis vector of a 2D transform as a temporary vector. */ -template -inline auto matrix_get_y_basis_vector_2D(const readable_matrix& m) - -> n_basis_vector_of_t; - -/** Get the basis vectors of 2D transform @c m. */ -template -inline void matrix_get_basis_vectors_2D(const readable_matrix& m, - writable_vector& x, writable_vector& y); - - -/** Get the i'th transposed basis vector of a 2D transform as a temporary - * vector. - */ -template -inline auto matrix_get_transposed_basis_vector_2D(const readable_matrix& m, - int i) -> n_basis_vector_of_t; - -/** Get the transposed x basis vector of a 2D transform as a temporary - * vector. - */ -template -inline auto matrix_get_transposed_x_basis_vector_2D( - const readable_matrix& m) -> n_basis_vector_of_t; - -/** Get the transposed y basis vector of a 2D transform as a temporary - * vector. - */ -template -inline auto matrix_get_transposed_y_basis_vector_2D( - const readable_matrix& m) -> n_basis_vector_of_t; - -/** Get the transposed basis vectors of 2D transform @c m. */ -template -inline void matrix_get_transposed_basis_vectors_2D( - const readable_matrix& m, writable_vector& v1, - writable_vector& v2); - -/*@}*/ // mathlib_matrix_basis_2D - - -/** @defgroup mathlib_matrix_basis_3D 3D Matrix Basis Functions */ -/*@{*/ - -/** Set the i'th basis vector of a 3D transform */ -template -inline void matrix_set_basis_vector(writable_matrix& m, int i, - const readable_vector& v); - -/** Set the x basis vector of a 3D transform */ -template -inline void matrix_set_x_basis_vector(writable_matrix& m, - const readable_vector& x); - -/** Set the y basis vector of a 3D transform */ -template -inline void matrix_set_y_basis_vector(writable_matrix& m, - const readable_vector& y); - -/** Set the z basis vector of a 3D transform */ -template -inline void matrix_set_z_basis_vector(writable_matrix& m, - const readable_vector& z); - -/** Set the basis vectors of 3D transform @c m. */ -template -inline void matrix_set_basis_vectors(writable_matrix& m, - const readable_vector& x, const readable_vector& y, - const readable_vector& z); - - -/** Set the i'th transposed basis vector of a 3D transform */ -template -inline void matrix_set_transposed_basis_vector(writable_matrix& m, int i, - const readable_vector& v); - -/** Set the transposed x basis vector of a 3D transform */ -template -inline void matrix_set_transposed_x_basis_vector(writable_matrix& m, - const readable_vector& x); - -/** Set the transposed y basis vector of a 3D transform */ -template -inline void matrix_set_transposed_y_basis_vector(writable_matrix& m, - const readable_vector& y); - -/** Set the transposed z basis vector of a 3D transform */ -template -inline void matrix_set_transposed_z_basis_vector(writable_matrix& m, - const readable_vector& z); - -/** Set the transposed basis vectors of 3D transform @c m. */ -template -inline void matrix_set_transposed_basis_vectors(writable_matrix& m, - const readable_vector& x, const readable_vector& y, - const readable_vector& z); - - -/** Get the i'th basis vector of a 3D transform as a temporary vector. */ -template -inline auto matrix_get_basis_vector(const readable_matrix& m, int i) - -> n_basis_vector_of_t; - -/** Get the x basis vector of a 3D transform as a temporary vector. */ -template -inline auto matrix_get_x_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t; - -/** Get the y basis vector of a 3D transform as a temporary vector. */ -template -inline auto matrix_get_y_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t; - -/** Get the z basis vector of a 3D transform as a temporary vector. */ -template -inline auto matrix_get_z_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t; - -/** Get the basis vectors of a 3D transform */ -template -inline void matrix_get_basis_vectors(const readable_matrix& m, - writable_vector& v1, writable_vector& v2, - writable_vector& v3); - - -/** Get the i'th transposed basis vector of a 3D transform as a temporary - * vector. - */ -template -inline auto matrix_get_transposed_basis_vector(const readable_matrix& m, - int i) -> n_basis_vector_of_t; - -/** Get the transposed x basis vector of a 3D transform as a temporary - * vector. - */ -template -inline auto matrix_get_transposed_x_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t; - -/** Get the transposed y basis vector of a 3D transform as a temporary - * vector. - */ -template -inline auto matrix_get_transposed_y_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t; - -/** Get the transposed z basis vector of a 3D transform as a temporary - * vector. - */ -template -inline auto matrix_get_transposed_z_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t; - -/** Get the transposed basis vectors of 3D transform @c m. */ -template -inline void matrix_get_transposed_basis_vectors(const readable_matrix& m, - writable_vector& x, writable_vector& y, writable_vector& z); - -/*@}*/ // mathlib_matrix_basis_3D - - -/** @defgroup mathlib_matrix_basis_nD nD Matrix Basis Functions */ -/*@{*/ - -template -auto matrix_get_basis_vector_nD(const readable_matrix& m, int i) - -> basis_vector_of_t; - -/*@}*/ // mathlib_matrix_basis_nD - -/*@}*/ // mathlib_matrix_basis - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_BASIS_TPP -#include -#undef __CML_MATHLIB_MATRIX_BASIS_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +/** @defgroup mathlib_matrix_basis Matrix Basis Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_basis */ +/*@{*/ + +/** @defgroup mathlib_matrix_basis_2D 2D Matrix Basis Functions */ +/*@{*/ + +/** Set the i'th basis vector of a 2D transform */ +template +inline void matrix_set_basis_vector_2D(writable_matrix& m, int i, + const readable_vector& v); + +/** Set the x basis vector of a 2D transform */ +template +inline void matrix_set_x_basis_vector_2D(writable_matrix& m, + const readable_vector& x); + +/** Set the y basis vector of a 2D transform */ +template +inline void matrix_set_y_basis_vector_2D(writable_matrix& m, + const readable_vector& y); + +/** Set the basis vectors of 2D transform @c m. */ +template +inline void matrix_set_basis_vectors_2D(writable_matrix& m, + const readable_vector& x, const readable_vector& y); + + +/** Set the i'th transposed basis vector of a 2D transform */ +template +inline void matrix_set_transposed_basis_vector_2D(writable_matrix& m, + int i, const readable_vector& v); + +/** Set the transposed x basis vector of a 2D transform */ +template +inline void matrix_set_transposed_x_basis_vector_2D(writable_matrix& m, + const readable_vector& x); + +/** Set the transposed y basis vector of a 2D transform */ +template +inline void matrix_set_transposed_y_basis_vector_2D(writable_matrix& m, + const readable_vector& y); + +/** Set the transposed basis vectors of 2D transform @c m. */ +template +inline void matrix_set_transposed_basis_vectors_2D(writable_matrix& m, + const readable_vector& x, const readable_vector& y); + + +/** Get the i'th basis vector of a 2D transform as a temporary vector. */ +template +inline auto matrix_get_basis_vector_2D(const readable_matrix& m, int i) + -> n_basis_vector_of_t; + +/** Get the x basis vector of a 2D transform as a temporary vector. */ +template +inline auto matrix_get_x_basis_vector_2D(const readable_matrix& m) + -> n_basis_vector_of_t; + +/** Get the y basis vector of a 2D transform as a temporary vector. */ +template +inline auto matrix_get_y_basis_vector_2D(const readable_matrix& m) + -> n_basis_vector_of_t; + +/** Get the basis vectors of 2D transform @c m. */ +template +inline void matrix_get_basis_vectors_2D(const readable_matrix& m, + writable_vector& x, writable_vector& y); + + +/** Get the i'th transposed basis vector of a 2D transform as a temporary + * vector. + */ +template +inline auto matrix_get_transposed_basis_vector_2D(const readable_matrix& m, + int i) -> n_basis_vector_of_t; + +/** Get the transposed x basis vector of a 2D transform as a temporary + * vector. + */ +template +inline auto matrix_get_transposed_x_basis_vector_2D( + const readable_matrix& m) -> n_basis_vector_of_t; + +/** Get the transposed y basis vector of a 2D transform as a temporary + * vector. + */ +template +inline auto matrix_get_transposed_y_basis_vector_2D( + const readable_matrix& m) -> n_basis_vector_of_t; + +/** Get the transposed basis vectors of 2D transform @c m. */ +template +inline void matrix_get_transposed_basis_vectors_2D( + const readable_matrix& m, writable_vector& v1, + writable_vector& v2); + +/*@}*/ // mathlib_matrix_basis_2D + + +/** @defgroup mathlib_matrix_basis_3D 3D Matrix Basis Functions */ +/*@{*/ + +/** Set the i'th basis vector of a 3D transform */ +template +inline void matrix_set_basis_vector(writable_matrix& m, int i, + const readable_vector& v); + +/** Set the x basis vector of a 3D transform */ +template +inline void matrix_set_x_basis_vector(writable_matrix& m, + const readable_vector& x); + +/** Set the y basis vector of a 3D transform */ +template +inline void matrix_set_y_basis_vector(writable_matrix& m, + const readable_vector& y); + +/** Set the z basis vector of a 3D transform */ +template +inline void matrix_set_z_basis_vector(writable_matrix& m, + const readable_vector& z); + +/** Set the basis vectors of 3D transform @c m. */ +template +inline void matrix_set_basis_vectors(writable_matrix& m, + const readable_vector& x, const readable_vector& y, + const readable_vector& z); + + +/** Set the i'th transposed basis vector of a 3D transform */ +template +inline void matrix_set_transposed_basis_vector(writable_matrix& m, int i, + const readable_vector& v); + +/** Set the transposed x basis vector of a 3D transform */ +template +inline void matrix_set_transposed_x_basis_vector(writable_matrix& m, + const readable_vector& x); + +/** Set the transposed y basis vector of a 3D transform */ +template +inline void matrix_set_transposed_y_basis_vector(writable_matrix& m, + const readable_vector& y); + +/** Set the transposed z basis vector of a 3D transform */ +template +inline void matrix_set_transposed_z_basis_vector(writable_matrix& m, + const readable_vector& z); + +/** Set the transposed basis vectors of 3D transform @c m. */ +template +inline void matrix_set_transposed_basis_vectors(writable_matrix& m, + const readable_vector& x, const readable_vector& y, + const readable_vector& z); + + +/** Get the i'th basis vector of a 3D transform as a temporary vector. */ +template +inline auto matrix_get_basis_vector(const readable_matrix& m, int i) + -> n_basis_vector_of_t; + +/** Get the x basis vector of a 3D transform as a temporary vector. */ +template +inline auto matrix_get_x_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t; + +/** Get the y basis vector of a 3D transform as a temporary vector. */ +template +inline auto matrix_get_y_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t; + +/** Get the z basis vector of a 3D transform as a temporary vector. */ +template +inline auto matrix_get_z_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t; + +/** Get the basis vectors of a 3D transform */ +template +inline void matrix_get_basis_vectors(const readable_matrix& m, + writable_vector& v1, writable_vector& v2, + writable_vector& v3); + + +/** Get the i'th transposed basis vector of a 3D transform as a temporary + * vector. + */ +template +inline auto matrix_get_transposed_basis_vector(const readable_matrix& m, + int i) -> n_basis_vector_of_t; + +/** Get the transposed x basis vector of a 3D transform as a temporary + * vector. + */ +template +inline auto matrix_get_transposed_x_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t; + +/** Get the transposed y basis vector of a 3D transform as a temporary + * vector. + */ +template +inline auto matrix_get_transposed_y_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t; + +/** Get the transposed z basis vector of a 3D transform as a temporary + * vector. + */ +template +inline auto matrix_get_transposed_z_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t; + +/** Get the transposed basis vectors of 3D transform @c m. */ +template +inline void matrix_get_transposed_basis_vectors(const readable_matrix& m, + writable_vector& x, writable_vector& y, writable_vector& z); + +/*@}*/ // mathlib_matrix_basis_3D + + +/** @defgroup mathlib_matrix_basis_nD nD Matrix Basis Functions */ +/*@{*/ + +template +auto matrix_get_basis_vector_nD(const readable_matrix& m, int i) + -> basis_vector_of_t; + +/*@}*/ // mathlib_matrix_basis_nD + +/*@}*/ // mathlib_matrix_basis + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_BASIS_TPP +#include +#undef __CML_MATHLIB_MATRIX_BASIS_TPP diff --git a/cml/mathlib/matrix/basis.tpp b/cml/mathlib/matrix/basis.tpp index 48b8aa1..e3465a8 100644 --- a/cml/mathlib/matrix/basis.tpp +++ b/cml/mathlib/matrix/basis.tpp @@ -1,386 +1,386 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_BASIS_TPP -# error "mathlib/matrix/basis.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -/* 2D basis functions: */ - -template -inline void -matrix_set_basis_vector_2D(writable_matrix& m, int i, - const readable_vector& v) -{ - cml::check_linear_2D(m); - cml::check_size(v, int_c<2>()); - cml_require(0 <= i && i <= 1, std::invalid_argument, "invalid 2D index"); - - m.set_basis_element(i, 0, v[0]); - m.set_basis_element(i, 1, v[1]); -} - -template -inline void -matrix_set_x_basis_vector_2D(writable_matrix& m, - const readable_vector& x) -{ - matrix_set_basis_vector_2D(m, 0, x); -} - -template -inline void -matrix_set_y_basis_vector_2D(writable_matrix& m, - const readable_vector& y) -{ - matrix_set_basis_vector_2D(m, 1, y); -} - -template -inline void -matrix_set_basis_vectors_2D(writable_matrix& m, - const readable_vector& x, const readable_vector& y) -{ - matrix_set_x_basis_vector_2D(m, x); - matrix_set_y_basis_vector_2D(m, y); -} - -template -inline void -matrix_set_transposed_basis_vector_2D(writable_matrix& m, int i, - const readable_vector& v) -{ - cml::check_linear_2D(m); - cml::check_size(v, int_c<2>()); - cml_require(0 <= i && i <= 1, std::invalid_argument, "invalid 2D index"); - - m.set_basis_element(0, i, v[0]); - m.set_basis_element(1, i, v[1]); -} - -template -inline void -matrix_set_transposed_x_basis_vector_2D(writable_matrix& m, - const readable_vector& x) -{ - matrix_set_transposed_basis_vector_2D(m, 0, x); -} - -template -inline void -matrix_set_transposed_y_basis_vector_2D(writable_matrix& m, - const readable_vector& y) -{ - matrix_set_transposed_basis_vector_2D(m, 1, y); -} - -template -inline void -matrix_set_transposed_basis_vectors_2D(writable_matrix& m, - const readable_vector& x, const readable_vector& y) -{ - matrix_set_transposed_x_basis_vector_2D(m, x); - matrix_set_transposed_y_basis_vector_2D(m, y); -} - -template -inline auto -matrix_get_basis_vector_2D(const readable_matrix& m, int i) - -> n_basis_vector_of_t -{ - cml::check_linear_2D(m); - cml_require(0 <= i && i <= 1, std::invalid_argument, "invalid 2D index"); - return n_basis_vector_of_t(m.basis_element(i, 0), - m.basis_element(i, 1)); -} - -template -inline auto -matrix_get_x_basis_vector_2D(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_basis_vector_2D(m, 0); -} - -template -inline auto -matrix_get_y_basis_vector_2D(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_basis_vector_2D(m, 1); -} - -template -inline void -matrix_get_basis_vectors_2D(const readable_matrix& m, - writable_vector& x, writable_vector& y) -{ - x = matrix_get_x_basis_vector_2D(m); - y = matrix_get_y_basis_vector_2D(m); -} - -template -inline auto -matrix_get_transposed_basis_vector_2D(const readable_matrix& m, int i) - -> n_basis_vector_of_t -{ - cml::check_linear_2D(m); - cml_require(0 <= i && i <= 1, std::invalid_argument, "invalid 2D index"); - return n_basis_vector_of_t(m.basis_element(0, i), - m.basis_element(1, i)); -} - -template -inline auto -matrix_get_transposed_x_basis_vector_2D(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_transposed_basis_vector_2D(m, 0); -} - -template -inline auto -matrix_get_transposed_y_basis_vector_2D(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_transposed_basis_vector_2D(m, 1); -} - -template -inline void -matrix_get_transposed_basis_vectors_2D(const readable_matrix& m, - writable_vector& x, writable_vector& y) -{ - x = matrix_get_transposed_x_basis_vector_2D(m); - y = matrix_get_transposed_y_basis_vector_2D(m); -} - -/* 3D basis functions: */ - -template -inline void -matrix_set_basis_vector(writable_matrix& m, int i, - const readable_vector& v) -{ - cml::check_linear_3D(m); - cml::check_size(v, int_c<3>()); - cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid 3D index"); - - m.set_basis_element(i, 0, v[0]); - m.set_basis_element(i, 1, v[1]); - m.set_basis_element(i, 2, v[2]); -} - -template -inline void -matrix_set_x_basis_vector(writable_matrix& m, - const readable_vector& x) -{ - matrix_set_basis_vector(m, 0, x); -} - -template -inline void -matrix_set_y_basis_vector(writable_matrix& m, - const readable_vector& y) -{ - matrix_set_basis_vector(m, 1, y); -} - -template -inline void -matrix_set_z_basis_vector(writable_matrix& m, - const readable_vector& z) -{ - matrix_set_basis_vector(m, 2, z); -} - -template -inline void -matrix_set_basis_vectors(writable_matrix& m, - const readable_vector& x, const readable_vector& y, - const readable_vector& z) -{ - matrix_set_x_basis_vector(m, x); - matrix_set_y_basis_vector(m, y); - matrix_set_z_basis_vector(m, z); -} - -template -inline void -matrix_set_transposed_basis_vector(writable_matrix& m, int i, - const readable_vector& v) -{ - cml::check_linear_3D(m); - cml::check_size(v, int_c<3>()); - cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid 3D index"); - - m.set_basis_element(0, i, v[0]); - m.set_basis_element(1, i, v[1]); - m.set_basis_element(2, i, v[2]); -} - -template -inline void -matrix_set_transposed_x_basis_vector(writable_matrix& m, - const readable_vector& x) -{ - matrix_set_transposed_basis_vector(m, 0, x); -} - -template -inline void -matrix_set_transposed_y_basis_vector(writable_matrix& m, - const readable_vector& y) -{ - matrix_set_transposed_basis_vector(m, 1, y); -} - -template -inline void -matrix_set_transposed_z_basis_vector(writable_matrix& m, - const readable_vector& z) -{ - matrix_set_transposed_basis_vector(m, 2, z); -} - -template -inline void -matrix_set_transposed_basis_vectors(writable_matrix& m, - const readable_vector& x, const readable_vector& y, - const readable_vector& z) -{ - matrix_set_transposed_x_basis_vector(m, x); - matrix_set_transposed_y_basis_vector(m, y); - matrix_set_transposed_z_basis_vector(m, z); -} - -template -inline auto -matrix_get_basis_vector(const readable_matrix& m, int i) - -> n_basis_vector_of_t -{ - cml::check_linear_3D(m); - cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid 3D index"); - return n_basis_vector_of_t(m.basis_element(i, 0), - m.basis_element(i, 1), m.basis_element(i, 2)); -} - -template -inline auto -matrix_get_x_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_basis_vector(m, 0); -} - -template -inline auto -matrix_get_y_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_basis_vector(m, 1); -} - -template -inline auto -matrix_get_z_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_basis_vector(m, 2); -} - -template -inline void -matrix_get_basis_vectors(const readable_matrix& m, - writable_vector& x, writable_vector& y, writable_vector& z) -{ - x = matrix_get_x_basis_vector(m); - y = matrix_get_y_basis_vector(m); - z = matrix_get_z_basis_vector(m); -} - -template -inline auto -matrix_get_transposed_basis_vector(const readable_matrix& m, int i) - -> n_basis_vector_of_t -{ - cml::check_linear_3D(m); - cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid 3D index"); - return n_basis_vector_of_t(m.basis_element(0, i), - m.basis_element(1, i), m.basis_element(2, i)); -} - -template -inline auto -matrix_get_transposed_x_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_transposed_basis_vector(m, 0); -} - -template -inline auto -matrix_get_transposed_y_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_transposed_basis_vector(m, 1); -} - -template -inline auto -matrix_get_transposed_z_basis_vector(const readable_matrix& m) - -> n_basis_vector_of_t -{ - return matrix_get_transposed_basis_vector(m, 2); -} - -template -inline void -matrix_get_transposed_basis_vectors(const readable_matrix& m, - writable_vector& x, writable_vector& y, writable_vector& z) -{ - x = matrix_get_transposed_x_basis_vector(m); - y = matrix_get_transposed_y_basis_vector(m); - z = matrix_get_transposed_z_basis_vector(m); -} - -/* nD basis functions: */ - -namespace detail { - -template -inline auto -matrix_get_basis_vector(const readable_matrix& m, int i, row_basis) - -> basis_vector_of_t -{ - return cml::row(m, i); -} - -template -inline auto -matrix_get_basis_vector(const readable_matrix& m, int i, col_basis) - -> basis_vector_of_t -{ - return cml::col(m, i); -} - -} // namespace detail - -template -auto -matrix_get_basis_vector_nD(const readable_matrix& m, int i) - -> basis_vector_of_t -{ - using tag = basis_tag_of_t; - return detail::matrix_get_basis_vector(m, i, tag()); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_BASIS_TPP +# error "mathlib/matrix/basis.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +/* 2D basis functions: */ + +template +inline void +matrix_set_basis_vector_2D(writable_matrix& m, int i, + const readable_vector& v) +{ + cml::check_linear_2D(m); + cml::check_size(v, int_c<2>()); + cml_require(0 <= i && i <= 1, std::invalid_argument, "invalid 2D index"); + + m.set_basis_element(i, 0, v[0]); + m.set_basis_element(i, 1, v[1]); +} + +template +inline void +matrix_set_x_basis_vector_2D(writable_matrix& m, + const readable_vector& x) +{ + matrix_set_basis_vector_2D(m, 0, x); +} + +template +inline void +matrix_set_y_basis_vector_2D(writable_matrix& m, + const readable_vector& y) +{ + matrix_set_basis_vector_2D(m, 1, y); +} + +template +inline void +matrix_set_basis_vectors_2D(writable_matrix& m, + const readable_vector& x, const readable_vector& y) +{ + matrix_set_x_basis_vector_2D(m, x); + matrix_set_y_basis_vector_2D(m, y); +} + +template +inline void +matrix_set_transposed_basis_vector_2D(writable_matrix& m, int i, + const readable_vector& v) +{ + cml::check_linear_2D(m); + cml::check_size(v, int_c<2>()); + cml_require(0 <= i && i <= 1, std::invalid_argument, "invalid 2D index"); + + m.set_basis_element(0, i, v[0]); + m.set_basis_element(1, i, v[1]); +} + +template +inline void +matrix_set_transposed_x_basis_vector_2D(writable_matrix& m, + const readable_vector& x) +{ + matrix_set_transposed_basis_vector_2D(m, 0, x); +} + +template +inline void +matrix_set_transposed_y_basis_vector_2D(writable_matrix& m, + const readable_vector& y) +{ + matrix_set_transposed_basis_vector_2D(m, 1, y); +} + +template +inline void +matrix_set_transposed_basis_vectors_2D(writable_matrix& m, + const readable_vector& x, const readable_vector& y) +{ + matrix_set_transposed_x_basis_vector_2D(m, x); + matrix_set_transposed_y_basis_vector_2D(m, y); +} + +template +inline auto +matrix_get_basis_vector_2D(const readable_matrix& m, int i) + -> n_basis_vector_of_t +{ + cml::check_linear_2D(m); + cml_require(0 <= i && i <= 1, std::invalid_argument, "invalid 2D index"); + return n_basis_vector_of_t(m.basis_element(i, 0), + m.basis_element(i, 1)); +} + +template +inline auto +matrix_get_x_basis_vector_2D(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_basis_vector_2D(m, 0); +} + +template +inline auto +matrix_get_y_basis_vector_2D(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_basis_vector_2D(m, 1); +} + +template +inline void +matrix_get_basis_vectors_2D(const readable_matrix& m, + writable_vector& x, writable_vector& y) +{ + x = matrix_get_x_basis_vector_2D(m); + y = matrix_get_y_basis_vector_2D(m); +} + +template +inline auto +matrix_get_transposed_basis_vector_2D(const readable_matrix& m, int i) + -> n_basis_vector_of_t +{ + cml::check_linear_2D(m); + cml_require(0 <= i && i <= 1, std::invalid_argument, "invalid 2D index"); + return n_basis_vector_of_t(m.basis_element(0, i), + m.basis_element(1, i)); +} + +template +inline auto +matrix_get_transposed_x_basis_vector_2D(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_transposed_basis_vector_2D(m, 0); +} + +template +inline auto +matrix_get_transposed_y_basis_vector_2D(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_transposed_basis_vector_2D(m, 1); +} + +template +inline void +matrix_get_transposed_basis_vectors_2D(const readable_matrix& m, + writable_vector& x, writable_vector& y) +{ + x = matrix_get_transposed_x_basis_vector_2D(m); + y = matrix_get_transposed_y_basis_vector_2D(m); +} + +/* 3D basis functions: */ + +template +inline void +matrix_set_basis_vector(writable_matrix& m, int i, + const readable_vector& v) +{ + cml::check_linear_3D(m); + cml::check_size(v, int_c<3>()); + cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid 3D index"); + + m.set_basis_element(i, 0, v[0]); + m.set_basis_element(i, 1, v[1]); + m.set_basis_element(i, 2, v[2]); +} + +template +inline void +matrix_set_x_basis_vector(writable_matrix& m, + const readable_vector& x) +{ + matrix_set_basis_vector(m, 0, x); +} + +template +inline void +matrix_set_y_basis_vector(writable_matrix& m, + const readable_vector& y) +{ + matrix_set_basis_vector(m, 1, y); +} + +template +inline void +matrix_set_z_basis_vector(writable_matrix& m, + const readable_vector& z) +{ + matrix_set_basis_vector(m, 2, z); +} + +template +inline void +matrix_set_basis_vectors(writable_matrix& m, + const readable_vector& x, const readable_vector& y, + const readable_vector& z) +{ + matrix_set_x_basis_vector(m, x); + matrix_set_y_basis_vector(m, y); + matrix_set_z_basis_vector(m, z); +} + +template +inline void +matrix_set_transposed_basis_vector(writable_matrix& m, int i, + const readable_vector& v) +{ + cml::check_linear_3D(m); + cml::check_size(v, int_c<3>()); + cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid 3D index"); + + m.set_basis_element(0, i, v[0]); + m.set_basis_element(1, i, v[1]); + m.set_basis_element(2, i, v[2]); +} + +template +inline void +matrix_set_transposed_x_basis_vector(writable_matrix& m, + const readable_vector& x) +{ + matrix_set_transposed_basis_vector(m, 0, x); +} + +template +inline void +matrix_set_transposed_y_basis_vector(writable_matrix& m, + const readable_vector& y) +{ + matrix_set_transposed_basis_vector(m, 1, y); +} + +template +inline void +matrix_set_transposed_z_basis_vector(writable_matrix& m, + const readable_vector& z) +{ + matrix_set_transposed_basis_vector(m, 2, z); +} + +template +inline void +matrix_set_transposed_basis_vectors(writable_matrix& m, + const readable_vector& x, const readable_vector& y, + const readable_vector& z) +{ + matrix_set_transposed_x_basis_vector(m, x); + matrix_set_transposed_y_basis_vector(m, y); + matrix_set_transposed_z_basis_vector(m, z); +} + +template +inline auto +matrix_get_basis_vector(const readable_matrix& m, int i) + -> n_basis_vector_of_t +{ + cml::check_linear_3D(m); + cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid 3D index"); + return n_basis_vector_of_t(m.basis_element(i, 0), + m.basis_element(i, 1), m.basis_element(i, 2)); +} + +template +inline auto +matrix_get_x_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_basis_vector(m, 0); +} + +template +inline auto +matrix_get_y_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_basis_vector(m, 1); +} + +template +inline auto +matrix_get_z_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_basis_vector(m, 2); +} + +template +inline void +matrix_get_basis_vectors(const readable_matrix& m, + writable_vector& x, writable_vector& y, writable_vector& z) +{ + x = matrix_get_x_basis_vector(m); + y = matrix_get_y_basis_vector(m); + z = matrix_get_z_basis_vector(m); +} + +template +inline auto +matrix_get_transposed_basis_vector(const readable_matrix& m, int i) + -> n_basis_vector_of_t +{ + cml::check_linear_3D(m); + cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid 3D index"); + return n_basis_vector_of_t(m.basis_element(0, i), + m.basis_element(1, i), m.basis_element(2, i)); +} + +template +inline auto +matrix_get_transposed_x_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_transposed_basis_vector(m, 0); +} + +template +inline auto +matrix_get_transposed_y_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_transposed_basis_vector(m, 1); +} + +template +inline auto +matrix_get_transposed_z_basis_vector(const readable_matrix& m) + -> n_basis_vector_of_t +{ + return matrix_get_transposed_basis_vector(m, 2); +} + +template +inline void +matrix_get_transposed_basis_vectors(const readable_matrix& m, + writable_vector& x, writable_vector& y, writable_vector& z) +{ + x = matrix_get_transposed_x_basis_vector(m); + y = matrix_get_transposed_y_basis_vector(m); + z = matrix_get_transposed_z_basis_vector(m); +} + +/* nD basis functions: */ + +namespace detail { + +template +inline auto +matrix_get_basis_vector(const readable_matrix& m, int i, row_basis) + -> basis_vector_of_t +{ + return cml::row(m, i); +} + +template +inline auto +matrix_get_basis_vector(const readable_matrix& m, int i, col_basis) + -> basis_vector_of_t +{ + return cml::col(m, i); +} + +} // namespace detail + +template +auto +matrix_get_basis_vector_nD(const readable_matrix& m, int i) + -> basis_vector_of_t +{ + using tag = basis_tag_of_t; + return detail::matrix_get_basis_vector(m, i, tag()); +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/matrix/concat.h b/cml/mathlib/matrix/concat.h index bdc14ec..1a0cb7c 100644 --- a/cml/mathlib/matrix/concat.h +++ b/cml/mathlib/matrix/concat.h @@ -1,39 +1,39 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_matrix_concat Ordered Matrix Concatenation Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_concat */ -/*@{*/ - -/** Concatenate two square transformation matrices, @c m1 and @c m2, taking - * basis orientation into account. - * - * - both col_basis, or col_basis with any_basis: return m1 * m2 - * - both row_basis, or row_basis with any_basis: return m2 * m1 - * - otherwise: compile-time error - * - * @throws non_square_matrix_error at run-time if @c m1 or @c m2 is - * dynamically-sized and non-square. The size is checked at compile-time - * for fixed-size matrices. - */ -template -auto matrix_concat(const readable_matrix& m1, - const readable_matrix& m2) - -> matrix_inner_product_promote_t; - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_CONCAT_TPP -#include -#undef __CML_MATHLIB_MATRIX_CONCAT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_matrix_concat Ordered Matrix Concatenation Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_concat */ +/*@{*/ + +/** Concatenate two square transformation matrices, @c m1 and @c m2, taking + * basis orientation into account. + * + * - both col_basis, or col_basis with any_basis: return m1 * m2 + * - both row_basis, or row_basis with any_basis: return m2 * m1 + * - otherwise: compile-time error + * + * @throws non_square_matrix_error at run-time if @c m1 or @c m2 is + * dynamically-sized and non-square. The size is checked at compile-time + * for fixed-size matrices. + */ +template +auto matrix_concat(const readable_matrix& m1, + const readable_matrix& m2) + -> matrix_inner_product_promote_t; + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_CONCAT_TPP +#include +#undef __CML_MATHLIB_MATRIX_CONCAT_TPP diff --git a/cml/mathlib/matrix/concat.tpp b/cml/mathlib/matrix/concat.tpp index 78cefa8..bce4302 100644 --- a/cml/mathlib/matrix/concat.tpp +++ b/cml/mathlib/matrix/concat.tpp @@ -1,50 +1,50 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_CONCAT_TPP -# error "mathlib/matrix/concat.tpp not included correctly" -#endif - -#include - -namespace cml { -namespace detail { - -/** Row-basis concatenation. */ -template -inline auto -matrix_concat(const readable_matrix& m1, const readable_matrix& m2, - row_basis) -> matrix_inner_product_promote_t -{ - return m1 * m2; -} - -/** Column-basis concatenation. */ -template -inline auto -matrix_concat(const readable_matrix& m1, const readable_matrix& m2, - col_basis) -> matrix_inner_product_promote_t -{ - return m2 * m1; -} - -} // namespace detail - -template -inline auto -matrix_concat(const readable_matrix& m1, const readable_matrix& m2) - -> matrix_inner_product_promote_t -{ - /* Use the promoted type to determine how to multiply: */ - using concat_type = matrix_inner_product_promote_t; - using tag = basis_tag_of_t; - static_assert(tag::value != any_basis_c, "invalid matrix basis orientations"); - - cml::check_square(m1); - cml::check_square(m2); - - return detail::matrix_concat(m1, m2, tag()); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_CONCAT_TPP +# error "mathlib/matrix/concat.tpp not included correctly" +#endif + +#include + +namespace cml { +namespace detail { + +/** Row-basis concatenation. */ +template +inline auto +matrix_concat(const readable_matrix& m1, const readable_matrix& m2, + row_basis) -> matrix_inner_product_promote_t +{ + return m1 * m2; +} + +/** Column-basis concatenation. */ +template +inline auto +matrix_concat(const readable_matrix& m1, const readable_matrix& m2, + col_basis) -> matrix_inner_product_promote_t +{ + return m2 * m1; +} + +} // namespace detail + +template +inline auto +matrix_concat(const readable_matrix& m1, const readable_matrix& m2) + -> matrix_inner_product_promote_t +{ + /* Use the promoted type to determine how to multiply: */ + using concat_type = matrix_inner_product_promote_t; + using tag = basis_tag_of_t; + static_assert(tag::value != any_basis_c, "invalid matrix basis orientations"); + + cml::check_square(m1); + cml::check_square(m2); + + return detail::matrix_concat(m1, m2, tag()); +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/matrix/generators.h b/cml/mathlib/matrix/generators.h index 3e552f9..2547445 100644 --- a/cml/mathlib/matrix/generators.h +++ b/cml/mathlib/matrix/generators.h @@ -1,86 +1,86 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -/** @defgroup mathlib_matrix_generators Matrix Generator Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_generators */ -/*@{*/ - -/** @defgroup mathlib_matrix_generators_zero Zero Matrix Generators */ -/*@{*/ - -/** Return a fixed-size double-precision zero matrix. */ -template -inline auto -zero() -> matrix> -{ - return matrix>().zero(); -} - -/** Return the 2x2 zero matrix */ -inline auto -zero_2x2() -> decltype(zero<2, 2>()) -{ - return zero<2, 2>(); -} - -/** Return the 3x3 zero matrix */ -inline auto -zero_3x3() -> decltype(zero<3, 3>()) -{ - return zero<3, 3>(); -} - -/** Return the 4x4 zero matrix */ -inline auto -zero_4x4() -> decltype(zero<4, 4>()) -{ - return zero<4, 4>(); -} - -/*@}*/ - -/** @defgroup mathlib_matrix_generators_identity Identity Matrix Generators */ -/*@{*/ - -/** Return a fixed-size double-precision identity matrix. */ -template -inline auto -identity() -> matrix> -{ - return matrix>().identity(); -} - -/** Return the 2x2 identity matrix */ -inline auto -identity_2x2() -> decltype(identity<2, 2>()) -{ - return identity<2, 2>(); -} - -/** Return the 3x3 identity matrix */ -inline auto -identity_3x3() -> decltype(identity<3, 3>()) -{ - return identity<3, 3>(); -} - -/** Return the 4x4 identity matrix */ -inline auto -identity_4x4() -> decltype(identity<4, 4>()) -{ - return identity<4, 4>(); -} - -/*@}*/ - -/*@}*/ - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +/** @defgroup mathlib_matrix_generators Matrix Generator Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_generators */ +/*@{*/ + +/** @defgroup mathlib_matrix_generators_zero Zero Matrix Generators */ +/*@{*/ + +/** Return a fixed-size double-precision zero matrix. */ +template +inline auto +zero() -> matrix> +{ + return matrix>().zero(); +} + +/** Return the 2x2 zero matrix */ +inline auto +zero_2x2() -> decltype(zero<2, 2>()) +{ + return zero<2, 2>(); +} + +/** Return the 3x3 zero matrix */ +inline auto +zero_3x3() -> decltype(zero<3, 3>()) +{ + return zero<3, 3>(); +} + +/** Return the 4x4 zero matrix */ +inline auto +zero_4x4() -> decltype(zero<4, 4>()) +{ + return zero<4, 4>(); +} + +/*@}*/ + +/** @defgroup mathlib_matrix_generators_identity Identity Matrix Generators */ +/*@{*/ + +/** Return a fixed-size double-precision identity matrix. */ +template +inline auto +identity() -> matrix> +{ + return matrix>().identity(); +} + +/** Return the 2x2 identity matrix */ +inline auto +identity_2x2() -> decltype(identity<2, 2>()) +{ + return identity<2, 2>(); +} + +/** Return the 3x3 identity matrix */ +inline auto +identity_3x3() -> decltype(identity<3, 3>()) +{ + return identity<3, 3>(); +} + +/** Return the 4x4 identity matrix */ +inline auto +identity_4x4() -> decltype(identity<4, 4>()) +{ + return identity<4, 4>(); +} + +/*@}*/ + +/*@}*/ + +} // namespace cml diff --git a/cml/mathlib/matrix/invert.h b/cml/mathlib/matrix/invert.h index 778774e..269a926 100644 --- a/cml/mathlib/matrix/invert.h +++ b/cml/mathlib/matrix/invert.h @@ -1,42 +1,42 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Invert a 2D affine transformation consisting of a rotation and a - * translation only. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template void matrix_invert_RT_only_2D(writable_matrix& m); - -/** Invert a 3D affine transformation consisting of a rotation and a - * translation only. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template void matrix_invert_RT_only(writable_matrix& m); - -/** Invert an n-D affine transformation consisting of a rotation and a - * translation only. - * - * @throws affine_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized an affine transformation. If @c m - * is fixed-size, the size is checked at compile-time. - */ -template void matrix_invert_RT(writable_matrix& m); - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_INVERT_TPP -#include -#undef __CML_MATHLIB_MATRIX_INVERT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Invert a 2D affine transformation consisting of a rotation and a + * translation only. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template void matrix_invert_RT_only_2D(writable_matrix& m); + +/** Invert a 3D affine transformation consisting of a rotation and a + * translation only. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template void matrix_invert_RT_only(writable_matrix& m); + +/** Invert an n-D affine transformation consisting of a rotation and a + * translation only. + * + * @throws affine_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized an affine transformation. If @c m + * is fixed-size, the size is checked at compile-time. + */ +template void matrix_invert_RT(writable_matrix& m); + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_INVERT_TPP +#include +#undef __CML_MATHLIB_MATRIX_INVERT_TPP diff --git a/cml/mathlib/matrix/invert.tpp b/cml/mathlib/matrix/invert.tpp index 36eb83b..2fdf2d8 100644 --- a/cml/mathlib/matrix/invert.tpp +++ b/cml/mathlib/matrix/invert.tpp @@ -1,78 +1,78 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#include -#include -#include - -namespace cml { - -template -void -matrix_invert_RT_only_2D(writable_matrix& m) -{ - cml::check_affine_2D(m); - - /* Transpose the basis vectors: */ - auto x = matrix_get_x_basis_vector_2D(m); - auto y = matrix_get_y_basis_vector_2D(m); - matrix_set_transposed_basis_vectors_2D(m, x, y); - - /* Transform the translation: */ - auto p = matrix_get_translation_2D(m); - matrix_set_translation_2D(m, -dot(p, x), -dot(p, y)); -} - -template -void -matrix_invert_RT_only(writable_matrix& m) -{ - cml::check_affine_3D(m); - - /* Transpose the basis vectors: */ - auto x = matrix_get_x_basis_vector(m); - auto y = matrix_get_y_basis_vector(m); - auto z = matrix_get_z_basis_vector(m); - matrix_set_transposed_basis_vectors(m, x, y, z); - - /* Transform the translation: */ - auto p = matrix_get_translation(m); - matrix_set_translation(m, -dot(p, x), -dot(p, y), -dot(p, z)); -} - -template -void -matrix_invert_RT(writable_matrix& m) -{ - cml::check_affine(m); - - int R = m.rows(), C = m.cols(); - int M; - /**/ if(R > C) - M = C; // Rectangular, row basis, e.g. 4x3 - else if(R < C) M = R; // Rectangular, col basis, e.g. 3x4 - else M = R - 1; // Square, either, e.g. 4x4. - - /* Transpose the MxM rotation part of m in-place: */ - for(int i = 0; i < M; ++i) { - for(int j = i + 1; j < M; ++j) { - auto e_ij = m.basis_element(i, j); - auto e_ji = m.basis_element(j, i); - m.set_basis_element(i, j, e_ji); - m.set_basis_element(j, i, e_ij); - } - } - - /* Negate the Mx1 translation (basis vector M) and multiply by the - * transposed rotation: - */ - auto T = matrix_get_basis_vector_nD(m, M); - for(int i = 0; i < M; ++i) { - auto e = m.basis_element(0, i) * T[0]; - for(int j = 1; j < M; ++j) e += m.basis_element(j, i) * T[j]; - m.set_basis_element(M, i, -e); - } -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#include +#include +#include + +namespace cml { + +template +void +matrix_invert_RT_only_2D(writable_matrix& m) +{ + cml::check_affine_2D(m); + + /* Transpose the basis vectors: */ + auto x = matrix_get_x_basis_vector_2D(m); + auto y = matrix_get_y_basis_vector_2D(m); + matrix_set_transposed_basis_vectors_2D(m, x, y); + + /* Transform the translation: */ + auto p = matrix_get_translation_2D(m); + matrix_set_translation_2D(m, -dot(p, x), -dot(p, y)); +} + +template +void +matrix_invert_RT_only(writable_matrix& m) +{ + cml::check_affine_3D(m); + + /* Transpose the basis vectors: */ + auto x = matrix_get_x_basis_vector(m); + auto y = matrix_get_y_basis_vector(m); + auto z = matrix_get_z_basis_vector(m); + matrix_set_transposed_basis_vectors(m, x, y, z); + + /* Transform the translation: */ + auto p = matrix_get_translation(m); + matrix_set_translation(m, -dot(p, x), -dot(p, y), -dot(p, z)); +} + +template +void +matrix_invert_RT(writable_matrix& m) +{ + cml::check_affine(m); + + int R = m.rows(), C = m.cols(); + int M; + /**/ if(R > C) + M = C; // Rectangular, row basis, e.g. 4x3 + else if(R < C) M = R; // Rectangular, col basis, e.g. 3x4 + else M = R - 1; // Square, either, e.g. 4x4. + + /* Transpose the MxM rotation part of m in-place: */ + for(int i = 0; i < M; ++i) { + for(int j = i + 1; j < M; ++j) { + auto e_ij = m.basis_element(i, j); + auto e_ji = m.basis_element(j, i); + m.set_basis_element(i, j, e_ji); + m.set_basis_element(j, i, e_ij); + } + } + + /* Negate the Mx1 translation (basis vector M) and multiply by the + * transposed rotation: + */ + auto T = matrix_get_basis_vector_nD(m, M); + for(int i = 0; i < M; ++i) { + auto e = m.basis_element(0, i) * T[0]; + for(int j = 1; j < M; ++j) e += m.basis_element(j, i) * T[j]; + m.set_basis_element(M, i, -e); + } +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/matrix/misc.h b/cml/mathlib/matrix/misc.h index 1350533..6bd9666 100644 --- a/cml/mathlib/matrix/misc.h +++ b/cml/mathlib/matrix/misc.h @@ -1,75 +1,75 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -/** @defgroup mathlib_matrix_misc Miscellaneous Matrix Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_misc */ -/*@{*/ - -/** Compute the trace of the upper-left 2x2 submatrix of @c m. - * - * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is - * not at least 2x2. If @c m is fixed-size, the size is checked at - * run-time. - */ -template -auto trace_2x2(const readable_matrix& m) -> value_type_trait_of_t; - -/** Compute the trace of the upper-left 3x3 submatrix of @c m. - * - * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is - * not at least 3x3. If @c m is fixed-size, the size is checked at - * run-time. - */ -template -auto trace_3x3(const readable_matrix& m) -> value_type_trait_of_t; - - -/** Generate an upper-left 3x3 skew-symmetric submatrix @c m from the - * elements of @c v, accounting for the basis orientation. - * - * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is - * not at least 3x3. If @c m is fixed-size, the size is checked at - * run-time. - * - * @throws vector_size_error if @c v is dynamically-sized, and is not 3D. - * If @c v is fixed-size, the size is checked at run-time. - */ -template -void matrix_skew_symmetric(writable_matrix& m, - const readable_vector& v); - -/** Generate an upper-left 2x2 skew-symmetric submatrix in @c m from the - * value of @c s, accounting for the basis orientation. - * - * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is - * not at least 2x2. If @c m is fixed-size, the size is checked at - * run-time. - */ -template -void matrix_skew_symmetric(writable_matrix& m, const Scalar& s); - - -/** Invert a 3D matrix composed of a rotation and translation. - * - * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is - * not at least 3x4. If @c m is fixed-size, the size is checked at - * run-time. - */ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_MISC_TPP -#include -#undef __CML_MATHLIB_MATRIX_MISC_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +/** @defgroup mathlib_matrix_misc Miscellaneous Matrix Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_misc */ +/*@{*/ + +/** Compute the trace of the upper-left 2x2 submatrix of @c m. + * + * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is + * not at least 2x2. If @c m is fixed-size, the size is checked at + * run-time. + */ +template +auto trace_2x2(const readable_matrix& m) -> value_type_trait_of_t; + +/** Compute the trace of the upper-left 3x3 submatrix of @c m. + * + * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is + * not at least 3x3. If @c m is fixed-size, the size is checked at + * run-time. + */ +template +auto trace_3x3(const readable_matrix& m) -> value_type_trait_of_t; + + +/** Generate an upper-left 3x3 skew-symmetric submatrix @c m from the + * elements of @c v, accounting for the basis orientation. + * + * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is + * not at least 3x3. If @c m is fixed-size, the size is checked at + * run-time. + * + * @throws vector_size_error if @c v is dynamically-sized, and is not 3D. + * If @c v is fixed-size, the size is checked at run-time. + */ +template +void matrix_skew_symmetric(writable_matrix& m, + const readable_vector& v); + +/** Generate an upper-left 2x2 skew-symmetric submatrix in @c m from the + * value of @c s, accounting for the basis orientation. + * + * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is + * not at least 2x2. If @c m is fixed-size, the size is checked at + * run-time. + */ +template +void matrix_skew_symmetric(writable_matrix& m, const Scalar& s); + + +/** Invert a 3D matrix composed of a rotation and translation. + * + * @throws minimum_matrix_size_error if @c m is dynamically-sized, and is + * not at least 3x4. If @c m is fixed-size, the size is checked at + * run-time. + */ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_MISC_TPP +#include +#undef __CML_MATHLIB_MATRIX_MISC_TPP diff --git a/cml/mathlib/matrix/misc.tpp b/cml/mathlib/matrix/misc.tpp index 3fd152b..a122b44 100644 --- a/cml/mathlib/matrix/misc.tpp +++ b/cml/mathlib/matrix/misc.tpp @@ -1,59 +1,59 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_MISC_TPP -# error "mathlib/matrix/misc.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -template -inline auto -trace_2x2(const readable_matrix& m) -> value_type_trait_of_t -{ - cml::check_linear_2D(m); - return m(0, 0) + m(1, 1); -} - -template -inline auto -trace_3x3(const readable_matrix& m) -> value_type_trait_of_t -{ - cml::check_linear_3D(m); - return m(0, 0) + m(1, 1) + m(2, 2); -} - -template -inline void -matrix_skew_symmetric(writable_matrix& m, const readable_vector& v) -{ - cml::check_linear_3D(m); - cml::check_size(v, int_c<3>()); - - m.zero(); - - m.set_basis_element(1, 2, v[0]); - m.set_basis_element(2, 1, -v[0]); - m.set_basis_element(2, 0, v[1]); - m.set_basis_element(0, 2, -v[1]); - m.set_basis_element(0, 1, v[2]); - m.set_basis_element(1, 0, -v[2]); -} - -template -inline void -matrix_skew_symmetric_2D(writable_matrix& m, const Scalar& s) -{ - cml::check_linear_2D(m); - - m.zero(); - m.set_basis_element(0, 1, s); - m.set_basis_element(1, 0, -s); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_MISC_TPP +# error "mathlib/matrix/misc.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +template +inline auto +trace_2x2(const readable_matrix& m) -> value_type_trait_of_t +{ + cml::check_linear_2D(m); + return m(0, 0) + m(1, 1); +} + +template +inline auto +trace_3x3(const readable_matrix& m) -> value_type_trait_of_t +{ + cml::check_linear_3D(m); + return m(0, 0) + m(1, 1) + m(2, 2); +} + +template +inline void +matrix_skew_symmetric(writable_matrix& m, const readable_vector& v) +{ + cml::check_linear_3D(m); + cml::check_size(v, int_c<3>()); + + m.zero(); + + m.set_basis_element(1, 2, v[0]); + m.set_basis_element(2, 1, -v[0]); + m.set_basis_element(2, 0, v[1]); + m.set_basis_element(0, 2, -v[1]); + m.set_basis_element(0, 1, v[2]); + m.set_basis_element(1, 0, -v[2]); +} + +template +inline void +matrix_skew_symmetric_2D(writable_matrix& m, const Scalar& s) +{ + cml::check_linear_2D(m); + + m.zero(); + m.set_basis_element(0, 1, s); + m.set_basis_element(1, 0, -s); +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/matrix/projection.h b/cml/mathlib/matrix/projection.h index 3ea2438..db691f5 100644 --- a/cml/mathlib/matrix/projection.h +++ b/cml/mathlib/matrix/projection.h @@ -1,242 +1,242 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_matrix_projection Projection Matrix Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_projection */ -/*@{*/ - -/** @defgroup mathlib_matrix_orthographic Orthographic Projection */ -/*@{*/ - -/** Build a matrix representing an orthographic projection given the - * handedness, z-clipping range, and frustum bounds. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_orthographic(writable_matrix& m, E left, E right, E bottom, - E top, E n, E f, AxisOrientation handedness, ZClip z_clip); - -/** Build a matrix representing a left-handed orthographic projection given - * the z-clipping range and frustum bounds. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_orthographic_LH(writable_matrix& m, E left, E right, E bottom, - E top, E n, E f, ZClip z_clip); - -/** Build a matrix representing a right-handed orthographic projection given - * the z-clipping range and frustum bounds. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_orthographic_RH(writable_matrix& m, E left, E right, E bottom, - E top, E n, E f, ZClip z_clip); - - -/** Build a matrix representing a orthographic projection given the - * handededness, z-clipping range, and frustum size. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_orthographic(writable_matrix& m, E width, E height, E n, E f, - AxisOrientation handedness, ZClip z_clip); - -/** Build a matrix representing a left-handed orthographic projection given - * the z-clipping range and frustum size. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_orthographic_LH(writable_matrix& m, E width, E height, E n, - E f, ZClip z_clip); - -/** Build a matrix representing a right-handed orthographic projection given - * the z-clipping range and frustum size. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_orthographic_RH(writable_matrix& m, E width, E height, E n, - E f, ZClip z_clip); - -/*@}*/ - - -/** @defgroup mathlib_matrix_perspective Perspective Projection */ -/*@{*/ - -/** Build a matrix representing a perspective projection given the - * handedness, z-clipping range, and frustum bounds. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective(writable_matrix& m, E left, E right, E bottom, - E top, E n, E f, AxisOrientation handedness, ZClip z_clip); - -/** Build a matrix representing a left-handed perspective projection given - * the z-clipping range and frustum bounds. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_LH(writable_matrix& m, E left, E right, E bottom, - E top, E n, E f, ZClip z_clip); - -/** Build a matrix representing a right-handed perspective projection given - * the z-clipping range and frustum bounds. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_RH(writable_matrix& m, E left, E right, E bottom, - E top, E n, E f, ZClip z_clip); - - -/** Build a matrix representing a perspective projection given the - * handededness, z-clipping range, and frustum size. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective(writable_matrix& m, E width, E height, E n, E f, - AxisOrientation handedness, ZClip z_clip); - -/** Build a matrix representing a left-handed perspective projection given - * the z-clipping range and frustum size. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_LH(writable_matrix& m, E width, E height, E n, E f, - ZClip z_clip); - -/** Build a matrix representing a right-handed perspective projection given - * the z-clipping range and frustum size. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_RH(writable_matrix& m, E width, E height, E n, E f, - ZClip z_clip); - - -/** Build a matrix representing a perspective projection given the - * handedness, z-clipping range, aspect ratio, horizontal field of view, - * and near and far clip plane positions. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_xfov(writable_matrix& m, E xfov, E aspect, E n, - E f, AxisOrientation handedness, ZClip z_clip); - -/** Build a matrix representing a left-hand perspective projection given - * the z-clipping range, aspect ratio, horizontal field of view, and near - * and far clip plane positions. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_xfov_LH(writable_matrix& m, E xfov, E aspect, E n, - E f, ZClip z_clip); - -/** Build a matrix representing a right-hand perspective projection given - * the z-clipping range, aspect ratio, horizontal field of view, and near - * and far clip plane positions. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_xfov_RH(writable_matrix& m, E xfov, E aspect, E n, - E f, ZClip z_clip); - - -/** Build a matrix representing a perspective projection given the - * handedness, z-clipping range, aspect ratio, vertical field of view, - * and near and far clip plane positions. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_yfov(writable_matrix& m, E yfov, E aspect, E n, - E f, AxisOrientation handedness, ZClip z_clip); - -/** Build a matrix representing a left-hand perspective projection given - * the z-clipping range, aspect ratio, vertical field of view, and near - * and far clip plane positions. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_yfov_LH(writable_matrix& m, E yfov, E aspect, E n, - E f, ZClip z_clip); - -/** Build a matrix representing a right-hand perspective projection given - * the z-clipping range, aspect ratio, vertical field of view, and near - * and far clip plane positions. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_perspective_yfov_RH(writable_matrix& m, E yfov, E aspect, E n, - E f, ZClip z_clip); - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_PROJECTION_TPP -#include -#undef __CML_MATHLIB_MATRIX_PROJECTION_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_matrix_projection Projection Matrix Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_projection */ +/*@{*/ + +/** @defgroup mathlib_matrix_orthographic Orthographic Projection */ +/*@{*/ + +/** Build a matrix representing an orthographic projection given the + * handedness, z-clipping range, and frustum bounds. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_orthographic(writable_matrix& m, E left, E right, E bottom, + E top, E n, E f, AxisOrientation handedness, ZClip z_clip); + +/** Build a matrix representing a left-handed orthographic projection given + * the z-clipping range and frustum bounds. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_orthographic_LH(writable_matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip); + +/** Build a matrix representing a right-handed orthographic projection given + * the z-clipping range and frustum bounds. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_orthographic_RH(writable_matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip); + + +/** Build a matrix representing a orthographic projection given the + * handededness, z-clipping range, and frustum size. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_orthographic(writable_matrix& m, E width, E height, E n, E f, + AxisOrientation handedness, ZClip z_clip); + +/** Build a matrix representing a left-handed orthographic projection given + * the z-clipping range and frustum size. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_orthographic_LH(writable_matrix& m, E width, E height, E n, + E f, ZClip z_clip); + +/** Build a matrix representing a right-handed orthographic projection given + * the z-clipping range and frustum size. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_orthographic_RH(writable_matrix& m, E width, E height, E n, + E f, ZClip z_clip); + +/*@}*/ + + +/** @defgroup mathlib_matrix_perspective Perspective Projection */ +/*@{*/ + +/** Build a matrix representing a perspective projection given the + * handedness, z-clipping range, and frustum bounds. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective(writable_matrix& m, E left, E right, E bottom, + E top, E n, E f, AxisOrientation handedness, ZClip z_clip); + +/** Build a matrix representing a left-handed perspective projection given + * the z-clipping range and frustum bounds. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_LH(writable_matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip); + +/** Build a matrix representing a right-handed perspective projection given + * the z-clipping range and frustum bounds. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_RH(writable_matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip); + + +/** Build a matrix representing a perspective projection given the + * handededness, z-clipping range, and frustum size. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective(writable_matrix& m, E width, E height, E n, E f, + AxisOrientation handedness, ZClip z_clip); + +/** Build a matrix representing a left-handed perspective projection given + * the z-clipping range and frustum size. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_LH(writable_matrix& m, E width, E height, E n, E f, + ZClip z_clip); + +/** Build a matrix representing a right-handed perspective projection given + * the z-clipping range and frustum size. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_RH(writable_matrix& m, E width, E height, E n, E f, + ZClip z_clip); + + +/** Build a matrix representing a perspective projection given the + * handedness, z-clipping range, aspect ratio, horizontal field of view, + * and near and far clip plane positions. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_xfov(writable_matrix& m, E xfov, E aspect, E n, + E f, AxisOrientation handedness, ZClip z_clip); + +/** Build a matrix representing a left-hand perspective projection given + * the z-clipping range, aspect ratio, horizontal field of view, and near + * and far clip plane positions. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_xfov_LH(writable_matrix& m, E xfov, E aspect, E n, + E f, ZClip z_clip); + +/** Build a matrix representing a right-hand perspective projection given + * the z-clipping range, aspect ratio, horizontal field of view, and near + * and far clip plane positions. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_xfov_RH(writable_matrix& m, E xfov, E aspect, E n, + E f, ZClip z_clip); + + +/** Build a matrix representing a perspective projection given the + * handedness, z-clipping range, aspect ratio, vertical field of view, + * and near and far clip plane positions. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_yfov(writable_matrix& m, E yfov, E aspect, E n, + E f, AxisOrientation handedness, ZClip z_clip); + +/** Build a matrix representing a left-hand perspective projection given + * the z-clipping range, aspect ratio, vertical field of view, and near + * and far clip plane positions. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_yfov_LH(writable_matrix& m, E yfov, E aspect, E n, + E f, ZClip z_clip); + +/** Build a matrix representing a right-hand perspective projection given + * the z-clipping range, aspect ratio, vertical field of view, and near + * and far clip plane positions. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_perspective_yfov_RH(writable_matrix& m, E yfov, E aspect, E n, + E f, ZClip z_clip); + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_PROJECTION_TPP +#include +#undef __CML_MATHLIB_MATRIX_PROJECTION_TPP diff --git a/cml/mathlib/matrix/projection.tpp b/cml/mathlib/matrix/projection.tpp index c191d60..08eec13 100644 --- a/cml/mathlib/matrix/projection.tpp +++ b/cml/mathlib/matrix/projection.tpp @@ -1,295 +1,295 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_PROJECTION_TPP -# error "mathlib/matrix/projection.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -/* Orthographic projection functions: */ - -/** Build a matrix representing an orthographic projection, specified by - * frustum bounds in l,r,b,t,n,f form, and with the given handedness and z - * clipping range - */ - -template -inline void -matrix_orthographic(writable_matrix& m, E left, E right, E bottom, E top, - E n, E f, AxisOrientation handedness, ZClip z_clip) -{ - static_assert(cml::are_convertible, E>::value, - "incompatible scalar types"); - - cml::check_minimum_size(m, int_c<4>(), int_c<4>()); - - /* Initialize: */ - m.identity(); - - auto inv_width = E(1) / (right - left); - auto inv_height = E(1) / (top - bottom); - auto inv_depth = E(1) / (f - n); - auto s = E(handedness == left_handed ? 1 : -1); - - if(z_clip == z_clip_neg_one) { - m.set_basis_element(2, 2, s * E(2) * inv_depth); - m.set_basis_element(3, 2, -(f + n) * inv_depth); - } else { // z_clip.z_clip() == 0 - m.set_basis_element(2, 2, s * inv_depth); - m.set_basis_element(3, 2, -n * inv_depth); - } - - m.set_basis_element(0, 0, E(2) * inv_width); - m.set_basis_element(1, 1, E(2) * inv_height); - m.set_basis_element(3, 0, -(right + left) * inv_width); - m.set_basis_element(3, 1, -(top + bottom) * inv_height); -} - -template -inline void -matrix_orthographic_LH(writable_matrix& m, E left, E right, E bottom, - E top, E n, E f, ZClip z_clip) -{ - matrix_orthographic(m, left, right, bottom, top, n, f, left_handed, z_clip); -} - -template -inline void -matrix_orthographic_RH(writable_matrix& m, E left, E right, E bottom, - E top, E n, E f, ZClip z_clip) -{ - matrix_orthographic(m, left, right, bottom, top, n, f, right_handed, z_clip); -} - -template -inline void -matrix_orthographic(writable_matrix& m, E width, E height, E n, E f, - AxisOrientation handedness, ZClip z_clip) -{ - auto half_width = width / E(2); - auto half_height = height / E(2); - matrix_orthographic(m, -half_width, half_width, -half_height, half_height, n, - f, handedness, z_clip); -} - -template -inline void -matrix_orthographic_LH(writable_matrix& m, E width, E height, E n, E f, - ZClip z_clip) -{ - matrix_orthographic(m, width, height, n, f, left_handed, z_clip); -} - -template -inline void -matrix_orthographic_RH(writable_matrix& m, E width, E height, E n, E f, - ZClip z_clip) -{ - matrix_orthographic(m, width, height, n, f, right_handed, z_clip); -} - -/* Perspective projection functions: */ - -template -inline void -matrix_perspective(writable_matrix& m, E left, E right, E bottom, E top, - E n, E f, AxisOrientation handedness, ZClip z_clip) -{ - static_assert(cml::are_convertible, E>::value, - "incompatible scalar types"); - - cml::check_minimum_size(m, int_c<4>(), int_c<4>()); - - /* Initialize: */ - m.identity(); - - auto inv_width = E(1) / (right - left); - auto inv_height = E(1) / (top - bottom); - auto inv_depth = E(1) / (f - n); - auto near2 = E(2) * n; - auto s = E(handedness == left_handed ? 1 : -1); - - if(z_clip == z_clip_neg_one) { - m.set_basis_element(2, 2, s * (f + n) * inv_depth); - m.set_basis_element(3, 2, -E(2) * f * n * inv_depth); - } else { // z_clip == z_clip_zero - m.set_basis_element(2, 2, s * f * inv_depth); - m.set_basis_element(3, 2, -s * n * m.basis_element(2, 2)); - } - - m.set_basis_element(0, 0, near2 * inv_width); - m.set_basis_element(1, 1, near2 * inv_height); - m.set_basis_element(2, 0, -s * (right + left) * inv_width); - m.set_basis_element(2, 1, -s * (top + bottom) * inv_height); - m.set_basis_element(2, 3, s); - m.set_basis_element(3, 3, 0); -} - -template -inline void -matrix_perspective_LH(writable_matrix& m, E left, E right, E bottom, E top, - E n, E f, ZClip z_clip) -{ - matrix_perspective(m, left, right, bottom, top, n, f, left_handed, z_clip); -} - -template -inline void -matrix_perspective_RH(writable_matrix& m, E left, E right, E bottom, E top, - E n, E f, ZClip z_clip) -{ - matrix_perspective(m, left, right, bottom, top, n, f, right_handed, z_clip); -} - -template -inline void -matrix_perspective(writable_matrix& m, E width, E height, E n, E f, - AxisOrientation handedness, ZClip z_clip) -{ - auto half_width = width / E(2); - auto half_height = height / E(2); - matrix_perspective(m, -half_width, half_width, -half_height, half_height, n, - f, handedness, z_clip); -} - -template -inline void -matrix_perspective_LH(writable_matrix& m, E width, E height, E n, E f, - ZClip z_clip) -{ - matrix_perspective(m, width, height, n, f, left_handed, z_clip); -} - -template -inline void -matrix_perspective_RH(writable_matrix& m, E width, E height, E n, E f, - ZClip z_clip) -{ - matrix_perspective(m, width, height, n, f, right_handed, z_clip); -} - -template -inline void -matrix_perspective_xfov(writable_matrix& m, E xfov, E aspect, E n, E f, - AxisOrientation handedness, ZClip z_clip) -{ - using E_traits = scalar_traits; - - /* Compute the view height from the field of view: */ - auto width = E(2) * n * E_traits::tan(xfov / E(2)); - matrix_perspective(m, width, width / aspect, n, f, handedness, z_clip); -} - -template -inline void -matrix_perspective_xfov_LH(writable_matrix& m, E xfov, E aspect, E n, E f, - ZClip z_clip) -{ - matrix_perspective_xfov(m, xfov, aspect, n, f, left_handed, z_clip); -} - -template -inline void -matrix_perspective_xfov_RH(writable_matrix& m, E xfov, E aspect, E n, E f, - ZClip z_clip) -{ - matrix_perspective_xfov(m, xfov, aspect, n, f, right_handed, z_clip); -} - -template -inline void -matrix_perspective_yfov(writable_matrix& m, E yfov, E aspect, E n, E f, - AxisOrientation handedness, ZClip z_clip) -{ - using E_traits = scalar_traits; - - /* Compute the view height from the field of view: */ - auto height = E(2) * n * E_traits::tan(yfov / E(2)); - matrix_perspective(m, height * aspect, height, n, f, handedness, z_clip); -} - -template -inline void -matrix_perspective_yfov_LH(writable_matrix& m, E yfov, E aspect, E n, E f, - ZClip z_clip) -{ - matrix_perspective_yfov(m, yfov, aspect, n, f, left_handed, z_clip); -} - -template -inline void -matrix_perspective_yfov_RH(writable_matrix& m, E yfov, E aspect, E n, E f, - ZClip z_clip) -{ - matrix_perspective_yfov(m, yfov, aspect, n, f, right_handed, z_clip); -} - -} // namespace cml - -#if 0 -// XXX INCOMPLETE XXX - -/* Build a viewport matrix - * - * Note: A viewport matrix is in a sense the opposite of an orthographics - * projection matrix, and can be build by constructing and inverting the - * latter. - * - * @todo: Need to look into D3D viewport conventions and see if this needs to - * be adapted accordingly. - */ - -template < typename E, class A, class B, class L > void -matrix_viewport(matrix& m, E left, E right, E bottom, - E top, ZClip z_clip, E n = E(0), E f = E(1)) -{ - matrix_orthographic_LH(m, left, right, bottom, top, n, f, z_clip); - /* @todo: invert(m), when available */ - m = inverse(m); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D picking volume -////////////////////////////////////////////////////////////////////////////// - -/* Build a pick volume matrix - * - * When post-concatenated with a projection matrix, the pick matrix modifies - * the view volume to create a 'picking volume'. This volume corresponds to - * a screen rectangle centered at (pick_x, pick_y) and with dimensions - * pick_widthXpick_height. - * - * @todo: Representation of viewport between this function and - * matrix_viewport() is inconsistent (position and dimensions vs. bounds). - * Should this be addressed? - */ - -template < typename E, class A, class B, class L > void -matrix_pick( - matrix& m, E pick_x, E pick_y, E pick_width, E pick_height, - E viewport_x, E viewport_y, E viewport_width, E viewport_height) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckMatHomogeneous3D(m); - - identity_transform(m); - - value_type inv_width = value_type(1) / pick_width; - value_type inv_height = value_type(1) / pick_height; - - m.set_basis_element(0,0,viewport_width*inv_width); - m.set_basis_element(1,1,viewport_height*inv_height); - m.set_basis_element(3,0, - (viewport_width+value_type(2)*(viewport_x-pick_x))*inv_width); - m.set_basis_element(3,1, - (viewport_height+value_type(2)*(viewport_y-pick_y))*inv_height); -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_PROJECTION_TPP +# error "mathlib/matrix/projection.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +/* Orthographic projection functions: */ + +/** Build a matrix representing an orthographic projection, specified by + * frustum bounds in l,r,b,t,n,f form, and with the given handedness and z + * clipping range + */ + +template +inline void +matrix_orthographic(writable_matrix& m, E left, E right, E bottom, E top, + E n, E f, AxisOrientation handedness, ZClip z_clip) +{ + static_assert(cml::are_convertible, E>::value, + "incompatible scalar types"); + + cml::check_minimum_size(m, int_c<4>(), int_c<4>()); + + /* Initialize: */ + m.identity(); + + auto inv_width = E(1) / (right - left); + auto inv_height = E(1) / (top - bottom); + auto inv_depth = E(1) / (f - n); + auto s = E(handedness == left_handed ? 1 : -1); + + if(z_clip == z_clip_neg_one) { + m.set_basis_element(2, 2, s * E(2) * inv_depth); + m.set_basis_element(3, 2, -(f + n) * inv_depth); + } else { // z_clip.z_clip() == 0 + m.set_basis_element(2, 2, s * inv_depth); + m.set_basis_element(3, 2, -n * inv_depth); + } + + m.set_basis_element(0, 0, E(2) * inv_width); + m.set_basis_element(1, 1, E(2) * inv_height); + m.set_basis_element(3, 0, -(right + left) * inv_width); + m.set_basis_element(3, 1, -(top + bottom) * inv_height); +} + +template +inline void +matrix_orthographic_LH(writable_matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip) +{ + matrix_orthographic(m, left, right, bottom, top, n, f, left_handed, z_clip); +} + +template +inline void +matrix_orthographic_RH(writable_matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip) +{ + matrix_orthographic(m, left, right, bottom, top, n, f, right_handed, z_clip); +} + +template +inline void +matrix_orthographic(writable_matrix& m, E width, E height, E n, E f, + AxisOrientation handedness, ZClip z_clip) +{ + auto half_width = width / E(2); + auto half_height = height / E(2); + matrix_orthographic(m, -half_width, half_width, -half_height, half_height, n, + f, handedness, z_clip); +} + +template +inline void +matrix_orthographic_LH(writable_matrix& m, E width, E height, E n, E f, + ZClip z_clip) +{ + matrix_orthographic(m, width, height, n, f, left_handed, z_clip); +} + +template +inline void +matrix_orthographic_RH(writable_matrix& m, E width, E height, E n, E f, + ZClip z_clip) +{ + matrix_orthographic(m, width, height, n, f, right_handed, z_clip); +} + +/* Perspective projection functions: */ + +template +inline void +matrix_perspective(writable_matrix& m, E left, E right, E bottom, E top, + E n, E f, AxisOrientation handedness, ZClip z_clip) +{ + static_assert(cml::are_convertible, E>::value, + "incompatible scalar types"); + + cml::check_minimum_size(m, int_c<4>(), int_c<4>()); + + /* Initialize: */ + m.identity(); + + auto inv_width = E(1) / (right - left); + auto inv_height = E(1) / (top - bottom); + auto inv_depth = E(1) / (f - n); + auto near2 = E(2) * n; + auto s = E(handedness == left_handed ? 1 : -1); + + if(z_clip == z_clip_neg_one) { + m.set_basis_element(2, 2, s * (f + n) * inv_depth); + m.set_basis_element(3, 2, -E(2) * f * n * inv_depth); + } else { // z_clip == z_clip_zero + m.set_basis_element(2, 2, s * f * inv_depth); + m.set_basis_element(3, 2, -s * n * m.basis_element(2, 2)); + } + + m.set_basis_element(0, 0, near2 * inv_width); + m.set_basis_element(1, 1, near2 * inv_height); + m.set_basis_element(2, 0, -s * (right + left) * inv_width); + m.set_basis_element(2, 1, -s * (top + bottom) * inv_height); + m.set_basis_element(2, 3, s); + m.set_basis_element(3, 3, 0); +} + +template +inline void +matrix_perspective_LH(writable_matrix& m, E left, E right, E bottom, E top, + E n, E f, ZClip z_clip) +{ + matrix_perspective(m, left, right, bottom, top, n, f, left_handed, z_clip); +} + +template +inline void +matrix_perspective_RH(writable_matrix& m, E left, E right, E bottom, E top, + E n, E f, ZClip z_clip) +{ + matrix_perspective(m, left, right, bottom, top, n, f, right_handed, z_clip); +} + +template +inline void +matrix_perspective(writable_matrix& m, E width, E height, E n, E f, + AxisOrientation handedness, ZClip z_clip) +{ + auto half_width = width / E(2); + auto half_height = height / E(2); + matrix_perspective(m, -half_width, half_width, -half_height, half_height, n, + f, handedness, z_clip); +} + +template +inline void +matrix_perspective_LH(writable_matrix& m, E width, E height, E n, E f, + ZClip z_clip) +{ + matrix_perspective(m, width, height, n, f, left_handed, z_clip); +} + +template +inline void +matrix_perspective_RH(writable_matrix& m, E width, E height, E n, E f, + ZClip z_clip) +{ + matrix_perspective(m, width, height, n, f, right_handed, z_clip); +} + +template +inline void +matrix_perspective_xfov(writable_matrix& m, E xfov, E aspect, E n, E f, + AxisOrientation handedness, ZClip z_clip) +{ + using E_traits = scalar_traits; + + /* Compute the view height from the field of view: */ + auto width = E(2) * n * E_traits::tan(xfov / E(2)); + matrix_perspective(m, width, width / aspect, n, f, handedness, z_clip); +} + +template +inline void +matrix_perspective_xfov_LH(writable_matrix& m, E xfov, E aspect, E n, E f, + ZClip z_clip) +{ + matrix_perspective_xfov(m, xfov, aspect, n, f, left_handed, z_clip); +} + +template +inline void +matrix_perspective_xfov_RH(writable_matrix& m, E xfov, E aspect, E n, E f, + ZClip z_clip) +{ + matrix_perspective_xfov(m, xfov, aspect, n, f, right_handed, z_clip); +} + +template +inline void +matrix_perspective_yfov(writable_matrix& m, E yfov, E aspect, E n, E f, + AxisOrientation handedness, ZClip z_clip) +{ + using E_traits = scalar_traits; + + /* Compute the view height from the field of view: */ + auto height = E(2) * n * E_traits::tan(yfov / E(2)); + matrix_perspective(m, height * aspect, height, n, f, handedness, z_clip); +} + +template +inline void +matrix_perspective_yfov_LH(writable_matrix& m, E yfov, E aspect, E n, E f, + ZClip z_clip) +{ + matrix_perspective_yfov(m, yfov, aspect, n, f, left_handed, z_clip); +} + +template +inline void +matrix_perspective_yfov_RH(writable_matrix& m, E yfov, E aspect, E n, E f, + ZClip z_clip) +{ + matrix_perspective_yfov(m, yfov, aspect, n, f, right_handed, z_clip); +} + +} // namespace cml + +#if 0 +// XXX INCOMPLETE XXX + +/* Build a viewport matrix + * + * Note: A viewport matrix is in a sense the opposite of an orthographics + * projection matrix, and can be build by constructing and inverting the + * latter. + * + * @todo: Need to look into D3D viewport conventions and see if this needs to + * be adapted accordingly. + */ + +template < typename E, class A, class B, class L > void +matrix_viewport(matrix& m, E left, E right, E bottom, + E top, ZClip z_clip, E n = E(0), E f = E(1)) +{ + matrix_orthographic_LH(m, left, right, bottom, top, n, f, z_clip); + /* @todo: invert(m), when available */ + m = inverse(m); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D picking volume +////////////////////////////////////////////////////////////////////////////// + +/* Build a pick volume matrix + * + * When post-concatenated with a projection matrix, the pick matrix modifies + * the view volume to create a 'picking volume'. This volume corresponds to + * a screen rectangle centered at (pick_x, pick_y) and with dimensions + * pick_widthXpick_height. + * + * @todo: Representation of viewport between this function and + * matrix_viewport() is inconsistent (position and dimensions vs. bounds). + * Should this be addressed? + */ + +template < typename E, class A, class B, class L > void +matrix_pick( + matrix& m, E pick_x, E pick_y, E pick_width, E pick_height, + E viewport_x, E viewport_y, E viewport_width, E viewport_height) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatHomogeneous3D(m); + + identity_transform(m); + + value_type inv_width = value_type(1) / pick_width; + value_type inv_height = value_type(1) / pick_height; + + m.set_basis_element(0,0,viewport_width*inv_width); + m.set_basis_element(1,1,viewport_height*inv_height); + m.set_basis_element(3,0, + (viewport_width+value_type(2)*(viewport_x-pick_x))*inv_width); + m.set_basis_element(3,1, + (viewport_height+value_type(2)*(viewport_y-pick_y))*inv_height); +} #endif \ No newline at end of file diff --git a/cml/mathlib/matrix/rotation.h b/cml/mathlib/matrix/rotation.h index 950b739..406c1cf 100644 --- a/cml/mathlib/matrix/rotation.h +++ b/cml/mathlib/matrix/rotation.h @@ -1,299 +1,299 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** @defgroup mathlib_matrix_rotation Matrix Rotation Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_rotation */ -/*@{*/ - -/** @defgroup mathlib_matrix_rotation_builders_2D 2D Rotation Matrix Builders */ -/*@{*/ - -/** Compute a 2D rotation matrix give @c angle. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 2x2. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_rotation_2D(writable_matrix& m, E angle); - -/*@}*/ - -/** @defgroup mathlib_matrix_rotation_alignment_2D 2D Rotation Alignment */ -/*@{*/ - -/** Compute a rotation matrix that aligns the x- or y-axis to @c align, - * based on the axis order @c order. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 2x2. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_rotation_align_2D(writable_matrix& m, - const readable_vector& align, bool normalize = true, - axis_order2D order = axis_order_xy); - -/*@}*/ - - -/** @defgroup mathlib_matrix_rotation_builders_3D 3D Rotation Matrix Builders */ -/*@{*/ - -/** Compute a matrix representing a 3D rotation @c angle about world axis - * @c axis. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - * - * @throws std::invalid_argument if @c axis < 0 or @c axis > 2. - */ -template -void matrix_rotation_world_axis(writable_matrix& m, int axis, - const E& angle); - -/** Compute a matrix representing a 3D rotation @c angle about the world - * x-axis. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_rotation_world_x(writable_matrix& m, const E& angle); - -/** Compute a matrix representing a 3D rotation @c angle about the world - * y-axis. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_rotation_world_y(writable_matrix& m, const E& angle); - -/** Compute a matrix representing a 3D rotation @c angle about the world - * z-axis. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_rotation_world_z(writable_matrix& m, const E& angle); - -/** Compute a rotation matrix from an axis and angle. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -void matrix_rotation_axis_angle(writable_matrix& m, - const readable_vector& axis, const E& angle); - -/** Compute a rotation matrix given three Euler angles and the required - * order. - * - * The rotations are applied about the cardinal axes in the order specified - * by the 'order' argument, where 'order' is one of the following - * enumerants: - * - * euler_order_xyz - * euler_order_xzy - * euler_order_xyx - * euler_order_xzx - * euler_order_yzx - * euler_order_yxz - * euler_order_yzy - * euler_order_yxy - * euler_order_zxy - * euler_order_zyx - * euler_order_zxz - * euler_order_zyz - * - * e.g. euler_order_xyz means compute the column-basis rotation matrix - * equivalent to R_x * R_y * R_z, where R_i is the rotation matrix above - * axis i (the row-basis matrix would be R_z * R_y * R_x). - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_rotation_euler(writable_matrix& m, E0 angle_0, E1 angle_1, - E2 angle_2, euler_order order); - -/** Compute a rotation matrix given a vector containing the Euler angles. - * - * @throws vector_size_error at run-time if @c euler is dynamically-sized, - * and is not 3D. If fixed-size, the sizs is checked at compile-time. - */ -template -void matrix_rotation_euler(writable_matrix& m, - const readable_vector& euler, euler_order order); - -/** Build a matrix of derivatives of Euler angles about the specified axis. - * - * The rotation derivatives are applied about the cardinal axes in the - * order specified by the 'order' argument, where 'order' is one of the - * following enumerants: - * - * euler_order_xyz - * euler_order_xzy - * euler_order_yzx - * euler_order_yxz - * euler_order_zxy - * euler_order_zyx - * - * e.g. euler_order_xyz means compute the column-basis rotation matrix - * equivalent to R_x * R_y * R_z, where R_i is the rotation matrix above - * axis i (the row-basis matrix would be R_z * R_y * R_x). - * - * The derivative is taken with respect to the specified 'axis', which is - * the position of the axis in the triple; e.g. if order = euler_order_xyz, - * then axis = 0 would mean take the derivative with respect to x. Note - * that repeated axes are not currently supported. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - * - * @throws std::invalid_argument if @c axis is not 0, 1, or 2, or if @c - * order has a repeated axis. - */ -template -void matrix_rotation_euler_derivatives(writable_matrix& m, int axis, - E0 angle_0, E1 angle_1, E2 angle_2, euler_order order); - -/** Build a matrix of derivatives of Euler angles about the specified axis, - * given the angles as a vector. - * - * @throws vector_size_error at run-time if @c euler is dynamically-sized, - * and is not 3D. If fixed-size, the sizs is checked at compile-time. - */ -template -void matrix_rotation_euler_derivatives(writable_matrix& m, int axis, - const readable_vector& euler, euler_order order); - -/** Compute a rotation matrix from a quaternion. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_rotation_quaternion(writable_matrix& m, - const readable_quaternion& q); - -/*@}*/ - -/** @defgroup mathlib_matrix_rotation_alignment 3D Rotation Alignment */ -/*@{*/ - -/** Compute a rotation matrix that aligns vector @c align to @c reference, - * using rotations in axis order @c order. - */ -template -void matrix_rotation_align(writable_matrix& m, - const readable_vector& align, const readable_vector& reference, - bool normalize = true, axis_order order = axis_order_zyx); - -/** Compute a rotation matrix to align the vector from @c pos to @c target - * with @c reference. - */ -template -void matrix_rotation_aim_at(writable_matrix& m, - const readable_vector& pos, const readable_vector& target, - const readable_vector& reference, axis_order order = axis_order_zyx); - -/*@}*/ - -/** @defgroup mathlib_matrix_rotation_conversion Rotation Matrix Conversion */ -/*@{*/ - -/** Convert a 3D rotation matrix @c m to an axis-angle pair. - * - * @note @c tolerance is used to detect a near-zero axis length. - */ -template> -void matrix_to_axis_angle(const readable_matrix& m, - writable_vector& axis, E& angle, - Tol tolerance = scalar_traits::epsilon()); - -/** Convert a 3D rotation matrix @c m to an axis-angle pair returned as a - * std::tuple. - * - * @note @c tolerance is used to detect a near-zero axis length. - */ -template> -std::tuple, compiled<3>>, - value_type_trait_of_t> -matrix_to_axis_angle(const readable_matrix& m, - Tol tolerance = scalar_traits::epsilon()); - -/** Convert a 3D rotation matrix @c m to an Euler-angle triple. - * - * @note @c tolerance is used to detect degeneracies. - */ -template> -void matrix_to_euler(const readable_matrix& m, E0& angle_0, E1& angle_1, - E2& angle_2, euler_order order, Tol tolerance = scalar_traits::epsilon(), - enable_if_matrix_t* = nullptr); - -/** Convert a 3D rotation matrix @c m to an Euler-angle triple, and return - * the result as a fixed-size 3D vector. - * - * @note @c tolerance is used to detect degeneracies. - */ -template> -vector, compiled<3>> matrix_to_euler( - const readable_matrix& m, euler_order order, - Tol tolerance = scalar_traits::epsilon(), - enable_if_matrix_t* = nullptr); - -/** Convert a 3D rotation matrix @c m to an Euler-angle triple, and return - * the result as a user-specified vector type. - * - * @note @c tolerance is used to detect degeneracies. - * - * @note @c VectorT can be any vector type with 3 elements, having internal - * storage (e.g. compiled<3> or allocated<>). The default is vector>, where T is the value_type of the matrix. - */ -template> -VectorT matrix_to_euler(const readable_matrix& m, euler_order order, - Tol tolerance = scalar_traits::epsilon(), - enable_if_vector_t* = nullptr, enable_if_matrix_t* = nullptr); - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_ROTATION_TPP -#include -#undef __CML_MATHLIB_MATRIX_ROTATION_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @defgroup mathlib_matrix_rotation Matrix Rotation Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_rotation */ +/*@{*/ + +/** @defgroup mathlib_matrix_rotation_builders_2D 2D Rotation Matrix Builders */ +/*@{*/ + +/** Compute a 2D rotation matrix give @c angle. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 2x2. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_rotation_2D(writable_matrix& m, E angle); + +/*@}*/ + +/** @defgroup mathlib_matrix_rotation_alignment_2D 2D Rotation Alignment */ +/*@{*/ + +/** Compute a rotation matrix that aligns the x- or y-axis to @c align, + * based on the axis order @c order. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 2x2. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_rotation_align_2D(writable_matrix& m, + const readable_vector& align, bool normalize = true, + axis_order2D order = axis_order_xy); + +/*@}*/ + + +/** @defgroup mathlib_matrix_rotation_builders_3D 3D Rotation Matrix Builders */ +/*@{*/ + +/** Compute a matrix representing a 3D rotation @c angle about world axis + * @c axis. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + * + * @throws std::invalid_argument if @c axis < 0 or @c axis > 2. + */ +template +void matrix_rotation_world_axis(writable_matrix& m, int axis, + const E& angle); + +/** Compute a matrix representing a 3D rotation @c angle about the world + * x-axis. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_rotation_world_x(writable_matrix& m, const E& angle); + +/** Compute a matrix representing a 3D rotation @c angle about the world + * y-axis. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_rotation_world_y(writable_matrix& m, const E& angle); + +/** Compute a matrix representing a 3D rotation @c angle about the world + * z-axis. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_rotation_world_z(writable_matrix& m, const E& angle); + +/** Compute a rotation matrix from an axis and angle. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +void matrix_rotation_axis_angle(writable_matrix& m, + const readable_vector& axis, const E& angle); + +/** Compute a rotation matrix given three Euler angles and the required + * order. + * + * The rotations are applied about the cardinal axes in the order specified + * by the 'order' argument, where 'order' is one of the following + * enumerants: + * + * euler_order_xyz + * euler_order_xzy + * euler_order_xyx + * euler_order_xzx + * euler_order_yzx + * euler_order_yxz + * euler_order_yzy + * euler_order_yxy + * euler_order_zxy + * euler_order_zyx + * euler_order_zxz + * euler_order_zyz + * + * e.g. euler_order_xyz means compute the column-basis rotation matrix + * equivalent to R_x * R_y * R_z, where R_i is the rotation matrix above + * axis i (the row-basis matrix would be R_z * R_y * R_x). + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_rotation_euler(writable_matrix& m, E0 angle_0, E1 angle_1, + E2 angle_2, euler_order order); + +/** Compute a rotation matrix given a vector containing the Euler angles. + * + * @throws vector_size_error at run-time if @c euler is dynamically-sized, + * and is not 3D. If fixed-size, the sizs is checked at compile-time. + */ +template +void matrix_rotation_euler(writable_matrix& m, + const readable_vector& euler, euler_order order); + +/** Build a matrix of derivatives of Euler angles about the specified axis. + * + * The rotation derivatives are applied about the cardinal axes in the + * order specified by the 'order' argument, where 'order' is one of the + * following enumerants: + * + * euler_order_xyz + * euler_order_xzy + * euler_order_yzx + * euler_order_yxz + * euler_order_zxy + * euler_order_zyx + * + * e.g. euler_order_xyz means compute the column-basis rotation matrix + * equivalent to R_x * R_y * R_z, where R_i is the rotation matrix above + * axis i (the row-basis matrix would be R_z * R_y * R_x). + * + * The derivative is taken with respect to the specified 'axis', which is + * the position of the axis in the triple; e.g. if order = euler_order_xyz, + * then axis = 0 would mean take the derivative with respect to x. Note + * that repeated axes are not currently supported. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + * + * @throws std::invalid_argument if @c axis is not 0, 1, or 2, or if @c + * order has a repeated axis. + */ +template +void matrix_rotation_euler_derivatives(writable_matrix& m, int axis, + E0 angle_0, E1 angle_1, E2 angle_2, euler_order order); + +/** Build a matrix of derivatives of Euler angles about the specified axis, + * given the angles as a vector. + * + * @throws vector_size_error at run-time if @c euler is dynamically-sized, + * and is not 3D. If fixed-size, the sizs is checked at compile-time. + */ +template +void matrix_rotation_euler_derivatives(writable_matrix& m, int axis, + const readable_vector& euler, euler_order order); + +/** Compute a rotation matrix from a quaternion. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_rotation_quaternion(writable_matrix& m, + const readable_quaternion& q); + +/*@}*/ + +/** @defgroup mathlib_matrix_rotation_alignment 3D Rotation Alignment */ +/*@{*/ + +/** Compute a rotation matrix that aligns vector @c align to @c reference, + * using rotations in axis order @c order. + */ +template +void matrix_rotation_align(writable_matrix& m, + const readable_vector& align, const readable_vector& reference, + bool normalize = true, axis_order order = axis_order_zyx); + +/** Compute a rotation matrix to align the vector from @c pos to @c target + * with @c reference. + */ +template +void matrix_rotation_aim_at(writable_matrix& m, + const readable_vector& pos, const readable_vector& target, + const readable_vector& reference, axis_order order = axis_order_zyx); + +/*@}*/ + +/** @defgroup mathlib_matrix_rotation_conversion Rotation Matrix Conversion */ +/*@{*/ + +/** Convert a 3D rotation matrix @c m to an axis-angle pair. + * + * @note @c tolerance is used to detect a near-zero axis length. + */ +template> +void matrix_to_axis_angle(const readable_matrix& m, + writable_vector& axis, E& angle, + Tol tolerance = scalar_traits::epsilon()); + +/** Convert a 3D rotation matrix @c m to an axis-angle pair returned as a + * std::tuple. + * + * @note @c tolerance is used to detect a near-zero axis length. + */ +template> +std::tuple, compiled<3>>, + value_type_trait_of_t> +matrix_to_axis_angle(const readable_matrix& m, + Tol tolerance = scalar_traits::epsilon()); + +/** Convert a 3D rotation matrix @c m to an Euler-angle triple. + * + * @note @c tolerance is used to detect degeneracies. + */ +template> +void matrix_to_euler(const readable_matrix& m, E0& angle_0, E1& angle_1, + E2& angle_2, euler_order order, Tol tolerance = scalar_traits::epsilon(), + enable_if_matrix_t* = nullptr); + +/** Convert a 3D rotation matrix @c m to an Euler-angle triple, and return + * the result as a fixed-size 3D vector. + * + * @note @c tolerance is used to detect degeneracies. + */ +template> +vector, compiled<3>> matrix_to_euler( + const readable_matrix& m, euler_order order, + Tol tolerance = scalar_traits::epsilon(), + enable_if_matrix_t* = nullptr); + +/** Convert a 3D rotation matrix @c m to an Euler-angle triple, and return + * the result as a user-specified vector type. + * + * @note @c tolerance is used to detect degeneracies. + * + * @note @c VectorT can be any vector type with 3 elements, having internal + * storage (e.g. compiled<3> or allocated<>). The default is vector>, where T is the value_type of the matrix. + */ +template> +VectorT matrix_to_euler(const readable_matrix& m, euler_order order, + Tol tolerance = scalar_traits::epsilon(), + enable_if_vector_t* = nullptr, enable_if_matrix_t* = nullptr); + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_ROTATION_TPP +#include +#undef __CML_MATHLIB_MATRIX_ROTATION_TPP diff --git a/cml/mathlib/matrix/rotation.tpp b/cml/mathlib/matrix/rotation.tpp index 5e83395..f2367c2 100644 --- a/cml/mathlib/matrix/rotation.tpp +++ b/cml/mathlib/matrix/rotation.tpp @@ -1,1040 +1,1040 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_ROTATION_TPP -# error "mathlib/matrix/rotation.tpp not included correctly" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cml { - -/* 2D rotations: */ - -template -inline void -matrix_rotation_2D(writable_matrix& m, E angle) -{ - static_assert(cml::are_convertible, E>::value, - "incompatible scalar types"); - - using angle_traits = scalar_traits; - - cml::check_linear_2D(m); - - /* Initialize: */ - m.identity(); - - /* Initialize m: */ - auto s = angle_traits::sin(angle); - auto c = angle_traits::cos(angle); - m.set_basis_element(0, 0, c); - m.set_basis_element(0, 1, s); - m.set_basis_element(1, 0, -s); - m.set_basis_element(1, 1, c); -} - -/* 2D alignment: */ - -template -void -matrix_rotation_align_2D(writable_matrix& m, - const readable_vector& align, bool normalize, axis_order2D order) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t>::value, - "incompatible scalar types"); - - using value_type = value_type_trait_of_t; - - cml::check_linear_2D(m); - - m.identity(); - - vector> x, y; - orthonormal_basis_2D(align, x, y, normalize, order); - matrix_set_basis_vectors_2D(m, x, y); -} - -/* 3D rotations: */ - -template -inline void -matrix_rotation_world_axis(writable_matrix& m, int axis, const E& angle) -{ - static_assert(cml::are_convertible, E>::value, - "incompatible scalar types"); - - using angle_traits = traits_of_t; - - cml::check_linear_3D(m); - cml_require(0 <= axis && axis <= 2, std::invalid_argument, "invalid axis"); - - /* Setup sin() and cos() for the chosen axis: */ - int i, j, k; - cml::cyclic_permutation(axis, i, j, k); - auto s = angle_traits::sin(angle); - auto c = angle_traits::cos(angle); - - /* Clear the matrix: */ - m.identity(); - - /* Set elements: */ - m.set_basis_element(j, j, c); - m.set_basis_element(j, k, s); - m.set_basis_element(k, j, -s); - m.set_basis_element(k, k, c); -} - -template -inline void -matrix_rotation_world_x(writable_matrix& m, const E& angle) -{ - matrix_rotation_world_axis(m, 0, angle); -} - -template -inline void -matrix_rotation_world_y(writable_matrix& m, const E& angle) -{ - matrix_rotation_world_axis(m, 1, angle); -} - -template -inline void -matrix_rotation_world_z(writable_matrix& m, const E& angle) -{ - matrix_rotation_world_axis(m, 2, angle); -} - -template -inline void -matrix_rotation_axis_angle(writable_matrix& m, - const readable_vector& axis, const E& angle) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, E>::value, - "incompatible scalar types"); - - using angle_traits = scalar_traits; - - cml::check_linear_3D(m); - cml::check_size(axis, int_c<3>()); - - /* Initialize: */ - m.identity(); - - /* Precompute values: */ - auto s = angle_traits::sin(angle); - auto c = angle_traits::cos(angle); - auto omc = E(1) - c; - - auto xomc = axis[0] * omc; - auto yomc = axis[1] * omc; - auto zomc = axis[2] * omc; - - auto xxomc = axis[0] * xomc; - auto yyomc = axis[1] * yomc; - auto zzomc = axis[2] * zomc; - auto xyomc = axis[0] * yomc; - auto yzomc = axis[1] * zomc; - auto zxomc = axis[2] * xomc; - - auto xs = axis[0] * s; - auto ys = axis[1] * s; - auto zs = axis[2] * s; - - m.set_basis_element(0, 0, xxomc + c); - m.set_basis_element(0, 1, xyomc + zs); - m.set_basis_element(0, 2, zxomc - ys); - m.set_basis_element(1, 0, xyomc - zs); - m.set_basis_element(1, 1, yyomc + c); - m.set_basis_element(1, 2, yzomc + xs); - m.set_basis_element(2, 0, zxomc + ys); - m.set_basis_element(2, 1, yzomc - xs); - m.set_basis_element(2, 2, zzomc + c); -} - -template -inline void -matrix_rotation_euler(writable_matrix& m, E0 angle_0, E1 angle_1, - E2 angle_2, euler_order order) -{ - static_assert( - cml::are_convertible, E0, E1, E2>::value, - "incompatible scalar types"); - - using angle0_traits = scalar_traits; - using angle1_traits = scalar_traits; - using angle2_traits = scalar_traits; - - cml::check_linear_3D(m); - - /* Initialize: */ - m.identity(); - - int i, j, k; - bool odd, repeat; - cml::unpack_euler_order(order, i, j, k, odd, repeat); - - if(odd) { - angle_0 = -angle_0; - angle_1 = -angle_1; - angle_2 = -angle_2; - } - - auto s0 = angle0_traits::sin(angle_0); - auto c0 = angle0_traits::cos(angle_0); - auto s1 = angle1_traits::sin(angle_1); - auto c1 = angle1_traits::cos(angle_1); - auto s2 = angle2_traits::sin(angle_2); - auto c2 = angle2_traits::cos(angle_2); - - auto s0s2 = s0 * s2; - auto s0c2 = s0 * c2; - auto c0s2 = c0 * s2; - auto c0c2 = c0 * c2; - - if(repeat) { - m.set_basis_element(i, i, c1); - m.set_basis_element(i, j, s1 * s2); - m.set_basis_element(i, k, -s1 * c2); - m.set_basis_element(j, i, s0 * s1); - m.set_basis_element(j, j, -c1 * s0s2 + c0c2); - m.set_basis_element(j, k, c1 * s0c2 + c0s2); - m.set_basis_element(k, i, c0 * s1); - m.set_basis_element(k, j, -c1 * c0s2 - s0c2); - m.set_basis_element(k, k, c1 * c0c2 - s0s2); - } else { - m.set_basis_element(i, i, c1 * c2); - m.set_basis_element(i, j, c1 * s2); - m.set_basis_element(i, k, -s1); - m.set_basis_element(j, i, s1 * s0c2 - c0s2); - m.set_basis_element(j, j, s1 * s0s2 + c0c2); - m.set_basis_element(j, k, s0 * c1); - m.set_basis_element(k, i, s1 * c0c2 + s0s2); - m.set_basis_element(k, j, s1 * c0s2 - s0c2); - m.set_basis_element(k, k, c0 * c1); - } -} - -template -inline void -matrix_rotation_euler(writable_matrix& m, - const readable_vector& euler, euler_order order) -{ - cml::check_size(euler, cml::int_c<3>()); - matrix_rotation_euler(m, euler[0], euler[1], euler[2], order); -} - -template -inline void -matrix_rotation_euler_derivatives(writable_matrix& m, int axis, E0 angle_0, - E1 angle_1, E2 angle_2, euler_order order) -{ - static_assert( - cml::are_convertible, E0, E1, E2>::value, - "incompatible scalar types"); - - using angle0_traits = scalar_traits; - using angle1_traits = scalar_traits; - using angle2_traits = scalar_traits; - - cml_require(0 <= axis && axis <= 2, std::invalid_argument, - "axis must be 0, 1, or 2"); - cml::check_linear_3D(m); - - /* Initialize: */ - m.identity(); - - int i, j, k; - bool odd, repeat; - cml::unpack_euler_order(order, i, j, k, odd, repeat); - cml_require(!repeat, std::invalid_argument, "repeated axis not supported"); - - if(odd) { - angle_0 = -angle_0; - angle_1 = -angle_1; - angle_2 = -angle_2; - } - - auto s0 = angle0_traits::sin(angle_0); - auto c0 = angle0_traits::cos(angle_0); - auto s1 = angle1_traits::sin(angle_1); - auto c1 = angle1_traits::cos(angle_1); - auto s2 = angle2_traits::sin(angle_2); - auto c2 = angle2_traits::cos(angle_2); - - auto s0s2 = s0 * s2; - auto s0c2 = s0 * c2; - auto c0s2 = c0 * s2; - auto c0c2 = c0 * c2; - - if(axis == 0) { - m.set_basis_element(i, i, 0.); - m.set_basis_element(i, j, 0.); - m.set_basis_element(i, k, 0.); - m.set_basis_element(j, i, s1 * c0c2 + s0s2); - m.set_basis_element(j, j, s1 * c0s2 - s0c2); - m.set_basis_element(j, k, c0 * c1); - m.set_basis_element(k, i, -s1 * s0c2 + c0s2); - m.set_basis_element(k, j, -s1 * s0s2 - c0c2); - m.set_basis_element(k, k, -s0 * c1); - } else if(axis == 1) { - m.set_basis_element(i, i, -s1 * c2); - m.set_basis_element(i, j, -s1 * s2); - m.set_basis_element(i, k, -c1); - m.set_basis_element(j, i, c1 * s0c2); - m.set_basis_element(j, j, c1 * s0s2); - m.set_basis_element(j, k, -s0 * s1); - m.set_basis_element(k, i, c1 * c0c2); - m.set_basis_element(k, j, c1 * c0s2); - m.set_basis_element(k, k, -c0 * s1); - } else if(axis == 2) { - m.set_basis_element(i, i, -c1 * s2); - m.set_basis_element(i, j, c1 * c2); - m.set_basis_element(i, k, 0.); - m.set_basis_element(j, i, -s1 * s0s2 - c0c2); - m.set_basis_element(j, j, s1 * s0c2 - c0s2); - m.set_basis_element(j, k, 0.); - m.set_basis_element(k, i, -s1 * c0s2 + s0c2); - m.set_basis_element(k, j, s1 * c0c2 + s0s2); - m.set_basis_element(k, k, 0.); - } -} - -template -inline void -matrix_rotation_euler_derivatives(writable_matrix& m, int axis, - const readable_vector& euler, euler_order order) -{ - cml::check_size(euler, cml::int_c<3>()); - matrix_rotation_euler_derivatives(m, axis, euler[0], euler[1], euler[2], - order); -} - -template -inline void -matrix_rotation_quaternion(writable_matrix& m, - const readable_quaternion& q) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t>::value, - "incompatible scalar types"); - - using order_type = order_type_trait_of_t; - using q_type = value_type_trait_of_t; - - cml::check_linear_3D(m); - - /* Local version of the quaternion ordering: */ - enum - { - W = order_type::W, - X = order_type::X, - Y = order_type::Y, - Z = order_type::Z - }; - - auto x2 = q[X] + q[X]; - auto y2 = q[Y] + q[Y]; - auto z2 = q[Z] + q[Z]; - - auto xx2 = q[X] * x2; - auto yy2 = q[Y] * y2; - auto zz2 = q[Z] * z2; - auto xy2 = q[X] * y2; - auto yz2 = q[Y] * z2; - auto zx2 = q[Z] * x2; - auto xw2 = q[W] * x2; - auto yw2 = q[W] * y2; - auto zw2 = q[W] * z2; - - m.identity(); - m.set_basis_element(0, 0, q_type(1) - yy2 - zz2); - m.set_basis_element(0, 1, xy2 + zw2); - m.set_basis_element(0, 2, zx2 - yw2); - m.set_basis_element(1, 0, xy2 - zw2); - m.set_basis_element(1, 1, q_type(1) - zz2 - xx2); - m.set_basis_element(1, 2, yz2 + xw2); - m.set_basis_element(2, 0, zx2 + yw2); - m.set_basis_element(2, 1, yz2 - xw2); - m.set_basis_element(2, 2, q_type(1) - xx2 - yy2); -} - -/* Alignment: */ - -template -inline void -matrix_rotation_align(writable_matrix& m, - const readable_vector& align, const readable_vector& reference, - bool normalize, axis_order order) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, value_type_trait_of_t>::value, - "incompatible scalar types"); - - using value_type = value_type_trait_of_t; - - m.identity(); - - vector> x, y, z; - orthonormal_basis(align, reference, x, y, z, normalize, order); - matrix_set_basis_vectors(m, x, y, z); -} - -template -void -matrix_rotation_aim_at(writable_matrix& m, - const readable_vector& pos, const readable_vector& target, - const readable_vector& reference, axis_order order) -{ - matrix_rotation_align(m, target - pos, reference, true, order); -} - -/* Conversion: */ - -template -inline void -matrix_to_axis_angle(const readable_matrix& m, writable_vector& axis, - E& angle, Tol tolerance) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, E, Tol>::value, - "incompatible scalar types"); - - using value_type = value_type_trait_of_t; - using value_traits = scalar_traits; - using asub_type = value_type_trait_of_t; - - cml::check_linear_3D(m); - cml::detail::check_or_resize(axis, int_c<3>()); - - /* Assign the axis first: */ - axis.set(m.basis_element(1, 2) - m.basis_element(2, 1), - m.basis_element(2, 0) - m.basis_element(0, 2), - m.basis_element(0, 1) - m.basis_element(1, 0)); - - /* Compute the angle: */ - auto l = axis.length(); - auto tmo = trace_3x3(m) - value_type(1); - - /* Normalize and compute the angle directly if possible: */ - if(l > tolerance) { - axis /= l; - angle = E(value_traits::atan2(l, tmo)); - /* Note: l = 2*sin(theta), tmo = 2*cos(theta) */ - } - - /* Near-zero axis: */ - else if(tmo > value_type(0)) - { - axis.zero(); - angle = E(0); - } - - /* Reflection: */ - else - { - auto largest_diagonal_element = cml::index_of_max(m.basis_element(0, 0), - m.basis_element(1, 1), m.basis_element(2, 2)); - - int i, j, k; - cyclic_permutation(largest_diagonal_element, i, j, k); - - axis[i] = asub_type( - value_traits::sqrt(m.basis_element(i, i) - m.basis_element(j, j) - - m.basis_element(k, k) + value_type(1)) - / value_type(2)); - - auto s = value_type(1) / (value_type(2) * axis[i]); - axis[j] = asub_type(m.basis_element(i, j) * s); - axis[k] = asub_type(m.basis_element(i, k) * s); - - angle = constants::pi(); - } - - /* Done. */ -} - -namespace detail { - -/** Helper for the matrix_to_axis_angle() overloads. */ -template -inline std::tuple> -matrix_to_axis_angle(const readable_matrix& m, Tol tolerance) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, Tol>::value, - "incompatible scalar types"); - - VectorT axis; - value_type_trait_of_t angle; - cml::matrix_to_axis_angle(m, axis, angle, tolerance); - return std::make_tuple(std::move(axis), std::move(angle)); -} - -} // namespace detail - -template -inline std::tuple, compiled<3>>, - value_type_trait_of_t> -matrix_to_axis_angle(const readable_matrix& m, Tol tolerance) -{ - using vector_type = vector, compiled<3>>; - return detail::matrix_to_axis_angle(m, tolerance); -} - -template -inline void -matrix_to_euler(const readable_matrix& m, E0& angle_0, E1& angle_1, - E2& angle_2, euler_order order, Tol tolerance, enable_if_matrix_t*) -{ - static_assert( - cml::are_convertible, E0, E1, E2, Tol>::value, - "incompatible scalar types"); - - using value_type = value_type_trait_of_t; - using value_traits = scalar_traits; - - cml::check_linear_3D(m); - - /* Unpack the order first: */ - int i, j, k; - bool odd, repeat; - cml::unpack_euler_order(order, i, j, k, odd, repeat); - - /* Detect repeated indices: */ - if(repeat) { - auto s1 = cml::length(m.basis_element(j, i), m.basis_element(k, i)); - auto c1 = m.basis_element(i, i); - - angle_1 = E1(value_traits::atan2(s1, c1)); - if(s1 > tolerance) { - angle_0 = - E0(value_traits::atan2(m.basis_element(j, i), m.basis_element(k, i))); - angle_2 = - E0(value_traits::atan2(m.basis_element(i, j), -m.basis_element(i, k))); - } else { - angle_0 = E0(0); - angle_2 = E2(cml::sign(c1) - * value_traits::atan2(-m.basis_element(k, j), m.basis_element(j, j))); - } - } else { - auto s1 = -m.basis_element(i, k); - auto c1 = cml::length(m.basis_element(i, i), m.basis_element(i, j)); - - angle_1 = E1(value_traits::atan2(s1, c1)); - if(c1 > tolerance) { - angle_0 = - E0(value_traits::atan2(m.basis_element(j, k), m.basis_element(k, k))); - angle_2 = - E2(value_traits::atan2(m.basis_element(i, j), m.basis_element(i, i))); - } else { - angle_0 = E0(0); - angle_2 = -E2(cml::sign(s1) - * value_traits::atan2(-m.basis_element(k, j), m.basis_element(j, j))); - } - } - - if(odd) { - angle_0 = -angle_0; - angle_1 = -angle_1; - angle_2 = -angle_2; - } - - /* Done. */ -} - -namespace detail { - -/** Helper for the matrix_to_euler() overloads. */ -template -inline VectorT -matrix_to_euler(const readable_matrix& m, euler_order order, Tol tolerance) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, Tol>::value, - "incompatible scalar types"); - - VectorT v; - cml::detail::check_or_resize(v, int_c<3>()); - cml::matrix_to_euler(m, v[0], v[1], v[2], order, tolerance); - return std::move(v); -} - -} // namespace detail - -template -inline vector, compiled<3>> -matrix_to_euler(const readable_matrix& m, euler_order order, Tol tolerance, - enable_if_matrix_t*) -{ - using vector_type = vector, compiled<3>>; - return detail::matrix_to_euler(m, order, tolerance); -} - -template -inline VectorT -matrix_to_euler(const readable_matrix& m, euler_order order, Tol tolerance, - enable_if_vector_t*, enable_if_matrix_t*) -{ - return detail::matrix_to_euler(m, order, tolerance); -} - -} // namespace cml - - -#if 0 -// XXX INCOMPLETE XXX - -////////////////////////////////////////////////////////////////////////////// -// 3D rotation to align with a vector, multiple vectors, or the view plane -////////////////////////////////////////////////////////////////////////////// - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, class VecT > void -matrix_rotation_align(matrix& m, const VecT& align, - bool normalize = true, axis_order order = axis_order_zyx) -{ - typedef vector< E,fixed<3> > vector_type; - - identity_transform(m); - - vector_type x, y, z; - - orthonormal_basis(align, x, y, z, normalize, order); - matrix_set_basis_vectors(m, x, y, z); -} - -/** See vector_ortho.h for details */ -template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void -matrix_rotation_align_axial(matrix& m, const VecT_1& align, - const VecT_2& axis, bool normalize = true, - axis_order order = axis_order_zyx) -{ - typedef vector< E,fixed<3> > vector_type; - - identity_transform(m); - - vector_type x, y, z; - - orthonormal_basis_axial(align, axis, x, y, z, normalize, order); - matrix_set_basis_vectors(m, x, y, z); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, class MatT > void -matrix_rotation_align_viewplane( - matrix& m, - const MatT& view_matrix, - Handedness handedness, - axis_order order = axis_order_zyx) -{ - typedef vector< E, fixed<3> > vector_type; - - identity_transform(m); - - vector_type x, y, z; - - orthonormal_basis_viewplane(view_matrix, x, y, z, handedness, order); - matrix_set_basis_vectors(m, x, y, z); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, class MatT > void -matrix_rotation_align_viewplane_LH( - matrix& m, - const MatT& view_matrix, - axis_order order = axis_order_zyx) -{ - matrix_rotation_align_viewplane( - m,view_matrix,left_handed,order); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, class MatT > void -matrix_rotation_align_viewplane_RH( - matrix& m, - const MatT& view_matrix, - axis_order order = axis_order_zyx) -{ - matrix_rotation_align_viewplane( - m,view_matrix,right_handed,order); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D rotation to aim at a target -////////////////////////////////////////////////////////////////////////////// - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, - class VecT_1, class VecT_2 > void -matrix_rotation_aim_at( - matrix& m, - const VecT_1& pos, - const VecT_2& target, - axis_order order = axis_order_zyx) -{ - matrix_rotation_align(m, target - pos, true, order); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, - class VecT_1, class VecT_2, class VecT_3 > void -matrix_rotation_aim_at_axial( - matrix& m, - const VecT_1& pos, - const VecT_2& target, - const VecT_3& axis, - axis_order order = axis_order_zyx) -{ - matrix_rotation_align_axial(m, target - pos, axis, true, order); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D rotation to align with a vector -////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////// -// 3D relative rotation about world axes -////////////////////////////////////////////////////////////////////////////// - -/** Rotate a rotation matrix about the given world axis */ -template < typename E, class A, class B, class L > void -matrix_rotate_about_world_axis(matrix& m, size_t axis, E angle) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckMatLinear3D(m); - detail::CheckIndex3(axis); - - size_t i, j, k; - cyclic_permutation(axis, i, j, k); - - value_type s = value_type(std::sin(angle)); - value_type c = value_type(std::cos(angle)); - - value_type ij = c * m.basis_element(i,j) - s * m.basis_element(i,k); - value_type jj = c * m.basis_element(j,j) - s * m.basis_element(j,k); - value_type kj = c * m.basis_element(k,j) - s * m.basis_element(k,k); - - m.set_basis_element(i,k, s*m.basis_element(i,j) + c*m.basis_element(i,k)); - m.set_basis_element(j,k, s*m.basis_element(j,j) + c*m.basis_element(j,k)); - m.set_basis_element(k,k, s*m.basis_element(k,j) + c*m.basis_element(k,k)); - - m.set_basis_element(i,j,ij); - m.set_basis_element(j,j,jj); - m.set_basis_element(k,j,kj); -} - -/** Rotate a rotation matrix about the world x axis */ -template < typename E, class A, class B, class L > void -matrix_rotate_about_world_x(matrix& m, E angle) { - matrix_rotate_about_world_axis(m,0,angle); -} - -/** Rotate a rotation matrix about the world y axis */ -template < typename E, class A, class B, class L > void -matrix_rotate_about_world_y(matrix& m, E angle) { - matrix_rotate_about_world_axis(m,1,angle); -} - -/** Rotate a rotation matrix about the world z axis */ -template < typename E, class A, class B, class L > void -matrix_rotate_about_world_z(matrix& m, E angle) { - matrix_rotate_about_world_axis(m,2,angle); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D relative rotation about local axes -////////////////////////////////////////////////////////////////////////////// - -/** Rotate a rotation matrix about the given local axis */ -template < typename E, class A, class B, class L > void -matrix_rotate_about_local_axis(matrix& m, size_t axis, E angle) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckMatLinear3D(m); - detail::CheckIndex3(axis); - - size_t i, j, k; - cyclic_permutation(axis, i, j, k); - - value_type s = value_type(std::sin(angle)); - value_type c = value_type(std::cos(angle)); - - value_type j0 = c * m.basis_element(j,0) + s * m.basis_element(k,0); - value_type j1 = c * m.basis_element(j,1) + s * m.basis_element(k,1); - value_type j2 = c * m.basis_element(j,2) + s * m.basis_element(k,2); - - m.set_basis_element(k,0, c*m.basis_element(k,0) - s*m.basis_element(j,0)); - m.set_basis_element(k,1, c*m.basis_element(k,1) - s*m.basis_element(j,1)); - m.set_basis_element(k,2, c*m.basis_element(k,2) - s*m.basis_element(j,2)); - - m.set_basis_element(j,0,j0); - m.set_basis_element(j,1,j1); - m.set_basis_element(j,2,j2); -} - -/** Rotate a rotation matrix about its local x axis */ -template < typename E, class A, class B, class L > void -matrix_rotate_about_local_x(matrix& m, E angle) { - matrix_rotate_about_local_axis(m,0,angle); -} - -/** Rotate a rotation matrix about its local y axis */ -template < typename E, class A, class B, class L > void -matrix_rotate_about_local_y(matrix& m, E angle) { - matrix_rotate_about_local_axis(m,1,angle); -} - -/** Rotate a rotation matrix about its local z axis */ -template < typename E, class A, class B, class L > void -matrix_rotate_about_local_z(matrix& m, E angle) { - matrix_rotate_about_local_axis(m,2,angle); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D relative rotation -////////////////////////////////////////////////////////////////////////////// - -template < typename E, class A, class B, class L > void -matrix_rotate_2D(matrix& m, E angle) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckMatLinear2D(m); - - value_type s = value_type(std::sin(angle)); - value_type c = value_type(std::cos(angle)); - - value_type m00 = c * m.basis_element(0,0) - s * m.basis_element(0,1); - value_type m10 = c * m.basis_element(1,0) - s * m.basis_element(1,1); - - m.set_basis_element(0,1, s*m.basis_element(0,0) + c*m.basis_element(0,1)); - m.set_basis_element(1,1, s*m.basis_element(1,0) + c*m.basis_element(1,1)); - - m.set_basis_element(0,0,m00); - m.set_basis_element(1,0,m10); -} - -////////////////////////////////////////////////////////////////////////////// -// Rotation from vector to vector -////////////////////////////////////////////////////////////////////////////// - -/** Build a rotation matrix to rotate from one vector to another - * - * Note: The quaternion algorithm is more stable than the matrix algorithm, so - * we simply pass off to the quaternion function here. - */ -template < class E,class A,class B,class L,class VecT_1,class VecT_2 > void -matrix_rotation_vec_to_vec( - matrix& m, - const VecT_1& v1, - const VecT_2& v2, - bool unit_length_vectors = false) -{ - typedef quaternion< E,fixed<>,vector_first,positive_cross > - quaternion_type; - - quaternion_type q; - quaternion_rotation_vec_to_vec(q,v1,v2,unit_length_vectors); - matrix_rotation_quaternion(m,q); -} - -////////////////////////////////////////////////////////////////////////////// -// Scale the angle of a rotation matrix -////////////////////////////////////////////////////////////////////////////// - -/** Scale the angle of a 3D rotation matrix */ -template < typename E, class A, class B, class L > void -matrix_scale_rotation_angle(matrix& m, E t, - E tolerance = epsilon::placeholder()) -{ - typedef vector< E,fixed<3> > vector_type; - typedef typename vector_type::value_type value_type; - - vector_type axis; - value_type angle; - matrix_to_axis_angle(m, axis, angle, tolerance); - matrix_rotation_axis_angle(m, axis, angle * t); -} - -/** Scale the angle of a 2D rotation matrix */ -template < typename E, class A, class B, class L > void -matrix_scale_rotation_angle_2D( - matrix& m, E t, E tolerance = epsilon::placeholder()) -{ - typedef vector< E,fixed<2> > vector_type; - typedef typename vector_type::value_type value_type; - - value_type angle = matrix_to_rotation_2D(m); - matrix_rotation_2D(m, angle * t); -} - -////////////////////////////////////////////////////////////////////////////// -// Support functions for uniform handling of row- and column-basis matrices -////////////////////////////////////////////////////////////////////////////// - -/* Note: The matrix rotation slerp, difference and concatenation functions do - * not use et::MatrixPromote::temporary_type as the return type, even - * though that is the return type of the underlying matrix multiplication. - * This is because the sizes of these matrices are known at compile time (3x3 - * and 2x2), and using fixed<> obviates the need for resizing of intermediate - * temporaries. - * - * Also, no size- or type-checking is done on the arguments to these - * functions, as any such errors will be caught by the matrix multiplication - * and assignment to the 3x3 temporary. - */ - -/** A fixed-size temporary 3x3 matrix */ -# define MAT_TEMP_3X3 \ - matrix::type, \ - fixed<3, 3>, typename MatT_1::basis_orient, row_major> - -/** A fixed-size temporary 2x2 matrix */ -# define MAT_TEMP_2X2 \ - matrix::type, \ - fixed<2, 2>, typename MatT_1::basis_orient, row_major> - -namespace detail { - -/** Concatenate two 3D row-basis rotation matrices in the order m1->m2 */ -template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 -matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2, row_basis) { - return m1*m2; -} - -/** Concatenate two 3D col-basis rotation matrices in the order m1->m2 */ -template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 -matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2, col_basis) { - return m2*m1; -} - -/** Concatenate two 3D rotation matrices in the order m1->m2 */ -template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 -matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2) { - return matrix_concat_rotations(m1,m2,typename MatT_1::basis_orient()); -} - -/** Concatenate two 2D row-basis rotation matrices in the order m1->m2 */ -template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 -matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2, row_basis) { - return m1*m2; -} - -/** Concatenate two 2D col-basis rotation matrices in the order m1->m2 */ -template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 -matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2, col_basis) { - return m2*m1; -} - -/** Concatenate two 2D rotation matrices in the order m1->m2 */ -template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 -matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2) { - return matrix_concat_rotations_2D(m1,m2,typename MatT_1::basis_orient()); -} - -} // namespace detail - -////////////////////////////////////////////////////////////////////////////// -// Matrix rotation difference -////////////////////////////////////////////////////////////////////////////// - -/** Return the rotational 'difference' between two 3D rotation matrices */ -template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 -matrix_rotation_difference(const MatT_1& m1, const MatT_2& m2) { - return detail::matrix_concat_rotations(transpose(m1),m2); -} - -/** Return the rotational 'difference' between two 2D rotation matrices */ -template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 -matrix_rotation_difference_2D(const MatT_1& m1, const MatT_2& m2) { - return detail::matrix_concat_rotations_2D(transpose(m1),m2); -} - -////////////////////////////////////////////////////////////////////////////// -// Spherical linear interpolation of rotation matrices -////////////////////////////////////////////////////////////////////////////// - -/* @todo: It might be as fast or faster to simply convert the matrices to - * quaternions, interpolate, and convert back. - * - * @todo: The behavior of matrix slerp is currently a little different than - * for quaternions: in the matrix function, when the two matrices are close - * to identical the first is returned, while in the quaternion function the - * quaternions are nlerp()'d in this case. - * - * I still need to do the equivalent of nlerp() for matrices, in which case - * these functions could be revised to pass off to nlerp() when the matrices - * are nearly aligned. -*/ - -/** Spherical linear interpolation of two 3D rotation matrices */ -template < class MatT_1, class MatT_2, typename E > MAT_TEMP_3X3 -matrix_slerp(const MatT_1& m1, const MatT_2& m2, E t, - E tolerance = epsilon::placeholder()) -{ - typedef MAT_TEMP_3X3 temporary_type; - - temporary_type m = matrix_rotation_difference(m1,m2); - matrix_scale_rotation_angle(m,t,tolerance); - return detail::matrix_concat_rotations(m1,m); -} - -/** Spherical linear interpolation of two 2D rotation matrices */ -template < class MatT_1, class MatT_2, typename E > MAT_TEMP_2X2 -matrix_slerp_2D(const MatT_1& m1, const MatT_2& m2, E t, - E tolerance = epsilon::placeholder()) -{ - typedef MAT_TEMP_2X2 temporary_type; - - temporary_type m = matrix_rotation_difference_2D(m1,m2); - matrix_scale_rotation_angle_2D(m,t,tolerance); - return detail::matrix_concat_rotations_2D(m1,m); -} - -# undef MAT_TEMP_3X3 -# undef MAT_TEMP_2X2 - -////////////////////////////////////////////////////////////////////////////// -// Conversions -////////////////////////////////////////////////////////////////////////////// - -/** Convert a 2D rotation matrix to a rotation angle */ -template < class MatT > typename MatT::value_type -matrix_to_rotation_2D(const MatT& m) -{ - /* Checking */ - detail::CheckMatLinear2D(m); - - return std::atan2(m.basis_element(0,1),m.basis_element(0,0)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_ROTATION_TPP +# error "mathlib/matrix/rotation.tpp not included correctly" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cml { + +/* 2D rotations: */ + +template +inline void +matrix_rotation_2D(writable_matrix& m, E angle) +{ + static_assert(cml::are_convertible, E>::value, + "incompatible scalar types"); + + using angle_traits = scalar_traits; + + cml::check_linear_2D(m); + + /* Initialize: */ + m.identity(); + + /* Initialize m: */ + auto s = angle_traits::sin(angle); + auto c = angle_traits::cos(angle); + m.set_basis_element(0, 0, c); + m.set_basis_element(0, 1, s); + m.set_basis_element(1, 0, -s); + m.set_basis_element(1, 1, c); +} + +/* 2D alignment: */ + +template +void +matrix_rotation_align_2D(writable_matrix& m, + const readable_vector& align, bool normalize, axis_order2D order) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t>::value, + "incompatible scalar types"); + + using value_type = value_type_trait_of_t; + + cml::check_linear_2D(m); + + m.identity(); + + vector> x, y; + orthonormal_basis_2D(align, x, y, normalize, order); + matrix_set_basis_vectors_2D(m, x, y); +} + +/* 3D rotations: */ + +template +inline void +matrix_rotation_world_axis(writable_matrix& m, int axis, const E& angle) +{ + static_assert(cml::are_convertible, E>::value, + "incompatible scalar types"); + + using angle_traits = traits_of_t; + + cml::check_linear_3D(m); + cml_require(0 <= axis && axis <= 2, std::invalid_argument, "invalid axis"); + + /* Setup sin() and cos() for the chosen axis: */ + int i, j, k; + cml::cyclic_permutation(axis, i, j, k); + auto s = angle_traits::sin(angle); + auto c = angle_traits::cos(angle); + + /* Clear the matrix: */ + m.identity(); + + /* Set elements: */ + m.set_basis_element(j, j, c); + m.set_basis_element(j, k, s); + m.set_basis_element(k, j, -s); + m.set_basis_element(k, k, c); +} + +template +inline void +matrix_rotation_world_x(writable_matrix& m, const E& angle) +{ + matrix_rotation_world_axis(m, 0, angle); +} + +template +inline void +matrix_rotation_world_y(writable_matrix& m, const E& angle) +{ + matrix_rotation_world_axis(m, 1, angle); +} + +template +inline void +matrix_rotation_world_z(writable_matrix& m, const E& angle) +{ + matrix_rotation_world_axis(m, 2, angle); +} + +template +inline void +matrix_rotation_axis_angle(writable_matrix& m, + const readable_vector& axis, const E& angle) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, E>::value, + "incompatible scalar types"); + + using angle_traits = scalar_traits; + + cml::check_linear_3D(m); + cml::check_size(axis, int_c<3>()); + + /* Initialize: */ + m.identity(); + + /* Precompute values: */ + auto s = angle_traits::sin(angle); + auto c = angle_traits::cos(angle); + auto omc = E(1) - c; + + auto xomc = axis[0] * omc; + auto yomc = axis[1] * omc; + auto zomc = axis[2] * omc; + + auto xxomc = axis[0] * xomc; + auto yyomc = axis[1] * yomc; + auto zzomc = axis[2] * zomc; + auto xyomc = axis[0] * yomc; + auto yzomc = axis[1] * zomc; + auto zxomc = axis[2] * xomc; + + auto xs = axis[0] * s; + auto ys = axis[1] * s; + auto zs = axis[2] * s; + + m.set_basis_element(0, 0, xxomc + c); + m.set_basis_element(0, 1, xyomc + zs); + m.set_basis_element(0, 2, zxomc - ys); + m.set_basis_element(1, 0, xyomc - zs); + m.set_basis_element(1, 1, yyomc + c); + m.set_basis_element(1, 2, yzomc + xs); + m.set_basis_element(2, 0, zxomc + ys); + m.set_basis_element(2, 1, yzomc - xs); + m.set_basis_element(2, 2, zzomc + c); +} + +template +inline void +matrix_rotation_euler(writable_matrix& m, E0 angle_0, E1 angle_1, + E2 angle_2, euler_order order) +{ + static_assert( + cml::are_convertible, E0, E1, E2>::value, + "incompatible scalar types"); + + using angle0_traits = scalar_traits; + using angle1_traits = scalar_traits; + using angle2_traits = scalar_traits; + + cml::check_linear_3D(m); + + /* Initialize: */ + m.identity(); + + int i, j, k; + bool odd, repeat; + cml::unpack_euler_order(order, i, j, k, odd, repeat); + + if(odd) { + angle_0 = -angle_0; + angle_1 = -angle_1; + angle_2 = -angle_2; + } + + auto s0 = angle0_traits::sin(angle_0); + auto c0 = angle0_traits::cos(angle_0); + auto s1 = angle1_traits::sin(angle_1); + auto c1 = angle1_traits::cos(angle_1); + auto s2 = angle2_traits::sin(angle_2); + auto c2 = angle2_traits::cos(angle_2); + + auto s0s2 = s0 * s2; + auto s0c2 = s0 * c2; + auto c0s2 = c0 * s2; + auto c0c2 = c0 * c2; + + if(repeat) { + m.set_basis_element(i, i, c1); + m.set_basis_element(i, j, s1 * s2); + m.set_basis_element(i, k, -s1 * c2); + m.set_basis_element(j, i, s0 * s1); + m.set_basis_element(j, j, -c1 * s0s2 + c0c2); + m.set_basis_element(j, k, c1 * s0c2 + c0s2); + m.set_basis_element(k, i, c0 * s1); + m.set_basis_element(k, j, -c1 * c0s2 - s0c2); + m.set_basis_element(k, k, c1 * c0c2 - s0s2); + } else { + m.set_basis_element(i, i, c1 * c2); + m.set_basis_element(i, j, c1 * s2); + m.set_basis_element(i, k, -s1); + m.set_basis_element(j, i, s1 * s0c2 - c0s2); + m.set_basis_element(j, j, s1 * s0s2 + c0c2); + m.set_basis_element(j, k, s0 * c1); + m.set_basis_element(k, i, s1 * c0c2 + s0s2); + m.set_basis_element(k, j, s1 * c0s2 - s0c2); + m.set_basis_element(k, k, c0 * c1); + } +} + +template +inline void +matrix_rotation_euler(writable_matrix& m, + const readable_vector& euler, euler_order order) +{ + cml::check_size(euler, cml::int_c<3>()); + matrix_rotation_euler(m, euler[0], euler[1], euler[2], order); +} + +template +inline void +matrix_rotation_euler_derivatives(writable_matrix& m, int axis, E0 angle_0, + E1 angle_1, E2 angle_2, euler_order order) +{ + static_assert( + cml::are_convertible, E0, E1, E2>::value, + "incompatible scalar types"); + + using angle0_traits = scalar_traits; + using angle1_traits = scalar_traits; + using angle2_traits = scalar_traits; + + cml_require(0 <= axis && axis <= 2, std::invalid_argument, + "axis must be 0, 1, or 2"); + cml::check_linear_3D(m); + + /* Initialize: */ + m.identity(); + + int i, j, k; + bool odd, repeat; + cml::unpack_euler_order(order, i, j, k, odd, repeat); + cml_require(!repeat, std::invalid_argument, "repeated axis not supported"); + + if(odd) { + angle_0 = -angle_0; + angle_1 = -angle_1; + angle_2 = -angle_2; + } + + auto s0 = angle0_traits::sin(angle_0); + auto c0 = angle0_traits::cos(angle_0); + auto s1 = angle1_traits::sin(angle_1); + auto c1 = angle1_traits::cos(angle_1); + auto s2 = angle2_traits::sin(angle_2); + auto c2 = angle2_traits::cos(angle_2); + + auto s0s2 = s0 * s2; + auto s0c2 = s0 * c2; + auto c0s2 = c0 * s2; + auto c0c2 = c0 * c2; + + if(axis == 0) { + m.set_basis_element(i, i, 0.); + m.set_basis_element(i, j, 0.); + m.set_basis_element(i, k, 0.); + m.set_basis_element(j, i, s1 * c0c2 + s0s2); + m.set_basis_element(j, j, s1 * c0s2 - s0c2); + m.set_basis_element(j, k, c0 * c1); + m.set_basis_element(k, i, -s1 * s0c2 + c0s2); + m.set_basis_element(k, j, -s1 * s0s2 - c0c2); + m.set_basis_element(k, k, -s0 * c1); + } else if(axis == 1) { + m.set_basis_element(i, i, -s1 * c2); + m.set_basis_element(i, j, -s1 * s2); + m.set_basis_element(i, k, -c1); + m.set_basis_element(j, i, c1 * s0c2); + m.set_basis_element(j, j, c1 * s0s2); + m.set_basis_element(j, k, -s0 * s1); + m.set_basis_element(k, i, c1 * c0c2); + m.set_basis_element(k, j, c1 * c0s2); + m.set_basis_element(k, k, -c0 * s1); + } else if(axis == 2) { + m.set_basis_element(i, i, -c1 * s2); + m.set_basis_element(i, j, c1 * c2); + m.set_basis_element(i, k, 0.); + m.set_basis_element(j, i, -s1 * s0s2 - c0c2); + m.set_basis_element(j, j, s1 * s0c2 - c0s2); + m.set_basis_element(j, k, 0.); + m.set_basis_element(k, i, -s1 * c0s2 + s0c2); + m.set_basis_element(k, j, s1 * c0c2 + s0s2); + m.set_basis_element(k, k, 0.); + } +} + +template +inline void +matrix_rotation_euler_derivatives(writable_matrix& m, int axis, + const readable_vector& euler, euler_order order) +{ + cml::check_size(euler, cml::int_c<3>()); + matrix_rotation_euler_derivatives(m, axis, euler[0], euler[1], euler[2], + order); +} + +template +inline void +matrix_rotation_quaternion(writable_matrix& m, + const readable_quaternion& q) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t>::value, + "incompatible scalar types"); + + using order_type = order_type_trait_of_t; + using q_type = value_type_trait_of_t; + + cml::check_linear_3D(m); + + /* Local version of the quaternion ordering: */ + enum + { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + auto x2 = q[X] + q[X]; + auto y2 = q[Y] + q[Y]; + auto z2 = q[Z] + q[Z]; + + auto xx2 = q[X] * x2; + auto yy2 = q[Y] * y2; + auto zz2 = q[Z] * z2; + auto xy2 = q[X] * y2; + auto yz2 = q[Y] * z2; + auto zx2 = q[Z] * x2; + auto xw2 = q[W] * x2; + auto yw2 = q[W] * y2; + auto zw2 = q[W] * z2; + + m.identity(); + m.set_basis_element(0, 0, q_type(1) - yy2 - zz2); + m.set_basis_element(0, 1, xy2 + zw2); + m.set_basis_element(0, 2, zx2 - yw2); + m.set_basis_element(1, 0, xy2 - zw2); + m.set_basis_element(1, 1, q_type(1) - zz2 - xx2); + m.set_basis_element(1, 2, yz2 + xw2); + m.set_basis_element(2, 0, zx2 + yw2); + m.set_basis_element(2, 1, yz2 - xw2); + m.set_basis_element(2, 2, q_type(1) - xx2 - yy2); +} + +/* Alignment: */ + +template +inline void +matrix_rotation_align(writable_matrix& m, + const readable_vector& align, const readable_vector& reference, + bool normalize, axis_order order) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, value_type_trait_of_t>::value, + "incompatible scalar types"); + + using value_type = value_type_trait_of_t; + + m.identity(); + + vector> x, y, z; + orthonormal_basis(align, reference, x, y, z, normalize, order); + matrix_set_basis_vectors(m, x, y, z); +} + +template +void +matrix_rotation_aim_at(writable_matrix& m, + const readable_vector& pos, const readable_vector& target, + const readable_vector& reference, axis_order order) +{ + matrix_rotation_align(m, target - pos, reference, true, order); +} + +/* Conversion: */ + +template +inline void +matrix_to_axis_angle(const readable_matrix& m, writable_vector& axis, + E& angle, Tol tolerance) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, E, Tol>::value, + "incompatible scalar types"); + + using value_type = value_type_trait_of_t; + using value_traits = scalar_traits; + using asub_type = value_type_trait_of_t; + + cml::check_linear_3D(m); + cml::detail::check_or_resize(axis, int_c<3>()); + + /* Assign the axis first: */ + axis.set(m.basis_element(1, 2) - m.basis_element(2, 1), + m.basis_element(2, 0) - m.basis_element(0, 2), + m.basis_element(0, 1) - m.basis_element(1, 0)); + + /* Compute the angle: */ + auto l = axis.length(); + auto tmo = trace_3x3(m) - value_type(1); + + /* Normalize and compute the angle directly if possible: */ + if(l > tolerance) { + axis /= l; + angle = E(value_traits::atan2(l, tmo)); + /* Note: l = 2*sin(theta), tmo = 2*cos(theta) */ + } + + /* Near-zero axis: */ + else if(tmo > value_type(0)) + { + axis.zero(); + angle = E(0); + } + + /* Reflection: */ + else + { + auto largest_diagonal_element = cml::index_of_max(m.basis_element(0, 0), + m.basis_element(1, 1), m.basis_element(2, 2)); + + int i, j, k; + cyclic_permutation(largest_diagonal_element, i, j, k); + + axis[i] = asub_type( + value_traits::sqrt(m.basis_element(i, i) - m.basis_element(j, j) + - m.basis_element(k, k) + value_type(1)) + / value_type(2)); + + auto s = value_type(1) / (value_type(2) * axis[i]); + axis[j] = asub_type(m.basis_element(i, j) * s); + axis[k] = asub_type(m.basis_element(i, k) * s); + + angle = constants::pi(); + } + + /* Done. */ +} + +namespace detail { + +/** Helper for the matrix_to_axis_angle() overloads. */ +template +inline std::tuple> +matrix_to_axis_angle(const readable_matrix& m, Tol tolerance) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, Tol>::value, + "incompatible scalar types"); + + VectorT axis; + value_type_trait_of_t angle; + cml::matrix_to_axis_angle(m, axis, angle, tolerance); + return std::make_tuple(std::move(axis), std::move(angle)); +} + +} // namespace detail + +template +inline std::tuple, compiled<3>>, + value_type_trait_of_t> +matrix_to_axis_angle(const readable_matrix& m, Tol tolerance) +{ + using vector_type = vector, compiled<3>>; + return detail::matrix_to_axis_angle(m, tolerance); +} + +template +inline void +matrix_to_euler(const readable_matrix& m, E0& angle_0, E1& angle_1, + E2& angle_2, euler_order order, Tol tolerance, enable_if_matrix_t*) +{ + static_assert( + cml::are_convertible, E0, E1, E2, Tol>::value, + "incompatible scalar types"); + + using value_type = value_type_trait_of_t; + using value_traits = scalar_traits; + + cml::check_linear_3D(m); + + /* Unpack the order first: */ + int i, j, k; + bool odd, repeat; + cml::unpack_euler_order(order, i, j, k, odd, repeat); + + /* Detect repeated indices: */ + if(repeat) { + auto s1 = cml::length(m.basis_element(j, i), m.basis_element(k, i)); + auto c1 = m.basis_element(i, i); + + angle_1 = E1(value_traits::atan2(s1, c1)); + if(s1 > tolerance) { + angle_0 = + E0(value_traits::atan2(m.basis_element(j, i), m.basis_element(k, i))); + angle_2 = + E0(value_traits::atan2(m.basis_element(i, j), -m.basis_element(i, k))); + } else { + angle_0 = E0(0); + angle_2 = E2(cml::sign(c1) + * value_traits::atan2(-m.basis_element(k, j), m.basis_element(j, j))); + } + } else { + auto s1 = -m.basis_element(i, k); + auto c1 = cml::length(m.basis_element(i, i), m.basis_element(i, j)); + + angle_1 = E1(value_traits::atan2(s1, c1)); + if(c1 > tolerance) { + angle_0 = + E0(value_traits::atan2(m.basis_element(j, k), m.basis_element(k, k))); + angle_2 = + E2(value_traits::atan2(m.basis_element(i, j), m.basis_element(i, i))); + } else { + angle_0 = E0(0); + angle_2 = -E2(cml::sign(s1) + * value_traits::atan2(-m.basis_element(k, j), m.basis_element(j, j))); + } + } + + if(odd) { + angle_0 = -angle_0; + angle_1 = -angle_1; + angle_2 = -angle_2; + } + + /* Done. */ +} + +namespace detail { + +/** Helper for the matrix_to_euler() overloads. */ +template +inline VectorT +matrix_to_euler(const readable_matrix& m, euler_order order, Tol tolerance) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, Tol>::value, + "incompatible scalar types"); + + VectorT v; + cml::detail::check_or_resize(v, int_c<3>()); + cml::matrix_to_euler(m, v[0], v[1], v[2], order, tolerance); + return std::move(v); +} + +} // namespace detail + +template +inline vector, compiled<3>> +matrix_to_euler(const readable_matrix& m, euler_order order, Tol tolerance, + enable_if_matrix_t*) +{ + using vector_type = vector, compiled<3>>; + return detail::matrix_to_euler(m, order, tolerance); +} + +template +inline VectorT +matrix_to_euler(const readable_matrix& m, euler_order order, Tol tolerance, + enable_if_vector_t*, enable_if_matrix_t*) +{ + return detail::matrix_to_euler(m, order, tolerance); +} + +} // namespace cml + + +#if 0 +// XXX INCOMPLETE XXX + +////////////////////////////////////////////////////////////////////////////// +// 3D rotation to align with a vector, multiple vectors, or the view plane +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class VecT > void +matrix_rotation_align(matrix& m, const VecT& align, + bool normalize = true, axis_order order = axis_order_zyx) +{ + typedef vector< E,fixed<3> > vector_type; + + identity_transform(m); + + vector_type x, y, z; + + orthonormal_basis(align, x, y, z, normalize, order); + matrix_set_basis_vectors(m, x, y, z); +} + +/** See vector_ortho.h for details */ +template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_rotation_align_axial(matrix& m, const VecT_1& align, + const VecT_2& axis, bool normalize = true, + axis_order order = axis_order_zyx) +{ + typedef vector< E,fixed<3> > vector_type; + + identity_transform(m); + + vector_type x, y, z; + + orthonormal_basis_axial(align, axis, x, y, z, normalize, order); + matrix_set_basis_vectors(m, x, y, z); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class MatT > void +matrix_rotation_align_viewplane( + matrix& m, + const MatT& view_matrix, + Handedness handedness, + axis_order order = axis_order_zyx) +{ + typedef vector< E, fixed<3> > vector_type; + + identity_transform(m); + + vector_type x, y, z; + + orthonormal_basis_viewplane(view_matrix, x, y, z, handedness, order); + matrix_set_basis_vectors(m, x, y, z); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class MatT > void +matrix_rotation_align_viewplane_LH( + matrix& m, + const MatT& view_matrix, + axis_order order = axis_order_zyx) +{ + matrix_rotation_align_viewplane( + m,view_matrix,left_handed,order); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class MatT > void +matrix_rotation_align_viewplane_RH( + matrix& m, + const MatT& view_matrix, + axis_order order = axis_order_zyx) +{ + matrix_rotation_align_viewplane( + m,view_matrix,right_handed,order); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D rotation to aim at a target +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2 > void +matrix_rotation_aim_at( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + axis_order order = axis_order_zyx) +{ + matrix_rotation_align(m, target - pos, true, order); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_rotation_aim_at_axial( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + const VecT_3& axis, + axis_order order = axis_order_zyx) +{ + matrix_rotation_align_axial(m, target - pos, axis, true, order); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D rotation to align with a vector +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// 3D relative rotation about world axes +////////////////////////////////////////////////////////////////////////////// + +/** Rotate a rotation matrix about the given world axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_world_axis(matrix& m, size_t axis, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + value_type ij = c * m.basis_element(i,j) - s * m.basis_element(i,k); + value_type jj = c * m.basis_element(j,j) - s * m.basis_element(j,k); + value_type kj = c * m.basis_element(k,j) - s * m.basis_element(k,k); + + m.set_basis_element(i,k, s*m.basis_element(i,j) + c*m.basis_element(i,k)); + m.set_basis_element(j,k, s*m.basis_element(j,j) + c*m.basis_element(j,k)); + m.set_basis_element(k,k, s*m.basis_element(k,j) + c*m.basis_element(k,k)); + + m.set_basis_element(i,j,ij); + m.set_basis_element(j,j,jj); + m.set_basis_element(k,j,kj); +} + +/** Rotate a rotation matrix about the world x axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_world_x(matrix& m, E angle) { + matrix_rotate_about_world_axis(m,0,angle); +} + +/** Rotate a rotation matrix about the world y axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_world_y(matrix& m, E angle) { + matrix_rotate_about_world_axis(m,1,angle); +} + +/** Rotate a rotation matrix about the world z axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_world_z(matrix& m, E angle) { + matrix_rotate_about_world_axis(m,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D relative rotation about local axes +////////////////////////////////////////////////////////////////////////////// + +/** Rotate a rotation matrix about the given local axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_local_axis(matrix& m, size_t axis, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + value_type j0 = c * m.basis_element(j,0) + s * m.basis_element(k,0); + value_type j1 = c * m.basis_element(j,1) + s * m.basis_element(k,1); + value_type j2 = c * m.basis_element(j,2) + s * m.basis_element(k,2); + + m.set_basis_element(k,0, c*m.basis_element(k,0) - s*m.basis_element(j,0)); + m.set_basis_element(k,1, c*m.basis_element(k,1) - s*m.basis_element(j,1)); + m.set_basis_element(k,2, c*m.basis_element(k,2) - s*m.basis_element(j,2)); + + m.set_basis_element(j,0,j0); + m.set_basis_element(j,1,j1); + m.set_basis_element(j,2,j2); +} + +/** Rotate a rotation matrix about its local x axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_local_x(matrix& m, E angle) { + matrix_rotate_about_local_axis(m,0,angle); +} + +/** Rotate a rotation matrix about its local y axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_local_y(matrix& m, E angle) { + matrix_rotate_about_local_axis(m,1,angle); +} + +/** Rotate a rotation matrix about its local z axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_local_z(matrix& m, E angle) { + matrix_rotate_about_local_axis(m,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D relative rotation +////////////////////////////////////////////////////////////////////////////// + +template < typename E, class A, class B, class L > void +matrix_rotate_2D(matrix& m, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + value_type m00 = c * m.basis_element(0,0) - s * m.basis_element(0,1); + value_type m10 = c * m.basis_element(1,0) - s * m.basis_element(1,1); + + m.set_basis_element(0,1, s*m.basis_element(0,0) + c*m.basis_element(0,1)); + m.set_basis_element(1,1, s*m.basis_element(1,0) + c*m.basis_element(1,1)); + + m.set_basis_element(0,0,m00); + m.set_basis_element(1,0,m10); +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation from vector to vector +////////////////////////////////////////////////////////////////////////////// + +/** Build a rotation matrix to rotate from one vector to another + * + * Note: The quaternion algorithm is more stable than the matrix algorithm, so + * we simply pass off to the quaternion function here. + */ +template < class E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_rotation_vec_to_vec( + matrix& m, + const VecT_1& v1, + const VecT_2& v2, + bool unit_length_vectors = false) +{ + typedef quaternion< E,fixed<>,vector_first,positive_cross > + quaternion_type; + + quaternion_type q; + quaternion_rotation_vec_to_vec(q,v1,v2,unit_length_vectors); + matrix_rotation_quaternion(m,q); +} + +////////////////////////////////////////////////////////////////////////////// +// Scale the angle of a rotation matrix +////////////////////////////////////////////////////////////////////////////// + +/** Scale the angle of a 3D rotation matrix */ +template < typename E, class A, class B, class L > void +matrix_scale_rotation_angle(matrix& m, E t, + E tolerance = epsilon::placeholder()) +{ + typedef vector< E,fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + vector_type axis; + value_type angle; + matrix_to_axis_angle(m, axis, angle, tolerance); + matrix_rotation_axis_angle(m, axis, angle * t); +} + +/** Scale the angle of a 2D rotation matrix */ +template < typename E, class A, class B, class L > void +matrix_scale_rotation_angle_2D( + matrix& m, E t, E tolerance = epsilon::placeholder()) +{ + typedef vector< E,fixed<2> > vector_type; + typedef typename vector_type::value_type value_type; + + value_type angle = matrix_to_rotation_2D(m); + matrix_rotation_2D(m, angle * t); +} + +////////////////////////////////////////////////////////////////////////////// +// Support functions for uniform handling of row- and column-basis matrices +////////////////////////////////////////////////////////////////////////////// + +/* Note: The matrix rotation slerp, difference and concatenation functions do + * not use et::MatrixPromote::temporary_type as the return type, even + * though that is the return type of the underlying matrix multiplication. + * This is because the sizes of these matrices are known at compile time (3x3 + * and 2x2), and using fixed<> obviates the need for resizing of intermediate + * temporaries. + * + * Also, no size- or type-checking is done on the arguments to these + * functions, as any such errors will be caught by the matrix multiplication + * and assignment to the 3x3 temporary. + */ + +/** A fixed-size temporary 3x3 matrix */ +# define MAT_TEMP_3X3 \ + matrix::type, \ + fixed<3, 3>, typename MatT_1::basis_orient, row_major> + +/** A fixed-size temporary 2x2 matrix */ +# define MAT_TEMP_2X2 \ + matrix::type, \ + fixed<2, 2>, typename MatT_1::basis_orient, row_major> + +namespace detail { + +/** Concatenate two 3D row-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 +matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2, row_basis) { + return m1*m2; +} + +/** Concatenate two 3D col-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 +matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2, col_basis) { + return m2*m1; +} + +/** Concatenate two 3D rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 +matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2) { + return matrix_concat_rotations(m1,m2,typename MatT_1::basis_orient()); +} + +/** Concatenate two 2D row-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 +matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2, row_basis) { + return m1*m2; +} + +/** Concatenate two 2D col-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 +matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2, col_basis) { + return m2*m1; +} + +/** Concatenate two 2D rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 +matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2) { + return matrix_concat_rotations_2D(m1,m2,typename MatT_1::basis_orient()); +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////////// +// Matrix rotation difference +////////////////////////////////////////////////////////////////////////////// + +/** Return the rotational 'difference' between two 3D rotation matrices */ +template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 +matrix_rotation_difference(const MatT_1& m1, const MatT_2& m2) { + return detail::matrix_concat_rotations(transpose(m1),m2); +} + +/** Return the rotational 'difference' between two 2D rotation matrices */ +template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 +matrix_rotation_difference_2D(const MatT_1& m1, const MatT_2& m2) { + return detail::matrix_concat_rotations_2D(transpose(m1),m2); +} + +////////////////////////////////////////////////////////////////////////////// +// Spherical linear interpolation of rotation matrices +////////////////////////////////////////////////////////////////////////////// + +/* @todo: It might be as fast or faster to simply convert the matrices to + * quaternions, interpolate, and convert back. + * + * @todo: The behavior of matrix slerp is currently a little different than + * for quaternions: in the matrix function, when the two matrices are close + * to identical the first is returned, while in the quaternion function the + * quaternions are nlerp()'d in this case. + * + * I still need to do the equivalent of nlerp() for matrices, in which case + * these functions could be revised to pass off to nlerp() when the matrices + * are nearly aligned. +*/ + +/** Spherical linear interpolation of two 3D rotation matrices */ +template < class MatT_1, class MatT_2, typename E > MAT_TEMP_3X3 +matrix_slerp(const MatT_1& m1, const MatT_2& m2, E t, + E tolerance = epsilon::placeholder()) +{ + typedef MAT_TEMP_3X3 temporary_type; + + temporary_type m = matrix_rotation_difference(m1,m2); + matrix_scale_rotation_angle(m,t,tolerance); + return detail::matrix_concat_rotations(m1,m); +} + +/** Spherical linear interpolation of two 2D rotation matrices */ +template < class MatT_1, class MatT_2, typename E > MAT_TEMP_2X2 +matrix_slerp_2D(const MatT_1& m1, const MatT_2& m2, E t, + E tolerance = epsilon::placeholder()) +{ + typedef MAT_TEMP_2X2 temporary_type; + + temporary_type m = matrix_rotation_difference_2D(m1,m2); + matrix_scale_rotation_angle_2D(m,t,tolerance); + return detail::matrix_concat_rotations_2D(m1,m); +} + +# undef MAT_TEMP_3X3 +# undef MAT_TEMP_2X2 + +////////////////////////////////////////////////////////////////////////////// +// Conversions +////////////////////////////////////////////////////////////////////////////// + +/** Convert a 2D rotation matrix to a rotation angle */ +template < class MatT > typename MatT::value_type +matrix_to_rotation_2D(const MatT& m) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + + return std::atan2(m.basis_element(0,1),m.basis_element(0,0)); +} + #endif \ No newline at end of file diff --git a/cml/mathlib/matrix/scale.h b/cml/mathlib/matrix/scale.h index 1750ba6..90f2b2e 100644 --- a/cml/mathlib/matrix/scale.h +++ b/cml/mathlib/matrix/scale.h @@ -1,148 +1,148 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_matrix_scale Matrix Scale Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_scale */ -/*@{*/ - -/** @defgroup mathlib_matrix_scale_2D 2D Matrix Scale Functions */ -/*@{*/ - -/** Initialize a non-uniform 2D scaling matrix with scales @c e0 and @c e1. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_scale_2D(writable_matrix& m, const E0& e0, const E1& e1); - -/** Initialize a non-uniform 2D scaling matrix, taking scales from the - * elements of @c v. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -void matrix_scale_2D(writable_matrix& m, const readable_vector& v); - -/** Initialize a uniform 2D scaling matrix with scale @c e0. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_uniform_scale_2D(writable_matrix& m, const E0& e0); - -/** Initialize a non-uniform 2D scaling matrix with the reciprocals of - * scales @c e0 and @c e1. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_inverse_scale_2D(writable_matrix& m, const E0& e0, - const E1& e1); - -/** Initialize a non-uniform 2D scaling matrix, taking scales from reciprocals - * of the elements of @c v. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -void matrix_inverse_scale_2D(writable_matrix& m, - const readable_vector& v); - -/*@}*/ - - -/** @defgroup mathlib_matrix_scale_3D 3D Matrix Scale Functions */ -/*@{*/ - -/** Initialize a non-uniform 3D scaling matrix with scales @c e0, @c e1, - * and @c e2. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_scale(writable_matrix& m, const E0& e0, const E1& e1, - const E2& e2); - -/** Initialize a non-uniform 3D scaling matrix, taking scales from the - * elements of @c v. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -void matrix_scale(writable_matrix& m, const readable_vector& v); - -/** Initialize a uniform 3D scaling matrix with scale @c e0. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_uniform_scale(writable_matrix& m, const E0& e0); - -/** Initialize a non-uniform 3D scaling matrix with the reciprocals of - * scales @c e0, @c e1, and @c e2. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_inverse_scale(writable_matrix& m, const E0& e0, const E1& e1, - const E2& e2); - -/** Initialize a non-uniform 3D scaling matrix, taking scales from reciprocals - * of the elements of @c v. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -void matrix_inverse_scale(writable_matrix& m, - const readable_vector& v); - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_SCALE_TPP -#include -#undef __CML_MATHLIB_MATRIX_SCALE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_matrix_scale Matrix Scale Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_scale */ +/*@{*/ + +/** @defgroup mathlib_matrix_scale_2D 2D Matrix Scale Functions */ +/*@{*/ + +/** Initialize a non-uniform 2D scaling matrix with scales @c e0 and @c e1. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_scale_2D(writable_matrix& m, const E0& e0, const E1& e1); + +/** Initialize a non-uniform 2D scaling matrix, taking scales from the + * elements of @c v. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +void matrix_scale_2D(writable_matrix& m, const readable_vector& v); + +/** Initialize a uniform 2D scaling matrix with scale @c e0. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_uniform_scale_2D(writable_matrix& m, const E0& e0); + +/** Initialize a non-uniform 2D scaling matrix with the reciprocals of + * scales @c e0 and @c e1. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_inverse_scale_2D(writable_matrix& m, const E0& e0, + const E1& e1); + +/** Initialize a non-uniform 2D scaling matrix, taking scales from reciprocals + * of the elements of @c v. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +void matrix_inverse_scale_2D(writable_matrix& m, + const readable_vector& v); + +/*@}*/ + + +/** @defgroup mathlib_matrix_scale_3D 3D Matrix Scale Functions */ +/*@{*/ + +/** Initialize a non-uniform 3D scaling matrix with scales @c e0, @c e1, + * and @c e2. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_scale(writable_matrix& m, const E0& e0, const E1& e1, + const E2& e2); + +/** Initialize a non-uniform 3D scaling matrix, taking scales from the + * elements of @c v. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +void matrix_scale(writable_matrix& m, const readable_vector& v); + +/** Initialize a uniform 3D scaling matrix with scale @c e0. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_uniform_scale(writable_matrix& m, const E0& e0); + +/** Initialize a non-uniform 3D scaling matrix with the reciprocals of + * scales @c e0, @c e1, and @c e2. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_inverse_scale(writable_matrix& m, const E0& e0, const E1& e1, + const E2& e2); + +/** Initialize a non-uniform 3D scaling matrix, taking scales from reciprocals + * of the elements of @c v. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +void matrix_inverse_scale(writable_matrix& m, + const readable_vector& v); + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_SCALE_TPP +#include +#undef __CML_MATHLIB_MATRIX_SCALE_TPP diff --git a/cml/mathlib/matrix/scale.tpp b/cml/mathlib/matrix/scale.tpp index 3991414..7764e95 100644 --- a/cml/mathlib/matrix/scale.tpp +++ b/cml/mathlib/matrix/scale.tpp @@ -1,159 +1,159 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_SCALE_TPP -# error "mathlib/matrix/scale.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -/* 2D scale: */ - -template -inline void -matrix_scale_2D(writable_matrix& m, const E0& e0, const E1& e1) -{ - static_assert(cml::are_convertible, E0, E1>::value, - "incompatible scalar types"); - - cml::check_affine_2D(m); - m.identity(); - m.set_basis_element(0, 0, e0); - m.set_basis_element(1, 1, e1); -} - -template -inline void -matrix_scale_2D(writable_matrix& m, const readable_vector& v) -{ - cml::check_size(v, int_c<2>()); - matrix_scale_2D(m, v[0], v[1]); -} - -template -inline void -matrix_uniform_scale_2D(writable_matrix& m, const E0& e0) -{ - matrix_scale_2D(m, e0, e0); -} - -template -inline void -matrix_inverse_scale_2D(writable_matrix& m, const E0& e0, const E1& e1) -{ - matrix_scale_2D(m, E0(1) / e0, E1(1) / e1); -} - -template -inline void -matrix_inverse_scale_2D(writable_matrix& m, - const readable_vector& v) -{ - cml::check_size(v, int_c<2>()); - matrix_inverse_scale_2D(m, v[0], v[1]); -} - -/* 3D scaling: */ - -template -inline void -matrix_scale(writable_matrix& m, const E0& e0, const E1& e1, const E2& e2) -{ - static_assert( - cml::are_convertible, E0, E1, E2>::value, - "incompatible scalar types"); - - cml::check_affine_3D(m); - m.identity(); - m.set_basis_element(0, 0, e0); - m.set_basis_element(1, 1, e1); - m.set_basis_element(2, 2, e2); -} - -template -inline void -matrix_scale(writable_matrix& m, const readable_vector& v) -{ - cml::check_size(v, int_c<3>()); - matrix_scale(m, v[0], v[1], v[2]); -} - -template -inline void -matrix_uniform_scale(writable_matrix& m, const E0& e0) -{ - matrix_scale(m, e0, e0, e0); -} - -template -inline void -matrix_inverse_scale(writable_matrix& m, const E0& e0, const E1& e1, - const E2& e2) -{ - matrix_scale(m, E0(1) / e0, E1(1) / e1, E2(1) / e2); -} - -template -inline void -matrix_inverse_scale(writable_matrix& m, const readable_vector& v) -{ - cml::check_size(v, int_c<3>()); - matrix_inverse_scale(m, v[0], v[1], v[2]); -} - -} // namespace cml - - -#if 0 -// XXX INCOMPLETE XXX - -////////////////////////////////////////////////////////////////////////////// -// 3D scale along axis -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 3D scale along an arbitrary axis */ -template < typename E, class A, class B, class L, class VecT > void -matrix_scale_along_axis(matrix&m, const VecT& axis, E scale) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckVec3(axis); - - matrix,B,L> outer_p = outer(axis,axis)*(scale-value_type(1)); - outer_p(0,0) += value_type(1); - outer_p(1,1) += value_type(1); - outer_p(2,2) += value_type(1); - - matrix_linear_transform(m, outer_p); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D scale along axis -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 2D scale along an arbitrary axis */ -template < typename E, class A, class B, class L, class VecT > -void matrix_scale_along_axis_2D(matrix& m, const VecT& axis, - E scale) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckVec2(axis); - - matrix,B,L> outer_p = outer(axis,axis)*(scale-value_type(1)); - outer_p(0,0) += value_type(1); - outer_p(1,1) += value_type(1); - - matrix_linear_transform_2D(m, outer_p); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_SCALE_TPP +# error "mathlib/matrix/scale.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +/* 2D scale: */ + +template +inline void +matrix_scale_2D(writable_matrix& m, const E0& e0, const E1& e1) +{ + static_assert(cml::are_convertible, E0, E1>::value, + "incompatible scalar types"); + + cml::check_affine_2D(m); + m.identity(); + m.set_basis_element(0, 0, e0); + m.set_basis_element(1, 1, e1); +} + +template +inline void +matrix_scale_2D(writable_matrix& m, const readable_vector& v) +{ + cml::check_size(v, int_c<2>()); + matrix_scale_2D(m, v[0], v[1]); +} + +template +inline void +matrix_uniform_scale_2D(writable_matrix& m, const E0& e0) +{ + matrix_scale_2D(m, e0, e0); +} + +template +inline void +matrix_inverse_scale_2D(writable_matrix& m, const E0& e0, const E1& e1) +{ + matrix_scale_2D(m, E0(1) / e0, E1(1) / e1); +} + +template +inline void +matrix_inverse_scale_2D(writable_matrix& m, + const readable_vector& v) +{ + cml::check_size(v, int_c<2>()); + matrix_inverse_scale_2D(m, v[0], v[1]); +} + +/* 3D scaling: */ + +template +inline void +matrix_scale(writable_matrix& m, const E0& e0, const E1& e1, const E2& e2) +{ + static_assert( + cml::are_convertible, E0, E1, E2>::value, + "incompatible scalar types"); + + cml::check_affine_3D(m); + m.identity(); + m.set_basis_element(0, 0, e0); + m.set_basis_element(1, 1, e1); + m.set_basis_element(2, 2, e2); +} + +template +inline void +matrix_scale(writable_matrix& m, const readable_vector& v) +{ + cml::check_size(v, int_c<3>()); + matrix_scale(m, v[0], v[1], v[2]); +} + +template +inline void +matrix_uniform_scale(writable_matrix& m, const E0& e0) +{ + matrix_scale(m, e0, e0, e0); +} + +template +inline void +matrix_inverse_scale(writable_matrix& m, const E0& e0, const E1& e1, + const E2& e2) +{ + matrix_scale(m, E0(1) / e0, E1(1) / e1, E2(1) / e2); +} + +template +inline void +matrix_inverse_scale(writable_matrix& m, const readable_vector& v) +{ + cml::check_size(v, int_c<3>()); + matrix_inverse_scale(m, v[0], v[1], v[2]); +} + +} // namespace cml + + +#if 0 +// XXX INCOMPLETE XXX + +////////////////////////////////////////////////////////////////////////////// +// 3D scale along axis +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D scale along an arbitrary axis */ +template < typename E, class A, class B, class L, class VecT > void +matrix_scale_along_axis(matrix&m, const VecT& axis, E scale) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckVec3(axis); + + matrix,B,L> outer_p = outer(axis,axis)*(scale-value_type(1)); + outer_p(0,0) += value_type(1); + outer_p(1,1) += value_type(1); + outer_p(2,2) += value_type(1); + + matrix_linear_transform(m, outer_p); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D scale along axis +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D scale along an arbitrary axis */ +template < typename E, class A, class B, class L, class VecT > +void matrix_scale_along_axis_2D(matrix& m, const VecT& axis, + E scale) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckVec2(axis); + + matrix,B,L> outer_p = outer(axis,axis)*(scale-value_type(1)); + outer_p(0,0) += value_type(1); + outer_p(1,1) += value_type(1); + + matrix_linear_transform_2D(m, outer_p); +} + #endif \ No newline at end of file diff --git a/cml/mathlib/matrix/size_checking.h b/cml/mathlib/matrix/size_checking.h index 4ae0ada..e72b36a 100644 --- a/cml/mathlib/matrix/size_checking.h +++ b/cml/mathlib/matrix/size_checking.h @@ -1,86 +1,86 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml { - -/** Exception thrown when run-time size checking is enabled, and a matrix - * is not sized to hold an affine transformation. - */ -struct affine_matrix_size_error : std::runtime_error -{ - affine_matrix_size_error() - : std::runtime_error("incorrect affine matrix size") - {} -}; - -/** Front-end for both compile-time and run-time 2D affine matrix size - * checking. A row-basis matrix must be at least 3x2, while a column-basis - * matrix must be at least 2x3. - * - * @tparam Sub the actual type of the matrix expression. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template void check_affine_2D(const readable_matrix& m); - -/** Front-end for both compile-time and run-time 3D affine matrix size - * checking. A row-basis matrix must be at least 4x3, while a column-basis - * matrix must be at least 3x4. - * - * @tparam Sub the actual type of the matrix expression. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template void check_affine_3D(const readable_matrix& m); - -/** Front-end for both compile-time and run-time affine matrix size - * checking. A row-basis matrix must have size (N,N) or (N+1,N), while - * a column-basis matrix must have size (N,N) or (N,N+1). - * - * @tparam Sub the actual type of the matrix expression. - * - * @throws affine_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for an affine transformation. If @c - * m is fixed-size, the size is checked at compile-time. - */ -template void check_affine(const readable_matrix& m); - -/** Front-end for both compile-time and run-time 2D linear matrix size - * checking. A linear matrix must be at least 2x2. - * - * @tparam Sub the actual type of the matrix expression. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D linear transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template void check_linear_2D(const readable_matrix& m); - -/** Front-end for both compile-time and run-time 3D linear matrix size - * checking. A linear matrix must be at least 3x3. - * - * @tparam Sub the actual type of the matrix expression. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D linear transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template void check_linear_3D(const readable_matrix& m); - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_SIZE_CHECKING_TPP -#include -#undef __CML_MATHLIB_MATRIX_SIZE_CHECKING_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml { + +/** Exception thrown when run-time size checking is enabled, and a matrix + * is not sized to hold an affine transformation. + */ +struct affine_matrix_size_error : std::runtime_error +{ + affine_matrix_size_error() + : std::runtime_error("incorrect affine matrix size") + {} +}; + +/** Front-end for both compile-time and run-time 2D affine matrix size + * checking. A row-basis matrix must be at least 3x2, while a column-basis + * matrix must be at least 2x3. + * + * @tparam Sub the actual type of the matrix expression. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template void check_affine_2D(const readable_matrix& m); + +/** Front-end for both compile-time and run-time 3D affine matrix size + * checking. A row-basis matrix must be at least 4x3, while a column-basis + * matrix must be at least 3x4. + * + * @tparam Sub the actual type of the matrix expression. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template void check_affine_3D(const readable_matrix& m); + +/** Front-end for both compile-time and run-time affine matrix size + * checking. A row-basis matrix must have size (N,N) or (N+1,N), while + * a column-basis matrix must have size (N,N) or (N,N+1). + * + * @tparam Sub the actual type of the matrix expression. + * + * @throws affine_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for an affine transformation. If @c + * m is fixed-size, the size is checked at compile-time. + */ +template void check_affine(const readable_matrix& m); + +/** Front-end for both compile-time and run-time 2D linear matrix size + * checking. A linear matrix must be at least 2x2. + * + * @tparam Sub the actual type of the matrix expression. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D linear transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template void check_linear_2D(const readable_matrix& m); + +/** Front-end for both compile-time and run-time 3D linear matrix size + * checking. A linear matrix must be at least 3x3. + * + * @tparam Sub the actual type of the matrix expression. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D linear transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template void check_linear_3D(const readable_matrix& m); + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_SIZE_CHECKING_TPP +#include +#undef __CML_MATHLIB_MATRIX_SIZE_CHECKING_TPP diff --git a/cml/mathlib/matrix/size_checking.tpp b/cml/mathlib/matrix/size_checking.tpp index 0fef830..5c46380 100644 --- a/cml/mathlib/matrix/size_checking.tpp +++ b/cml/mathlib/matrix/size_checking.tpp @@ -1,131 +1,131 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_SIZE_CHECKING_TPP -# error "mathlib/matrix/size_checking.tpp not included correctly" -#endif - -#include - -namespace cml { -namespace detail { - -/* No-op matrix size checking. */ -template -inline void -check_affine_2D(const readable_matrix&, any_basis) -{} - -/* Size checking for a row-basis matrix: */ -template -inline void -check_affine_2D(const readable_matrix& m, row_basis) -{ - cml::check_minimum_size(m, cml::int_c<3>(), cml::int_c<2>()); -} - -/* Size checking for a column-basis matrix: */ -template -inline void -check_affine_2D(const readable_matrix& m, col_basis) -{ - cml::check_minimum_size(m, cml::int_c<2>(), cml::int_c<3>()); -} - -/* No-op matrix size checking. */ -template -inline void -check_affine_3D(const readable_matrix&, any_basis) -{} - -/* Size checking for a row-basis matrix: */ -template -inline void -check_affine_3D(const readable_matrix& m, row_basis) -{ - cml::check_minimum_size(m, cml::int_c<4>(), cml::int_c<3>()); -} - -/* Size checking for a column-basis matrix: */ -template -inline void -check_affine_3D(const readable_matrix& m, col_basis) -{ - cml::check_minimum_size(m, cml::int_c<3>(), cml::int_c<4>()); -} - -/* Compile-time affine matrix size checking: */ -template -inline void -check_affine(const readable_matrix&, fixed_size_tag) -{ - using traits = matrix_traits; - - /* If m is row basis, then rows == cols or rows == cols+1. Otherwise, m - * is column basis, and cols == rows or cols == rows+1: - */ - static const int M = - is_row_basis::value ? traits::array_rows : traits::array_cols; - static const int N = - is_row_basis::value ? traits::array_cols : traits::array_rows; - static_assert(M == N || M == N + 1, "incorrect affine matrix size"); -} - -/* Run-time affine matrix size checking: */ -template -inline void -check_affine(const readable_matrix& m, dynamic_size_tag) -{ - using traits = matrix_traits; - - /* If m is row basis, then rows == cols or rows == cols+1. Otherwise, m - * is column basis, and cols == rows or cols == rows+1: - */ - int M = is_row_basis::value ? m.rows() : m.cols(); - int N = is_row_basis::value ? m.cols() : m.rows(); - cml_require(M == N || M == N + 1, affine_matrix_size_error, /**/); -} - -} // namespace detail - -template -inline void -check_affine_2D(const readable_matrix& m) -{ - using tag = basis_tag_of_t; - detail::check_affine_2D(m, tag()); -} - -template -inline void -check_affine_3D(const readable_matrix& m) -{ - using tag = basis_tag_of_t; - detail::check_affine_3D(m, tag()); -} - -template -inline void -check_affine(const readable_matrix& m) -{ - using size_tag = size_tag_of_t; - static_assert(!is_any_basis::value, "row_basis or col_basis required"); - detail::check_affine(m, size_tag()); -} - -template -inline void -check_linear_2D(const readable_matrix& m) -{ - cml::check_minimum_size(m, cml::int_c<2>(), cml::int_c<2>()); -} - -template -inline void -check_linear_3D(const readable_matrix& m) -{ - cml::check_minimum_size(m, cml::int_c<3>(), cml::int_c<3>()); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_SIZE_CHECKING_TPP +# error "mathlib/matrix/size_checking.tpp not included correctly" +#endif + +#include + +namespace cml { +namespace detail { + +/* No-op matrix size checking. */ +template +inline void +check_affine_2D(const readable_matrix&, any_basis) +{} + +/* Size checking for a row-basis matrix: */ +template +inline void +check_affine_2D(const readable_matrix& m, row_basis) +{ + cml::check_minimum_size(m, cml::int_c<3>(), cml::int_c<2>()); +} + +/* Size checking for a column-basis matrix: */ +template +inline void +check_affine_2D(const readable_matrix& m, col_basis) +{ + cml::check_minimum_size(m, cml::int_c<2>(), cml::int_c<3>()); +} + +/* No-op matrix size checking. */ +template +inline void +check_affine_3D(const readable_matrix&, any_basis) +{} + +/* Size checking for a row-basis matrix: */ +template +inline void +check_affine_3D(const readable_matrix& m, row_basis) +{ + cml::check_minimum_size(m, cml::int_c<4>(), cml::int_c<3>()); +} + +/* Size checking for a column-basis matrix: */ +template +inline void +check_affine_3D(const readable_matrix& m, col_basis) +{ + cml::check_minimum_size(m, cml::int_c<3>(), cml::int_c<4>()); +} + +/* Compile-time affine matrix size checking: */ +template +inline void +check_affine(const readable_matrix&, fixed_size_tag) +{ + using traits = matrix_traits; + + /* If m is row basis, then rows == cols or rows == cols+1. Otherwise, m + * is column basis, and cols == rows or cols == rows+1: + */ + static const int M = + is_row_basis::value ? traits::array_rows : traits::array_cols; + static const int N = + is_row_basis::value ? traits::array_cols : traits::array_rows; + static_assert(M == N || M == N + 1, "incorrect affine matrix size"); +} + +/* Run-time affine matrix size checking: */ +template +inline void +check_affine(const readable_matrix& m, dynamic_size_tag) +{ + using traits = matrix_traits; + + /* If m is row basis, then rows == cols or rows == cols+1. Otherwise, m + * is column basis, and cols == rows or cols == rows+1: + */ + int M = is_row_basis::value ? m.rows() : m.cols(); + int N = is_row_basis::value ? m.cols() : m.rows(); + cml_require(M == N || M == N + 1, affine_matrix_size_error, /**/); +} + +} // namespace detail + +template +inline void +check_affine_2D(const readable_matrix& m) +{ + using tag = basis_tag_of_t; + detail::check_affine_2D(m, tag()); +} + +template +inline void +check_affine_3D(const readable_matrix& m) +{ + using tag = basis_tag_of_t; + detail::check_affine_3D(m, tag()); +} + +template +inline void +check_affine(const readable_matrix& m) +{ + using size_tag = size_tag_of_t; + static_assert(!is_any_basis::value, "row_basis or col_basis required"); + detail::check_affine(m, size_tag()); +} + +template +inline void +check_linear_2D(const readable_matrix& m) +{ + cml::check_minimum_size(m, cml::int_c<2>(), cml::int_c<2>()); +} + +template +inline void +check_linear_3D(const readable_matrix& m) +{ + cml::check_minimum_size(m, cml::int_c<3>(), cml::int_c<3>()); +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/matrix/temporary.h b/cml/mathlib/matrix/temporary.h index 57803dd..a205ba1 100644 --- a/cml/mathlib/matrix/temporary.h +++ b/cml/mathlib/matrix/temporary.h @@ -1,66 +1,66 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace cml { - -/** Deduce a temporary for basis @c N-vectors of @c Matrix. */ -template* = nullptr> -struct n_basis_vector_of -{ - /* Query the unbound storage type: */ - using traits = matrix_traits; - using value_type = typename traits::value_type; - using matrix_storage_type = typename traits::storage_type; - using unbound_storage_type = typename matrix_storage_type::unbound_type; - - /* Rebind to a proxy vector storage type with the requested size: */ - using resized_type = resize_storage_t; - using rebound_type = rebind_vector_storage_t; - using storage_type = proxy_type_of_t; - using type = vector; -}; - -/** Convenience alias for n_basis_vector_of. */ -template -using n_basis_vector_of_t = typename n_basis_vector_of::type; - -/** Deduce a temporary for basis vectors of @c Matrix. */ -template* = nullptr> -struct basis_vector_of -{ - /* Query the unbound storage type: */ - using traits = matrix_traits; - using value_type = typename traits::value_type; - using matrix_storage_type = typename traits::storage_type; - using basis_tag = typename traits::basis_tag; - using unbound_storage_type = typename matrix_storage_type::unbound_type; - - /* any_basis is not allowed: */ - static_assert(!is_any_basis::value, - "any_basis invalid for basis vector type deduction"); - - /* Determine the vector size based on the basis: */ - static const int N = - is_row_basis::value ? traits::array_cols : traits::array_rows; - - /* Rebind to a proxy vector storage type with the requested size: */ - using resized_type = resize_storage_t; - using rebound_type = rebind_vector_storage_t; - using storage_type = proxy_type_of_t; - using type = vector; -}; - -/** Convenience alias for basis_vector_of. */ -template -using basis_vector_of_t = typename basis_vector_of::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace cml { + +/** Deduce a temporary for basis @c N-vectors of @c Matrix. */ +template* = nullptr> +struct n_basis_vector_of +{ + /* Query the unbound storage type: */ + using traits = matrix_traits; + using value_type = typename traits::value_type; + using matrix_storage_type = typename traits::storage_type; + using unbound_storage_type = typename matrix_storage_type::unbound_type; + + /* Rebind to a proxy vector storage type with the requested size: */ + using resized_type = resize_storage_t; + using rebound_type = rebind_vector_storage_t; + using storage_type = proxy_type_of_t; + using type = vector; +}; + +/** Convenience alias for n_basis_vector_of. */ +template +using n_basis_vector_of_t = typename n_basis_vector_of::type; + +/** Deduce a temporary for basis vectors of @c Matrix. */ +template* = nullptr> +struct basis_vector_of +{ + /* Query the unbound storage type: */ + using traits = matrix_traits; + using value_type = typename traits::value_type; + using matrix_storage_type = typename traits::storage_type; + using basis_tag = typename traits::basis_tag; + using unbound_storage_type = typename matrix_storage_type::unbound_type; + + /* any_basis is not allowed: */ + static_assert(!is_any_basis::value, + "any_basis invalid for basis vector type deduction"); + + /* Determine the vector size based on the basis: */ + static const int N = + is_row_basis::value ? traits::array_cols : traits::array_rows; + + /* Rebind to a proxy vector storage type with the requested size: */ + using resized_type = resize_storage_t; + using rebound_type = rebind_vector_storage_t; + using storage_type = proxy_type_of_t; + using type = vector; +}; + +/** Convenience alias for basis_vector_of. */ +template +using basis_vector_of_t = typename basis_vector_of::type; + +} // namespace cml diff --git a/cml/mathlib/matrix/transform.h b/cml/mathlib/matrix/transform.h index 87f16a6..07e7214 100644 --- a/cml/mathlib/matrix/transform.h +++ b/cml/mathlib/matrix/transform.h @@ -1,128 +1,128 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -/** @defgroup mathlib_matrix_transform Matrix Transform Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_transform */ -/*@{*/ - -/** @defgroup mathlib_matrix_lookat_3D 3D Matrix "Look-At" Functions */ -/*@{*/ - -/** Build a matrix representing a 'look at' view transform given the eye - * position, target, reference up vector, and the handedness. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_look_at(writable_matrix& m, - const readable_vector& position, - const readable_vector& target, const readable_vector& up, - AxisOrientation handedness); - -/** Build a matrix representing a left-handed 'look at' view transform - * given the eye position, target, and reference up vector. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_look_at_LH(writable_matrix& m, - const readable_vector& position, - const readable_vector& target, const readable_vector& up); - -/** Build a matrix representing a right-handed 'look at' view transform - * given the eye position, target, and reference up vector. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void matrix_look_at_RH(writable_matrix& m, - const readable_vector& position, - const readable_vector& target, const readable_vector& up); - -/*@}*/ - -/** @defgroup mathlib_matrix_linear_3D 3D Matrix Linear Transform Functions */ -/*@{*/ - -/** Build a matrix @c m from the 3x3 linear transform part of matrix @c l. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -inline void matrix_linear_transform(writable_matrix& m, - const readable_matrix& l); - -/*@}*/ - -/** @defgroup mathlib_matrix_affine_3D 3D Matrix Affine Transform Functions */ -/*@{*/ - -/** Build an affine transform @c m from an axis-angle pair and a - * translation. If @c normalize is true, @c axis will be made a unit - * vector before computing rotations. The default is false. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized as a 3D affine matrix. If @c m is - * fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c axis is dynamically-sized, - * and is not 3D. If @c axis is fixed-size, the size is checked at - * compile-time. - * - * @throws vector_size_error at run-time if @c translation is - * dynamically-sized, and is not 3D. If @c translation is fixed-size, the - * size is checked at compile-time. - */ -template -inline void matrix_affine_transform(writable_matrix& m, - const readable_vector& axis, const E& angle, - const readable_vector& translation, bool normalize = false); - -/** Build an affine transform @c m from a linear matrix and a translation. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized as a 3D affine matrix. If @c m is - * fixed-size, the size is checked at compile-time. - * - * @throws minimum_matrix_size_error at run-time if @c linear is - * dynamically-sized, and is not 3x3. If @c linear is fixed-size, the size - * is checked at compile-time. - * - * @throws vector_size_error at run-time if @c translation is - * dynamically-sized, and is not 3D. If @c translation is fixed-size, the - * size is checked at compile-time. - */ -template -inline void matrix_affine_transform(writable_matrix& m, - const readable_matrix& linear, - const readable_vector& translation); - -/*@}*/ - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_TRANSFORM_TPP -#include -#undef __CML_MATHLIB_MATRIX_TRANSFORM_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +/** @defgroup mathlib_matrix_transform Matrix Transform Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_transform */ +/*@{*/ + +/** @defgroup mathlib_matrix_lookat_3D 3D Matrix "Look-At" Functions */ +/*@{*/ + +/** Build a matrix representing a 'look at' view transform given the eye + * position, target, reference up vector, and the handedness. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_look_at(writable_matrix& m, + const readable_vector& position, + const readable_vector& target, const readable_vector& up, + AxisOrientation handedness); + +/** Build a matrix representing a left-handed 'look at' view transform + * given the eye position, target, and reference up vector. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_look_at_LH(writable_matrix& m, + const readable_vector& position, + const readable_vector& target, const readable_vector& up); + +/** Build a matrix representing a right-handed 'look at' view transform + * given the eye position, target, and reference up vector. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 4x4. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void matrix_look_at_RH(writable_matrix& m, + const readable_vector& position, + const readable_vector& target, const readable_vector& up); + +/*@}*/ + +/** @defgroup mathlib_matrix_linear_3D 3D Matrix Linear Transform Functions */ +/*@{*/ + +/** Build a matrix @c m from the 3x3 linear transform part of matrix @c l. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +inline void matrix_linear_transform(writable_matrix& m, + const readable_matrix& l); + +/*@}*/ + +/** @defgroup mathlib_matrix_affine_3D 3D Matrix Affine Transform Functions */ +/*@{*/ + +/** Build an affine transform @c m from an axis-angle pair and a + * translation. If @c normalize is true, @c axis will be made a unit + * vector before computing rotations. The default is false. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized as a 3D affine matrix. If @c m is + * fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c axis is dynamically-sized, + * and is not 3D. If @c axis is fixed-size, the size is checked at + * compile-time. + * + * @throws vector_size_error at run-time if @c translation is + * dynamically-sized, and is not 3D. If @c translation is fixed-size, the + * size is checked at compile-time. + */ +template +inline void matrix_affine_transform(writable_matrix& m, + const readable_vector& axis, const E& angle, + const readable_vector& translation, bool normalize = false); + +/** Build an affine transform @c m from a linear matrix and a translation. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized as a 3D affine matrix. If @c m is + * fixed-size, the size is checked at compile-time. + * + * @throws minimum_matrix_size_error at run-time if @c linear is + * dynamically-sized, and is not 3x3. If @c linear is fixed-size, the size + * is checked at compile-time. + * + * @throws vector_size_error at run-time if @c translation is + * dynamically-sized, and is not 3D. If @c translation is fixed-size, the + * size is checked at compile-time. + */ +template +inline void matrix_affine_transform(writable_matrix& m, + const readable_matrix& linear, + const readable_vector& translation); + +/*@}*/ + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_TRANSFORM_TPP +#include +#undef __CML_MATHLIB_MATRIX_TRANSFORM_TPP diff --git a/cml/mathlib/matrix/transform.tpp b/cml/mathlib/matrix/transform.tpp index 6af62c2..eda472c 100644 --- a/cml/mathlib/matrix/transform.tpp +++ b/cml/mathlib/matrix/transform.tpp @@ -1,805 +1,805 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_TRANSFORM_TPP -# error "mathlib/matrix/transform.tpp not included correctly" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cml { - -/* Look-at functions: */ - -template -inline void -matrix_look_at(writable_matrix& m, const readable_vector& position, - const readable_vector& target, const readable_vector& up, - const AxisOrientation handedness) -{ - using value_type = value_type_trait_of_t; - - cml::check_affine_3D(m); - - /* Initialize: */ - m.identity(); - - auto s = value_type(handedness == left_handed ? 1 : -1); - auto z = s * (target - position).normalize(); - auto x = cross(up, z).normalize(); - auto y = cross(z, x); - - matrix_set_transposed_basis_vectors(m, x, y, z); - matrix_set_translation(m, -dot(position, x), -dot(position, y), - -dot(position, z)); -} - -template -inline void -matrix_look_at_LH(writable_matrix& m, - const readable_vector& position, - const readable_vector& target, const readable_vector& up) -{ - matrix_look_at(m, position, target, up, left_handed); -} - -template -inline void -matrix_look_at_RH(writable_matrix& m, - const readable_vector& position, - const readable_vector& target, const readable_vector& up) -{ - matrix_look_at(m, position, target, up, right_handed); -} - -/* 3D Linear transform functions: */ - -template -inline void -matrix_linear_transform(writable_matrix& m, - const readable_matrix& l) -{ - cml::check_linear_3D(m); - cml::check_linear_3D(l); - - /* Initialize: */ - m.identity(); - - /* Copy basis elements: */ - for(int i = 0; i < 3; ++i) { - for(int j = 0; j < 3; ++j) { - m.set_basis_element(i, j, l.basis_element(i, j)); - } - } -} - -/* 3D Affine transform functions: */ - -template -inline void -matrix_affine_transform(writable_matrix& m, - const readable_vector& axis, const E& angle, - const readable_vector& translation, bool normalize) -{ - cml::check_affine_3D(m); - if(normalize) { - cml::matrix_rotation_axis_angle(m, cml::normalize(axis), angle); - } else { - cml::matrix_rotation_axis_angle(m, axis, angle); - } - cml::matrix_set_translation(m, translation); -} - -template -inline void -matrix_affine_transform(writable_matrix& m, - const readable_matrix& linear, const readable_vector& translation) -{ - cml::check_affine_3D(m); - cml::matrix_linear_transform(m, linear); - cml::matrix_set_translation(m, translation); -} - -} // namespace cml - - -#if 0 - -// XXX INCOMPLETE XXX - -////////////////////////////////////////////////////////////////////////////// -// 3D shear -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 3D shear along the specified world axis */ -template < typename E, class A, class B, class L > void -matrix_shear(matrix& m, size_t axis, E shear_s, E shear_t) -{ - /* Checking */ - detail::CheckMatLinear3D(m); - detail::CheckIndex3(axis); - - identity_transform(m); - - size_t i, j, k; - cyclic_permutation(axis, i, j, k); - - m.set_basis_element(i,j,shear_s); - m.set_basis_element(i,k,shear_t); -} - -/** Build a matrix representing a 3D shear along the world x axis */ -template < typename E, class A, class B, class L > void -matrix_shear_x(matrix& m, E shear_s, E shear_t) { - matrix_shear(m,0,shear_s,shear_t); -} - -/** Build a matrix representing a 3D shear along the world y axis */ -template < typename E, class A, class B, class L > void -matrix_shear_y(matrix& m, E shear_s, E shear_t) { - matrix_shear(m,1,shear_s,shear_t); -} - -/** Build a matrix representing a 3D shear along the world z axis */ -template < typename E, class A, class B, class L > void -matrix_shear_z(matrix& m, E shear_s, E shear_t) { - matrix_shear(m,2,shear_s,shear_t); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D shear -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 2D shear along the specified world axis */ -template < typename E, class A, class B, class L > void -matrix_shear_2D(matrix& m, size_t axis, E shear) -{ - /* Checking */ - detail::CheckMatLinear2D(m); - detail::CheckIndex2(axis); - - identity_transform(m); - - size_t i, j; - cyclic_permutation(axis, i, j); - - m.set_basis_element(i,j,shear); -} - -/** Build a matrix representing a 2D shear along the world x axis */ -template < typename E, class A, class B, class L > void -matrix_shear_x_2D(matrix& m, E shear) { - matrix_shear_2D(m,0,shear); -} - -/** Build a matrix representing a 2D shear along the world y axis */ -template < typename E, class A, class B, class L > void -matrix_shear_y_2D(matrix& m, E shear) { - matrix_shear_2D(m,1,shear); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D reflection -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 3D reflection along the given world axis */ -template < typename E, class A, class B, class L > void -matrix_reflect(matrix& m, size_t axis) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckMatLinear3D(m); - detail::CheckIndex3(axis); - - identity_transform(m); - - m(axis,axis) = value_type(-1); -} - -/** Build a matrix representing a 3D reflection along the world x axis */ -template < typename E, class A, class B, class L > void -matrix_reflect_x(matrix& m) { - matrix_reflect(m,0); -} - -/** Build a matrix representing a 3D reflection along the world y axis */ -template < typename E, class A, class B, class L > void -matrix_reflect_y(matrix& m) { - matrix_reflect(m,1); -} - -/** Build a matrix representing a 3D reflection along the world z axis */ -template < typename E, class A, class B, class L > void -matrix_reflect_z(matrix& m) { - matrix_reflect(m,2); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D reflection -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 2D reflection along the given world axis */ -template < typename E, class A, class B, class L > void -matrix_reflect_2D(matrix& m, size_t axis) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckMatLinear2D(m); - detail::CheckIndex2(axis); - - identity_transform(m); - - m(axis,axis) = value_type(-1); -} - -/** Build a matrix representing a 2D reflection along the world x axis */ -template < typename E, class A, class B, class L > void -matrix_reflect_x_2D(matrix& m) { - matrix_reflect_2D(m,0); -} - -/** Build a matrix representing a 2D reflection along the world y axis */ -template < typename E, class A, class B, class L > void -matrix_reflect_y_2D(matrix& m) { - matrix_reflect_2D(m,1); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D reflection about hyperplane -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 3D reflection about the given hyperplane */ -template < typename E, class A, class B, class L, class VecT > void -matrix_reflect_about_hplane(matrix& m, const VecT& normal) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - matrix_scale_along_axis(m, normal, value_type(-1)); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D reflection about hyperplane -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 2D reflection about the given hyperplane */ -template < typename E, class A, class B, class L, class VecT > void -matrix_reflect_about_hplane_2D(matrix&m, const VecT& normal) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - matrix_scale_along_axis_2D(m, normal, value_type(-1)); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D orthographic projection to cardinal hyperplane -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing an orthographic projection onto a plane */ -template < typename E, class A, class B, class L > void -matrix_ortho_project(matrix& m, size_t axis) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckMatLinear3D(m); - detail::CheckIndex3(axis); - - identity_transform(m); - - m(axis,axis) = value_type(0); -} - -/** Build a matrix representing an orthographic projection onto the yz plane*/ -template < typename E, class A, class B, class L > void -matrix_ortho_project_yz(matrix& m) { - matrix_ortho_project(m,0); -} - -/** Build a matrix representing an orthographic projection onto the zx plane*/ -template < typename E, class A, class B, class L > void -matrix_ortho_project_zx(matrix& m) { - matrix_ortho_project(m,1); -} - -/** Build a matrix representing an orthographic projection onto the zy plane*/ -template < typename E, class A, class B, class L > void -matrix_ortho_project_xy(matrix& m) { - matrix_ortho_project(m,2); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D orthographic projection to cardinal hyperplane -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 2D orthographic projection */ -template < typename E, class A, class B, class L > void -matrix_ortho_project_2D(matrix& m, size_t axis) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - /* Checking */ - detail::CheckMatLinear2D(m); - detail::CheckIndex2(axis); - - identity_transform(m); - - m(axis,axis) = value_type(0); -} - -/** Build a matrix representing an orthographic projection onto the y axis */ -template < typename E, class A, class B, class L > void -matrix_ortho_project_y_2D(matrix& m) { - matrix_ortho_project_2D(m,0); -} - -/** Build a matrix representing an orthographic projection onto the x axis */ -template < typename E, class A, class B, class L > void -matrix_ortho_project_x_2D(matrix& m) { - matrix_ortho_project_2D(m,1); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D orthographic projection to hyperplane -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 3D orthographic projection about the given - * hyperplane passing through the origin. - */ -template < typename E, class A, class B, class L, class VecT > void -matrix_ortho_project_to_hplane(matrix& m, const VecT& normal) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - matrix_scale_along_axis(m, normal, value_type(0)); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D orthographic projection to hyperplane -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 2D orthographic projection about the given - * hyperplane passing through the origin. - */ -template < typename E, class A, class B, class L, class VecT > void -matrix_ortho_project_to_hplane_2D(matrix& m, const VecT& normal) -{ - typedef matrix matrix_type; - typedef typename matrix_type::value_type value_type; - - matrix_scale_along_axis_2D(m, normal, value_type(0)); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D 'aim at' -////////////////////////////////////////////////////////////////////////////// - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, - class VecT_1, class VecT_2, class VecT_3 > void -matrix_aim_at(matrix& m, const VecT_1& pos, const VecT_2& target, - const VecT_3& reference, - axis_order order = axis_order_zyx) -{ - matrix_rotation_aim_at(m, pos, target, reference, order); - matrix_set_translation(m, pos); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, - class VecT_1, class VecT_2 > void -matrix_aim_at(matrix& m, const VecT_1& pos, const VecT_2& target, - axis_order order = axis_order_zyx) -{ - matrix_rotation_aim_at(m, pos, target, order); - matrix_set_translation(m, pos); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class B, class L, - class VecT_1, class VecT_2, class VecT_3 > void -matrix_aim_at_axial( - matrix& m, - const VecT_1& pos, - const VecT_2& target, - const VecT_3& axis, - axis_order order = axis_order_zyx) -{ - matrix_rotation_aim_at_axial(m, pos, target, axis, order); - matrix_set_translation(m, pos); -} - -/** See vector_ortho.h for details */ -template < typename E,class A,class B,class L,class VecT,class MatT > void -matrix_aim_at_viewplane( - matrix& m, - const VecT& pos, - const MatT& view_matrix, - Handedness handedness, - axis_order order = axis_order_zyx) -{ - matrix_rotation_align_viewplane(m, view_matrix, handedness, order); - matrix_set_translation(m, pos); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D 'aim at' -////////////////////////////////////////////////////////////////////////////// - -/** See vector_ortho.h for details */ -template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void -matrix_aim_at_2D( - matrix& m, - const VecT_1& pos, - const VecT_2& target, - axis_order2D order = axis_order_xy) -{ - matrix_rotation_align_2D(m, target - pos, true, order); - matrix_set_translation_2D(m, pos); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D 'look at' view matrix -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix representing a 'look at' view transform */ -template < typename E, class A, class B, class L > void -matrix_look_at(matrix& m, E eye_x, E eye_y, E eye_z, E target_x, - E target_y, E target_z, E up_x, E up_y, E up_z, - Handedness handedness) -{ - typedef vector< E, fixed<3> > vector_type; - - matrix_look_at(m, - vector_type(eye_x,eye_y,eye_z), - vector_type(target_x,target_y,target_z), - vector_type(up_x,up_y,up_z), - handedness - ); -} - -/** Build a matrix representing a left-handed'look at' view transform */ -template < typename E, class A, class B, class L > void -matrix_look_at_LH(matrix& m, E eye_x, E eye_y, E eye_z, - E target_x, E target_y, E target_z, E up_x, E up_y, E up_z) -{ - matrix_look_at(m,eye_x,eye_y,eye_z,target_x,target_y,target_z,up_x,up_y, - up_z,left_handed); -} - -/** Build a matrix representing a right-handed'look at' view transform */ -template < typename E, class A, class B, class L > void -matrix_look_at_RH(matrix& m, E eye_x, E eye_y, E eye_z, - E target_x, E target_y, E target_z, E up_x, E up_y, E up_z) -{ - matrix_look_at(m,eye_x,eye_y,eye_z,target_x,target_y,target_z,up_x,up_y, - up_z,right_handed); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D linear transform -////////////////////////////////////////////////////////////////////////////// - -/** Build a matrix from the 2x2 linear transform part of another matrix */ -template < typename E, class A, class B, class L, class MatT > void -matrix_linear_transform_2D(matrix& m, const MatT& linear) -{ - /* Checking */ - detail::CheckMatLinear2D(m); - detail::CheckMatLinear2D(linear); - - identity_transform(m); - - for(size_t i = 0; i < 2; ++i) { - for(size_t j = 0; j < 2; ++j) { - m.set_basis_element(i,j,linear.basis_element(i,j)); - } - } -} - -////////////////////////////////////////////////////////////////////////////// -// 3D affine transform -////////////////////////////////////////////////////////////////////////////// - -/** 3D affine transform from three basis vectors and a translation */ -template void -matrix_affine_transform(matrix& m, const VecT_1& x, const VecT_2& y, - const VecT_3& z, const VecT_4& translation) -{ - identity_transform(m); - matrix_set_basis_vectors(m,x,y,z); - matrix_set_translation(m,translation); -} - -/** 3D affine transform from a quaternion and a translation */ -template < - typename E, class A, class B, class L, - typename QE, class QA, class O, class C, class VecT > void -matrix_affine_transform( - matrix& m, const quaternion& q, - const VecT& translation) -{ - matrix_rotation_quaternion(m,q); - matrix_set_translation(m,translation); -} - -/** 3D affine transform from an Euler-angle triple and a translation */ -template < typename E, class A, class B, class L, class VecT > void -matrix_affine_transform(matrix& m, E angle_0, E angle_1, - E angle_2, EulerOrder order, const VecT& translation) -{ - matrix_rotation_euler(m,angle_0,angle_1,angle_2,order); - matrix_set_translation(m,translation); -} - -////////////////////////////////////////////////////////////////////////////// -// 2D affine transform -////////////////////////////////////////////////////////////////////////////// - -/** 2D affine transform from two basis vectors and a translation */ -template void -matrix_affine_transform_2D(matrix& m, const VecT_1& x, - const VecT_2& y, const VecT_3& translation) -{ - identity_transform(m); - matrix_set_basis_vectors_2D(m,x,y); - matrix_set_translation_2D(m,translation); -} - -/** 2D affine transform from a rotation angle and a translation */ -template -void matrix_affine_transform_2D(matrix& m, E angle, - const VecT& translation) -{ - matrix_rotation_2D(m,angle); - matrix_set_translation_2D(m,translation); -} - -/** 2D affine transform from a matrix and a translation */ -template < typename E,class A,class B,class L,class MatT,class VecT > void -matrix_affine_transform_2D( - matrix& m, const MatT& linear, const VecT& translation) -{ - matrix_linear_transform_2D(m, linear); - matrix_set_translation_2D(m,translation); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D affine from 2D affine -////////////////////////////////////////////////////////////////////////////// - -/** Construct a 3D affine transform from a 2D affine transform */ -template < typename E, class A, class B, class L, class MatT > void -matrix_3D_affine_from_2D_affine(matrix& m, const MatT& affine_2D) -{ - typedef vector< E, fixed<2> > vector_type; - - vector_type x = matrix_get_x_basis_vector_2D(affine_2D); - vector_type y = matrix_get_y_basis_vector_2D(affine_2D); - vector_type p = matrix_get_translation_2D(affine_2D); - - identity_transform(m); - - matrix_set_basis_vectors_2D(m,x,y); - matrix_set_translation(m,p); -} - -////////////////////////////////////////////////////////////////////////////// -// 3D affine from 3D affine -////////////////////////////////////////////////////////////////////////////// - -/** Construct a 3D affine transform from another 3D affine transform */ -template < typename E, class A, class B, class L, class MatT > void -matrix_3D_affine_from_3D_affine(matrix& m, const MatT& affine_3D) -{ - typedef vector< E, fixed<3> > vector_type; - - vector_type x = matrix_get_x_basis_vector(affine_3D); - vector_type y = matrix_get_y_basis_vector(affine_3D); - vector_type z = matrix_get_z_basis_vector(affine_3D); - vector_type p = matrix_get_translation(affine_3D); - - identity_transform(m); - - matrix_set_basis_vectors(m,x,y,z); - matrix_set_translation(m,p); -} - -////////////////////////////////////////////////////////////////////////////// -// Matrix decomposition (scale->rotate->translate) -////////////////////////////////////////////////////////////////////////////// - -/* 3x3 matrix version */ -template < - class MatT, - typename Real, - typename ME, - class MA, - class B, - class L, - typename VE, - class VA -> -void matrix_decompose_SRT( - const MatT& m, - Real& scale_x, - Real& scale_y, - Real& scale_z, - matrix& rotation, - vector& translation) -{ - typedef MatT matrix_type; - typedef typename matrix_type::value_type value_type; - typedef vector > vector_type; - - /* Checking */ - detail::CheckMatAffine3D(m); - detail::CheckMatLinear3D(rotation); - - vector_type x, y, z; - matrix_get_basis_vectors(m, x, y, z); - - scale_x = x.length(); - scale_y = y.length(); - scale_z = z.length(); - - x /= scale_x; - y /= scale_y; - z /= scale_z; - - matrix_set_basis_vectors(rotation, x, y, z); - translation = matrix_get_translation(m); -} - -/* Quaternion version */ -template < - class MatT, - typename Real, - typename QE, - class QA, - class O, - class C, - typename VE, - class VA -> -void matrix_decompose_SRT( - const MatT& m, - Real& scale_x, - Real& scale_y, - Real& scale_z, - quaternion& rotation, - vector& translation) -{ - typedef MatT matrix_type; - typedef typename matrix_type::value_type value_type; - typedef matrix< value_type, fixed<3,3> > rotation_type; - - rotation_type rotation_matrix; - matrix_decompose_SRT( - m, scale_x, scale_y, scale_z, rotation_matrix, translation); - quaternion_rotation_matrix(rotation, rotation_matrix); -} - -/* Euler angle version */ -template < class MatT, typename Real, typename E, class A > -void matrix_decompose_SRT( - const MatT& m, - Real& scale_x, - Real& scale_y, - Real& scale_z, - Real& angle_0, - Real& angle_1, - Real& angle_2, - EulerOrder order, - vector& translation, - Real tolerance = epsilon::placeholder()) -{ - typedef MatT matrix_type; - typedef typename matrix_type::value_type value_type; - typedef matrix< value_type, fixed<3,3> > rotation_type; - - rotation_type rotation_matrix; - matrix_decompose_SRT( - m, scale_x, scale_y, scale_z, rotation_matrix, translation); - matrix_to_euler( - rotation_matrix, angle_0, angle_1, angle_2, order, tolerance); -} - -/* Axis-angle version */ -template < class MatT, typename Real, typename E, class A > -void matrix_decompose_SRT( - const MatT& m, - Real& scale_x, - Real& scale_y, - Real& scale_z, - vector& axis, - Real& angle, - vector& translation, - Real tolerance = epsilon::placeholder()) -{ - typedef MatT matrix_type; - typedef typename matrix_type::value_type value_type; - typedef matrix< value_type, fixed<3,3> > rotation_type; - - rotation_type rotation_matrix; - matrix_decompose_SRT( - m, scale_x, scale_y, scale_z, rotation_matrix, translation); - matrix_to_axis_angle(rotation_matrix, axis, angle, tolerance); -} - -/* 2x2 matrix version, 2-d */ -template < - class MatT, - typename Real, - typename ME, - class MA, - class B, - class L, - typename VE, - class VA -> -void matrix_decompose_SRT_2D( - const MatT& m, - Real& scale_x, - Real& scale_y, - matrix& rotation, - vector& translation) -{ - typedef MatT matrix_type; - typedef typename matrix_type::value_type value_type; - typedef vector > vector_type; - - /* Checking */ - detail::CheckMatAffine2D(m); - detail::CheckMatLinear2D(rotation); - - vector_type x, y; - matrix_get_basis_vectors_2D(m, x, y); - - scale_x = x.length(); - scale_y = y.length(); - - x /= scale_x; - y /= scale_y; - - matrix_set_basis_vectors_2D(rotation, x, y); - translation = matrix_get_translation_2D(m); -} - -/* Angle version, 2-d */ -template < class MatT, typename Real, typename E, class A > -void matrix_decompose_SRT_2D( - const MatT& m, - Real& scale_x, - Real& scale_y, - Real& angle, - vector& translation) -{ - typedef MatT matrix_type; - typedef typename matrix_type::value_type value_type; - typedef matrix< value_type, fixed<2,2> > rotation_type; - - rotation_type rotation_matrix; - matrix_decompose_SRT_2D( - m, scale_x, scale_y, rotation_matrix, translation); - angle = matrix_to_rotation_2D(rotation_matrix); -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_TRANSFORM_TPP +# error "mathlib/matrix/transform.tpp not included correctly" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cml { + +/* Look-at functions: */ + +template +inline void +matrix_look_at(writable_matrix& m, const readable_vector& position, + const readable_vector& target, const readable_vector& up, + const AxisOrientation handedness) +{ + using value_type = value_type_trait_of_t; + + cml::check_affine_3D(m); + + /* Initialize: */ + m.identity(); + + auto s = value_type(handedness == left_handed ? 1 : -1); + auto z = s * (target - position).normalize(); + auto x = cross(up, z).normalize(); + auto y = cross(z, x); + + matrix_set_transposed_basis_vectors(m, x, y, z); + matrix_set_translation(m, -dot(position, x), -dot(position, y), + -dot(position, z)); +} + +template +inline void +matrix_look_at_LH(writable_matrix& m, + const readable_vector& position, + const readable_vector& target, const readable_vector& up) +{ + matrix_look_at(m, position, target, up, left_handed); +} + +template +inline void +matrix_look_at_RH(writable_matrix& m, + const readable_vector& position, + const readable_vector& target, const readable_vector& up) +{ + matrix_look_at(m, position, target, up, right_handed); +} + +/* 3D Linear transform functions: */ + +template +inline void +matrix_linear_transform(writable_matrix& m, + const readable_matrix& l) +{ + cml::check_linear_3D(m); + cml::check_linear_3D(l); + + /* Initialize: */ + m.identity(); + + /* Copy basis elements: */ + for(int i = 0; i < 3; ++i) { + for(int j = 0; j < 3; ++j) { + m.set_basis_element(i, j, l.basis_element(i, j)); + } + } +} + +/* 3D Affine transform functions: */ + +template +inline void +matrix_affine_transform(writable_matrix& m, + const readable_vector& axis, const E& angle, + const readable_vector& translation, bool normalize) +{ + cml::check_affine_3D(m); + if(normalize) { + cml::matrix_rotation_axis_angle(m, cml::normalize(axis), angle); + } else { + cml::matrix_rotation_axis_angle(m, axis, angle); + } + cml::matrix_set_translation(m, translation); +} + +template +inline void +matrix_affine_transform(writable_matrix& m, + const readable_matrix& linear, const readable_vector& translation) +{ + cml::check_affine_3D(m); + cml::matrix_linear_transform(m, linear); + cml::matrix_set_translation(m, translation); +} + +} // namespace cml + + +#if 0 + +// XXX INCOMPLETE XXX + +////////////////////////////////////////////////////////////////////////////// +// 3D shear +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D shear along the specified world axis */ +template < typename E, class A, class B, class L > void +matrix_shear(matrix& m, size_t axis, E shear_s, E shear_t) +{ + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + identity_transform(m); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + m.set_basis_element(i,j,shear_s); + m.set_basis_element(i,k,shear_t); +} + +/** Build a matrix representing a 3D shear along the world x axis */ +template < typename E, class A, class B, class L > void +matrix_shear_x(matrix& m, E shear_s, E shear_t) { + matrix_shear(m,0,shear_s,shear_t); +} + +/** Build a matrix representing a 3D shear along the world y axis */ +template < typename E, class A, class B, class L > void +matrix_shear_y(matrix& m, E shear_s, E shear_t) { + matrix_shear(m,1,shear_s,shear_t); +} + +/** Build a matrix representing a 3D shear along the world z axis */ +template < typename E, class A, class B, class L > void +matrix_shear_z(matrix& m, E shear_s, E shear_t) { + matrix_shear(m,2,shear_s,shear_t); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D shear +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D shear along the specified world axis */ +template < typename E, class A, class B, class L > void +matrix_shear_2D(matrix& m, size_t axis, E shear) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckIndex2(axis); + + identity_transform(m); + + size_t i, j; + cyclic_permutation(axis, i, j); + + m.set_basis_element(i,j,shear); +} + +/** Build a matrix representing a 2D shear along the world x axis */ +template < typename E, class A, class B, class L > void +matrix_shear_x_2D(matrix& m, E shear) { + matrix_shear_2D(m,0,shear); +} + +/** Build a matrix representing a 2D shear along the world y axis */ +template < typename E, class A, class B, class L > void +matrix_shear_y_2D(matrix& m, E shear) { + matrix_shear_2D(m,1,shear); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D reflection +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D reflection along the given world axis */ +template < typename E, class A, class B, class L > void +matrix_reflect(matrix& m, size_t axis) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + identity_transform(m); + + m(axis,axis) = value_type(-1); +} + +/** Build a matrix representing a 3D reflection along the world x axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_x(matrix& m) { + matrix_reflect(m,0); +} + +/** Build a matrix representing a 3D reflection along the world y axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_y(matrix& m) { + matrix_reflect(m,1); +} + +/** Build a matrix representing a 3D reflection along the world z axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_z(matrix& m) { + matrix_reflect(m,2); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D reflection +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D reflection along the given world axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_2D(matrix& m, size_t axis) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckIndex2(axis); + + identity_transform(m); + + m(axis,axis) = value_type(-1); +} + +/** Build a matrix representing a 2D reflection along the world x axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_x_2D(matrix& m) { + matrix_reflect_2D(m,0); +} + +/** Build a matrix representing a 2D reflection along the world y axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_y_2D(matrix& m) { + matrix_reflect_2D(m,1); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D reflection about hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D reflection about the given hyperplane */ +template < typename E, class A, class B, class L, class VecT > void +matrix_reflect_about_hplane(matrix& m, const VecT& normal) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_scale_along_axis(m, normal, value_type(-1)); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D reflection about hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D reflection about the given hyperplane */ +template < typename E, class A, class B, class L, class VecT > void +matrix_reflect_about_hplane_2D(matrix&m, const VecT& normal) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_scale_along_axis_2D(m, normal, value_type(-1)); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D orthographic projection to cardinal hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing an orthographic projection onto a plane */ +template < typename E, class A, class B, class L > void +matrix_ortho_project(matrix& m, size_t axis) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + identity_transform(m); + + m(axis,axis) = value_type(0); +} + +/** Build a matrix representing an orthographic projection onto the yz plane*/ +template < typename E, class A, class B, class L > void +matrix_ortho_project_yz(matrix& m) { + matrix_ortho_project(m,0); +} + +/** Build a matrix representing an orthographic projection onto the zx plane*/ +template < typename E, class A, class B, class L > void +matrix_ortho_project_zx(matrix& m) { + matrix_ortho_project(m,1); +} + +/** Build a matrix representing an orthographic projection onto the zy plane*/ +template < typename E, class A, class B, class L > void +matrix_ortho_project_xy(matrix& m) { + matrix_ortho_project(m,2); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D orthographic projection to cardinal hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D orthographic projection */ +template < typename E, class A, class B, class L > void +matrix_ortho_project_2D(matrix& m, size_t axis) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckIndex2(axis); + + identity_transform(m); + + m(axis,axis) = value_type(0); +} + +/** Build a matrix representing an orthographic projection onto the y axis */ +template < typename E, class A, class B, class L > void +matrix_ortho_project_y_2D(matrix& m) { + matrix_ortho_project_2D(m,0); +} + +/** Build a matrix representing an orthographic projection onto the x axis */ +template < typename E, class A, class B, class L > void +matrix_ortho_project_x_2D(matrix& m) { + matrix_ortho_project_2D(m,1); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D orthographic projection to hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D orthographic projection about the given + * hyperplane passing through the origin. + */ +template < typename E, class A, class B, class L, class VecT > void +matrix_ortho_project_to_hplane(matrix& m, const VecT& normal) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_scale_along_axis(m, normal, value_type(0)); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D orthographic projection to hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D orthographic projection about the given + * hyperplane passing through the origin. + */ +template < typename E, class A, class B, class L, class VecT > void +matrix_ortho_project_to_hplane_2D(matrix& m, const VecT& normal) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_scale_along_axis_2D(m, normal, value_type(0)); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D 'aim at' +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_aim_at(matrix& m, const VecT_1& pos, const VecT_2& target, + const VecT_3& reference, + axis_order order = axis_order_zyx) +{ + matrix_rotation_aim_at(m, pos, target, reference, order); + matrix_set_translation(m, pos); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2 > void +matrix_aim_at(matrix& m, const VecT_1& pos, const VecT_2& target, + axis_order order = axis_order_zyx) +{ + matrix_rotation_aim_at(m, pos, target, order); + matrix_set_translation(m, pos); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_aim_at_axial( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + const VecT_3& axis, + axis_order order = axis_order_zyx) +{ + matrix_rotation_aim_at_axial(m, pos, target, axis, order); + matrix_set_translation(m, pos); +} + +/** See vector_ortho.h for details */ +template < typename E,class A,class B,class L,class VecT,class MatT > void +matrix_aim_at_viewplane( + matrix& m, + const VecT& pos, + const MatT& view_matrix, + Handedness handedness, + axis_order order = axis_order_zyx) +{ + matrix_rotation_align_viewplane(m, view_matrix, handedness, order); + matrix_set_translation(m, pos); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D 'aim at' +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_aim_at_2D( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + axis_order2D order = axis_order_xy) +{ + matrix_rotation_align_2D(m, target - pos, true, order); + matrix_set_translation_2D(m, pos); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D 'look at' view matrix +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 'look at' view transform */ +template < typename E, class A, class B, class L > void +matrix_look_at(matrix& m, E eye_x, E eye_y, E eye_z, E target_x, + E target_y, E target_z, E up_x, E up_y, E up_z, + Handedness handedness) +{ + typedef vector< E, fixed<3> > vector_type; + + matrix_look_at(m, + vector_type(eye_x,eye_y,eye_z), + vector_type(target_x,target_y,target_z), + vector_type(up_x,up_y,up_z), + handedness + ); +} + +/** Build a matrix representing a left-handed'look at' view transform */ +template < typename E, class A, class B, class L > void +matrix_look_at_LH(matrix& m, E eye_x, E eye_y, E eye_z, + E target_x, E target_y, E target_z, E up_x, E up_y, E up_z) +{ + matrix_look_at(m,eye_x,eye_y,eye_z,target_x,target_y,target_z,up_x,up_y, + up_z,left_handed); +} + +/** Build a matrix representing a right-handed'look at' view transform */ +template < typename E, class A, class B, class L > void +matrix_look_at_RH(matrix& m, E eye_x, E eye_y, E eye_z, + E target_x, E target_y, E target_z, E up_x, E up_y, E up_z) +{ + matrix_look_at(m,eye_x,eye_y,eye_z,target_x,target_y,target_z,up_x,up_y, + up_z,right_handed); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D linear transform +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix from the 2x2 linear transform part of another matrix */ +template < typename E, class A, class B, class L, class MatT > void +matrix_linear_transform_2D(matrix& m, const MatT& linear) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckMatLinear2D(linear); + + identity_transform(m); + + for(size_t i = 0; i < 2; ++i) { + for(size_t j = 0; j < 2; ++j) { + m.set_basis_element(i,j,linear.basis_element(i,j)); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// 3D affine transform +////////////////////////////////////////////////////////////////////////////// + +/** 3D affine transform from three basis vectors and a translation */ +template void +matrix_affine_transform(matrix& m, const VecT_1& x, const VecT_2& y, + const VecT_3& z, const VecT_4& translation) +{ + identity_transform(m); + matrix_set_basis_vectors(m,x,y,z); + matrix_set_translation(m,translation); +} + +/** 3D affine transform from a quaternion and a translation */ +template < + typename E, class A, class B, class L, + typename QE, class QA, class O, class C, class VecT > void +matrix_affine_transform( + matrix& m, const quaternion& q, + const VecT& translation) +{ + matrix_rotation_quaternion(m,q); + matrix_set_translation(m,translation); +} + +/** 3D affine transform from an Euler-angle triple and a translation */ +template < typename E, class A, class B, class L, class VecT > void +matrix_affine_transform(matrix& m, E angle_0, E angle_1, + E angle_2, EulerOrder order, const VecT& translation) +{ + matrix_rotation_euler(m,angle_0,angle_1,angle_2,order); + matrix_set_translation(m,translation); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D affine transform +////////////////////////////////////////////////////////////////////////////// + +/** 2D affine transform from two basis vectors and a translation */ +template void +matrix_affine_transform_2D(matrix& m, const VecT_1& x, + const VecT_2& y, const VecT_3& translation) +{ + identity_transform(m); + matrix_set_basis_vectors_2D(m,x,y); + matrix_set_translation_2D(m,translation); +} + +/** 2D affine transform from a rotation angle and a translation */ +template +void matrix_affine_transform_2D(matrix& m, E angle, + const VecT& translation) +{ + matrix_rotation_2D(m,angle); + matrix_set_translation_2D(m,translation); +} + +/** 2D affine transform from a matrix and a translation */ +template < typename E,class A,class B,class L,class MatT,class VecT > void +matrix_affine_transform_2D( + matrix& m, const MatT& linear, const VecT& translation) +{ + matrix_linear_transform_2D(m, linear); + matrix_set_translation_2D(m,translation); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D affine from 2D affine +////////////////////////////////////////////////////////////////////////////// + +/** Construct a 3D affine transform from a 2D affine transform */ +template < typename E, class A, class B, class L, class MatT > void +matrix_3D_affine_from_2D_affine(matrix& m, const MatT& affine_2D) +{ + typedef vector< E, fixed<2> > vector_type; + + vector_type x = matrix_get_x_basis_vector_2D(affine_2D); + vector_type y = matrix_get_y_basis_vector_2D(affine_2D); + vector_type p = matrix_get_translation_2D(affine_2D); + + identity_transform(m); + + matrix_set_basis_vectors_2D(m,x,y); + matrix_set_translation(m,p); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D affine from 3D affine +////////////////////////////////////////////////////////////////////////////// + +/** Construct a 3D affine transform from another 3D affine transform */ +template < typename E, class A, class B, class L, class MatT > void +matrix_3D_affine_from_3D_affine(matrix& m, const MatT& affine_3D) +{ + typedef vector< E, fixed<3> > vector_type; + + vector_type x = matrix_get_x_basis_vector(affine_3D); + vector_type y = matrix_get_y_basis_vector(affine_3D); + vector_type z = matrix_get_z_basis_vector(affine_3D); + vector_type p = matrix_get_translation(affine_3D); + + identity_transform(m); + + matrix_set_basis_vectors(m,x,y,z); + matrix_set_translation(m,p); +} + +////////////////////////////////////////////////////////////////////////////// +// Matrix decomposition (scale->rotate->translate) +////////////////////////////////////////////////////////////////////////////// + +/* 3x3 matrix version */ +template < + class MatT, + typename Real, + typename ME, + class MA, + class B, + class L, + typename VE, + class VA +> +void matrix_decompose_SRT( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& scale_z, + matrix& rotation, + vector& translation) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef vector > vector_type; + + /* Checking */ + detail::CheckMatAffine3D(m); + detail::CheckMatLinear3D(rotation); + + vector_type x, y, z; + matrix_get_basis_vectors(m, x, y, z); + + scale_x = x.length(); + scale_y = y.length(); + scale_z = z.length(); + + x /= scale_x; + y /= scale_y; + z /= scale_z; + + matrix_set_basis_vectors(rotation, x, y, z); + translation = matrix_get_translation(m); +} + +/* Quaternion version */ +template < + class MatT, + typename Real, + typename QE, + class QA, + class O, + class C, + typename VE, + class VA +> +void matrix_decompose_SRT( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& scale_z, + quaternion& rotation, + vector& translation) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef matrix< value_type, fixed<3,3> > rotation_type; + + rotation_type rotation_matrix; + matrix_decompose_SRT( + m, scale_x, scale_y, scale_z, rotation_matrix, translation); + quaternion_rotation_matrix(rotation, rotation_matrix); +} + +/* Euler angle version */ +template < class MatT, typename Real, typename E, class A > +void matrix_decompose_SRT( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& scale_z, + Real& angle_0, + Real& angle_1, + Real& angle_2, + EulerOrder order, + vector& translation, + Real tolerance = epsilon::placeholder()) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef matrix< value_type, fixed<3,3> > rotation_type; + + rotation_type rotation_matrix; + matrix_decompose_SRT( + m, scale_x, scale_y, scale_z, rotation_matrix, translation); + matrix_to_euler( + rotation_matrix, angle_0, angle_1, angle_2, order, tolerance); +} + +/* Axis-angle version */ +template < class MatT, typename Real, typename E, class A > +void matrix_decompose_SRT( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& scale_z, + vector& axis, + Real& angle, + vector& translation, + Real tolerance = epsilon::placeholder()) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef matrix< value_type, fixed<3,3> > rotation_type; + + rotation_type rotation_matrix; + matrix_decompose_SRT( + m, scale_x, scale_y, scale_z, rotation_matrix, translation); + matrix_to_axis_angle(rotation_matrix, axis, angle, tolerance); +} + +/* 2x2 matrix version, 2-d */ +template < + class MatT, + typename Real, + typename ME, + class MA, + class B, + class L, + typename VE, + class VA +> +void matrix_decompose_SRT_2D( + const MatT& m, + Real& scale_x, + Real& scale_y, + matrix& rotation, + vector& translation) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef vector > vector_type; + + /* Checking */ + detail::CheckMatAffine2D(m); + detail::CheckMatLinear2D(rotation); + + vector_type x, y; + matrix_get_basis_vectors_2D(m, x, y); + + scale_x = x.length(); + scale_y = y.length(); + + x /= scale_x; + y /= scale_y; + + matrix_set_basis_vectors_2D(rotation, x, y); + translation = matrix_get_translation_2D(m); +} + +/* Angle version, 2-d */ +template < class MatT, typename Real, typename E, class A > +void matrix_decompose_SRT_2D( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& angle, + vector& translation) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef matrix< value_type, fixed<2,2> > rotation_type; + + rotation_type rotation_matrix; + matrix_decompose_SRT_2D( + m, scale_x, scale_y, rotation_matrix, translation); + angle = matrix_to_rotation_2D(rotation_matrix); +} #endif \ No newline at end of file diff --git a/cml/mathlib/matrix/translation.h b/cml/mathlib/matrix/translation.h index c307883..2c789b2 100644 --- a/cml/mathlib/matrix/translation.h +++ b/cml/mathlib/matrix/translation.h @@ -1,196 +1,196 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -/** @defgroup mathlib_matrix_translation Matrix Translation Functions */ - -namespace cml { - -/** @addtogroup mathlib_matrix_translation */ -/*@{*/ - -/** @defgroup mathlib_matrix_translation_2D 2D Matrix Translation Functions */ -/*@{*/ - -/** Set the translation of a 2D affine transformation, @c m, to @c e0 and - * @c e1. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_set_translation_2D(writable_matrix& m, const E0& e0, - const E1& e1); - -/** Set the translation of a 2D affine transformation, @c m, to the 2D - * vector @c v. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -void matrix_set_translation_2D(writable_matrix& m, - const readable_vector& v); - - -/** Get the translation vector of a 2D affine transformation as two scalar - * values. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_get_translation_2D(const readable_matrix& m, E0& e0, E1& e1); - -/** Get the translation of a 2D affine transformation as a 2D vector. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -auto matrix_get_translation_2D(const readable_matrix& m) - -> n_basis_vector_of_t; - - -/** Initialize a 2D translation matrix, @c m, from @c e0 and @c e1. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_translation_2D(writable_matrix& m, const E0& e0, const E1& e1); - -/** Initialize a 2D translation matrix, @c m, from the 2D vector @c v. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -void matrix_translation_2D(writable_matrix& m, - const readable_vector& v); - -/*@}*/ - - -/** @defgroup mathlib_matrix_translation_3D 3D Matrix Translation Functions */ -/*@{*/ - -/** Set the translation of a 3D affine transformation, @c m, to @c e0, @c - * e1, and @c e2. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_set_translation(writable_matrix& m, const E0& e0, const E1& e1, - const E2& e2); - -/** Set the translation of a 3D affine transformation, @c m, to @c e0, @c - * e1, and 0. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_set_translation(writable_matrix& m, const E0& e0, - const E1& e1); - -/** Set the translation of a 3D affine transformation, @c m, to the - * 2D or 3D vector @c v (if @c v is 2D the last element is 0). - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D or 3D. If @c v is fixed-size, the size is checked at - * compile-time. - */ -template -void matrix_set_translation(writable_matrix& m, - const readable_vector& v); - - -/** Get the translation vector of a 3D affine transformation as three - * scalar values. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_get_translation(const readable_matrix& m, E0& e0, E1& e1, - E2& e2); - -/** Get the translation of a 3D affine transformation as a 3D vector. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -auto matrix_get_translation(const readable_matrix& m) - -> n_basis_vector_of_t; - - -/** Initialize a 3D translation matrix, @c m, from @c e0, @c e1, and @c e2. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_translation(writable_matrix& m, const E0& e0, const E1& e1, - const E2& e2); - -/** Initialize a 3D translation matrix, @c m, from @c e0, @c e1, and 0. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - */ -template -void matrix_translation(writable_matrix& m, const E0& e0, const E1& e1); - -/** Initialize a 3D translation matrix, @c m, from the 3D vector @c v. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -void matrix_translation(writable_matrix& m, - const readable_vector& v); - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_MATRIX_TRANSLATION_TPP -#include -#undef __CML_MATHLIB_MATRIX_TRANSLATION_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +/** @defgroup mathlib_matrix_translation Matrix Translation Functions */ + +namespace cml { + +/** @addtogroup mathlib_matrix_translation */ +/*@{*/ + +/** @defgroup mathlib_matrix_translation_2D 2D Matrix Translation Functions */ +/*@{*/ + +/** Set the translation of a 2D affine transformation, @c m, to @c e0 and + * @c e1. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_set_translation_2D(writable_matrix& m, const E0& e0, + const E1& e1); + +/** Set the translation of a 2D affine transformation, @c m, to the 2D + * vector @c v. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +void matrix_set_translation_2D(writable_matrix& m, + const readable_vector& v); + + +/** Get the translation vector of a 2D affine transformation as two scalar + * values. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_get_translation_2D(const readable_matrix& m, E0& e0, E1& e1); + +/** Get the translation of a 2D affine transformation as a 2D vector. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +auto matrix_get_translation_2D(const readable_matrix& m) + -> n_basis_vector_of_t; + + +/** Initialize a 2D translation matrix, @c m, from @c e0 and @c e1. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_translation_2D(writable_matrix& m, const E0& e0, const E1& e1); + +/** Initialize a 2D translation matrix, @c m, from the 2D vector @c v. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +void matrix_translation_2D(writable_matrix& m, + const readable_vector& v); + +/*@}*/ + + +/** @defgroup mathlib_matrix_translation_3D 3D Matrix Translation Functions */ +/*@{*/ + +/** Set the translation of a 3D affine transformation, @c m, to @c e0, @c + * e1, and @c e2. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_set_translation(writable_matrix& m, const E0& e0, const E1& e1, + const E2& e2); + +/** Set the translation of a 3D affine transformation, @c m, to @c e0, @c + * e1, and 0. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_set_translation(writable_matrix& m, const E0& e0, + const E1& e1); + +/** Set the translation of a 3D affine transformation, @c m, to the + * 2D or 3D vector @c v (if @c v is 2D the last element is 0). + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D or 3D. If @c v is fixed-size, the size is checked at + * compile-time. + */ +template +void matrix_set_translation(writable_matrix& m, + const readable_vector& v); + + +/** Get the translation vector of a 3D affine transformation as three + * scalar values. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_get_translation(const readable_matrix& m, E0& e0, E1& e1, + E2& e2); + +/** Get the translation of a 3D affine transformation as a 3D vector. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +auto matrix_get_translation(const readable_matrix& m) + -> n_basis_vector_of_t; + + +/** Initialize a 3D translation matrix, @c m, from @c e0, @c e1, and @c e2. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_translation(writable_matrix& m, const E0& e0, const E1& e1, + const E2& e2); + +/** Initialize a 3D translation matrix, @c m, from @c e0, @c e1, and 0. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + */ +template +void matrix_translation(writable_matrix& m, const E0& e0, const E1& e1); + +/** Initialize a 3D translation matrix, @c m, from the 3D vector @c v. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +void matrix_translation(writable_matrix& m, + const readable_vector& v); + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_MATRIX_TRANSLATION_TPP +#include +#undef __CML_MATHLIB_MATRIX_TRANSLATION_TPP diff --git a/cml/mathlib/matrix/translation.tpp b/cml/mathlib/matrix/translation.tpp index c0a6dad..1ea4841 100644 --- a/cml/mathlib/matrix/translation.tpp +++ b/cml/mathlib/matrix/translation.tpp @@ -1,218 +1,218 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_MATRIX_TRANSLATION_TPP -# error "mathlib/matrix/translation.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { -namespace detail { - -/* Base case, set a single basis element (I,J): */ -template -inline void -matrix_set_basis(writable_matrix& m, const E& e) -{ - m.set_basis_element(I, J, e); -} - -/* Recursive case: set basis element (I,J) to e, then recursively set - * (I,J+1): - */ -template -inline void -matrix_set_basis(writable_matrix& m, const E& e, const Es&... es) -{ - m.set_basis_element(I, J, e); - matrix_set_basis(m, es...); -} - -/* Entry case: set basis vector I from the items in Es: */ -template -inline void -matrix_set_basis(writable_matrix& m, const Es&... es) -{ - static_assert(cml::are_convertible, Es...>::value, - "incompatible scalar types"); - - /* Recursively set basis vector I, starting at element 0: */ - matrix_set_basis(m, es...); -} - -} // namespace detail - -/* 2D translation: */ - -template -inline void -matrix_set_translation_2D(writable_matrix& m, const E0& e0, const E1& e1) -{ - cml::check_affine_2D(m); - detail::matrix_set_basis<2>(m, e0, e1); -} - -template -inline void -matrix_set_translation_2D(writable_matrix& m, - const readable_vector& v) -{ - cml::check_size(v, int_c<2>()); - cml::check_affine_2D(m); - detail::matrix_set_basis<2>(m, v[0], v[1]); -} - -template -inline void -matrix_get_translation_2D(const readable_matrix& m, E0& e0, E1& e1) -{ - static_assert(cml::are_convertible, E0, E1>::value, - "incompatible scalar types"); - - cml::check_affine_2D(m); - e0 = E0(m.basis_element(2, 0)); - e1 = E1(m.basis_element(2, 1)); -} - -template -inline auto -matrix_get_translation_2D(const readable_matrix& m) - -> n_basis_vector_of_t -{ - cml::check_affine_2D(m); -#if defined(_MSC_VER) && (_MSC_VER >= 1900) - return n_basis_vector_of_t(m.basis_element(2, 0), - m.basis_element(2, 1)); -#else - return {m.basis_element(2, 0), m.basis_element(2, 1)}; -#endif -} - -template -inline void -matrix_translation_2D(writable_matrix& m, const E0& e0, const E1& e1) -{ - m.identity(); - matrix_set_translation_2D(m, e0, e1); -} - -template -inline void -matrix_translation_2D(writable_matrix& m, const readable_vector& v) -{ - m.identity(); - matrix_set_translation_2D(m, v); -} - -/* 3D translation: */ - -template -inline void -matrix_set_translation(writable_matrix& m, const E0& e0, const E1& e1, - const E2& e2) -{ - cml::check_affine_3D(m); - detail::matrix_set_basis<3>(m, e0, e1, e2); -} - -template -inline void -matrix_set_translation(writable_matrix& m, const E0& e0, const E1& e1) -{ - using zero_type = value_type_trait_of_t; - cml::check_affine_3D(m); - detail::matrix_set_basis<3>(m, e0, e1, zero_type(0)); -} - -template -inline void -matrix_set_translation(writable_matrix& m, const readable_vector& v) -{ - using zero_type = value_type_trait_of_t; - cml::check_size_range(v, int_c<2>(), int_c<3>()); - cml::check_affine_3D(m); - detail::matrix_set_basis<3>(m, v[0], v[1], - ((v.size() == 3) ? zero_type(v[2]) : zero_type(0))); -} - -template -inline void -matrix_get_translation(const readable_matrix& m, E0& e0, E1& e1, E2& e2) -{ - static_assert( - cml::are_convertible, E0, E1, E2>::value, - "incompatible scalar types"); - - cml::check_affine_3D(m); - e0 = E0(m.basis_element(3, 0)); - e1 = E1(m.basis_element(3, 1)); - e2 = E2(m.basis_element(3, 2)); -} - -template -inline auto -matrix_get_translation(const readable_matrix& m) - -> n_basis_vector_of_t -{ - cml::check_affine_3D(m); -#if defined(_MSC_VER) && (_MSC_VER >= 1900) - return n_basis_vector_of_t(m.basis_element(3, 0), - m.basis_element(3, 1), m.basis_element(3, 2)); -#else - return {m.basis_element(3, 0), m.basis_element(3, 1), m.basis_element(3, 2)}; -#endif -} - -template -inline void -matrix_translation(writable_matrix& m, const E0& e0, const E1& e1, - const E2& e2) -{ - m.identity(); - matrix_set_translation(m, e0, e1, e2); -} - -template -inline void -matrix_translation(writable_matrix& m, const readable_vector& v) -{ - m.identity(); - matrix_set_translation(m, v); -} - -template -inline void -matrix_translation(writable_matrix& m, const E0& e0, const E1& e1) -{ - m.identity(); - matrix_set_translation(m, e0, e1); -} - -} // namespace cml - - -#if 0 -// XXX INCOMPLETE XXX - -////////////////////////////////////////////////////////////////////////////// -// Function for getting the translation of a 3D view matrix -////////////////////////////////////////////////////////////////////////////// - -/** Get the translation of a 3D affine transform */ -template < class MatT > vector< typename MatT::value_type, fixed<3> > -matrix_get_view_translation(const MatT& m) -{ - typedef typename MatT::value_type value_type; - typedef vector< value_type, fixed<3> > vector_type; - - vector_type x, y, z; - matrix_get_basis_vectors(m,x,y,z); - vector_type p = matrix_get_translation(m); - return vector_type(-dot(p,x),-dot(p,y),-dot(p,z)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_MATRIX_TRANSLATION_TPP +# error "mathlib/matrix/translation.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { +namespace detail { + +/* Base case, set a single basis element (I,J): */ +template +inline void +matrix_set_basis(writable_matrix& m, const E& e) +{ + m.set_basis_element(I, J, e); +} + +/* Recursive case: set basis element (I,J) to e, then recursively set + * (I,J+1): + */ +template +inline void +matrix_set_basis(writable_matrix& m, const E& e, const Es&... es) +{ + m.set_basis_element(I, J, e); + matrix_set_basis(m, es...); +} + +/* Entry case: set basis vector I from the items in Es: */ +template +inline void +matrix_set_basis(writable_matrix& m, const Es&... es) +{ + static_assert(cml::are_convertible, Es...>::value, + "incompatible scalar types"); + + /* Recursively set basis vector I, starting at element 0: */ + matrix_set_basis(m, es...); +} + +} // namespace detail + +/* 2D translation: */ + +template +inline void +matrix_set_translation_2D(writable_matrix& m, const E0& e0, const E1& e1) +{ + cml::check_affine_2D(m); + detail::matrix_set_basis<2>(m, e0, e1); +} + +template +inline void +matrix_set_translation_2D(writable_matrix& m, + const readable_vector& v) +{ + cml::check_size(v, int_c<2>()); + cml::check_affine_2D(m); + detail::matrix_set_basis<2>(m, v[0], v[1]); +} + +template +inline void +matrix_get_translation_2D(const readable_matrix& m, E0& e0, E1& e1) +{ + static_assert(cml::are_convertible, E0, E1>::value, + "incompatible scalar types"); + + cml::check_affine_2D(m); + e0 = E0(m.basis_element(2, 0)); + e1 = E1(m.basis_element(2, 1)); +} + +template +inline auto +matrix_get_translation_2D(const readable_matrix& m) + -> n_basis_vector_of_t +{ + cml::check_affine_2D(m); +#if defined(_MSC_VER) && (_MSC_VER >= 1900) + return n_basis_vector_of_t(m.basis_element(2, 0), + m.basis_element(2, 1)); +#else + return {m.basis_element(2, 0), m.basis_element(2, 1)}; +#endif +} + +template +inline void +matrix_translation_2D(writable_matrix& m, const E0& e0, const E1& e1) +{ + m.identity(); + matrix_set_translation_2D(m, e0, e1); +} + +template +inline void +matrix_translation_2D(writable_matrix& m, const readable_vector& v) +{ + m.identity(); + matrix_set_translation_2D(m, v); +} + +/* 3D translation: */ + +template +inline void +matrix_set_translation(writable_matrix& m, const E0& e0, const E1& e1, + const E2& e2) +{ + cml::check_affine_3D(m); + detail::matrix_set_basis<3>(m, e0, e1, e2); +} + +template +inline void +matrix_set_translation(writable_matrix& m, const E0& e0, const E1& e1) +{ + using zero_type = value_type_trait_of_t; + cml::check_affine_3D(m); + detail::matrix_set_basis<3>(m, e0, e1, zero_type(0)); +} + +template +inline void +matrix_set_translation(writable_matrix& m, const readable_vector& v) +{ + using zero_type = value_type_trait_of_t; + cml::check_size_range(v, int_c<2>(), int_c<3>()); + cml::check_affine_3D(m); + detail::matrix_set_basis<3>(m, v[0], v[1], + ((v.size() == 3) ? zero_type(v[2]) : zero_type(0))); +} + +template +inline void +matrix_get_translation(const readable_matrix& m, E0& e0, E1& e1, E2& e2) +{ + static_assert( + cml::are_convertible, E0, E1, E2>::value, + "incompatible scalar types"); + + cml::check_affine_3D(m); + e0 = E0(m.basis_element(3, 0)); + e1 = E1(m.basis_element(3, 1)); + e2 = E2(m.basis_element(3, 2)); +} + +template +inline auto +matrix_get_translation(const readable_matrix& m) + -> n_basis_vector_of_t +{ + cml::check_affine_3D(m); +#if defined(_MSC_VER) && (_MSC_VER >= 1900) + return n_basis_vector_of_t(m.basis_element(3, 0), + m.basis_element(3, 1), m.basis_element(3, 2)); +#else + return {m.basis_element(3, 0), m.basis_element(3, 1), m.basis_element(3, 2)}; +#endif +} + +template +inline void +matrix_translation(writable_matrix& m, const E0& e0, const E1& e1, + const E2& e2) +{ + m.identity(); + matrix_set_translation(m, e0, e1, e2); +} + +template +inline void +matrix_translation(writable_matrix& m, const readable_vector& v) +{ + m.identity(); + matrix_set_translation(m, v); +} + +template +inline void +matrix_translation(writable_matrix& m, const E0& e0, const E1& e1) +{ + m.identity(); + matrix_set_translation(m, e0, e1); +} + +} // namespace cml + + +#if 0 +// XXX INCOMPLETE XXX + +////////////////////////////////////////////////////////////////////////////// +// Function for getting the translation of a 3D view matrix +////////////////////////////////////////////////////////////////////////////// + +/** Get the translation of a 3D affine transform */ +template < class MatT > vector< typename MatT::value_type, fixed<3> > +matrix_get_view_translation(const MatT& m) +{ + typedef typename MatT::value_type value_type; + typedef vector< value_type, fixed<3> > vector_type; + + vector_type x, y, z; + matrix_get_basis_vectors(m,x,y,z); + vector_type p = matrix_get_translation(m); + return vector_type(-dot(p,x),-dot(p,y),-dot(p,z)); +} + #endif \ No newline at end of file diff --git a/cml/mathlib/quaternion/basis.h b/cml/mathlib/quaternion/basis.h index 6f6835f..726b86f 100644 --- a/cml/mathlib/quaternion/basis.h +++ b/cml/mathlib/quaternion/basis.h @@ -1,59 +1,59 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_quaternion_basis Quaternion Basis Vector Functions */ - -namespace cml { - -/** @addtogroup mathlib_quaternion_basis */ -/*@{*/ - -/** Get basis vector @c i of quaternion rotation @c q. - * - * @throws std::invalid_argument if @c i < 0 or @c i > 2. - */ -template -auto quaternion_get_basis_vector(const readable_quaternion& q, int i) - -> temporary_of_t; - -/** Get the x-basis vector of @c q. */ -template -auto quaternion_get_x_basis_vector(const readable_quaternion& q) - -> temporary_of_t; - -/** Get the y-basis vector of @c q. */ -template -auto quaternion_get_y_basis_vector(const readable_quaternion& q) - -> temporary_of_t; - -/** Get the z-basis vector of @c q. */ -template -auto quaternion_get_z_basis_vector(const readable_quaternion& q) - -> temporary_of_t; - -/** Return the basis vectors of @c q as three vectors, @c x, @c y, and @c - * z. - * - * @throws vector_size_error at run-time if any of @c x, @c y, or @c z is - * dynamically-sized, and is not 3D. Fixed-size vectors are checked at - * compile-time. - */ -template* = nullptr, enable_if_vector_t* = nullptr, - enable_if_vector_t* = nullptr> -void quaternion_get_basis_vectors(const readable_quaternion& q, XBasis& x, - YBasis& y, ZBasis& z); - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_QUATERNION_BASIS_TPP -#include -#undef __CML_MATHLIB_QUATERNION_BASIS_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_quaternion_basis Quaternion Basis Vector Functions */ + +namespace cml { + +/** @addtogroup mathlib_quaternion_basis */ +/*@{*/ + +/** Get basis vector @c i of quaternion rotation @c q. + * + * @throws std::invalid_argument if @c i < 0 or @c i > 2. + */ +template +auto quaternion_get_basis_vector(const readable_quaternion& q, int i) + -> temporary_of_t; + +/** Get the x-basis vector of @c q. */ +template +auto quaternion_get_x_basis_vector(const readable_quaternion& q) + -> temporary_of_t; + +/** Get the y-basis vector of @c q. */ +template +auto quaternion_get_y_basis_vector(const readable_quaternion& q) + -> temporary_of_t; + +/** Get the z-basis vector of @c q. */ +template +auto quaternion_get_z_basis_vector(const readable_quaternion& q) + -> temporary_of_t; + +/** Return the basis vectors of @c q as three vectors, @c x, @c y, and @c + * z. + * + * @throws vector_size_error at run-time if any of @c x, @c y, or @c z is + * dynamically-sized, and is not 3D. Fixed-size vectors are checked at + * compile-time. + */ +template* = nullptr, enable_if_vector_t* = nullptr, + enable_if_vector_t* = nullptr> +void quaternion_get_basis_vectors(const readable_quaternion& q, XBasis& x, + YBasis& y, ZBasis& z); + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_QUATERNION_BASIS_TPP +#include +#undef __CML_MATHLIB_QUATERNION_BASIS_TPP diff --git a/cml/mathlib/quaternion/basis.tpp b/cml/mathlib/quaternion/basis.tpp index dec54b6..9456022 100644 --- a/cml/mathlib/quaternion/basis.tpp +++ b/cml/mathlib/quaternion/basis.tpp @@ -1,77 +1,77 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_QUATERNION_BASIS_TPP -# error "mathlib/quaternion/basis.tpp not included correctly" -#endif - -#include - -namespace cml { - -template -auto -quaternion_get_basis_vector(const readable_quaternion& q, int i) - -> temporary_of_t -{ - using value_type = value_type_trait_of_t; - using order_type = order_type_trait_of_t; - using result_type = temporary_of_t; - - cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid axis"); - - int j = (i + 1) % 3, k = (i + 2) % 3; - const auto W = order_type::W; - const auto I = order_type::X + i; - const auto J = order_type::X + j; - const auto K = order_type::X + k; - - auto j2 = q[J] + q[J]; - auto k2 = q[K] + q[K]; - - /* Done: */ - result_type basis; - basis[i] = value_type(1) - q[J] * j2 - q[K] * k2; - basis[j] = q[I] * j2 + q[W] * k2; - basis[k] = q[I] * k2 - q[W] * j2; - return basis; -} - -template -auto -quaternion_get_x_basis_vector(const readable_quaternion& q) - -> temporary_of_t -{ - return quaternion_get_basis_vector(q, 0); -} - -template -auto -quaternion_get_y_basis_vector(const readable_quaternion& q) - -> temporary_of_t -{ - return quaternion_get_basis_vector(q, 1); -} - -template -auto -quaternion_get_z_basis_vector(const readable_quaternion& q) - -> temporary_of_t -{ - return quaternion_get_basis_vector(q, 2); -} - -template*, enable_if_vector_t*, - enable_if_vector_t*> -void -quaternion_get_basis_vectors(const readable_quaternion& q, XBasis& x, - YBasis& y, ZBasis& z) -{ - x = quaternion_get_x_basis_vector(q); - y = quaternion_get_y_basis_vector(q); - z = quaternion_get_z_basis_vector(q); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_QUATERNION_BASIS_TPP +# error "mathlib/quaternion/basis.tpp not included correctly" +#endif + +#include + +namespace cml { + +template +auto +quaternion_get_basis_vector(const readable_quaternion& q, int i) + -> temporary_of_t +{ + using value_type = value_type_trait_of_t; + using order_type = order_type_trait_of_t; + using result_type = temporary_of_t; + + cml_require(0 <= i && i <= 2, std::invalid_argument, "invalid axis"); + + int j = (i + 1) % 3, k = (i + 2) % 3; + const auto W = order_type::W; + const auto I = order_type::X + i; + const auto J = order_type::X + j; + const auto K = order_type::X + k; + + auto j2 = q[J] + q[J]; + auto k2 = q[K] + q[K]; + + /* Done: */ + result_type basis; + basis[i] = value_type(1) - q[J] * j2 - q[K] * k2; + basis[j] = q[I] * j2 + q[W] * k2; + basis[k] = q[I] * k2 - q[W] * j2; + return basis; +} + +template +auto +quaternion_get_x_basis_vector(const readable_quaternion& q) + -> temporary_of_t +{ + return quaternion_get_basis_vector(q, 0); +} + +template +auto +quaternion_get_y_basis_vector(const readable_quaternion& q) + -> temporary_of_t +{ + return quaternion_get_basis_vector(q, 1); +} + +template +auto +quaternion_get_z_basis_vector(const readable_quaternion& q) + -> temporary_of_t +{ + return quaternion_get_basis_vector(q, 2); +} + +template*, enable_if_vector_t*, + enable_if_vector_t*> +void +quaternion_get_basis_vectors(const readable_quaternion& q, XBasis& x, + YBasis& y, ZBasis& z) +{ + x = quaternion_get_x_basis_vector(q); + y = quaternion_get_y_basis_vector(q); + z = quaternion_get_z_basis_vector(q); +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/quaternion/rotation.h b/cml/mathlib/quaternion/rotation.h index 83af97a..b294f1d 100644 --- a/cml/mathlib/quaternion/rotation.h +++ b/cml/mathlib/quaternion/rotation.h @@ -1,205 +1,205 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -/** @defgroup mathlib_quaternion_rotation Quaternion Rotation Functions - * - * @note A number of these functions simply wrap calls to the corresponding - * matrix functions. Some of them (the 'aim-at' and 'align' functions in - * particular) might be considered a bit superfluous, since the resulting - * quaternion will most likely be converted to a matrix at some point - * anyway. However, they're included here for completeness, and for - * convenience in cases where a quaternion is being used as the primary - * rotation representation. - */ - -namespace cml { - -/** @addtogroup mathlib_quaternion_rotation */ -/*@{*/ - -/** @defgroup mathlib_quaternion_rotation_builders Quaternion Rotation Builders */ -/*@{*/ - -/** Build a quaternion representing a rotation about world axis @c axis. - * - * @throws std::invalid_argument if @c axis < 0 or @c axis > 2. - */ -template -void quaternion_rotation_world_axis(writable_quaternion& q, int axis, - E angle); - -/** Build a quaternion representing a rotation about world x-axis. */ -template -void quaternion_rotation_world_x(writable_quaternion& q, E angle); - -/** Build a quaternion representing a rotation about world y-axis. */ -template -void quaternion_rotation_world_y(writable_quaternion& q, E angle); - -/** Build a quaternion representing a rotation about world z-axis. */ -template -void quaternion_rotation_world_z(writable_quaternion& q, E angle); - -/** Build a quaternion from an axis-angle pair. - * - * @throws vector_size_error at run-time if @c axis is dynamically-sized, - * and is not 3D. If @c axis is fixed-size, the size is checked at - * compile-time. - */ -template -void quaternion_rotation_axis_angle(writable_quaternion& q, - const readable_vector& axis, E angle); - -/** Build a quaternion from a rotation matrix. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - */ -template -void quaternion_rotation_matrix(writable_quaternion& q, - const readable_matrix& m); - -/** Compute a quaternion given three Euler angles and the required - * order. - * - * The rotations are applied about the cardinal axes in the order specified - * by the 'order' argument, where 'order' is one of the following - * enumerants: - * - * euler_order_xyz - * euler_order_xzy - * euler_order_xyx - * euler_order_xzx - * euler_order_yzx - * euler_order_yxz - * euler_order_yzy - * euler_order_yxy - * euler_order_zxy - * euler_order_zyx - * euler_order_zxz - * euler_order_zyz - * - * e.g. euler_order_xyz means compute the quaternion equivalent to R_x * - * R_y * R_z, where R_i is the rotation matrix above axis i (the row-basis - * matrix would be R_z * R_y * R_x). - */ -template -void quaternion_rotation_euler(writable_quaternion& q, E0 angle_0, - E1 angle_1, E2 angle_2, euler_order order); - -/** Compute a quaternion given a vector containing the Euler angles. - * - * @throws vector_size_error at run-time if @c euler is dynamically-sized, - * and is not 3D. If fixed-size, the sizs is checked at compile-time. - */ -template -void quaternion_rotation_euler(writable_quaternion& q, - const readable_vector& euler, euler_order order); - -/*@}*/ - - -/** @defgroup mathlib_quaternion_rotation_alignment Quaternion Alignment */ -/*@{*/ - -/** Compute a quaternion that aligns vector @c align to @c reference, - * using rotations in axis order @c order. - * - * @note This uses matrix_rotation_align internally. - */ -template -void quaternion_rotation_align(writable_quaternion& q, - const readable_vector& align, const readable_vector& reference, - bool normalize = true, axis_order order = axis_order_zyx); - -/** Compute a quaternion to align the vector from @c pos to @c target - * with @c reference. - * - * @note This uses matrix_rotation_aim_at internally. - */ -template -void quaternion_rotation_aim_at(writable_quaternion& q, - const readable_vector& pos, const readable_vector& target, - const readable_vector& reference, axis_order order = axis_order_zyx); - -/*@}*/ - -/** @defgroup mathlib_quaternion_rotation_conversion Quaternion Conversion */ -/*@{*/ - -/** Convert a quaternion @c q to an axis-angle pair. - * - * @note @c tolerance is used to detect a near-zero axis length. - */ -template> -void quaternion_to_axis_angle(const readable_quaternion& q, - writable_vector& axis, E& angle, - Tol tolerance = scalar_traits::epsilon()); - -/** Convert a quaternion @c q to an axis-angle pair returned as a - * std::tuple. - * - * @note @c tolerance is used to detect a near-zero axis length. - */ -template> -std::tuple, compiled<3>>, - value_type_trait_of_t> -quaternion_to_axis_angle(const readable_quaternion& q, - Tol tolerance = scalar_traits::epsilon()); - -/** Convert a quaternion @c q to an Euler-angle triple. - * - * @note @c tolerance is used to detect degeneracies. - */ -template> -void quaternion_to_euler(const readable_quaternion& q, E0& angle_0, - E1& angle_1, E2& angle_2, euler_order order, - Tol tolerance = scalar_traits::epsilon(), - enable_if_quaternion_t* = nullptr); - -/** Convert a quaternion @c q to an Euler-angle triple, and return - * the result as a fixed-size 3D vector. - * - * @note @c tolerance is used to detect degeneracies. - */ -template> -vector, compiled<3>> quaternion_to_euler( - const readable_quaternion& q, euler_order order, - Tol tolerance = scalar_traits::epsilon(), - enable_if_quaternion_t* = nullptr); - -/** Convert a quaternion @c q to an Euler-angle triple, and return - * the result as a user-specified vector type. - * - * @note @c tolerance is used to detect degeneracies. - * - * @note @c VectorT can be any vector type with 3 elements, having internal - * storage (e.g. compiled<3> or allocated<>). The default is vector>, where T is the value_type of the matrix. - */ -template> -VectorT quaternion_to_euler(const readable_quaternion& q, - euler_order order, Tol tolerance = scalar_traits::epsilon(), - enable_if_vector_t* = nullptr, - enable_if_quaternion_t* = nullptr); - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_QUATERNION_ROTATION_TPP -#include -#undef __CML_MATHLIB_QUATERNION_ROTATION_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +/** @defgroup mathlib_quaternion_rotation Quaternion Rotation Functions + * + * @note A number of these functions simply wrap calls to the corresponding + * matrix functions. Some of them (the 'aim-at' and 'align' functions in + * particular) might be considered a bit superfluous, since the resulting + * quaternion will most likely be converted to a matrix at some point + * anyway. However, they're included here for completeness, and for + * convenience in cases where a quaternion is being used as the primary + * rotation representation. + */ + +namespace cml { + +/** @addtogroup mathlib_quaternion_rotation */ +/*@{*/ + +/** @defgroup mathlib_quaternion_rotation_builders Quaternion Rotation Builders */ +/*@{*/ + +/** Build a quaternion representing a rotation about world axis @c axis. + * + * @throws std::invalid_argument if @c axis < 0 or @c axis > 2. + */ +template +void quaternion_rotation_world_axis(writable_quaternion& q, int axis, + E angle); + +/** Build a quaternion representing a rotation about world x-axis. */ +template +void quaternion_rotation_world_x(writable_quaternion& q, E angle); + +/** Build a quaternion representing a rotation about world y-axis. */ +template +void quaternion_rotation_world_y(writable_quaternion& q, E angle); + +/** Build a quaternion representing a rotation about world z-axis. */ +template +void quaternion_rotation_world_z(writable_quaternion& q, E angle); + +/** Build a quaternion from an axis-angle pair. + * + * @throws vector_size_error at run-time if @c axis is dynamically-sized, + * and is not 3D. If @c axis is fixed-size, the size is checked at + * compile-time. + */ +template +void quaternion_rotation_axis_angle(writable_quaternion& q, + const readable_vector& axis, E angle); + +/** Build a quaternion from a rotation matrix. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + */ +template +void quaternion_rotation_matrix(writable_quaternion& q, + const readable_matrix& m); + +/** Compute a quaternion given three Euler angles and the required + * order. + * + * The rotations are applied about the cardinal axes in the order specified + * by the 'order' argument, where 'order' is one of the following + * enumerants: + * + * euler_order_xyz + * euler_order_xzy + * euler_order_xyx + * euler_order_xzx + * euler_order_yzx + * euler_order_yxz + * euler_order_yzy + * euler_order_yxy + * euler_order_zxy + * euler_order_zyx + * euler_order_zxz + * euler_order_zyz + * + * e.g. euler_order_xyz means compute the quaternion equivalent to R_x * + * R_y * R_z, where R_i is the rotation matrix above axis i (the row-basis + * matrix would be R_z * R_y * R_x). + */ +template +void quaternion_rotation_euler(writable_quaternion& q, E0 angle_0, + E1 angle_1, E2 angle_2, euler_order order); + +/** Compute a quaternion given a vector containing the Euler angles. + * + * @throws vector_size_error at run-time if @c euler is dynamically-sized, + * and is not 3D. If fixed-size, the sizs is checked at compile-time. + */ +template +void quaternion_rotation_euler(writable_quaternion& q, + const readable_vector& euler, euler_order order); + +/*@}*/ + + +/** @defgroup mathlib_quaternion_rotation_alignment Quaternion Alignment */ +/*@{*/ + +/** Compute a quaternion that aligns vector @c align to @c reference, + * using rotations in axis order @c order. + * + * @note This uses matrix_rotation_align internally. + */ +template +void quaternion_rotation_align(writable_quaternion& q, + const readable_vector& align, const readable_vector& reference, + bool normalize = true, axis_order order = axis_order_zyx); + +/** Compute a quaternion to align the vector from @c pos to @c target + * with @c reference. + * + * @note This uses matrix_rotation_aim_at internally. + */ +template +void quaternion_rotation_aim_at(writable_quaternion& q, + const readable_vector& pos, const readable_vector& target, + const readable_vector& reference, axis_order order = axis_order_zyx); + +/*@}*/ + +/** @defgroup mathlib_quaternion_rotation_conversion Quaternion Conversion */ +/*@{*/ + +/** Convert a quaternion @c q to an axis-angle pair. + * + * @note @c tolerance is used to detect a near-zero axis length. + */ +template> +void quaternion_to_axis_angle(const readable_quaternion& q, + writable_vector& axis, E& angle, + Tol tolerance = scalar_traits::epsilon()); + +/** Convert a quaternion @c q to an axis-angle pair returned as a + * std::tuple. + * + * @note @c tolerance is used to detect a near-zero axis length. + */ +template> +std::tuple, compiled<3>>, + value_type_trait_of_t> +quaternion_to_axis_angle(const readable_quaternion& q, + Tol tolerance = scalar_traits::epsilon()); + +/** Convert a quaternion @c q to an Euler-angle triple. + * + * @note @c tolerance is used to detect degeneracies. + */ +template> +void quaternion_to_euler(const readable_quaternion& q, E0& angle_0, + E1& angle_1, E2& angle_2, euler_order order, + Tol tolerance = scalar_traits::epsilon(), + enable_if_quaternion_t* = nullptr); + +/** Convert a quaternion @c q to an Euler-angle triple, and return + * the result as a fixed-size 3D vector. + * + * @note @c tolerance is used to detect degeneracies. + */ +template> +vector, compiled<3>> quaternion_to_euler( + const readable_quaternion& q, euler_order order, + Tol tolerance = scalar_traits::epsilon(), + enable_if_quaternion_t* = nullptr); + +/** Convert a quaternion @c q to an Euler-angle triple, and return + * the result as a user-specified vector type. + * + * @note @c tolerance is used to detect degeneracies. + * + * @note @c VectorT can be any vector type with 3 elements, having internal + * storage (e.g. compiled<3> or allocated<>). The default is vector>, where T is the value_type of the matrix. + */ +template> +VectorT quaternion_to_euler(const readable_quaternion& q, + euler_order order, Tol tolerance = scalar_traits::epsilon(), + enable_if_vector_t* = nullptr, + enable_if_quaternion_t* = nullptr); + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_QUATERNION_ROTATION_TPP +#include +#undef __CML_MATHLIB_QUATERNION_ROTATION_TPP diff --git a/cml/mathlib/quaternion/rotation.tpp b/cml/mathlib/quaternion/rotation.tpp index 98766e7..a94e28d 100644 --- a/cml/mathlib/quaternion/rotation.tpp +++ b/cml/mathlib/quaternion/rotation.tpp @@ -1,670 +1,670 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_QUATERNION_ROTATION_TPP -# error "mathlib/quaternion/rotation.tpp not included correctly" -#endif - -#include -#include -#include -#include -#include -#include - -namespace cml { - -/* Builders: */ - -template -inline void -quaternion_rotation_world_axis(writable_quaternion& q, int axis, E angle) -{ - static_assert(cml::are_convertible, E>::value, - "incompatible scalar types"); - - using order_type = order_type_trait_of_t; - using angle_traits = traits_of_t; - - cml_require(0 <= axis && axis <= 2, std::invalid_argument, "invalid axis"); - - q.identity(); - q[order_type::W] = angle_traits::cos(angle / E(2)); - q[order_type::X + axis] = angle_traits::sin(angle / E(2)); -} - -template -inline void -quaternion_rotation_world_x(writable_quaternion& q, E angle) -{ - quaternion_rotation_world_axis(q, 0, angle); -} - -template -inline void -quaternion_rotation_world_y(writable_quaternion& q, E angle) -{ - quaternion_rotation_world_axis(q, 1, angle); -} - -template -inline void -quaternion_rotation_world_z(writable_quaternion& q, E angle) -{ - quaternion_rotation_world_axis(q, 2, angle); -} - -template -inline void -quaternion_rotation_axis_angle(writable_quaternion& q, - const readable_vector& axis, E angle) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, E>::value, - "incompatible scalar types"); - - using angle_traits = traits_of_t; - - cml::check_size(axis, int_c<3>()); - q.set(angle_traits::cos(angle / E(2)), - angle_traits::sin(angle / E(2)) * axis); -} - -template -inline void -quaternion_rotation_matrix(writable_quaternion& q, - const readable_matrix& m) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t>::value, - "incompatible scalar types"); - - using order_type = order_type_trait_of_t; - using value_type = value_type_trait_of_t; - using value_traits = traits_of_t; - using M_type = value_type_trait_of_t; - using M_traits = traits_of_t; - - cml::check_minimum_size(m, int_c<3>(), int_c<3>()); - - /* Local version of the quaternion ordering: */ - enum - { - W = order_type::W, - X = order_type::X, - Y = order_type::Y, - Z = order_type::Z - }; - - auto tr = trace_3x3(m); - if(tr >= value_type(0)) { - q[W] = value_traits::sqrt(tr + value_type(1)) / value_type(2); - value_type s = (value_type(1) / value_type(4)) / q[W]; - q[X] = (m.basis_element(1, 2) - m.basis_element(2, 1)) * s; - q[Y] = (m.basis_element(2, 0) - m.basis_element(0, 2)) * s; - q[Z] = (m.basis_element(0, 1) - m.basis_element(1, 0)) * s; - } else { - int largest_diagonal_element = index_of_max(m.basis_element(0, 0), - m.basis_element(1, 1), m.basis_element(2, 2)); - int i, j, k; - cyclic_permutation(largest_diagonal_element, i, j, k); - const int I = X + i; - const int J = X + j; - const int K = X + k; - q[I] = - value_type(M_traits::sqrt(m.basis_element(i, i) - m.basis_element(j, j) - - m.basis_element(k, k) + value_type(1))) - / value_type(2); - value_type s = (value_type(1) / value_type(4)) / q[I]; - q[J] = (m.basis_element(i, j) + m.basis_element(j, i)) * s; - q[K] = (m.basis_element(i, k) + m.basis_element(k, i)) * s; - q[W] = (m.basis_element(j, k) - m.basis_element(k, j)) * s; - } -} - -template -void -quaternion_rotation_euler(writable_quaternion& q, E0 angle_0, E1 angle_1, - E2 angle_2, euler_order order) -{ - static_assert( - cml::are_convertible, E0, E1, E2>::value, - "incompatible scalar types"); - - using order_type = order_type_trait_of_t; - using angle0_traits = scalar_traits; - using angle1_traits = scalar_traits; - using angle2_traits = scalar_traits; - - int i, j, k; - bool odd, repeat; - cml::unpack_euler_order(order, i, j, k, odd, repeat); - - const int W = order_type::W; - const int I = order_type::X + i; - const int J = order_type::X + j; - const int K = order_type::X + k; - - if(odd) angle_1 = -angle_1; - - angle_0 /= E0(2); - angle_1 /= E1(2); - angle_2 /= E2(2); - - auto s0 = angle0_traits::sin(angle_0); - auto c0 = angle0_traits::cos(angle_0); - auto s1 = angle1_traits::sin(angle_1); - auto c1 = angle1_traits::cos(angle_1); - auto s2 = angle2_traits::sin(angle_2); - auto c2 = angle2_traits::cos(angle_2); - - auto s0s2 = s0 * s2; - auto s0c2 = s0 * c2; - auto c0s2 = c0 * s2; - auto c0c2 = c0 * c2; - - if(repeat) { - q[I] = c1 * (c0s2 + s0c2); - q[J] = s1 * (c0c2 + s0s2); - q[K] = s1 * (c0s2 - s0c2); - q[W] = c1 * (c0c2 - s0s2); - } else { - q[I] = c1 * s0c2 - s1 * c0s2; - q[J] = c1 * s0s2 + s1 * c0c2; - q[K] = c1 * c0s2 - s1 * s0c2; - q[W] = c1 * c0c2 + s1 * s0s2; - } - - if(odd) q[J] = -q[J]; -} - -template -void -quaternion_rotation_euler(writable_quaternion& q, - const readable_vector& euler, euler_order order) -{ - cml::check_size(euler, cml::int_c<3>()); - quaternion_rotation_euler(q, euler[0], euler[1], euler[2], order); -} - -/* Alignment: */ - -template -inline void -quaternion_rotation_align(writable_quaternion& q, - const readable_vector& align, const readable_vector& reference, - bool normalize, axis_order order) -{ - using value_type = value_type_trait_of_t; - using temporary_type = matrix>; - - temporary_type m; - matrix_rotation_align(m, align, reference, normalize, order); - quaternion_rotation_matrix(q, m); -} - -template -void -quaternion_rotation_aim_at(writable_quaternion& q, - const readable_vector& pos, const readable_vector& target, - const readable_vector& reference, axis_order order) -{ - using value_type = value_type_trait_of_t; - using temporary_type = matrix>; - - temporary_type m; - matrix_rotation_aim_at(m, pos, target, reference, order); - quaternion_rotation_matrix(q, m); -} - -/* Conversion: */ - -template -void -quaternion_to_axis_angle(const readable_quaternion& q, - writable_vector& axis, E& angle, Tol tolerance) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, E, Tol>::value, - "incompatible scalar types"); - - using angle_traits = scalar_traits; - - cml::detail::check_or_resize(axis, int_c<3>()); - - axis = q.imaginary(); - auto l = axis.length(); - if(l > tolerance) { - axis /= l; - angle = E(2) * angle_traits::atan2(l, q.real()); - } else { - axis.zero(); - angle = E(0); - } -} - -namespace detail { - -/** Helper for the quaternion_to_axis_angle() overloads. */ -template -inline std::tuple> -quaternion_to_axis_angle(const readable_quaternion& q, Tol tolerance) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, Tol>::value, - "incompatible scalar types"); - - VectorT axis; - cml::detail::check_or_resize(axis, int_c<3>()); - value_type_trait_of_t angle; - cml::quaternion_to_axis_angle(q, axis, angle, tolerance); - return std::make_tuple(axis, angle); -} - -} // namespace detail - -template -inline std::tuple, compiled<3>>, - value_type_trait_of_t> -quaternion_to_axis_angle(const readable_quaternion& q, Tol tolerance) -{ - using vector_type = vector, compiled<3>>; - return detail::quaternion_to_axis_angle(q, tolerance); -} - -template -inline void -quaternion_to_euler(const readable_quaternion& q, E0& angle_0, E1& angle_1, - E2& angle_2, euler_order order, Tol tolerance, enable_if_quaternion_t*) -{ - static_assert( - cml::are_convertible, E0, E1, E2, Tol>::value, - "incompatible scalar types"); - - using value_type = value_type_trait_of_t; - using temporary_type = matrix>; - - temporary_type m; - matrix_rotation_quaternion(m, q); - matrix_to_euler(m, angle_0, angle_1, angle_2, order, tolerance); -} - -template -inline vector, compiled<3>> -quaternion_to_euler(const readable_quaternion& q, euler_order order, - Tol tolerance, enable_if_quaternion_t*) -{ - using value_type = value_type_trait_of_t; - using temporary_type = matrix>; - - temporary_type m; - matrix_rotation_quaternion(m, q); - return matrix_to_euler(m, order, tolerance); -} - -template -inline VectorT -quaternion_to_euler(const readable_quaternion& q, euler_order order, - Tol tolerance, enable_if_vector_t*, enable_if_quaternion_t*) -{ - using value_type = value_type_trait_of_t; - using temporary_type = matrix>; - - temporary_type m; - matrix_rotation_quaternion(m, q); - return matrix_to_euler(m, order, tolerance); -} - -} // namespace cml - -#if 0 -// XXX INCOMPLETE XXX - -////////////////////////////////////////////////////////////////////////////// -// Rotation to align with a vector, multiple vectors, or the view plane -////////////////////////////////////////////////////////////////////////////// - -/** See vector_ortho.h for details */ -template < typename E, class A, class O, class C, class VecT > void -quaternion_rotation_align(quaternion& q, const VecT& align, - bool normalize = true, axis_order order = axis_order_zyx) -{ - typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; - - matrix_type m; - matrix_rotation_align(m,align,normalize,order); - quaternion_rotation_matrix(q,m); -} - -/** See vector_ortho.h for details */ -template < typename E,class A,class O,class C,class VecT_1,class VecT_2 > void -quaternion_rotation_align_axial(quaternion& q, const VecT_1& align, - const VecT_2& axis, bool normalize = true, - axis_order order = axis_order_zyx) -{ - typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; - - matrix_type m; - matrix_rotation_align_axial(m,align,axis,normalize,order); - quaternion_rotation_matrix(q,m); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class O, class C, class MatT > void -quaternion_rotation_align_viewplane( - quaternion& q, - const MatT& view_matrix, - Handedness handedness, - axis_order order = axis_order_zyx) -{ - typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; - - matrix_type m; - matrix_rotation_align_viewplane(m,view_matrix,handedness,order); - quaternion_rotation_matrix(q,m); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class O, class C, class MatT > void -quaternion_rotation_align_viewplane_LH( - quaternion& q, - const MatT& view_matrix, - axis_order order = axis_order_zyx) -{ - typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; - - matrix_type m; - matrix_rotation_align_viewplane_LH(m,view_matrix,order); - quaternion_rotation_matrix(q,m); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class O, class C, class MatT > void -quaternion_rotation_align_viewplane_RH( - quaternion& q, - const MatT& view_matrix, - axis_order order = axis_order_zyx) -{ - typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; - - matrix_type m; - matrix_rotation_align_viewplane_RH(m,view_matrix,order); - quaternion_rotation_matrix(q,m); -} - -////////////////////////////////////////////////////////////////////////////// -// Rotation to aim at a target -////////////////////////////////////////////////////////////////////////////// - -/** See vector_ortho.h for details */ -template < typename E, class A, class O, class C, - class VecT_1, class VecT_2 > void -quaternion_rotation_aim_at( - quaternion& q, - const VecT_1& pos, - const VecT_2& target, - axis_order order = axis_order_zyx) -{ - typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; - - matrix_type m; - matrix_rotation_aim_at(m,pos,target,order); - quaternion_rotation_matrix(q,m); -} - -/** See vector_ortho.h for details */ -template < typename E, class A, class O, class C, - class VecT_1, class VecT_2, class VecT_3 > void -quaternion_rotation_aim_at_axial( - quaternion& q, - const VecT_1& pos, - const VecT_2& target, - const VecT_3& axis, - axis_order order = axis_order_zyx) -{ - typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; - - matrix_type m; - matrix_rotation_aim_at_axial(m,pos,target,axis,order); - quaternion_rotation_matrix(q,m); -} - -////////////////////////////////////////////////////////////////////////////// -// Relative rotation about world axes -////////////////////////////////////////////////////////////////////////////// - -/* Rotate a quaternion about the given world axis */ -template < class E, class A, class O, class C > void -quaternion_rotate_about_world_axis(quaternion& q,size_t axis, E angle) -{ - typedef quaternion quaternion_type; - typedef typename quaternion_type::value_type value_type; - typedef typename quaternion_type::order_type order_type; - - /* Checking */ - detail::CheckIndex3(axis); - - size_t i, j, k; - cyclic_permutation(axis, i, j, k); - - const size_t W = order_type::W; - const size_t I = order_type::X + i; - const size_t J = order_type::X + j; - const size_t K = order_type::X + k; - - angle *= value_type(.5); - value_type s = value_type(std::sin(angle)); - value_type c = value_type(std::cos(angle)); - - quaternion_type result; - result[I] = c * q[I] + s * q[W]; - result[J] = c * q[J] - s * q[K]; - result[K] = c * q[K] + s * q[J]; - result[W] = c * q[W] - s * q[I]; - q = result; -} - -/* Rotate a quaternion about the world x axis */ -template < class E, class A, class O, class C > void -quaternion_rotate_about_world_x(quaternion& q, E angle) { - quaternion_rotate_about_world_axis(q,0,angle); -} - -/* Rotate a quaternion about the world y axis */ -template < class E, class A, class O, class C > void -quaternion_rotate_about_world_y(quaternion& q, E angle) { - quaternion_rotate_about_world_axis(q,1,angle); -} - -/* Rotate a quaternion about the world z axis */ -template < class E, class A, class O, class C > void -quaternion_rotate_about_world_z(quaternion& q, E angle) { - quaternion_rotate_about_world_axis(q,2,angle); -} - -////////////////////////////////////////////////////////////////////////////// -// Relative rotation about local axes -////////////////////////////////////////////////////////////////////////////// - -/* Rotate a quaternion about the given local axis */ -template < class E, class A, class O, class C > void -quaternion_rotate_about_local_axis(quaternion& q,size_t axis, E angle) -{ - typedef quaternion quaternion_type; - typedef typename quaternion_type::value_type value_type; - typedef typename quaternion_type::order_type order_type; - - /* Checking */ - detail::CheckIndex3(axis); - - size_t i, j, k; - cyclic_permutation(axis, i, j, k); - - const size_t W = order_type::W; - const size_t I = order_type::X + i; - const size_t J = order_type::X + j; - const size_t K = order_type::X + k; - - angle *= value_type(.5); - value_type s = value_type(std::sin(angle)); - value_type c = value_type(std::cos(angle)); - - quaternion_type result; - result[I] = c * q[I] + s * q[W]; - result[J] = c * q[J] + s * q[K]; - result[K] = c * q[K] - s * q[J]; - result[W] = c * q[W] - s * q[I]; - q = result; -} - -/* Rotate a quaternion about its local x axis */ -template < class E, class A, class O, class C > void -quaternion_rotate_about_local_x(quaternion& q, E angle) { - quaternion_rotate_about_local_axis(q,0,angle); -} - -/* Rotate a quaternion about its local y axis */ -template < class E, class A, class O, class C > void -quaternion_rotate_about_local_y(quaternion& q, E angle) { - quaternion_rotate_about_local_axis(q,1,angle); -} - -/* Rotate a quaternion about its local z axis */ -template < class E, class A, class O, class C > void -quaternion_rotate_about_local_z(quaternion& q, E angle) { - quaternion_rotate_about_local_axis(q,2,angle); -} - -////////////////////////////////////////////////////////////////////////////// -// Rotation from vector to vector -////////////////////////////////////////////////////////////////////////////// - -/* http://www.martinb.com/maths/algebra/vectors/angleBetween/index.htm. */ - -/** Build a quaternion to rotate from one vector to another */ -template < class E,class A,class O,class C,class VecT_1,class VecT_2 > void -quaternion_rotation_vec_to_vec( - quaternion& q, - const VecT_1& v1, - const VecT_2& v2, - bool unit_length_vectors = false) -{ - typedef quaternion quaternion_type; - typedef typename quaternion_type::value_type value_type; - typedef vector< value_type, fixed<3> > vector_type; - - /* Checking handled by cross() */ - - /* @todo: If at some point quaternion<> has a set() function that takes a - * vector and a scalar, this can then be written as: - * - * if (...) { - * q.set(value_type(1)+dot(v1,v2), cross(v1,v2)); - * } else { - * q.set(std::sqrt(...)+dot(v1,v2), cross(v1,v2)); - * } - */ - - vector_type c = cross(v1,v2); - if (unit_length_vectors) { - q = quaternion_type(value_type(1) + dot(v1,v2), c.data()); - } else { - q = quaternion_type( - std::sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2), - c/*.data()*/ - ); - } - q.normalize(); -} - -////////////////////////////////////////////////////////////////////////////// -// Scale the angle of a rotation matrix -////////////////////////////////////////////////////////////////////////////// - -template < typename E, class A, class O, class C > void -quaternion_scale_angle(quaternion& q, E t, - E tolerance = epsilon::placeholder()) -{ - typedef vector< E,fixed<3> > vector_type; - typedef typename vector_type::value_type value_type; - - vector_type axis; - value_type angle; - quaternion_to_axis_angle(q, axis, angle, tolerance); - quaternion_rotation_axis_angle(q, axis, angle * t); -} - -////////////////////////////////////////////////////////////////////////////// -// Support functions for uniform handling of pos- and neg-cross quaternions -////////////////////////////////////////////////////////////////////////////// - -namespace detail { - -/** Concatenate two quaternions in the order q1->q2 */ -template < class QuatT_1, class QuatT_2 > -typename et::QuaternionPromote2::temporary_type -quaternion_rotation_difference( - const QuatT_1& q1, const QuatT_2& q2, positive_cross) -{ - return q2 * conjugate(q1); -} - -/** Concatenate two quaternions in the order q1->q2 */ -template < class QuatT_1, class QuatT_2 > -typename et::QuaternionPromote2::temporary_type -quaternion_rotation_difference( - const QuatT_1& q1, const QuatT_2& q2, negative_cross) -{ - return conjugate(q1) * q2; -} - -} // namespace detail - -////////////////////////////////////////////////////////////////////////////// -// Quaternions rotation difference -////////////////////////////////////////////////////////////////////////////// - -/** Return the rotational 'difference' between two quaternions */ -template < class QuatT_1, class QuatT_2 > -typename et::QuaternionPromote2::temporary_type -quaternion_rotation_difference(const QuatT_1& q1, const QuatT_2& q2) { - return detail::quaternion_rotation_difference( - q1, q2, typename QuatT_1::cross_type()); -} - -////////////////////////////////////////////////////////////////////////////// -// Conversions -////////////////////////////////////////////////////////////////////////////// - -/** Convert a quaternion to an axis-angle pair */ -template < class QuatT, typename E, class A > void -quaternion_to_axis_angle( - const QuatT& q, - vector& axis, - E& angle, - E tolerance = epsilon::placeholder()) -{ - typedef QuatT quaternion_type; - typedef typename quaternion_type::value_type value_type; - typedef typename quaternion_type::order_type order_type; - - /* Checking */ - detail::CheckQuat(q); - - axis = q.imaginary(); - value_type l = length(axis); - if (l > tolerance) { - axis /= l; - angle = value_type(2) * std::atan2(l,q.real()); - } else { - axis.zero(); - angle = value_type(0); - } -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_QUATERNION_ROTATION_TPP +# error "mathlib/quaternion/rotation.tpp not included correctly" +#endif + +#include +#include +#include +#include +#include +#include + +namespace cml { + +/* Builders: */ + +template +inline void +quaternion_rotation_world_axis(writable_quaternion& q, int axis, E angle) +{ + static_assert(cml::are_convertible, E>::value, + "incompatible scalar types"); + + using order_type = order_type_trait_of_t; + using angle_traits = traits_of_t; + + cml_require(0 <= axis && axis <= 2, std::invalid_argument, "invalid axis"); + + q.identity(); + q[order_type::W] = angle_traits::cos(angle / E(2)); + q[order_type::X + axis] = angle_traits::sin(angle / E(2)); +} + +template +inline void +quaternion_rotation_world_x(writable_quaternion& q, E angle) +{ + quaternion_rotation_world_axis(q, 0, angle); +} + +template +inline void +quaternion_rotation_world_y(writable_quaternion& q, E angle) +{ + quaternion_rotation_world_axis(q, 1, angle); +} + +template +inline void +quaternion_rotation_world_z(writable_quaternion& q, E angle) +{ + quaternion_rotation_world_axis(q, 2, angle); +} + +template +inline void +quaternion_rotation_axis_angle(writable_quaternion& q, + const readable_vector& axis, E angle) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, E>::value, + "incompatible scalar types"); + + using angle_traits = traits_of_t; + + cml::check_size(axis, int_c<3>()); + q.set(angle_traits::cos(angle / E(2)), + angle_traits::sin(angle / E(2)) * axis); +} + +template +inline void +quaternion_rotation_matrix(writable_quaternion& q, + const readable_matrix& m) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t>::value, + "incompatible scalar types"); + + using order_type = order_type_trait_of_t; + using value_type = value_type_trait_of_t; + using value_traits = traits_of_t; + using M_type = value_type_trait_of_t; + using M_traits = traits_of_t; + + cml::check_minimum_size(m, int_c<3>(), int_c<3>()); + + /* Local version of the quaternion ordering: */ + enum + { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + auto tr = trace_3x3(m); + if(tr >= value_type(0)) { + q[W] = value_traits::sqrt(tr + value_type(1)) / value_type(2); + value_type s = (value_type(1) / value_type(4)) / q[W]; + q[X] = (m.basis_element(1, 2) - m.basis_element(2, 1)) * s; + q[Y] = (m.basis_element(2, 0) - m.basis_element(0, 2)) * s; + q[Z] = (m.basis_element(0, 1) - m.basis_element(1, 0)) * s; + } else { + int largest_diagonal_element = index_of_max(m.basis_element(0, 0), + m.basis_element(1, 1), m.basis_element(2, 2)); + int i, j, k; + cyclic_permutation(largest_diagonal_element, i, j, k); + const int I = X + i; + const int J = X + j; + const int K = X + k; + q[I] = + value_type(M_traits::sqrt(m.basis_element(i, i) - m.basis_element(j, j) + - m.basis_element(k, k) + value_type(1))) + / value_type(2); + value_type s = (value_type(1) / value_type(4)) / q[I]; + q[J] = (m.basis_element(i, j) + m.basis_element(j, i)) * s; + q[K] = (m.basis_element(i, k) + m.basis_element(k, i)) * s; + q[W] = (m.basis_element(j, k) - m.basis_element(k, j)) * s; + } +} + +template +void +quaternion_rotation_euler(writable_quaternion& q, E0 angle_0, E1 angle_1, + E2 angle_2, euler_order order) +{ + static_assert( + cml::are_convertible, E0, E1, E2>::value, + "incompatible scalar types"); + + using order_type = order_type_trait_of_t; + using angle0_traits = scalar_traits; + using angle1_traits = scalar_traits; + using angle2_traits = scalar_traits; + + int i, j, k; + bool odd, repeat; + cml::unpack_euler_order(order, i, j, k, odd, repeat); + + const int W = order_type::W; + const int I = order_type::X + i; + const int J = order_type::X + j; + const int K = order_type::X + k; + + if(odd) angle_1 = -angle_1; + + angle_0 /= E0(2); + angle_1 /= E1(2); + angle_2 /= E2(2); + + auto s0 = angle0_traits::sin(angle_0); + auto c0 = angle0_traits::cos(angle_0); + auto s1 = angle1_traits::sin(angle_1); + auto c1 = angle1_traits::cos(angle_1); + auto s2 = angle2_traits::sin(angle_2); + auto c2 = angle2_traits::cos(angle_2); + + auto s0s2 = s0 * s2; + auto s0c2 = s0 * c2; + auto c0s2 = c0 * s2; + auto c0c2 = c0 * c2; + + if(repeat) { + q[I] = c1 * (c0s2 + s0c2); + q[J] = s1 * (c0c2 + s0s2); + q[K] = s1 * (c0s2 - s0c2); + q[W] = c1 * (c0c2 - s0s2); + } else { + q[I] = c1 * s0c2 - s1 * c0s2; + q[J] = c1 * s0s2 + s1 * c0c2; + q[K] = c1 * c0s2 - s1 * s0c2; + q[W] = c1 * c0c2 + s1 * s0s2; + } + + if(odd) q[J] = -q[J]; +} + +template +void +quaternion_rotation_euler(writable_quaternion& q, + const readable_vector& euler, euler_order order) +{ + cml::check_size(euler, cml::int_c<3>()); + quaternion_rotation_euler(q, euler[0], euler[1], euler[2], order); +} + +/* Alignment: */ + +template +inline void +quaternion_rotation_align(writable_quaternion& q, + const readable_vector& align, const readable_vector& reference, + bool normalize, axis_order order) +{ + using value_type = value_type_trait_of_t; + using temporary_type = matrix>; + + temporary_type m; + matrix_rotation_align(m, align, reference, normalize, order); + quaternion_rotation_matrix(q, m); +} + +template +void +quaternion_rotation_aim_at(writable_quaternion& q, + const readable_vector& pos, const readable_vector& target, + const readable_vector& reference, axis_order order) +{ + using value_type = value_type_trait_of_t; + using temporary_type = matrix>; + + temporary_type m; + matrix_rotation_aim_at(m, pos, target, reference, order); + quaternion_rotation_matrix(q, m); +} + +/* Conversion: */ + +template +void +quaternion_to_axis_angle(const readable_quaternion& q, + writable_vector& axis, E& angle, Tol tolerance) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, E, Tol>::value, + "incompatible scalar types"); + + using angle_traits = scalar_traits; + + cml::detail::check_or_resize(axis, int_c<3>()); + + axis = q.imaginary(); + auto l = axis.length(); + if(l > tolerance) { + axis /= l; + angle = E(2) * angle_traits::atan2(l, q.real()); + } else { + axis.zero(); + angle = E(0); + } +} + +namespace detail { + +/** Helper for the quaternion_to_axis_angle() overloads. */ +template +inline std::tuple> +quaternion_to_axis_angle(const readable_quaternion& q, Tol tolerance) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, Tol>::value, + "incompatible scalar types"); + + VectorT axis; + cml::detail::check_or_resize(axis, int_c<3>()); + value_type_trait_of_t angle; + cml::quaternion_to_axis_angle(q, axis, angle, tolerance); + return std::make_tuple(axis, angle); +} + +} // namespace detail + +template +inline std::tuple, compiled<3>>, + value_type_trait_of_t> +quaternion_to_axis_angle(const readable_quaternion& q, Tol tolerance) +{ + using vector_type = vector, compiled<3>>; + return detail::quaternion_to_axis_angle(q, tolerance); +} + +template +inline void +quaternion_to_euler(const readable_quaternion& q, E0& angle_0, E1& angle_1, + E2& angle_2, euler_order order, Tol tolerance, enable_if_quaternion_t*) +{ + static_assert( + cml::are_convertible, E0, E1, E2, Tol>::value, + "incompatible scalar types"); + + using value_type = value_type_trait_of_t; + using temporary_type = matrix>; + + temporary_type m; + matrix_rotation_quaternion(m, q); + matrix_to_euler(m, angle_0, angle_1, angle_2, order, tolerance); +} + +template +inline vector, compiled<3>> +quaternion_to_euler(const readable_quaternion& q, euler_order order, + Tol tolerance, enable_if_quaternion_t*) +{ + using value_type = value_type_trait_of_t; + using temporary_type = matrix>; + + temporary_type m; + matrix_rotation_quaternion(m, q); + return matrix_to_euler(m, order, tolerance); +} + +template +inline VectorT +quaternion_to_euler(const readable_quaternion& q, euler_order order, + Tol tolerance, enable_if_vector_t*, enable_if_quaternion_t*) +{ + using value_type = value_type_trait_of_t; + using temporary_type = matrix>; + + temporary_type m; + matrix_rotation_quaternion(m, q); + return matrix_to_euler(m, order, tolerance); +} + +} // namespace cml + +#if 0 +// XXX INCOMPLETE XXX + +////////////////////////////////////////////////////////////////////////////// +// Rotation to align with a vector, multiple vectors, or the view plane +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, class VecT > void +quaternion_rotation_align(quaternion& q, const VecT& align, + bool normalize = true, axis_order order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align(m,align,normalize,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E,class A,class O,class C,class VecT_1,class VecT_2 > void +quaternion_rotation_align_axial(quaternion& q, const VecT_1& align, + const VecT_2& axis, bool normalize = true, + axis_order order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align_axial(m,align,axis,normalize,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, class MatT > void +quaternion_rotation_align_viewplane( + quaternion& q, + const MatT& view_matrix, + Handedness handedness, + axis_order order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align_viewplane(m,view_matrix,handedness,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, class MatT > void +quaternion_rotation_align_viewplane_LH( + quaternion& q, + const MatT& view_matrix, + axis_order order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align_viewplane_LH(m,view_matrix,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, class MatT > void +quaternion_rotation_align_viewplane_RH( + quaternion& q, + const MatT& view_matrix, + axis_order order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align_viewplane_RH(m,view_matrix,order); + quaternion_rotation_matrix(q,m); +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation to aim at a target +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, + class VecT_1, class VecT_2 > void +quaternion_rotation_aim_at( + quaternion& q, + const VecT_1& pos, + const VecT_2& target, + axis_order order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_aim_at(m,pos,target,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, + class VecT_1, class VecT_2, class VecT_3 > void +quaternion_rotation_aim_at_axial( + quaternion& q, + const VecT_1& pos, + const VecT_2& target, + const VecT_3& axis, + axis_order order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_aim_at_axial(m,pos,target,axis,order); + quaternion_rotation_matrix(q,m); +} + +////////////////////////////////////////////////////////////////////////////// +// Relative rotation about world axes +////////////////////////////////////////////////////////////////////////////// + +/* Rotate a quaternion about the given world axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_world_axis(quaternion& q,size_t axis, E angle) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + const size_t W = order_type::W; + const size_t I = order_type::X + i; + const size_t J = order_type::X + j; + const size_t K = order_type::X + k; + + angle *= value_type(.5); + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + quaternion_type result; + result[I] = c * q[I] + s * q[W]; + result[J] = c * q[J] - s * q[K]; + result[K] = c * q[K] + s * q[J]; + result[W] = c * q[W] - s * q[I]; + q = result; +} + +/* Rotate a quaternion about the world x axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_world_x(quaternion& q, E angle) { + quaternion_rotate_about_world_axis(q,0,angle); +} + +/* Rotate a quaternion about the world y axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_world_y(quaternion& q, E angle) { + quaternion_rotate_about_world_axis(q,1,angle); +} + +/* Rotate a quaternion about the world z axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_world_z(quaternion& q, E angle) { + quaternion_rotate_about_world_axis(q,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// Relative rotation about local axes +////////////////////////////////////////////////////////////////////////////// + +/* Rotate a quaternion about the given local axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_local_axis(quaternion& q,size_t axis, E angle) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + const size_t W = order_type::W; + const size_t I = order_type::X + i; + const size_t J = order_type::X + j; + const size_t K = order_type::X + k; + + angle *= value_type(.5); + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + quaternion_type result; + result[I] = c * q[I] + s * q[W]; + result[J] = c * q[J] + s * q[K]; + result[K] = c * q[K] - s * q[J]; + result[W] = c * q[W] - s * q[I]; + q = result; +} + +/* Rotate a quaternion about its local x axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_local_x(quaternion& q, E angle) { + quaternion_rotate_about_local_axis(q,0,angle); +} + +/* Rotate a quaternion about its local y axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_local_y(quaternion& q, E angle) { + quaternion_rotate_about_local_axis(q,1,angle); +} + +/* Rotate a quaternion about its local z axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_local_z(quaternion& q, E angle) { + quaternion_rotate_about_local_axis(q,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation from vector to vector +////////////////////////////////////////////////////////////////////////////// + +/* http://www.martinb.com/maths/algebra/vectors/angleBetween/index.htm. */ + +/** Build a quaternion to rotate from one vector to another */ +template < class E,class A,class O,class C,class VecT_1,class VecT_2 > void +quaternion_rotation_vec_to_vec( + quaternion& q, + const VecT_1& v1, + const VecT_2& v2, + bool unit_length_vectors = false) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef vector< value_type, fixed<3> > vector_type; + + /* Checking handled by cross() */ + + /* @todo: If at some point quaternion<> has a set() function that takes a + * vector and a scalar, this can then be written as: + * + * if (...) { + * q.set(value_type(1)+dot(v1,v2), cross(v1,v2)); + * } else { + * q.set(std::sqrt(...)+dot(v1,v2), cross(v1,v2)); + * } + */ + + vector_type c = cross(v1,v2); + if (unit_length_vectors) { + q = quaternion_type(value_type(1) + dot(v1,v2), c.data()); + } else { + q = quaternion_type( + std::sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2), + c/*.data()*/ + ); + } + q.normalize(); +} + +////////////////////////////////////////////////////////////////////////////// +// Scale the angle of a rotation matrix +////////////////////////////////////////////////////////////////////////////// + +template < typename E, class A, class O, class C > void +quaternion_scale_angle(quaternion& q, E t, + E tolerance = epsilon::placeholder()) +{ + typedef vector< E,fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + vector_type axis; + value_type angle; + quaternion_to_axis_angle(q, axis, angle, tolerance); + quaternion_rotation_axis_angle(q, axis, angle * t); +} + +////////////////////////////////////////////////////////////////////////////// +// Support functions for uniform handling of pos- and neg-cross quaternions +////////////////////////////////////////////////////////////////////////////// + +namespace detail { + +/** Concatenate two quaternions in the order q1->q2 */ +template < class QuatT_1, class QuatT_2 > +typename et::QuaternionPromote2::temporary_type +quaternion_rotation_difference( + const QuatT_1& q1, const QuatT_2& q2, positive_cross) +{ + return q2 * conjugate(q1); +} + +/** Concatenate two quaternions in the order q1->q2 */ +template < class QuatT_1, class QuatT_2 > +typename et::QuaternionPromote2::temporary_type +quaternion_rotation_difference( + const QuatT_1& q1, const QuatT_2& q2, negative_cross) +{ + return conjugate(q1) * q2; +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////////// +// Quaternions rotation difference +////////////////////////////////////////////////////////////////////////////// + +/** Return the rotational 'difference' between two quaternions */ +template < class QuatT_1, class QuatT_2 > +typename et::QuaternionPromote2::temporary_type +quaternion_rotation_difference(const QuatT_1& q1, const QuatT_2& q2) { + return detail::quaternion_rotation_difference( + q1, q2, typename QuatT_1::cross_type()); +} + +////////////////////////////////////////////////////////////////////////////// +// Conversions +////////////////////////////////////////////////////////////////////////////// + +/** Convert a quaternion to an axis-angle pair */ +template < class QuatT, typename E, class A > void +quaternion_to_axis_angle( + const QuatT& q, + vector& axis, + E& angle, + E tolerance = epsilon::placeholder()) +{ + typedef QuatT quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckQuat(q); + + axis = q.imaginary(); + value_type l = length(axis); + if (l > tolerance) { + axis /= l; + angle = value_type(2) * std::atan2(l,q.real()); + } else { + axis.zero(); + angle = value_type(0); + } +} + #endif \ No newline at end of file diff --git a/cml/mathlib/random_unit.h b/cml/mathlib/random_unit.h index ed3c935..3171662 100644 --- a/cml/mathlib/random_unit.h +++ b/cml/mathlib/random_unit.h @@ -1,83 +1,83 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** @addtogroup mathlib_vector_misc */ -/*@{*/ - -/** Replace @c n with a uniformly random unit vector, using the specified - * random number generator @c gen. - * - * This generates the coordinates of the vector from a Gaussian - * distribution having mean 0 and standard deviation 1. The vector must - * have a floating point coordinate type, otherwise a compile-time error - * will be raised. - * - * @note @c n must have non-zero size on entry. The coordinates of @c n - * are overwritten on exit. - * - * @note @c gen must be compatible with the standard (STL) random number - * engines. - * - * @note Use std::srand() to seed the random number generator. - * - * @throws minimum_vector_size_error if @c n has zero size. - */ -template -void random_unit(writable_vector& n, RNG& gen); - -/** Replace @c n with a uniformly random unit vector. - * - * This generates the coordinates of the vector from a Gaussian - * distribution having mean 0 and standard deviation 1. The vector must - * have a floating point coordinate type, otherwise a compile-time error - * will be raised. - * - * @note @c n must have non-zero size on entry. The coordinates of @c n - * are overwritten on exit. - * - * @note Use std::srand() to seed the random number generator. - * - * @throws minimum_vector_size_error if @c n has zero size. - */ -template void random_unit(writable_vector& n); - -/** Generate a random unit vector @c n within a cone having unit direction - * @c d and non-zero half-angle @c a no greater than 90 deg, specified in - * radians. This function works for any vector dimension - * - * @c n must have a floating point coordinate type, otherwise a - * compile-time error will be raised. - * - * @note @c d is assumed to be normalized. - * - * @note Use std::srand() to seed the random number generator. - * - * @warning The algorithm was independently developed by the authors, and - * has not yet been proven to generate vectors uniformly distributed over - * the cone. - * - * @throws std::invalid_argument if @c a < 0 or @c a > 90 deg. - * - * @throws incompatible_vector_size_error if @c n.size() != @c d.size, and - * @c d is dynamically-sized and @c n is fixed-size. If @c n is - * dynamically-sized, it will be resized to @c d.size(). If both @c n and - * @c d are fixed-size, then the size is checked at compile-time. - */ -template -void random_unit(writable_vector& n, const readable_vector& d, - const Scalar& a); - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_RANDOM_UNIT_TPP -#include -#undef __CML_MATHLIB_RANDOM_UNIT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** @addtogroup mathlib_vector_misc */ +/*@{*/ + +/** Replace @c n with a uniformly random unit vector, using the specified + * random number generator @c gen. + * + * This generates the coordinates of the vector from a Gaussian + * distribution having mean 0 and standard deviation 1. The vector must + * have a floating point coordinate type, otherwise a compile-time error + * will be raised. + * + * @note @c n must have non-zero size on entry. The coordinates of @c n + * are overwritten on exit. + * + * @note @c gen must be compatible with the standard (STL) random number + * engines. + * + * @note Use std::srand() to seed the random number generator. + * + * @throws minimum_vector_size_error if @c n has zero size. + */ +template +void random_unit(writable_vector& n, RNG& gen); + +/** Replace @c n with a uniformly random unit vector. + * + * This generates the coordinates of the vector from a Gaussian + * distribution having mean 0 and standard deviation 1. The vector must + * have a floating point coordinate type, otherwise a compile-time error + * will be raised. + * + * @note @c n must have non-zero size on entry. The coordinates of @c n + * are overwritten on exit. + * + * @note Use std::srand() to seed the random number generator. + * + * @throws minimum_vector_size_error if @c n has zero size. + */ +template void random_unit(writable_vector& n); + +/** Generate a random unit vector @c n within a cone having unit direction + * @c d and non-zero half-angle @c a no greater than 90 deg, specified in + * radians. This function works for any vector dimension + * + * @c n must have a floating point coordinate type, otherwise a + * compile-time error will be raised. + * + * @note @c d is assumed to be normalized. + * + * @note Use std::srand() to seed the random number generator. + * + * @warning The algorithm was independently developed by the authors, and + * has not yet been proven to generate vectors uniformly distributed over + * the cone. + * + * @throws std::invalid_argument if @c a < 0 or @c a > 90 deg. + * + * @throws incompatible_vector_size_error if @c n.size() != @c d.size, and + * @c d is dynamically-sized and @c n is fixed-size. If @c n is + * dynamically-sized, it will be resized to @c d.size(). If both @c n and + * @c d are fixed-size, then the size is checked at compile-time. + */ +template +void random_unit(writable_vector& n, const readable_vector& d, + const Scalar& a); + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_RANDOM_UNIT_TPP +#include +#undef __CML_MATHLIB_RANDOM_UNIT_TPP diff --git a/cml/mathlib/random_unit.tpp b/cml/mathlib/random_unit.tpp index c2f325f..7d3fdab 100644 --- a/cml/mathlib/random_unit.tpp +++ b/cml/mathlib/random_unit.tpp @@ -1,140 +1,140 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_RANDOM_UNIT_TPP -# error "mathlib/random_unit.tpp not included correctly" -#endif - -#include -#include -#include -#include - -namespace cml { -namespace detail { - -/** Generate a random 2D unit vector in a cone with direction @c d and - * half-angle @c a, given in radians. - */ -template -void -random_unit(writable_vector& n, const readable_vector& d, - const Scalar& a, cml::int_c<2>) -{ - using theta_traits = scalar_traits; - - /* Generate a uniformly random angle in [-a,a]: */ - auto theta = cml::random_real(-a, a); - - /* sin(theta) and cos(theta): */ - auto st = theta_traits::sin(theta); - auto ct = theta_traits::cos(theta); - - /* Compute n by rotating d by theta: */ - n[0] = ct * d[0] - st * d[1]; - n[1] = st * d[0] + ct * d[1]; - - /* Normalize: */ - n.normalize(); -} - -/** Generate a random n-D unit vector in a cone with direction @c d and - * half-angle @c a, given in radians. The vector is generated by using two - * slerps to linearly map a random vector on the unit hemisphere to the - * spherical cone cap. This seems to produce nice (uniform) 3D - * distributions, at least visually. - */ -template -void -random_unit(writable_vector& n, const readable_vector& d, - const Scalar& a, cml::int_c) -{ - using a_traits = scalar_traits; - - /* Generate a uniformly random vector on the unit sphere: */ - cml::random_unit(n); - - /* Reorient n to be within 90 degrees of d: */ - auto cos_O = dot(n, d); // [-1,1] - if(cos_O < 0) { - n = -n; - cos_O = -cos_O; - } - - /* Compute the angle between d and n: */ - auto O = acos_safe(cos_O); - using O_type = decltype(O); - using O_traits = scalar_traits; - using Oa_traits = scalar_traits; - - /* Use slerp between d (t=0) and n (t=1) to find the unit vector n_a - * (t=a/O) lying on the cone between d and n: - */ - auto n_a = - (Oa_traits::sin(O - a) * d + a_traits::sin(a) * n) / O_traits::sin(O); - /* Note: n_a is normalized by dividing by sin(O). */ - - /* Use a second slerp to "scale" the cone with half-angle O to the cone - * with half-angle a, taking the random vector n along with it: - */ - auto t = O / constants::pi_over_2(); - n = (Oa_traits::sin((O_type(1) - t) * a) * d + Oa_traits::sin(t * a) * n_a) - / a_traits::sin(a); - /* Note: n is normalized by dividing by sin(a). */ -} - -} // namespace detail - -template -inline void -random_unit(writable_vector& n, RNG& gen) -{ - using value_type = value_type_trait_of_t; - static_assert(std::is_floating_point::value, - "floating-point coordinates required"); - cml::check_minimum_size(n, cml::int_c<1>()); - - /* Generate coordinates using a normal distribution having mean of 0 and - * standard deviation of 1: - */ - std::normal_distribution d(value_type(0), value_type(1)); - - /* Generate coordinates, avoiding the (improbable) case of 0 length: */ - value_type length(0); - do { - for(int i = 0; i < n.size(); ++i) n[i] = d(gen); - length = n.length_squared(); - } while(length == value_type(0)); - - /* Normalize the vector: */ - n.normalize(); -} - -template -inline void -random_unit(writable_vector& n) -{ - /* Use the default generator: */ - std::default_random_engine gen(std::rand()); - - /* Generate n: */ - random_unit(n, gen); -} - -template -void -random_unit(writable_vector& n, const readable_vector& d, - const Scalar& a) -{ - using value_type = value_type_trait_of_t; - static_assert(std::is_floating_point::value, - "floating-point coordinates required"); - cml_require(a > 0 && a <= constants::pi_over_2(), - std::invalid_argument, "a must be in (0,90] deg"); - - cml::detail::check_or_resize(n, d); - detail::random_unit(n, d, a, cml::int_c::value>()); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_RANDOM_UNIT_TPP +# error "mathlib/random_unit.tpp not included correctly" +#endif + +#include +#include +#include +#include + +namespace cml { +namespace detail { + +/** Generate a random 2D unit vector in a cone with direction @c d and + * half-angle @c a, given in radians. + */ +template +void +random_unit(writable_vector& n, const readable_vector& d, + const Scalar& a, cml::int_c<2>) +{ + using theta_traits = scalar_traits; + + /* Generate a uniformly random angle in [-a,a]: */ + auto theta = cml::random_real(-a, a); + + /* sin(theta) and cos(theta): */ + auto st = theta_traits::sin(theta); + auto ct = theta_traits::cos(theta); + + /* Compute n by rotating d by theta: */ + n[0] = ct * d[0] - st * d[1]; + n[1] = st * d[0] + ct * d[1]; + + /* Normalize: */ + n.normalize(); +} + +/** Generate a random n-D unit vector in a cone with direction @c d and + * half-angle @c a, given in radians. The vector is generated by using two + * slerps to linearly map a random vector on the unit hemisphere to the + * spherical cone cap. This seems to produce nice (uniform) 3D + * distributions, at least visually. + */ +template +void +random_unit(writable_vector& n, const readable_vector& d, + const Scalar& a, cml::int_c) +{ + using a_traits = scalar_traits; + + /* Generate a uniformly random vector on the unit sphere: */ + cml::random_unit(n); + + /* Reorient n to be within 90 degrees of d: */ + auto cos_O = dot(n, d); // [-1,1] + if(cos_O < 0) { + n = -n; + cos_O = -cos_O; + } + + /* Compute the angle between d and n: */ + auto O = acos_safe(cos_O); + using O_type = decltype(O); + using O_traits = scalar_traits; + using Oa_traits = scalar_traits; + + /* Use slerp between d (t=0) and n (t=1) to find the unit vector n_a + * (t=a/O) lying on the cone between d and n: + */ + auto n_a = + (Oa_traits::sin(O - a) * d + a_traits::sin(a) * n) / O_traits::sin(O); + /* Note: n_a is normalized by dividing by sin(O). */ + + /* Use a second slerp to "scale" the cone with half-angle O to the cone + * with half-angle a, taking the random vector n along with it: + */ + auto t = O / constants::pi_over_2(); + n = (Oa_traits::sin((O_type(1) - t) * a) * d + Oa_traits::sin(t * a) * n_a) + / a_traits::sin(a); + /* Note: n is normalized by dividing by sin(a). */ +} + +} // namespace detail + +template +inline void +random_unit(writable_vector& n, RNG& gen) +{ + using value_type = value_type_trait_of_t; + static_assert(std::is_floating_point::value, + "floating-point coordinates required"); + cml::check_minimum_size(n, cml::int_c<1>()); + + /* Generate coordinates using a normal distribution having mean of 0 and + * standard deviation of 1: + */ + std::normal_distribution d(value_type(0), value_type(1)); + + /* Generate coordinates, avoiding the (improbable) case of 0 length: */ + value_type length(0); + do { + for(int i = 0; i < n.size(); ++i) n[i] = d(gen); + length = n.length_squared(); + } while(length == value_type(0)); + + /* Normalize the vector: */ + n.normalize(); +} + +template +inline void +random_unit(writable_vector& n) +{ + /* Use the default generator: */ + std::default_random_engine gen(std::rand()); + + /* Generate n: */ + random_unit(n, gen); +} + +template +void +random_unit(writable_vector& n, const readable_vector& d, + const Scalar& a) +{ + using value_type = value_type_trait_of_t; + static_assert(std::is_floating_point::value, + "floating-point coordinates required"); + cml_require(a > 0 && a <= constants::pi_over_2(), + std::invalid_argument, "a must be in (0,90] deg"); + + cml::detail::check_or_resize(n, d); + detail::random_unit(n, d, a, cml::int_c::value>()); +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/vector/angle.h b/cml/mathlib/vector/angle.h index 5e1ff4b..f393805 100644 --- a/cml/mathlib/vector/angle.h +++ b/cml/mathlib/vector/angle.h @@ -1,46 +1,46 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_vector_angle Vector Angle Functions */ - -namespace cml { - -/** @addtogroup mathlib_vector_angle */ -/*@{*/ - -/** Signed angle between two 2D vectors @c v1 and @c v2. */ -template -inline auto signed_angle_2D(const readable_vector& v1, - const readable_vector& v2) -> value_type_trait_promote_t; - -/** Unsigned angle between two 2D vectors @c v1 and @c v2. */ -template -inline auto unsigned_angle_2D(const readable_vector& v1, - const readable_vector& v2) -> value_type_trait_promote_t; - -/** Signed angle between two 3D vectors @c v1 and @c v2, relative @c - * reference. - */ -template -inline auto signed_angle(const readable_vector& v1, - const readable_vector& v2, const readable_vector& reference) - -> value_type_trait_promote_t; - -/** Unsigned angle between two 3D vectors @c v1 and @c v2. */ -template -inline auto unsigned_angle(const readable_vector& v1, - const readable_vector& v2) -> value_type_trait_promote_t; - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_VECTOR_ANGLE_TPP -#include -#undef __CML_MATHLIB_VECTOR_ANGLE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_vector_angle Vector Angle Functions */ + +namespace cml { + +/** @addtogroup mathlib_vector_angle */ +/*@{*/ + +/** Signed angle between two 2D vectors @c v1 and @c v2. */ +template +inline auto signed_angle_2D(const readable_vector& v1, + const readable_vector& v2) -> value_type_trait_promote_t; + +/** Unsigned angle between two 2D vectors @c v1 and @c v2. */ +template +inline auto unsigned_angle_2D(const readable_vector& v1, + const readable_vector& v2) -> value_type_trait_promote_t; + +/** Signed angle between two 3D vectors @c v1 and @c v2, relative @c + * reference. + */ +template +inline auto signed_angle(const readable_vector& v1, + const readable_vector& v2, const readable_vector& reference) + -> value_type_trait_promote_t; + +/** Unsigned angle between two 3D vectors @c v1 and @c v2. */ +template +inline auto unsigned_angle(const readable_vector& v1, + const readable_vector& v2) -> value_type_trait_promote_t; + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_VECTOR_ANGLE_TPP +#include +#undef __CML_MATHLIB_VECTOR_ANGLE_TPP diff --git a/cml/mathlib/vector/angle.tpp b/cml/mathlib/vector/angle.tpp index 5b726c6..42dbf2a 100644 --- a/cml/mathlib/vector/angle.tpp +++ b/cml/mathlib/vector/angle.tpp @@ -1,59 +1,59 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_VECTOR_ANGLE_TPP -# error "mathlib/vector/angle.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -template -inline auto -signed_angle_2D(const readable_vector& v1, - const readable_vector& v2) -> value_type_trait_promote_t -{ - using value_type = value_type_trait_promote_t; - using value_traits = scalar_traits; - return value_traits::atan2(perp_dot(v1, v2), dot(v1, v2)); -} - -template -inline auto -unsigned_angle_2D(const readable_vector& v1, - const readable_vector& v2) -> value_type_trait_promote_t -{ - using value_type = value_type_trait_promote_t; - using value_traits = scalar_traits; - return value_traits::fabs(signed_angle_2D(v1, v2)); -} - -template -inline auto -signed_angle(const readable_vector& v1, const readable_vector& v2, - const readable_vector& reference) - -> value_type_trait_promote_t -{ - using value_type = value_type_trait_promote_t; - using value_traits = scalar_traits; - - auto c = cross(v1, v2); - auto angle = value_traits::atan2(c.length(), dot(v1, v2)); - return (dot(c, reference) < value_type(0)) ? -angle : angle; -} - -template -inline auto -unsigned_angle(const readable_vector& v1, const readable_vector& v2) - -> value_type_trait_promote_t -{ - using value_type = value_type_trait_promote_t; - using value_traits = scalar_traits; - return value_traits::atan2(cross(v1, v2).length(), dot(v1, v2)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_VECTOR_ANGLE_TPP +# error "mathlib/vector/angle.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +template +inline auto +signed_angle_2D(const readable_vector& v1, + const readable_vector& v2) -> value_type_trait_promote_t +{ + using value_type = value_type_trait_promote_t; + using value_traits = scalar_traits; + return value_traits::atan2(perp_dot(v1, v2), dot(v1, v2)); +} + +template +inline auto +unsigned_angle_2D(const readable_vector& v1, + const readable_vector& v2) -> value_type_trait_promote_t +{ + using value_type = value_type_trait_promote_t; + using value_traits = scalar_traits; + return value_traits::fabs(signed_angle_2D(v1, v2)); +} + +template +inline auto +signed_angle(const readable_vector& v1, const readable_vector& v2, + const readable_vector& reference) + -> value_type_trait_promote_t +{ + using value_type = value_type_trait_promote_t; + using value_traits = scalar_traits; + + auto c = cross(v1, v2); + auto angle = value_traits::atan2(c.length(), dot(v1, v2)); + return (dot(c, reference) < value_type(0)) ? -angle : angle; +} + +template +inline auto +unsigned_angle(const readable_vector& v1, const readable_vector& v2) + -> value_type_trait_promote_t +{ + using value_type = value_type_trait_promote_t; + using value_traits = scalar_traits; + return value_traits::atan2(cross(v1, v2).length(), dot(v1, v2)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/vector/generators.h b/cml/mathlib/vector/generators.h index f82c128..5c0e3a6 100644 --- a/cml/mathlib/vector/generators.h +++ b/cml/mathlib/vector/generators.h @@ -1,114 +1,114 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -/** @defgroup mathlib_vector_generators Vector Generator Functions */ - -namespace cml { - -/** @addtogroup mathlib_vector_generators */ -/*@{*/ - -/** @defgroup mathlib_vector_generators_zero Zero Vector Generators */ -/*@{*/ - -/** Return a fixed-size double-precision N-d zero vector. */ -template -inline auto -zero() -> vector> -{ - return vector>().zero(); -} - -/** Return the 2D zero vector */ -inline auto -zero_2D() -> decltype(zero<2>()) -{ - return zero<2>(); -} - -/** Return the 3D zero vector */ -inline auto -zero_3D() -> decltype(zero<3>()) -{ - return zero<3>(); -} - -/** Return the 4D zero vector */ -inline auto -zero_4D() -> decltype(zero<4>()) -{ - return zero<4>(); -} - -/*@}*/ - -/** @defgroup mathlib_vector_generators_cardinal Cardinal Axis Generators */ -/*@{*/ - -/** Return a fixed-size double-precision N-d cardinal axis by index. */ -template -inline auto -axis(int i) -> vector> -{ - return vector>().cardinal(i); -} - -/** Return a 2D cardinal axis by index. */ -inline auto -axis_2D(int i) -> decltype(axis<2>(i)) -{ - return axis<2>(i); -} - -/** Return the 2D x-axis. */ -inline auto -x_axis_2D() -> decltype(axis<2>(0)) -{ - return axis<2>(0); -} - -/** Return the 2D y-axis. */ -inline auto -y_axis_2D() -> decltype(axis<2>(1)) -{ - return axis<2>(1); -} - -/** Return a 3D cardinal axis by index. */ -inline auto -axis_3D(int i) -> decltype(axis<3>(i)) -{ - return axis<3>(i); -} - -/** Return the 3D x-axis. */ -inline auto -x_axis_3D() -> decltype(axis<3>(0)) -{ - return axis<3>(0); -} - -/** Return the 3D y-axis. */ -inline auto -y_axis_3D() -> decltype(axis<3>(1)) -{ - return axis<3>(1); -} - -/** Return the 3D z-axis. */ -inline auto -z_axis_3D() -> decltype(axis<3>(2)) -{ - return axis<3>(2); -} - -/*@}*/ - -/*@}*/ - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +/** @defgroup mathlib_vector_generators Vector Generator Functions */ + +namespace cml { + +/** @addtogroup mathlib_vector_generators */ +/*@{*/ + +/** @defgroup mathlib_vector_generators_zero Zero Vector Generators */ +/*@{*/ + +/** Return a fixed-size double-precision N-d zero vector. */ +template +inline auto +zero() -> vector> +{ + return vector>().zero(); +} + +/** Return the 2D zero vector */ +inline auto +zero_2D() -> decltype(zero<2>()) +{ + return zero<2>(); +} + +/** Return the 3D zero vector */ +inline auto +zero_3D() -> decltype(zero<3>()) +{ + return zero<3>(); +} + +/** Return the 4D zero vector */ +inline auto +zero_4D() -> decltype(zero<4>()) +{ + return zero<4>(); +} + +/*@}*/ + +/** @defgroup mathlib_vector_generators_cardinal Cardinal Axis Generators */ +/*@{*/ + +/** Return a fixed-size double-precision N-d cardinal axis by index. */ +template +inline auto +axis(int i) -> vector> +{ + return vector>().cardinal(i); +} + +/** Return a 2D cardinal axis by index. */ +inline auto +axis_2D(int i) -> decltype(axis<2>(i)) +{ + return axis<2>(i); +} + +/** Return the 2D x-axis. */ +inline auto +x_axis_2D() -> decltype(axis<2>(0)) +{ + return axis<2>(0); +} + +/** Return the 2D y-axis. */ +inline auto +y_axis_2D() -> decltype(axis<2>(1)) +{ + return axis<2>(1); +} + +/** Return a 3D cardinal axis by index. */ +inline auto +axis_3D(int i) -> decltype(axis<3>(i)) +{ + return axis<3>(i); +} + +/** Return the 3D x-axis. */ +inline auto +x_axis_3D() -> decltype(axis<3>(0)) +{ + return axis<3>(0); +} + +/** Return the 3D y-axis. */ +inline auto +y_axis_3D() -> decltype(axis<3>(1)) +{ + return axis<3>(1); +} + +/** Return the 3D z-axis. */ +inline auto +z_axis_3D() -> decltype(axis<3>(2)) +{ + return axis<3>(2); +} + +/*@}*/ + +/*@}*/ + +} // namespace cml diff --git a/cml/mathlib/vector/misc.h b/cml/mathlib/vector/misc.h index 5a8f7ef..528ce34 100644 --- a/cml/mathlib/vector/misc.h +++ b/cml/mathlib/vector/misc.h @@ -1,77 +1,77 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -/** @defgroup mathlib_vector_misc Miscellaneous Vector Functions */ - -namespace cml { - -/** @addtogroup mathlib_vector_misc */ -/*@{*/ - -/** Project @c u onto another vector @c v. - * - * @throws minimum_vector_size_error at run-time if @c u or @c v has - * fewer than one element. If both vectors are fixed-size, the size is - * checked at compile-time. - * - * @throws incompatible_vector_size_error at run-time if @c u and @v n - * are different sizes, and at least one is dynamically-sized. If both - * vectors are fixed-size, the size is checked at compile-time. - */ -template -auto project_to_vector(const readable_vector& u, - const readable_vector& v) -> vector_promote_t; - -/** Project @c v onto a hyperplane with normal @c n. - * - * @note @c n is assumed to be normalized. - * - * @throws minimum_vector_size_error at run-time if @c v or @c n has - * fewer than one element. If both vectors are fixed-size, the size is - * checked at compile-time. - * - * @throws incompatible_vector_size_error at run-time if @c v and @c n - * are different sizes, and at least one is dynamically-sized. If both - * vectors are fixed-size, the size is checked at compile-time. - */ -template -auto project_to_hplane(const readable_vector& v, - const readable_vector& n) -> vector_promote_t; - -/** Return a vector counter-clockwise perpendicular to @c v. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized and - * is not a 2D vector. The size is checked at compile-time if @c v is - * fixed-size. - */ -template -auto perp(const readable_vector& v) -> temporary_of_t; - -/** Compute the Manhattan (city-block) distance between @c v1 and @c v2. - * - * @throws minimum_vector_size_error at run-time if @c v1 or @c v2 has - * fewer than one element. If both vectors are fixed-size, the size is - * checked at compile-time. - * - * @throws incompatible_vector_size_error at run-time if @c v1 and @c v2 - * are different sizes, and at least one is dynamically-sized. If both - * vectors are fixed-size, the size is checked at compile-time. - */ -template -auto manhattan_distance(const readable_vector& v1, - const readable_vector& v2) -> value_type_trait_promote_t; - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_VECTOR_MISC_TPP -#include -#undef __CML_MATHLIB_VECTOR_MISC_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +/** @defgroup mathlib_vector_misc Miscellaneous Vector Functions */ + +namespace cml { + +/** @addtogroup mathlib_vector_misc */ +/*@{*/ + +/** Project @c u onto another vector @c v. + * + * @throws minimum_vector_size_error at run-time if @c u or @c v has + * fewer than one element. If both vectors are fixed-size, the size is + * checked at compile-time. + * + * @throws incompatible_vector_size_error at run-time if @c u and @v n + * are different sizes, and at least one is dynamically-sized. If both + * vectors are fixed-size, the size is checked at compile-time. + */ +template +auto project_to_vector(const readable_vector& u, + const readable_vector& v) -> vector_promote_t; + +/** Project @c v onto a hyperplane with normal @c n. + * + * @note @c n is assumed to be normalized. + * + * @throws minimum_vector_size_error at run-time if @c v or @c n has + * fewer than one element. If both vectors are fixed-size, the size is + * checked at compile-time. + * + * @throws incompatible_vector_size_error at run-time if @c v and @c n + * are different sizes, and at least one is dynamically-sized. If both + * vectors are fixed-size, the size is checked at compile-time. + */ +template +auto project_to_hplane(const readable_vector& v, + const readable_vector& n) -> vector_promote_t; + +/** Return a vector counter-clockwise perpendicular to @c v. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized and + * is not a 2D vector. The size is checked at compile-time if @c v is + * fixed-size. + */ +template +auto perp(const readable_vector& v) -> temporary_of_t; + +/** Compute the Manhattan (city-block) distance between @c v1 and @c v2. + * + * @throws minimum_vector_size_error at run-time if @c v1 or @c v2 has + * fewer than one element. If both vectors are fixed-size, the size is + * checked at compile-time. + * + * @throws incompatible_vector_size_error at run-time if @c v1 and @c v2 + * are different sizes, and at least one is dynamically-sized. If both + * vectors are fixed-size, the size is checked at compile-time. + */ +template +auto manhattan_distance(const readable_vector& v1, + const readable_vector& v2) -> value_type_trait_promote_t; + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_VECTOR_MISC_TPP +#include +#undef __CML_MATHLIB_VECTOR_MISC_TPP diff --git a/cml/mathlib/vector/misc.tpp b/cml/mathlib/vector/misc.tpp index 5a4f6b7..6f3292f 100644 --- a/cml/mathlib/vector/misc.tpp +++ b/cml/mathlib/vector/misc.tpp @@ -1,62 +1,62 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_VECTOR_MISC_TPP -# error "mathlib/vector/misc.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -template -inline auto -project_to_vector(const readable_vector& u, - const readable_vector& v) -> vector_promote_t -{ - using result_type = vector_promote_t; - return result_type((dot(u, v) / length_squared(v)) * v); -} - -template -inline auto -project_to_hplane(const readable_vector& v, - const readable_vector& n) -> vector_promote_t -{ - using result_type = vector_promote_t; - return result_type(v - dot(v, n) * n); -} - -template -inline auto -perp(const readable_vector& v) -> temporary_of_t -{ - cml::check_size(v, cml::int_c<2>()); -#if defined(_MSC_VER) && (_MSC_VER >= 1900) - return temporary_of_t(-v[1], v[0]); -#else - return {-v[1], v[0]}; -#endif -} - -template -inline auto -manhattan_distance(const readable_vector& v1, - const readable_vector& v2) -> value_type_trait_promote_t -{ - using value_type = value_type_trait_promote_t; - using value_traits = scalar_traits; - - cml::check_minimum_size(v1, cml::int_c<1>()); - cml::check_minimum_size(v2, cml::int_c<1>()); - cml::check_same_size(v1, v2); - - auto fabs = &value_traits::fabs; - auto sum = fabs(value_type(v1[0] - v2[0])); - for(int i = 1; i < v1.size(); ++i) sum += fabs(value_type(v1[i] - v2[i])); - return sum; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_VECTOR_MISC_TPP +# error "mathlib/vector/misc.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +template +inline auto +project_to_vector(const readable_vector& u, + const readable_vector& v) -> vector_promote_t +{ + using result_type = vector_promote_t; + return result_type((dot(u, v) / length_squared(v)) * v); +} + +template +inline auto +project_to_hplane(const readable_vector& v, + const readable_vector& n) -> vector_promote_t +{ + using result_type = vector_promote_t; + return result_type(v - dot(v, n) * n); +} + +template +inline auto +perp(const readable_vector& v) -> temporary_of_t +{ + cml::check_size(v, cml::int_c<2>()); +#if defined(_MSC_VER) && (_MSC_VER >= 1900) + return temporary_of_t(-v[1], v[0]); +#else + return {-v[1], v[0]}; +#endif +} + +template +inline auto +manhattan_distance(const readable_vector& v1, + const readable_vector& v2) -> value_type_trait_promote_t +{ + using value_type = value_type_trait_promote_t; + using value_traits = scalar_traits; + + cml::check_minimum_size(v1, cml::int_c<1>()); + cml::check_minimum_size(v2, cml::int_c<1>()); + cml::check_same_size(v1, v2); + + auto fabs = &value_traits::fabs; + auto sum = fabs(value_type(v1[0] - v2[0])); + for(int i = 1; i < v1.size(); ++i) sum += fabs(value_type(v1[i] - v2[i])); + return sum; +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/vector/orthonormal.h b/cml/mathlib/vector/orthonormal.h index 90fad30..4c6179a 100644 --- a/cml/mathlib/vector/orthonormal.h +++ b/cml/mathlib/vector/orthonormal.h @@ -1,57 +1,57 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_vector_ortho Vector Orthonormalization Functions */ - -namespace cml { - -/** @addtogroup mathlib_vector_ortho */ -/*@{*/ - -/** @defgroup mathlib_vector_ortho_basis_2D 2D Orthonormal Basis Construction */ -/*@{*/ - -/** Build a 2D orthonormal basis. */ -template -void orthonormal_basis_2D(const readable_vector& align, - writable_vector& x, writable_vector& y, - bool normalize_align = true, axis_order2D order = axis_order_xy); - -/*@}*/ - -/** @defgroup mathlib_vector_ortho_basis_3D 3D Orthonormal Basis Construction */ -/*@{*/ - -/** This version of orthonormal_basis() ultimately does the work for all - * orthonormal_basis_*() functions. Given input vectors 'align' and - * 'reference', and an order 'axis_order_\\\', it constructs an - * orthonormal basis such that the i'th basis vector is aligned with - * (parallel to and pointing in the same direction as) 'align', and the - * j'th basis vector is maximally aligned with 'reference'. The k'th basis - * vector is chosen such that the basis has a determinant of +1. - * - * @note The algorithm fails when 'align' is nearly parallel to - * 'reference'; this should be checked for and handled externally if it's a - * case that may occur. - */ -template -void orthonormal_basis(const readable_vector& align, - const readable_vector& reference, writable_vector& x, - writable_vector& y, writable_vector& z, - bool normalize_align = true, axis_order order = axis_order_zyx); - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_VECTOR_ORTHONORMAL_TPP -#include -#undef __CML_MATHLIB_VECTOR_ORTHONORMAL_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_vector_ortho Vector Orthonormalization Functions */ + +namespace cml { + +/** @addtogroup mathlib_vector_ortho */ +/*@{*/ + +/** @defgroup mathlib_vector_ortho_basis_2D 2D Orthonormal Basis Construction */ +/*@{*/ + +/** Build a 2D orthonormal basis. */ +template +void orthonormal_basis_2D(const readable_vector& align, + writable_vector& x, writable_vector& y, + bool normalize_align = true, axis_order2D order = axis_order_xy); + +/*@}*/ + +/** @defgroup mathlib_vector_ortho_basis_3D 3D Orthonormal Basis Construction */ +/*@{*/ + +/** This version of orthonormal_basis() ultimately does the work for all + * orthonormal_basis_*() functions. Given input vectors 'align' and + * 'reference', and an order 'axis_order_\\\', it constructs an + * orthonormal basis such that the i'th basis vector is aligned with + * (parallel to and pointing in the same direction as) 'align', and the + * j'th basis vector is maximally aligned with 'reference'. The k'th basis + * vector is chosen such that the basis has a determinant of +1. + * + * @note The algorithm fails when 'align' is nearly parallel to + * 'reference'; this should be checked for and handled externally if it's a + * case that may occur. + */ +template +void orthonormal_basis(const readable_vector& align, + const readable_vector& reference, writable_vector& x, + writable_vector& y, writable_vector& z, + bool normalize_align = true, axis_order order = axis_order_zyx); + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_VECTOR_ORTHONORMAL_TPP +#include +#undef __CML_MATHLIB_VECTOR_ORTHONORMAL_TPP diff --git a/cml/mathlib/vector/orthonormal.tpp b/cml/mathlib/vector/orthonormal.tpp index abc0670..702d4b9 100644 --- a/cml/mathlib/vector/orthonormal.tpp +++ b/cml/mathlib/vector/orthonormal.tpp @@ -1,316 +1,316 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_VECTOR_ORTHONORMAL_TPP -# error "mathlib/vector/orthonormal.tpp not included correctly" -#endif - -#include -#include -#include -#include - -namespace cml { - -template -void -orthonormal_basis_2D(const readable_vector& align, - writable_vector& x, writable_vector& y, bool normalize_align, - axis_order2D order) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, value_type_trait_of_t>::value, - "incompatible scalar types"); - - using value_type = value_type_trait_of_t; - using temporary_type = vector>; - - /* Checking handled by perp() and assignment to fixed<2>. */ - - int i, j; - bool odd; - unpack_axis_order2D(order, i, j, odd); - - temporary_type axes[2]; - - axes[i] = align; - if(normalize_align) axes[i].normalize(); - axes[j] = cml::perp(axes[i]); - - if(odd) axes[j] = -axes[j]; - - x = axes[0]; - y = axes[1]; -} - -template -void -orthonormal_basis(const readable_vector& align, - const readable_vector& reference, writable_vector& x, - writable_vector& y, writable_vector& z, bool normalize_align, - axis_order order) -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, value_type_trait_of_t, - value_type_trait_of_t, value_type_trait_of_t>::value, - "incompatible scalar types"); - - using value_type = value_type_trait_of_t; - using temporary_type = vector>; - - int i, j, k; - bool odd; - unpack_axis_order(order, i, j, k, odd); - - temporary_type axes[3]; - axes[i] = align; - if(normalize_align) axes[i].normalize(); - axes[k] = cml::cross(axes[i], reference).normalize(); - axes[j] = cml::cross(axes[k], axes[i]); - - if(odd) axes[k] = -axes[k]; - - x = axes[0]; - y = axes[1]; - z = axes[2]; -} - -} // namespace cml - - -#if 0 -// XXX INCOMPLETE XXX - -////////////////////////////////////////////////////////////////////////////// -// Orthonormalization in 3D and 2D -////////////////////////////////////////////////////////////////////////////// - - -/** Orthonormalize 3 basis vectors in R3. - * - * Called with the default values, this function performs a single Gram- - * Schmidt step to orthonormalize the input vectors. By default, the direction - * of the 3rd basis vector is unchanged by this operation, but the unaffected - * axis can be specified via the 'stable_axis' parameter. - * - * The arguments 'num_iter' and 's' can be specified to an iterative Gram- - * Schmidt step. 'num_iter' is the number of iterations applied, and 's' is - * the fraction applied towards orthonormality each step. - * - * In most cases, the default arguments can be ignored, leaving only the three - * input vectors. - */ -template < typename E, class A > void -orthonormalize(vector& v0, vector& v1, vector& v2, - size_t stable_axis = 2, size_t num_iter = 0, E s = E(1)) -{ - /* Checking */ - detail::CheckVec3(v0); - detail::CheckVec3(v1); - detail::CheckVec3(v2); - detail::CheckIndex3(stable_axis); - - typedef vector< E, fixed<3> > vector_type; - typedef typename vector_type::value_type value_type; - - /* Iterative Gram-Schmidt; this step is skipped by default. */ - - for (size_t i = 0; i < num_iter; ++i) { - value_type dot01 = dot(v0,v1); - value_type dot12 = dot(v1,v2); - value_type dot20 = dot(v2,v0); - value_type inv_dot00 = value_type(1) / dot(v0,v0); - value_type inv_dot11 = value_type(1) / dot(v1,v1); - value_type inv_dot22 = value_type(1) / dot(v2,v2); - - vector_type temp0 = v0 - s*dot01*inv_dot11*v1 - s*dot20*inv_dot22*v2; - vector_type temp1 = v1 - s*dot12*inv_dot22*v2 - s*dot01*inv_dot00*v0; - vector_type temp2 = v2 - s*dot20*inv_dot00*v0 - s*dot12*inv_dot11*v1; - - v0 = temp0; - v1 = temp1; - v2 = temp2; - } - - /* Final Gram-Schmidt step to ensure orthonormality. If no iterations - * have been requested (num_iter = 0), this is the only step. The step - * is performed such that the direction of the axis indexed by - * 'stable_axis' is unchanged. - */ - - size_t i, j, k; - cyclic_permutation(stable_axis, i, j, k); - vector_type v[] = { v0, v1, v2 }; - - v[i].normalize(); - v[j] = normalize(project_to_hplane(v[j],v[i])); - v[k] = normalize(project_to_hplane(project_to_hplane(v[k],v[i]),v[j])); - - v0 = v[0]; - v1 = v[1]; - v2 = v[2]; -} - -/** Orthonormalize 2 basis vectors in R2 */ -template < typename E, class A > void -orthonormalize(vector& v0, vector& v1, - size_t stable_axis = 0, size_t num_iter = 0, E s = E(1)) -{ - typedef vector< E, fixed<2> > vector_type; - typedef typename vector_type::value_type value_type; - - /* Checking */ - detail::CheckVec2(v0); - detail::CheckVec2(v1); - detail::CheckIndex2(stable_axis); - - /* Iterative Gram-Schmidt; this step is skipped by default. */ - - for (size_t i = 0; i < num_iter; ++i) { - value_type dot01 = dot(v0,v1); - - vector_type temp0 = v0 - (s * dot01 * v1) / dot(v1,v1); - vector_type temp1 = v1 - (s * dot01 * v0) / dot(v0,v0); - - v0 = temp0; - v1 = temp1; - } - - /* Final Gram-Schmidt step to ensure orthonormality. If no iterations - * have been requested (num_iter = 0), this is the only step. The step - * is performed such that the direction of the axis indexed by - * 'stable_axis' is unchanged. - */ - - size_t i, j; - cyclic_permutation(stable_axis, i, j); - vector_type v[] = { v0, v1 }; - - v[i].normalize(); - v[j] = normalize(project_to_hplane(v[j],v[i])); - - v0 = v[0]; - v1 = v[1]; -} - -////////////////////////////////////////////////////////////////////////////// -// Orthonormal basis construction in 3D and 2D -////////////////////////////////////////////////////////////////////////////// - -/** This version of orthonormal_basis() constructs in arbitrary basis given a - * vector with which to align the i'th basis vector. To avoid the failure - * case, the reference vector is always chosen so as to not be parallel to - * 'align'. This means the algorithm will always generate a valid basis, which - * can be useful in some circumstances; however, it should be noted that the - * basis will likely 'pop' as the alignment vector changes, and so may not be - * suitable for billboarding or other similar applications. - */ -template < class VecT, typename E, class A > -void orthonormal_basis( - const VecT& align, - vector& x, - vector& y, - vector& z, - bool normalize_align = true, - axis_order order = axis_order_zyx) -{ - /* Checking (won't be necessary with index_of_min_abs() member function */ - detail::CheckVec3(align); - - /* @todo: vector member function index_of_min_abs() would clean this up */ - - orthonormal_basis( - align, - axis_3D(cml::index_of_min_abs(align[0],align[1],align[2])), - x, y, z, normalize_align, order - ); -} - -/** orthonormal_basis_axial() generates a basis in which the j'th basis vector - * is aligned with 'axis' and the i'th basis vector is maximally aligned (as - * 'aligned as possible') with 'align'. This can be used for e.g. axial - * billboarding for, say, trees or beam effects. - * - * Note that the implementation simply passes off to the 'reference' version - * of orthonormal_basis(), with the parameters adjusted so that the alignment - * is axial. - * - * @note With this algorithm the failure case is when 'align' and 'axis' - * are nearly parallel; if this is likely, it should be checked for and - * handled externally. - */ -template < class VecT_1, class VecT_2, typename E, class A > -void orthonormal_basis_axial( - const VecT_1& align, - const VecT_2& axis, - vector& x, - vector& y, - vector& z, - bool normalize_align = true, - axis_order order = axis_order_zyx) -{ - orthonormal_basis( - axis, - align, - x, - y, - z, - normalize_align, - detail::swap_axis_order(order)); -} - -/** orthonormal_basis_viewplane() builds a basis aligned with a viewplane, as - * extracted from the input view matrix. The function takes into account the - * handedness of the input view matrix and orients the basis accordingly. - * - * @note The generated basis will always be valid. - */ -template < class MatT, typename E, class A > -void orthonormal_basis_viewplane( - const MatT& view_matrix, - vector& x, - vector& y, - vector& z, - Handedness handedness, - axis_order order = axis_order_zyx) -{ - typedef MatT matrix_type; - typedef typename matrix_type::value_type value_type; - - orthonormal_basis( - -(handedness == left_handed ? value_type(1) : value_type(-1)) * - matrix_get_transposed_z_basis_vector(view_matrix), - matrix_get_transposed_y_basis_vector(view_matrix), - x, y, z, false, order - ); -} - -/** Build a viewplane-oriented basis from a left-handedness view matrix. */ -template < class MatT, typename E, class A > -void orthonormal_basis_viewplane_LH( - const MatT& view_matrix, - vector& x, - vector& y, - vector& z, - axis_order order = axis_order_zyx) -{ - orthonormal_basis_viewplane( - view_matrix,x,y,z,left_handed,order); -} - -/** Build a viewplane-oriented basis from a right-handedness view matrix. */ -template < class MatT, typename E, class A > -void orthonormal_basis_viewplane_RH( - const MatT& view_matrix, - vector& x, - vector& y, - vector& z, - axis_order order = axis_order_zyx) -{ - orthonormal_basis_viewplane( - view_matrix,x,y,z,right_handed,order); -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_VECTOR_ORTHONORMAL_TPP +# error "mathlib/vector/orthonormal.tpp not included correctly" +#endif + +#include +#include +#include +#include + +namespace cml { + +template +void +orthonormal_basis_2D(const readable_vector& align, + writable_vector& x, writable_vector& y, bool normalize_align, + axis_order2D order) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, value_type_trait_of_t>::value, + "incompatible scalar types"); + + using value_type = value_type_trait_of_t; + using temporary_type = vector>; + + /* Checking handled by perp() and assignment to fixed<2>. */ + + int i, j; + bool odd; + unpack_axis_order2D(order, i, j, odd); + + temporary_type axes[2]; + + axes[i] = align; + if(normalize_align) axes[i].normalize(); + axes[j] = cml::perp(axes[i]); + + if(odd) axes[j] = -axes[j]; + + x = axes[0]; + y = axes[1]; +} + +template +void +orthonormal_basis(const readable_vector& align, + const readable_vector& reference, writable_vector& x, + writable_vector& y, writable_vector& z, bool normalize_align, + axis_order order) +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, value_type_trait_of_t, + value_type_trait_of_t, value_type_trait_of_t>::value, + "incompatible scalar types"); + + using value_type = value_type_trait_of_t; + using temporary_type = vector>; + + int i, j, k; + bool odd; + unpack_axis_order(order, i, j, k, odd); + + temporary_type axes[3]; + axes[i] = align; + if(normalize_align) axes[i].normalize(); + axes[k] = cml::cross(axes[i], reference).normalize(); + axes[j] = cml::cross(axes[k], axes[i]); + + if(odd) axes[k] = -axes[k]; + + x = axes[0]; + y = axes[1]; + z = axes[2]; +} + +} // namespace cml + + +#if 0 +// XXX INCOMPLETE XXX + +////////////////////////////////////////////////////////////////////////////// +// Orthonormalization in 3D and 2D +////////////////////////////////////////////////////////////////////////////// + + +/** Orthonormalize 3 basis vectors in R3. + * + * Called with the default values, this function performs a single Gram- + * Schmidt step to orthonormalize the input vectors. By default, the direction + * of the 3rd basis vector is unchanged by this operation, but the unaffected + * axis can be specified via the 'stable_axis' parameter. + * + * The arguments 'num_iter' and 's' can be specified to an iterative Gram- + * Schmidt step. 'num_iter' is the number of iterations applied, and 's' is + * the fraction applied towards orthonormality each step. + * + * In most cases, the default arguments can be ignored, leaving only the three + * input vectors. + */ +template < typename E, class A > void +orthonormalize(vector& v0, vector& v1, vector& v2, + size_t stable_axis = 2, size_t num_iter = 0, E s = E(1)) +{ + /* Checking */ + detail::CheckVec3(v0); + detail::CheckVec3(v1); + detail::CheckVec3(v2); + detail::CheckIndex3(stable_axis); + + typedef vector< E, fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + /* Iterative Gram-Schmidt; this step is skipped by default. */ + + for (size_t i = 0; i < num_iter; ++i) { + value_type dot01 = dot(v0,v1); + value_type dot12 = dot(v1,v2); + value_type dot20 = dot(v2,v0); + value_type inv_dot00 = value_type(1) / dot(v0,v0); + value_type inv_dot11 = value_type(1) / dot(v1,v1); + value_type inv_dot22 = value_type(1) / dot(v2,v2); + + vector_type temp0 = v0 - s*dot01*inv_dot11*v1 - s*dot20*inv_dot22*v2; + vector_type temp1 = v1 - s*dot12*inv_dot22*v2 - s*dot01*inv_dot00*v0; + vector_type temp2 = v2 - s*dot20*inv_dot00*v0 - s*dot12*inv_dot11*v1; + + v0 = temp0; + v1 = temp1; + v2 = temp2; + } + + /* Final Gram-Schmidt step to ensure orthonormality. If no iterations + * have been requested (num_iter = 0), this is the only step. The step + * is performed such that the direction of the axis indexed by + * 'stable_axis' is unchanged. + */ + + size_t i, j, k; + cyclic_permutation(stable_axis, i, j, k); + vector_type v[] = { v0, v1, v2 }; + + v[i].normalize(); + v[j] = normalize(project_to_hplane(v[j],v[i])); + v[k] = normalize(project_to_hplane(project_to_hplane(v[k],v[i]),v[j])); + + v0 = v[0]; + v1 = v[1]; + v2 = v[2]; +} + +/** Orthonormalize 2 basis vectors in R2 */ +template < typename E, class A > void +orthonormalize(vector& v0, vector& v1, + size_t stable_axis = 0, size_t num_iter = 0, E s = E(1)) +{ + typedef vector< E, fixed<2> > vector_type; + typedef typename vector_type::value_type value_type; + + /* Checking */ + detail::CheckVec2(v0); + detail::CheckVec2(v1); + detail::CheckIndex2(stable_axis); + + /* Iterative Gram-Schmidt; this step is skipped by default. */ + + for (size_t i = 0; i < num_iter; ++i) { + value_type dot01 = dot(v0,v1); + + vector_type temp0 = v0 - (s * dot01 * v1) / dot(v1,v1); + vector_type temp1 = v1 - (s * dot01 * v0) / dot(v0,v0); + + v0 = temp0; + v1 = temp1; + } + + /* Final Gram-Schmidt step to ensure orthonormality. If no iterations + * have been requested (num_iter = 0), this is the only step. The step + * is performed such that the direction of the axis indexed by + * 'stable_axis' is unchanged. + */ + + size_t i, j; + cyclic_permutation(stable_axis, i, j); + vector_type v[] = { v0, v1 }; + + v[i].normalize(); + v[j] = normalize(project_to_hplane(v[j],v[i])); + + v0 = v[0]; + v1 = v[1]; +} + +////////////////////////////////////////////////////////////////////////////// +// Orthonormal basis construction in 3D and 2D +////////////////////////////////////////////////////////////////////////////// + +/** This version of orthonormal_basis() constructs in arbitrary basis given a + * vector with which to align the i'th basis vector. To avoid the failure + * case, the reference vector is always chosen so as to not be parallel to + * 'align'. This means the algorithm will always generate a valid basis, which + * can be useful in some circumstances; however, it should be noted that the + * basis will likely 'pop' as the alignment vector changes, and so may not be + * suitable for billboarding or other similar applications. + */ +template < class VecT, typename E, class A > +void orthonormal_basis( + const VecT& align, + vector& x, + vector& y, + vector& z, + bool normalize_align = true, + axis_order order = axis_order_zyx) +{ + /* Checking (won't be necessary with index_of_min_abs() member function */ + detail::CheckVec3(align); + + /* @todo: vector member function index_of_min_abs() would clean this up */ + + orthonormal_basis( + align, + axis_3D(cml::index_of_min_abs(align[0],align[1],align[2])), + x, y, z, normalize_align, order + ); +} + +/** orthonormal_basis_axial() generates a basis in which the j'th basis vector + * is aligned with 'axis' and the i'th basis vector is maximally aligned (as + * 'aligned as possible') with 'align'. This can be used for e.g. axial + * billboarding for, say, trees or beam effects. + * + * Note that the implementation simply passes off to the 'reference' version + * of orthonormal_basis(), with the parameters adjusted so that the alignment + * is axial. + * + * @note With this algorithm the failure case is when 'align' and 'axis' + * are nearly parallel; if this is likely, it should be checked for and + * handled externally. + */ +template < class VecT_1, class VecT_2, typename E, class A > +void orthonormal_basis_axial( + const VecT_1& align, + const VecT_2& axis, + vector& x, + vector& y, + vector& z, + bool normalize_align = true, + axis_order order = axis_order_zyx) +{ + orthonormal_basis( + axis, + align, + x, + y, + z, + normalize_align, + detail::swap_axis_order(order)); +} + +/** orthonormal_basis_viewplane() builds a basis aligned with a viewplane, as + * extracted from the input view matrix. The function takes into account the + * handedness of the input view matrix and orients the basis accordingly. + * + * @note The generated basis will always be valid. + */ +template < class MatT, typename E, class A > +void orthonormal_basis_viewplane( + const MatT& view_matrix, + vector& x, + vector& y, + vector& z, + Handedness handedness, + axis_order order = axis_order_zyx) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + + orthonormal_basis( + -(handedness == left_handed ? value_type(1) : value_type(-1)) * + matrix_get_transposed_z_basis_vector(view_matrix), + matrix_get_transposed_y_basis_vector(view_matrix), + x, y, z, false, order + ); +} + +/** Build a viewplane-oriented basis from a left-handedness view matrix. */ +template < class MatT, typename E, class A > +void orthonormal_basis_viewplane_LH( + const MatT& view_matrix, + vector& x, + vector& y, + vector& z, + axis_order order = axis_order_zyx) +{ + orthonormal_basis_viewplane( + view_matrix,x,y,z,left_handed,order); +} + +/** Build a viewplane-oriented basis from a right-handedness view matrix. */ +template < class MatT, typename E, class A > +void orthonormal_basis_viewplane_RH( + const MatT& view_matrix, + vector& x, + vector& y, + vector& z, + axis_order order = axis_order_zyx) +{ + orthonormal_basis_viewplane( + view_matrix,x,y,z,right_handed,order); +} #endif \ No newline at end of file diff --git a/cml/mathlib/vector/rotation.h b/cml/mathlib/vector/rotation.h index c7b2de7..eeec509 100644 --- a/cml/mathlib/vector/rotation.h +++ b/cml/mathlib/vector/rotation.h @@ -1,33 +1,33 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -/** @defgroup mathlib_vector_rotation Vector Rotation Functions */ - -namespace cml { - -/** @addtogroup mathlib_vector_rotation_3D */ -/*@{*/ - -/** Rotate by @c angle a 3D vector @c v about a unit-length vector @c n. - * - * @throws vector_size_error at run-time if @c v or @c n is - * dynamically-sized, and are not 3D. If fixed-size, the sizes are checked - * at compile-time. - */ -template -auto rotate_vector(const readable_vector& v, - const readable_vector& n, const E& angle) - -> vector_promote_t; - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_VECTOR_ROTATION_TPP -#include -#undef __CML_MATHLIB_VECTOR_ROTATION_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +/** @defgroup mathlib_vector_rotation Vector Rotation Functions */ + +namespace cml { + +/** @addtogroup mathlib_vector_rotation_3D */ +/*@{*/ + +/** Rotate by @c angle a 3D vector @c v about a unit-length vector @c n. + * + * @throws vector_size_error at run-time if @c v or @c n is + * dynamically-sized, and are not 3D. If fixed-size, the sizes are checked + * at compile-time. + */ +template +auto rotate_vector(const readable_vector& v, + const readable_vector& n, const E& angle) + -> vector_promote_t; + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_VECTOR_ROTATION_TPP +#include +#undef __CML_MATHLIB_VECTOR_ROTATION_TPP diff --git a/cml/mathlib/vector/rotation.tpp b/cml/mathlib/vector/rotation.tpp index 529f4e6..2a1b30d 100644 --- a/cml/mathlib/vector/rotation.tpp +++ b/cml/mathlib/vector/rotation.tpp @@ -1,36 +1,36 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_VECTOR_ROTATION_TPP -# error "mathlib/vector/rotation.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -template -inline auto -rotate_vector(const readable_vector& v, const readable_vector& n, - const E& angle) -> vector_promote_t -{ - static_assert( - cml::are_convertible, - value_type_trait_of_t, E>::value, - "incompatible scalar types"); - - using angle_traits = scalar_traits; - - cml::check_size(v, cml::int_c<3>()); - cml::check_size(n, cml::int_c<3>()); - - auto parallel = dot(v, n) * n; - auto sin_angle = angle_traits::sin(angle); - auto cos_angle = angle_traits::cos(angle); - return cos_angle * (v - parallel) + sin_angle * cross(n, v) + parallel; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_VECTOR_ROTATION_TPP +# error "mathlib/vector/rotation.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +template +inline auto +rotate_vector(const readable_vector& v, const readable_vector& n, + const E& angle) -> vector_promote_t +{ + static_assert( + cml::are_convertible, + value_type_trait_of_t, E>::value, + "incompatible scalar types"); + + using angle_traits = scalar_traits; + + cml::check_size(v, cml::int_c<3>()); + cml::check_size(n, cml::int_c<3>()); + + auto parallel = dot(v, n) * n; + auto sin_angle = angle_traits::sin(angle); + auto cos_angle = angle_traits::cos(angle); + return cos_angle * (v - parallel) + sin_angle * cross(n, v) + parallel; +} + } // namespace cml \ No newline at end of file diff --git a/cml/mathlib/vector/transform.h b/cml/mathlib/vector/transform.h index 70fdee2..166cb85 100644 --- a/cml/mathlib/vector/transform.h +++ b/cml/mathlib/vector/transform.h @@ -1,118 +1,118 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/** @defgroup mathlib_vector_transform Vector Transformation Functions */ - -namespace cml { - -/** @addtogroup mathlib_vector_transform */ -/*@{*/ - -/** @defgroup mathlib_vector_transform_2D 2D Vector Transformations */ -/*@{*/ - -/** Apply a 2D linear transform to a 2D vector, taking basis orientation - * into account. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 2x2. If @c m is fixed-size, the - * size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -auto transform_vector_2D(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t; - -/** Apply a 2D affine transform to a 2D point, taking basis orientation - * into account. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 2D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 2D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -auto transform_point_2D(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t; - -/*@}*/ - - -/** @defgroup mathlib_vector_transform_3D 3D Vector Transformations */ -/*@{*/ - -/** Apply a 3D linear transform to a 3D vector, taking basis orientation - * into account. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the - * size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -auto transform_vector(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t; - -/** Apply a 3D affine transform to a 3D point, taking basis orientation - * into account. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not sized for a 3D affine transformation. If - * @c m is fixed-size, the size is checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -auto transform_point(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t; - -/** Apply a 3D homogeneous transformation to a 4D vector, taking basis - * orientation into account. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not 4x4. If @c m is fixed-size, the size is - * checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 4D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -auto transform_vector_4D(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t; - -/** Apply a 3D homogeneous transformation to a 3D point, taking basis - * orientation into account. - * - * @throws minimum_matrix_size_error at run-time if @c m is - * dynamically-sized, and is not 4x4. If @c m is fixed-size, the size is - * checked at compile-time. - * - * @throws vector_size_error at run-time if @c v is dynamically-sized, and - * is not 3D. If @c v is fixed-size, the size is checked at compile-time. - */ -template -auto transform_point_4D(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t; - -/*@}*/ - -/*@}*/ - -} // namespace cml - -#define __CML_MATHLIB_VECTOR_TRANSFORM_TPP -#include -#undef __CML_MATHLIB_VECTOR_TRANSFORM_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +/** @defgroup mathlib_vector_transform Vector Transformation Functions */ + +namespace cml { + +/** @addtogroup mathlib_vector_transform */ +/*@{*/ + +/** @defgroup mathlib_vector_transform_2D 2D Vector Transformations */ +/*@{*/ + +/** Apply a 2D linear transform to a 2D vector, taking basis orientation + * into account. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 2x2. If @c m is fixed-size, the + * size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +auto transform_vector_2D(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t; + +/** Apply a 2D affine transform to a 2D point, taking basis orientation + * into account. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 2D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 2D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +auto transform_point_2D(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t; + +/*@}*/ + + +/** @defgroup mathlib_vector_transform_3D 3D Vector Transformations */ +/*@{*/ + +/** Apply a 3D linear transform to a 3D vector, taking basis orientation + * into account. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not at least 3x3. If @c m is fixed-size, the + * size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +auto transform_vector(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t; + +/** Apply a 3D affine transform to a 3D point, taking basis orientation + * into account. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not sized for a 3D affine transformation. If + * @c m is fixed-size, the size is checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +auto transform_point(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t; + +/** Apply a 3D homogeneous transformation to a 4D vector, taking basis + * orientation into account. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not 4x4. If @c m is fixed-size, the size is + * checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 4D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +auto transform_vector_4D(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t; + +/** Apply a 3D homogeneous transformation to a 3D point, taking basis + * orientation into account. + * + * @throws minimum_matrix_size_error at run-time if @c m is + * dynamically-sized, and is not 4x4. If @c m is fixed-size, the size is + * checked at compile-time. + * + * @throws vector_size_error at run-time if @c v is dynamically-sized, and + * is not 3D. If @c v is fixed-size, the size is checked at compile-time. + */ +template +auto transform_point_4D(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t; + +/*@}*/ + +/*@}*/ + +} // namespace cml + +#define __CML_MATHLIB_VECTOR_TRANSFORM_TPP +#include +#undef __CML_MATHLIB_VECTOR_TRANSFORM_TPP diff --git a/cml/mathlib/vector/transform.tpp b/cml/mathlib/vector/transform.tpp index 8525dca..803f696 100644 --- a/cml/mathlib/vector/transform.tpp +++ b/cml/mathlib/vector/transform.tpp @@ -1,152 +1,152 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATHLIB_VECTOR_TRANSFORM_TPP -# error "mathlib/vector/transform.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { -namespace detail { - -/** Matrix-vector pre-multiplication. */ -template -inline auto -transform_vector_4D(const readable_matrix& m, - const readable_vector& v, col_basis) -> temporary_of_t -{ - return m * v; -} - -/** Matrix-vector post-multiplication. */ -template -inline auto -transform_vector_4D(const readable_matrix& m, - const readable_vector& v, row_basis) -> temporary_of_t -{ - return v * m; -} - -} // namespace detail - -/* 2D transformations: */ - -template -inline auto -transform_vector_2D(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t -{ - using result_type = temporary_of_t; - using value_type = value_type_trait_of_t; - cml::check_minimum_size(m, int_c<2>(), int_c<2>()); - cml::check_size(v, int_c<2>()); - return result_type( - value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1]), - value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1])); -} - -template -inline auto -transform_point_2D(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t -{ - using result_type = temporary_of_t; - using value_type = value_type_trait_of_t; - cml::check_affine_2D(m); - cml::check_size(v, int_c<2>()); - return result_type( - value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1] - + m.basis_element(2, 0)), - - value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1] - + m.basis_element(2, 1))); -} - -/* 3D transformations: */ - -template -inline auto -transform_vector(const readable_matrix& m, const readable_vector& v) - -> temporary_of_t -{ - using result_type = temporary_of_t; - using value_type = value_type_trait_of_t; - cml::check_minimum_size(m, int_c<3>(), int_c<3>()); - cml::check_size(v, int_c<3>()); - return result_type( - value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1] - + m.basis_element(2, 0) * v[2]), - - value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1] - + m.basis_element(2, 1) * v[2]), - - value_type(m.basis_element(0, 2) * v[0] + m.basis_element(1, 2) * v[1] - + m.basis_element(2, 2) * v[2])); -} - -template -inline auto -transform_point(const readable_matrix& m, const readable_vector& v) - -> temporary_of_t -{ - using result_type = temporary_of_t; - using value_type = value_type_trait_of_t; - cml::check_affine_3D(m); - cml::check_size(v, int_c<3>()); - return result_type( - value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1] - + m.basis_element(2, 0) * v[2] + m.basis_element(3, 0)), - - value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1] - + m.basis_element(2, 1) * v[2] + m.basis_element(3, 1)), - - value_type(m.basis_element(0, 2) * v[0] + m.basis_element(1, 2) * v[1] - + m.basis_element(2, 2) * v[2] + m.basis_element(3, 2))); -} - -template -inline auto -transform_vector_4D(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t -{ - using tag = basis_tag_of_t; - static_assert(tag::value != any_basis_c, "invalid matrix basis orientation"); - cml::check_size(m, int_c<4>(), int_c<4>()); - cml::check_size(v, int_c<4>()); - return detail::transform_vector_4D(m, v, tag()); -} - -template -inline auto -transform_point_4D(const readable_matrix& m, - const readable_vector& v) -> temporary_of_t -{ - using result_type = temporary_of_t; - using value_type = value_type_trait_of_t; - - cml::check_size(m, int_c<4>(), int_c<4>()); - cml::check_size(v, int_c<3>()); - - /* 4D vector temporary: */ - vector> h( - value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1] - + m.basis_element(2, 0) * v[2] + m.basis_element(3, 0)), - - value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1] - + m.basis_element(2, 1) * v[2] + m.basis_element(3, 1)), - - value_type(m.basis_element(0, 2) * v[0] + m.basis_element(1, 2) * v[1] - + m.basis_element(2, 2) * v[2] + m.basis_element(3, 2)), - - value_type(m.basis_element(0, 3) * v[0] + m.basis_element(1, 3) * v[1] - + m.basis_element(2, 3) * v[2] + m.basis_element(3, 3))); - - /* Return projection: */ - return result_type(h[0] / h[3], h[1] / h[3], h[2] / h[3]); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATHLIB_VECTOR_TRANSFORM_TPP +# error "mathlib/vector/transform.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { +namespace detail { + +/** Matrix-vector pre-multiplication. */ +template +inline auto +transform_vector_4D(const readable_matrix& m, + const readable_vector& v, col_basis) -> temporary_of_t +{ + return m * v; +} + +/** Matrix-vector post-multiplication. */ +template +inline auto +transform_vector_4D(const readable_matrix& m, + const readable_vector& v, row_basis) -> temporary_of_t +{ + return v * m; +} + +} // namespace detail + +/* 2D transformations: */ + +template +inline auto +transform_vector_2D(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t +{ + using result_type = temporary_of_t; + using value_type = value_type_trait_of_t; + cml::check_minimum_size(m, int_c<2>(), int_c<2>()); + cml::check_size(v, int_c<2>()); + return result_type( + value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1]), + value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1])); +} + +template +inline auto +transform_point_2D(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t +{ + using result_type = temporary_of_t; + using value_type = value_type_trait_of_t; + cml::check_affine_2D(m); + cml::check_size(v, int_c<2>()); + return result_type( + value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1] + + m.basis_element(2, 0)), + + value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1] + + m.basis_element(2, 1))); +} + +/* 3D transformations: */ + +template +inline auto +transform_vector(const readable_matrix& m, const readable_vector& v) + -> temporary_of_t +{ + using result_type = temporary_of_t; + using value_type = value_type_trait_of_t; + cml::check_minimum_size(m, int_c<3>(), int_c<3>()); + cml::check_size(v, int_c<3>()); + return result_type( + value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1] + + m.basis_element(2, 0) * v[2]), + + value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1] + + m.basis_element(2, 1) * v[2]), + + value_type(m.basis_element(0, 2) * v[0] + m.basis_element(1, 2) * v[1] + + m.basis_element(2, 2) * v[2])); +} + +template +inline auto +transform_point(const readable_matrix& m, const readable_vector& v) + -> temporary_of_t +{ + using result_type = temporary_of_t; + using value_type = value_type_trait_of_t; + cml::check_affine_3D(m); + cml::check_size(v, int_c<3>()); + return result_type( + value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1] + + m.basis_element(2, 0) * v[2] + m.basis_element(3, 0)), + + value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1] + + m.basis_element(2, 1) * v[2] + m.basis_element(3, 1)), + + value_type(m.basis_element(0, 2) * v[0] + m.basis_element(1, 2) * v[1] + + m.basis_element(2, 2) * v[2] + m.basis_element(3, 2))); +} + +template +inline auto +transform_vector_4D(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t +{ + using tag = basis_tag_of_t; + static_assert(tag::value != any_basis_c, "invalid matrix basis orientation"); + cml::check_size(m, int_c<4>(), int_c<4>()); + cml::check_size(v, int_c<4>()); + return detail::transform_vector_4D(m, v, tag()); +} + +template +inline auto +transform_point_4D(const readable_matrix& m, + const readable_vector& v) -> temporary_of_t +{ + using result_type = temporary_of_t; + using value_type = value_type_trait_of_t; + + cml::check_size(m, int_c<4>(), int_c<4>()); + cml::check_size(v, int_c<3>()); + + /* 4D vector temporary: */ + vector> h( + value_type(m.basis_element(0, 0) * v[0] + m.basis_element(1, 0) * v[1] + + m.basis_element(2, 0) * v[2] + m.basis_element(3, 0)), + + value_type(m.basis_element(0, 1) * v[0] + m.basis_element(1, 1) * v[1] + + m.basis_element(2, 1) * v[2] + m.basis_element(3, 1)), + + value_type(m.basis_element(0, 2) * v[0] + m.basis_element(1, 2) * v[1] + + m.basis_element(2, 2) * v[2] + m.basis_element(3, 2)), + + value_type(m.basis_element(0, 3) * v[0] + m.basis_element(1, 3) * v[1] + + m.basis_element(2, 3) * v[2] + m.basis_element(3, 3))); + + /* Return projection: */ + return result_type(h[0] / h[3], h[1] / h[3], h[2] / h[3]); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix.h b/cml/matrix.h index e2a5832..732aa14 100644 --- a/cml/matrix.h +++ b/cml/matrix.h @@ -1,17 +1,17 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/cml/matrix/array_size_of.h b/cml/matrix/array_size_of.h index 989cdac..f8f5895 100644 --- a/cml/matrix/array_size_of.h +++ b/cml/matrix/array_size_of.h @@ -1,24 +1,24 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Specialize array_rows_of_c for vectors to return 1. */ -template struct array_rows_of_c> -{ - static const int value = 1; -}; - -/** Specialize array_cols_of_c for vectors to return 1. */ -template struct array_cols_of_c> -{ - static const int value = 1; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Specialize array_rows_of_c for vectors to return 1. */ +template struct array_rows_of_c> +{ + static const int value = 1; +}; + +/** Specialize array_cols_of_c for vectors to return 1. */ +template struct array_cols_of_c> +{ + static const int value = 1; +}; + +} // namespace cml diff --git a/cml/matrix/basis.h b/cml/matrix/basis.h index 6ccc473..a8b1d6c 100644 --- a/cml/matrix/basis.h +++ b/cml/matrix/basis.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/matrix/basis_node.h b/cml/matrix/basis_node.h index 1016f4c..92e25e0 100644 --- a/cml/matrix/basis_node.h +++ b/cml/matrix/basis_node.h @@ -1,120 +1,120 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template class matrix_basis_node; - -/** matrix_basis_node<> traits. */ -template struct vector_traits> -{ - using vector_type = matrix_basis_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = matrix_traits; - using element_traits = typename sub_traits::element_traits; - using value_type = typename sub_traits::value_type; - using immutable_value = typename sub_traits::immutable_value; - - /* Propagate the column count from the subexpression: */ - static const int array_size = sub_traits::array_cols; - - /* Deduce the vector storage type: */ - using sub_storage_type = typename sub_traits::storage_type; - using sub_unbound_type = typename sub_storage_type::unbound_type; - using resized_type = resize_storage_t; - using storage_type = rebind_vector_storage_t; - - /* Take the size type from the storage type: */ - using size_tag = typename storage_type::size_tag; -}; - -/** Represents a read-only matrix basis vector, specified at run-time by - * its index, as a node in an expression tree. - */ -template -class matrix_basis_node -: public readable_vector> -{ - public: - using node_type = matrix_basis_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** Constant containing the number of elements. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expression and the basis index. @c - * sub must be an lvalue reference or rvalue reference type. - * - * @throws std::invalid_argument if @c i < 0. - */ - explicit matrix_basis_node(Sub sub, int i); - - /** Move constructor. */ - matrix_basis_node(node_type&& other); - - /** Copy constructor. */ - matrix_basis_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Return element @c (,j) of the matrix. */ - immutable_value i_get(int j) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using sub_wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - - protected: - /** The wrapped subexpression. */ - sub_wrap_type m_sub; - - /** The basis index. */ - int m_i; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_MATRIX_BASIS_NODE_TPP -#include -#undef __CML_MATRIX_BASIS_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template class matrix_basis_node; + +/** matrix_basis_node<> traits. */ +template struct vector_traits> +{ + using vector_type = matrix_basis_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = matrix_traits; + using element_traits = typename sub_traits::element_traits; + using value_type = typename sub_traits::value_type; + using immutable_value = typename sub_traits::immutable_value; + + /* Propagate the column count from the subexpression: */ + static const int array_size = sub_traits::array_cols; + + /* Deduce the vector storage type: */ + using sub_storage_type = typename sub_traits::storage_type; + using sub_unbound_type = typename sub_storage_type::unbound_type; + using resized_type = resize_storage_t; + using storage_type = rebind_vector_storage_t; + + /* Take the size type from the storage type: */ + using size_tag = typename storage_type::size_tag; +}; + +/** Represents a read-only matrix basis vector, specified at run-time by + * its index, as a node in an expression tree. + */ +template +class matrix_basis_node +: public readable_vector> +{ + public: + using node_type = matrix_basis_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** Constant containing the number of elements. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expression and the basis index. @c + * sub must be an lvalue reference or rvalue reference type. + * + * @throws std::invalid_argument if @c i < 0. + */ + explicit matrix_basis_node(Sub sub, int i); + + /** Move constructor. */ + matrix_basis_node(node_type&& other); + + /** Copy constructor. */ + matrix_basis_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Return element @c (,j) of the matrix. */ + immutable_value i_get(int j) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using sub_wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + + protected: + /** The wrapped subexpression. */ + sub_wrap_type m_sub; + + /** The basis index. */ + int m_i; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_MATRIX_BASIS_NODE_TPP +#include +#undef __CML_MATRIX_BASIS_NODE_TPP diff --git a/cml/matrix/basis_node.tpp b/cml/matrix/basis_node.tpp index f42a5d4..d5cf5eb 100644 --- a/cml/matrix/basis_node.tpp +++ b/cml/matrix/basis_node.tpp @@ -1,52 +1,52 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_BASIS_NODE_TPP -# error "matrix/basis_node.tpp not included correctly" -#endif - -namespace cml { - -/* matrix_basis_node 'structors: */ - -template -matrix_basis_node::matrix_basis_node(Sub sub, int i) -: m_sub(std::move(sub)) -, m_i(i) -{ - cml_require(i >= 0, std::invalid_argument, "i < 0"); -} - -template -matrix_basis_node::matrix_basis_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -, m_i(other.m_i) -{} - -template -matrix_basis_node::matrix_basis_node(const node_type& other) -: m_sub(other.m_sub) -, m_i(other.m_i) -{} - - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -matrix_basis_node::i_size() const -{ - return this->m_sub.basis_size(); -} - -template -auto -matrix_basis_node::i_get(int j) const -> immutable_value -{ - return this->m_sub.basis_element(this->m_i, j); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_BASIS_NODE_TPP +# error "matrix/basis_node.tpp not included correctly" +#endif + +namespace cml { + +/* matrix_basis_node 'structors: */ + +template +matrix_basis_node::matrix_basis_node(Sub sub, int i) +: m_sub(std::move(sub)) +, m_i(i) +{ + cml_require(i >= 0, std::invalid_argument, "i < 0"); +} + +template +matrix_basis_node::matrix_basis_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +, m_i(other.m_i) +{} + +template +matrix_basis_node::matrix_basis_node(const node_type& other) +: m_sub(other.m_sub) +, m_i(other.m_i) +{} + + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +matrix_basis_node::i_size() const +{ + return this->m_sub.basis_size(); +} + +template +auto +matrix_basis_node::i_get(int j) const -> immutable_value +{ + return this->m_sub.basis_element(this->m_i, j); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/basis_ops.h b/cml/matrix/basis_ops.h index 506be69..13eeb37 100644 --- a/cml/matrix/basis_ops.h +++ b/cml/matrix/basis_ops.h @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template* = nullptr> -inline auto -basis(Sub&& sub, int i) - -> matrix_basis_node, -1> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type"); - - /* Deduce the operand type of the subexpression (&, const&, &&): */ - using sub_type = actual_operand_type_of_t; - return matrix_basis_node((sub_type) sub, i); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template* = nullptr> +inline auto +basis(Sub&& sub, int i) + -> matrix_basis_node, -1> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type"); + + /* Deduce the operand type of the subexpression (&, const&, &&): */ + using sub_type = actual_operand_type_of_t; + return matrix_basis_node((sub_type) sub, i); +} + +} // namespace cml diff --git a/cml/matrix/binary_node.h b/cml/matrix/binary_node.h index 4f6bce5..d1ea622 100644 --- a/cml/matrix/binary_node.h +++ b/cml/matrix/binary_node.h @@ -1,166 +1,166 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class matrix_binary_node; - -/** matrix_binary_node<> traits. */ -template -struct matrix_traits> -{ - using matrix_type = matrix_binary_node; - using left_arg_type = Sub1; - using right_arg_type = Sub2; - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = matrix_traits; - using right_traits = matrix_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - - /* Determine the common storage type for the node, based on the storage - * types of its subexpressions: - */ - using storage_type = matrix_binary_storage_promote_t, - storage_type_of_t>; - - /* Traits and types for the storage: */ - using size_tag = typename storage_type::size_tag; - - /* Array rows: */ - static const int array_rows = storage_type::array_rows; - - /* Array cols: */ - static const int array_cols = storage_type::array_cols; - - /* Determine the common basis type: */ - using basis_tag = basis_tag_promote_t, - basis_tag_of_t>; - - /* Determine the common layout type: */ - using layout_tag = layout_tag_promote_t, - layout_tag_of_t>; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; -}; - -/** Represents a binary matrix operation in an expression tree. */ -template -class matrix_binary_node -: public readable_matrix> -{ - public: - using node_type = matrix_binary_node; - using readable_type = readable_matrix; - using traits_type = matrix_traits; - using left_arg_type = typename traits_type::left_arg_type; - using right_arg_type = typename traits_type::right_arg_type; - using left_type = typename traits_type::left_type; - using right_type = typename traits_type::right_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /** Constant containing the number of rows. */ - static const int array_rows = traits_type::array_rows; - - /** Constant containing the number of columns. */ - static const int array_cols = traits_type::array_cols; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - - public: - /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be - * lvalue reference or rvalue reference types. - * - * @throws incompatible_matrix_sizes at run-time if either Sub1 or Sub2 - * is a dynamically-sized matrix, and sub1.size() != sub2.size(). If - * both Sub1 and Sub2 are fixed-size expressions, then the sizes are - * checked at compile time. - */ - matrix_binary_node(Sub1 left, Sub2 right); - - /** Move constructor. */ - matrix_binary_node(node_type&& other); - - /** Copy constructor. */ - matrix_binary_node(const node_type& other); - - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the row size of the matrix expression. */ - int i_rows() const; - - /** Return the column size of the matrix expression. */ - int i_cols() const; - - /** Apply the operator to element @c (i,j) of the subexpressions and - * return the result. - */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** The type used to store the left subexpression. The expression is - * stored as a copy if Sub1 is an rvalue reference (temporary), or by - * const reference if Sub1 is an lvalue reference. - */ - using left_wrap_type = cml::if_t::value, const left_type&, - left_type>; - - /** The type used to store the right subexpression. The expression is - * stored as a copy if Sub2 is an rvalue reference (temporary), or by - * const reference if Sub2 is an lvalue reference. - */ - using right_wrap_type = cml::if_t::value, const right_type&, - right_type>; - - - protected: - /** The wrapped left subexpression. */ - left_wrap_type m_left; - - /** The wrapped right subexpression. */ - right_wrap_type m_right; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_MATRIX_BINARY_NODE_TPP -#include -#undef __CML_MATRIX_BINARY_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class matrix_binary_node; + +/** matrix_binary_node<> traits. */ +template +struct matrix_traits> +{ + using matrix_type = matrix_binary_node; + using left_arg_type = Sub1; + using right_arg_type = Sub2; + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = matrix_traits; + using right_traits = matrix_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + + /* Determine the common storage type for the node, based on the storage + * types of its subexpressions: + */ + using storage_type = matrix_binary_storage_promote_t, + storage_type_of_t>; + + /* Traits and types for the storage: */ + using size_tag = typename storage_type::size_tag; + + /* Array rows: */ + static const int array_rows = storage_type::array_rows; + + /* Array cols: */ + static const int array_cols = storage_type::array_cols; + + /* Determine the common basis type: */ + using basis_tag = basis_tag_promote_t, + basis_tag_of_t>; + + /* Determine the common layout type: */ + using layout_tag = layout_tag_promote_t, + layout_tag_of_t>; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; +}; + +/** Represents a binary matrix operation in an expression tree. */ +template +class matrix_binary_node +: public readable_matrix> +{ + public: + using node_type = matrix_binary_node; + using readable_type = readable_matrix; + using traits_type = matrix_traits; + using left_arg_type = typename traits_type::left_arg_type; + using right_arg_type = typename traits_type::right_arg_type; + using left_type = typename traits_type::left_type; + using right_type = typename traits_type::right_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /** Constant containing the number of rows. */ + static const int array_rows = traits_type::array_rows; + + /** Constant containing the number of columns. */ + static const int array_cols = traits_type::array_cols; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + + public: + /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be + * lvalue reference or rvalue reference types. + * + * @throws incompatible_matrix_sizes at run-time if either Sub1 or Sub2 + * is a dynamically-sized matrix, and sub1.size() != sub2.size(). If + * both Sub1 and Sub2 are fixed-size expressions, then the sizes are + * checked at compile time. + */ + matrix_binary_node(Sub1 left, Sub2 right); + + /** Move constructor. */ + matrix_binary_node(node_type&& other); + + /** Copy constructor. */ + matrix_binary_node(const node_type& other); + + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the row size of the matrix expression. */ + int i_rows() const; + + /** Return the column size of the matrix expression. */ + int i_cols() const; + + /** Apply the operator to element @c (i,j) of the subexpressions and + * return the result. + */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** The type used to store the left subexpression. The expression is + * stored as a copy if Sub1 is an rvalue reference (temporary), or by + * const reference if Sub1 is an lvalue reference. + */ + using left_wrap_type = cml::if_t::value, const left_type&, + left_type>; + + /** The type used to store the right subexpression. The expression is + * stored as a copy if Sub2 is an rvalue reference (temporary), or by + * const reference if Sub2 is an lvalue reference. + */ + using right_wrap_type = cml::if_t::value, const right_type&, + right_type>; + + + protected: + /** The wrapped left subexpression. */ + left_wrap_type m_left; + + /** The wrapped right subexpression. */ + right_wrap_type m_right; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_MATRIX_BINARY_NODE_TPP +#include +#undef __CML_MATRIX_BINARY_NODE_TPP diff --git a/cml/matrix/binary_node.tpp b/cml/matrix/binary_node.tpp index 0acb65d..835798e 100644 --- a/cml/matrix/binary_node.tpp +++ b/cml/matrix/binary_node.tpp @@ -1,64 +1,64 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_BINARY_NODE_TPP -# error "matrix/binary_node.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* matrix_binary_node 'structors: */ - -template -matrix_binary_node::matrix_binary_node(Sub1 left, Sub2 right) -: m_left(std::move(left)) -, m_right(std::move(right)) -{ - cml::check_same_size(this->m_left, this->m_right); - /* Note: this seems to be exception-safe since temporaries are stored by - * value and references by reference. - */ -} - -template -matrix_binary_node::matrix_binary_node(node_type&& other) -: m_left(std::move(other.m_left)) -, m_right(std::move(other.m_right)) -{} - -template -matrix_binary_node::matrix_binary_node(const node_type& other) -: m_left(other.m_left) -, m_right(other.m_right) -{} - - -/* Internal methods: */ - -/* readable_matrix interface: */ - -template -int -matrix_binary_node::i_rows() const -{ - return this->m_left.rows(); -} - -template -int -matrix_binary_node::i_cols() const -{ - return this->m_left.cols(); -} - -template -auto -matrix_binary_node::i_get(int i, int j) const -> immutable_value -{ - return Op().apply(this->m_left.get(i, j), this->m_right.get(i, j)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_BINARY_NODE_TPP +# error "matrix/binary_node.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* matrix_binary_node 'structors: */ + +template +matrix_binary_node::matrix_binary_node(Sub1 left, Sub2 right) +: m_left(std::move(left)) +, m_right(std::move(right)) +{ + cml::check_same_size(this->m_left, this->m_right); + /* Note: this seems to be exception-safe since temporaries are stored by + * value and references by reference. + */ +} + +template +matrix_binary_node::matrix_binary_node(node_type&& other) +: m_left(std::move(other.m_left)) +, m_right(std::move(other.m_right)) +{} + +template +matrix_binary_node::matrix_binary_node(const node_type& other) +: m_left(other.m_left) +, m_right(other.m_right) +{} + + +/* Internal methods: */ + +/* readable_matrix interface: */ + +template +int +matrix_binary_node::i_rows() const +{ + return this->m_left.rows(); +} + +template +int +matrix_binary_node::i_cols() const +{ + return this->m_left.cols(); +} + +template +auto +matrix_binary_node::i_get(int i, int j) const -> immutable_value +{ + return Op().apply(this->m_left.get(i, j), this->m_right.get(i, j)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/binary_ops.h b/cml/matrix/binary_ops.h index 5b62e66..f3d5b17 100644 --- a/cml/matrix/binary_ops.h +++ b/cml/matrix/binary_ops.h @@ -1,58 +1,58 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Helper function to generate a matrix_binary_node from two matrix types - * (i.e. derived from readable_matrix<>). - */ -template* = nullptr, - enable_if_matrix_t* = nullptr> -inline auto -make_matrix_binary_node(Sub1&& sub1, - Sub2&& sub2) -> matrix_binary_node, - actual_operand_type_of_t, Op> -{ - static_assert( - std::is_same(sub1))>::value, - "internal error: unexpected expression type (sub1)"); - static_assert( - std::is_same(sub2))>::value, - "internal error: unexpected expression type (sub2)"); - - /* Deduce the operand types of the subexpressions (&, const&, &&): */ - using sub1_type = actual_operand_type_of_t; - using sub2_type = actual_operand_type_of_t; - return matrix_binary_node((sub1_type) sub1, - (sub2_type) sub2); -} - -template* = nullptr, - enable_if_matrix_t* = nullptr> -inline auto -operator-(Sub1&& sub1, Sub2&& sub2) - -> decltype(make_matrix_binary_node>( - std::forward(sub1), std::forward(sub2))) -{ - return make_matrix_binary_node>( - std::forward(sub1), std::forward(sub2)); -} - -template* = nullptr, - enable_if_matrix_t* = nullptr> -inline auto -operator+(Sub1&& sub1, Sub2&& sub2) - -> decltype(make_matrix_binary_node>( - std::forward(sub1), std::forward(sub2))) -{ - return make_matrix_binary_node>( - std::forward(sub1), std::forward(sub2)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Helper function to generate a matrix_binary_node from two matrix types + * (i.e. derived from readable_matrix<>). + */ +template* = nullptr, + enable_if_matrix_t* = nullptr> +inline auto +make_matrix_binary_node(Sub1&& sub1, + Sub2&& sub2) -> matrix_binary_node, + actual_operand_type_of_t, Op> +{ + static_assert( + std::is_same(sub1))>::value, + "internal error: unexpected expression type (sub1)"); + static_assert( + std::is_same(sub2))>::value, + "internal error: unexpected expression type (sub2)"); + + /* Deduce the operand types of the subexpressions (&, const&, &&): */ + using sub1_type = actual_operand_type_of_t; + using sub2_type = actual_operand_type_of_t; + return matrix_binary_node((sub1_type) sub1, + (sub2_type) sub2); +} + +template* = nullptr, + enable_if_matrix_t* = nullptr> +inline auto +operator-(Sub1&& sub1, Sub2&& sub2) + -> decltype(make_matrix_binary_node>( + std::forward(sub1), std::forward(sub2))) +{ + return make_matrix_binary_node>( + std::forward(sub1), std::forward(sub2)); +} + +template* = nullptr, + enable_if_matrix_t* = nullptr> +inline auto +operator+(Sub1&& sub1, Sub2&& sub2) + -> decltype(make_matrix_binary_node>( + std::forward(sub1), std::forward(sub2))) +{ + return make_matrix_binary_node>( + std::forward(sub1), std::forward(sub2)); +} + +} // namespace cml diff --git a/cml/matrix/col_node.h b/cml/matrix/col_node.h index 0266fb7..b03af93 100644 --- a/cml/matrix/col_node.h +++ b/cml/matrix/col_node.h @@ -1,120 +1,120 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template class matrix_col_node; - -/** matrix_col_node<> traits. */ -template struct vector_traits> -{ - using vector_type = matrix_col_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = matrix_traits; - using element_traits = typename sub_traits::element_traits; - using value_type = typename sub_traits::value_type; - using immutable_value = typename sub_traits::immutable_value; - - /* Propagate the column count from the subexpression: */ - static const int array_size = sub_traits::array_rows; - - /* Deduce the vector storage type: */ - using sub_storage_type = typename sub_traits::storage_type; - using sub_unbound_type = typename sub_storage_type::unbound_type; - using resized_type = resize_storage_t; - using storage_type = rebind_vector_storage_t; - - /* Take the size type from the storage type: */ - using size_tag = typename storage_type::size_tag; -}; - -/** Represents a read-only matrix column, specified at run-time by its - * index, as a node in an expression tree. - */ -template -class matrix_col_node -: public readable_vector> -{ - public: - using node_type = matrix_col_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** Constant containing the number of elements. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expression and the column index. @c - * sub must be an lvalue reference or rvalue reference type. - * - * @throws std::invalid_argument if @c col < 0. - */ - explicit matrix_col_node(Sub sub, int col); - - /** Move constructor. */ - matrix_col_node(node_type&& other); - - /** Copy constructor. */ - matrix_col_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Return element @c (i,col) of the matrix. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using sub_wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - - protected: - /** The wrapped subexpression. */ - sub_wrap_type m_sub; - - /** The column index. */ - int m_col; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_MATRIX_COL_NODE_TPP -#include -#undef __CML_MATRIX_COL_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template class matrix_col_node; + +/** matrix_col_node<> traits. */ +template struct vector_traits> +{ + using vector_type = matrix_col_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = matrix_traits; + using element_traits = typename sub_traits::element_traits; + using value_type = typename sub_traits::value_type; + using immutable_value = typename sub_traits::immutable_value; + + /* Propagate the column count from the subexpression: */ + static const int array_size = sub_traits::array_rows; + + /* Deduce the vector storage type: */ + using sub_storage_type = typename sub_traits::storage_type; + using sub_unbound_type = typename sub_storage_type::unbound_type; + using resized_type = resize_storage_t; + using storage_type = rebind_vector_storage_t; + + /* Take the size type from the storage type: */ + using size_tag = typename storage_type::size_tag; +}; + +/** Represents a read-only matrix column, specified at run-time by its + * index, as a node in an expression tree. + */ +template +class matrix_col_node +: public readable_vector> +{ + public: + using node_type = matrix_col_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** Constant containing the number of elements. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expression and the column index. @c + * sub must be an lvalue reference or rvalue reference type. + * + * @throws std::invalid_argument if @c col < 0. + */ + explicit matrix_col_node(Sub sub, int col); + + /** Move constructor. */ + matrix_col_node(node_type&& other); + + /** Copy constructor. */ + matrix_col_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Return element @c (i,col) of the matrix. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using sub_wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + + protected: + /** The wrapped subexpression. */ + sub_wrap_type m_sub; + + /** The column index. */ + int m_col; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_MATRIX_COL_NODE_TPP +#include +#undef __CML_MATRIX_COL_NODE_TPP diff --git a/cml/matrix/col_node.tpp b/cml/matrix/col_node.tpp index a82db82..269b64c 100644 --- a/cml/matrix/col_node.tpp +++ b/cml/matrix/col_node.tpp @@ -1,52 +1,52 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_COL_NODE_TPP -# error "matrix/col_node.tpp not included correctly" -#endif - -namespace cml { - -/* matrix_col_node 'structors: */ - -template -matrix_col_node::matrix_col_node(Sub sub, int col) -: m_sub(std::move(sub)) -, m_col(col) -{ - cml_require(col >= 0, std::invalid_argument, "col < 0"); -} - -template -matrix_col_node::matrix_col_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -, m_col(other.m_col) -{} - -template -matrix_col_node::matrix_col_node(const node_type& other) -: m_sub(other.m_sub) -, m_col(other.m_col) -{} - - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -matrix_col_node::i_size() const -{ - return this->m_sub.rows(); -} - -template -auto -matrix_col_node::i_get(int i) const -> immutable_value -{ - return this->m_sub.get(i, this->m_col); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_COL_NODE_TPP +# error "matrix/col_node.tpp not included correctly" +#endif + +namespace cml { + +/* matrix_col_node 'structors: */ + +template +matrix_col_node::matrix_col_node(Sub sub, int col) +: m_sub(std::move(sub)) +, m_col(col) +{ + cml_require(col >= 0, std::invalid_argument, "col < 0"); +} + +template +matrix_col_node::matrix_col_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +, m_col(other.m_col) +{} + +template +matrix_col_node::matrix_col_node(const node_type& other) +: m_sub(other.m_sub) +, m_col(other.m_col) +{} + + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +matrix_col_node::i_size() const +{ + return this->m_sub.rows(); +} + +template +auto +matrix_col_node::i_get(int i) const -> immutable_value +{ + return this->m_sub.get(i, this->m_col); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/col_ops.h b/cml/matrix/col_ops.h index b960da6..b431ef5 100644 --- a/cml/matrix/col_ops.h +++ b/cml/matrix/col_ops.h @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template* = nullptr> -inline auto -col(Sub&& sub, int row) - -> matrix_col_node, -1> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type"); - - /* Deduce the operand type of the subexpression (&, const&, &&): */ - using sub_type = actual_operand_type_of_t; - return matrix_col_node((sub_type) sub, row); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template* = nullptr> +inline auto +col(Sub&& sub, int row) + -> matrix_col_node, -1> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type"); + + /* Deduce the operand type of the subexpression (&, const&, &&): */ + using sub_type = actual_operand_type_of_t; + return matrix_col_node((sub_type) sub, row); +} + +} // namespace cml diff --git a/cml/matrix/comparison.h b/cml/matrix/comparison.h index 0762224..d6e6073 100644 --- a/cml/matrix/comparison.h +++ b/cml/matrix/comparison.h @@ -1,29 +1,29 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Returns true if the elements of @c left are all equal to the elements - * of @c right. - */ -template -bool operator==(const readable_matrix& left, - const readable_matrix& right); - -/** Returns true if some element of @c left is not equal to the same element - * of @c right. - */ -template -bool operator!=(const readable_matrix& left, - const readable_matrix& right); - -} // namespace cml - -#define __CML_MATRIX_COMPARISON_TPP -#include -#undef __CML_MATRIX_COMPARISON_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Returns true if the elements of @c left are all equal to the elements + * of @c right. + */ +template +bool operator==(const readable_matrix& left, + const readable_matrix& right); + +/** Returns true if some element of @c left is not equal to the same element + * of @c right. + */ +template +bool operator!=(const readable_matrix& left, + const readable_matrix& right); + +} // namespace cml + +#define __CML_MATRIX_COMPARISON_TPP +#include +#undef __CML_MATRIX_COMPARISON_TPP diff --git a/cml/matrix/comparison.tpp b/cml/matrix/comparison.tpp index 97c4f7c..0ffc41f 100644 --- a/cml/matrix/comparison.tpp +++ b/cml/matrix/comparison.tpp @@ -1,39 +1,39 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_COMPARISON_TPP -# error "matrix/comparison.tpp not included correctly" -#endif - -#include - -namespace cml { - -template -inline bool -operator==(const readable_matrix& left, - const readable_matrix& right) -{ - /* Possibly equal only if the same dimensions: */ - if(left.size() != right.size()) return false; - for(int i = 0; i < left.rows(); i++) { - for(int j = 0; j < left.cols(); j++) { - /**/ if(left(i, j) < right(i, j)) - return false; // Strictly less. - else if(right(i, j) < left(i, j)) return false; // Strictly greater. - else continue; // Possibly equal. - } - } - return true; -} - -template -inline bool -operator!=(const readable_matrix& left, - const readable_matrix& right) -{ - return !(left == right); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_COMPARISON_TPP +# error "matrix/comparison.tpp not included correctly" +#endif + +#include + +namespace cml { + +template +inline bool +operator==(const readable_matrix& left, + const readable_matrix& right) +{ + /* Possibly equal only if the same dimensions: */ + if(left.size() != right.size()) return false; + for(int i = 0; i < left.rows(); i++) { + for(int j = 0; j < left.cols(); j++) { + /**/ if(left(i, j) < right(i, j)) + return false; // Strictly less. + else if(right(i, j) < left(i, j)) return false; // Strictly greater. + else continue; // Possibly equal. + } + } + return true; +} + +template +inline bool +operator!=(const readable_matrix& left, + const readable_matrix& right) +{ + return !(left == right); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/detail/apply.h b/cml/matrix/detail/apply.h index 5160934..9a226f2 100644 --- a/cml/matrix/detail/apply.h +++ b/cml/matrix/detail/apply.h @@ -1,35 +1,35 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml::detail { - -/** Apply @c Op pairwise to @c left and @c right and assign the result to @c - * left, where @c left is assumed to have a row-major layout. - */ -template -inline void -apply(writable_matrix& left, const Other& right, row_major) -{ - for(int i = 0; i < left.rows(); ++i) - for(int j = 0; j < left.cols(); ++j) - left.put(i, j, Op().apply(left.get(i, j), get(right, i, j))); -} - -/** Apply @c Op pairwise to @c left and @c right and assign the result to - * @c left, where @c left is assumed to have a column-major layout. - */ -template -inline void -apply(writable_matrix& left, const Other& right, col_major) -{ - for(int j = 0; j < left.cols(); ++j) - for(int i = 0; i < left.rows(); ++i) - left.put(i, j, Op().apply(left.get(i, j), get(right, i, j))); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml::detail { + +/** Apply @c Op pairwise to @c left and @c right and assign the result to @c + * left, where @c left is assumed to have a row-major layout. + */ +template +inline void +apply(writable_matrix& left, const Other& right, row_major) +{ + for(int i = 0; i < left.rows(); ++i) + for(int j = 0; j < left.cols(); ++j) + left.put(i, j, Op().apply(left.get(i, j), get(right, i, j))); +} + +/** Apply @c Op pairwise to @c left and @c right and assign the result to + * @c left, where @c left is assumed to have a column-major layout. + */ +template +inline void +apply(writable_matrix& left, const Other& right, col_major) +{ + for(int j = 0; j < left.cols(); ++j) + for(int i = 0; i < left.rows(); ++i) + left.put(i, j, Op().apply(left.get(i, j), get(right, i, j))); +} + +} diff --git a/cml/matrix/detail/check_or_resize.h b/cml/matrix/detail/check_or_resize.h index fabb7a0..d56533f 100644 --- a/cml/matrix/detail/check_or_resize.h +++ b/cml/matrix/detail/check_or_resize.h @@ -1,80 +1,80 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml::detail { - -/** Ensure non-resizable matrix @c left is the same size as @c right. */ -template -inline void -check_or_resize(const readable_matrix& left, const Other& right) -{ - cml::check_same_size(left, right); -} - -/** Ensure resizable matrix @c left is the same size as @c right. */ -template -inline auto -check_or_resize(writable_matrix& left, const readable_matrix& right) - -> decltype(left.actual().resize(0, 0), void()) -{ - left.actual().resize(right.rows(), right.cols()); -} - -/** Ensure resizable matrix @c left is the same size as array @c right. */ -template -inline auto -check_or_resize(writable_matrix& left, Other const (&)[Rows][Cols]) - -> decltype(left.actual().resize(0, 0), void()) -{ - left.actual().resize(Rows, Cols); -} - -/* check_or_resize for a read-only matrix left and constant size RxC that - * just forwards to check_size. - */ -template -inline void -check_or_resize(const readable_matrix& sub, int_c, int_c) -{ - cml::check_size(sub, int_c(), int_c()); -} - -/* check_or_resize for a read-only matrix left and run-time size RxC that - * just forwards to check_size. - */ -template -inline void -check_or_resize(const readable_matrix& sub, int R, int C) -{ - cml::check_size(sub, R, C); -} - -/* check_or_resize for a resizable matrix left and compile-time size that - * resizes the matrix to RxC. - */ -template -inline auto -check_or_resize(writable_matrix& sub, int_c, int_c) - -> decltype(sub.actual().resize(0, 0), void()) -{ - sub.actual().resize(R, C); -} - -/* check_or_resize for a resizable matrix left and run-time size that - * resizes the matrix to RxC. - */ -template -inline auto -check_or_resize(writable_matrix& sub, int R, int C) - -> decltype(sub.actual().resize(0, 0), void()) -{ - sub.actual().resize(R, C); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml::detail { + +/** Ensure non-resizable matrix @c left is the same size as @c right. */ +template +inline void +check_or_resize(const readable_matrix& left, const Other& right) +{ + cml::check_same_size(left, right); +} + +/** Ensure resizable matrix @c left is the same size as @c right. */ +template +inline auto +check_or_resize(writable_matrix& left, const readable_matrix& right) + -> decltype(left.actual().resize(0, 0), void()) +{ + left.actual().resize(right.rows(), right.cols()); +} + +/** Ensure resizable matrix @c left is the same size as array @c right. */ +template +inline auto +check_or_resize(writable_matrix& left, Other const (&)[Rows][Cols]) + -> decltype(left.actual().resize(0, 0), void()) +{ + left.actual().resize(Rows, Cols); +} + +/* check_or_resize for a read-only matrix left and constant size RxC that + * just forwards to check_size. + */ +template +inline void +check_or_resize(const readable_matrix& sub, int_c, int_c) +{ + cml::check_size(sub, int_c(), int_c()); +} + +/* check_or_resize for a read-only matrix left and run-time size RxC that + * just forwards to check_size. + */ +template +inline void +check_or_resize(const readable_matrix& sub, int R, int C) +{ + cml::check_size(sub, R, C); +} + +/* check_or_resize for a resizable matrix left and compile-time size that + * resizes the matrix to RxC. + */ +template +inline auto +check_or_resize(writable_matrix& sub, int_c, int_c) + -> decltype(sub.actual().resize(0, 0), void()) +{ + sub.actual().resize(R, C); +} + +/* check_or_resize for a resizable matrix left and run-time size that + * resizes the matrix to RxC. + */ +template +inline auto +check_or_resize(writable_matrix& sub, int R, int C) + -> decltype(sub.actual().resize(0, 0), void()) +{ + sub.actual().resize(R, C); +} + +} diff --git a/cml/matrix/detail/copy.h b/cml/matrix/detail/copy.h index dcca3fb..234a974 100644 --- a/cml/matrix/detail/copy.h +++ b/cml/matrix/detail/copy.h @@ -1,33 +1,33 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml::detail { - -/** Assign @c left from the elements of @c right, where @c left is assumed - * to have a row-major layout. - */ -template -inline void -copy(writable_matrix& left, const Other& right, row_major) -{ - for(int i = 0; i < left.rows(); ++i) - for(int j = 0; j < left.cols(); ++j) left.put(i, j, get(right, i, j)); -} - -/** Assign @c left from the elements of @c right, where @c left is assumed - * to have a column-major layout. - */ -template -inline void -copy(writable_matrix& left, const Other& right, col_major) -{ - for(int j = 0; j < left.cols(); ++j) - for(int i = 0; i < left.rows(); ++i) left.put(i, j, get(right, i, j)); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml::detail { + +/** Assign @c left from the elements of @c right, where @c left is assumed + * to have a row-major layout. + */ +template +inline void +copy(writable_matrix& left, const Other& right, row_major) +{ + for(int i = 0; i < left.rows(); ++i) + for(int j = 0; j < left.cols(); ++j) left.put(i, j, get(right, i, j)); +} + +/** Assign @c left from the elements of @c right, where @c left is assumed + * to have a column-major layout. + */ +template +inline void +copy(writable_matrix& left, const Other& right, col_major) +{ + for(int j = 0; j < left.cols(); ++j) + for(int i = 0; i < left.rows(); ++i) left.put(i, j, get(right, i, j)); +} + +} diff --git a/cml/matrix/detail/determinant.h b/cml/matrix/detail/determinant.h index 9105fd6..4e408f5 100644 --- a/cml/matrix/detail/determinant.h +++ b/cml/matrix/detail/determinant.h @@ -1,53 +1,53 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml::detail { - -/** 2x2 determinant implementation. */ -template -inline auto determinant(const readable_matrix& M, int_c<2>) - -> value_type_trait_of_t; - -/** 3x3 determinant implementation. */ -template -inline auto determinant(const readable_matrix& M, int_c<3>) - -> value_type_trait_of_t; - -/** 4x4 determinant implementation. */ -template -inline auto determinant(const readable_matrix& M, int_c<4>) - -> value_type_trait_of_t; - -/** Determinant implementation for statically-sized square matrices with - * dimension greater than 4, using a pivoting algorithm to compute the - * result. - * - * @note It is up to the caller to ensure @c M is a square matrix. - */ -template -inline auto determinant(const readable_matrix& M, int_c) - -> value_type_trait_of_t; - -/** Determinant implementation for dynamically-sized matrices. This - * dispatches to a small matrix implementation when the dimension of @c M - * is no more than 4. Otherwise, the general pivoting implementation is - * used. - * - * @note It is up to the caller to ensure @c M is a square matrix. - */ -template -inline auto determinant(const readable_matrix& M, int_c<-1>) - -> value_type_trait_of_t; - -} - -#define __CML_MATRIX_DETAIL_DETERMINANT_TPP -#include -#undef __CML_MATRIX_DETAIL_DETERMINANT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml::detail { + +/** 2x2 determinant implementation. */ +template +inline auto determinant(const readable_matrix& M, int_c<2>) + -> value_type_trait_of_t; + +/** 3x3 determinant implementation. */ +template +inline auto determinant(const readable_matrix& M, int_c<3>) + -> value_type_trait_of_t; + +/** 4x4 determinant implementation. */ +template +inline auto determinant(const readable_matrix& M, int_c<4>) + -> value_type_trait_of_t; + +/** Determinant implementation for statically-sized square matrices with + * dimension greater than 4, using a pivoting algorithm to compute the + * result. + * + * @note It is up to the caller to ensure @c M is a square matrix. + */ +template +inline auto determinant(const readable_matrix& M, int_c) + -> value_type_trait_of_t; + +/** Determinant implementation for dynamically-sized matrices. This + * dispatches to a small matrix implementation when the dimension of @c M + * is no more than 4. Otherwise, the general pivoting implementation is + * used. + * + * @note It is up to the caller to ensure @c M is a square matrix. + */ +template +inline auto determinant(const readable_matrix& M, int_c<-1>) + -> value_type_trait_of_t; + +} + +#define __CML_MATRIX_DETAIL_DETERMINANT_TPP +#include +#undef __CML_MATRIX_DETAIL_DETERMINANT_TPP diff --git a/cml/matrix/detail/determinant.tpp b/cml/matrix/detail/determinant.tpp index 51e6bcc..21cbaf7 100644 --- a/cml/matrix/detail/determinant.tpp +++ b/cml/matrix/detail/determinant.tpp @@ -1,129 +1,129 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_DETAIL_DETERMINANT_TPP -# error "matrix/detail/determinant.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml::detail { -namespace { - -template -inline auto -diagonal_product(const Matrix& A) -> value_type_of_t -{ - auto D = A(0, 0); - for(int i = 1; i < A.rows(); ++i) D *= A(i, i); - return D; -} - -} // namespace - -/** 2x2 determinant implementation. */ -template -inline auto -determinant(const readable_matrix& M, int_c<2>) - -> value_type_trait_of_t -{ - return M(0, 0) * M(1, 1) - M(1, 0) * M(0, 1); -} - -/** 3x3 determinant implementation. */ -template -inline auto -determinant(const readable_matrix& M, int_c<3>) - -> value_type_trait_of_t -{ - return M(0, 0) * (M(1, 1) * M(2, 2) - M(1, 2) * M(2, 1)) - + M(0, 1) * (M(1, 2) * M(2, 0) - M(1, 0) * M(2, 2)) - + M(0, 2) * (M(1, 0) * M(2, 1) - M(1, 1) * M(2, 0)); -} - -/** 4x4 determinant implementation. */ -template -inline auto -determinant(const readable_matrix& M, int_c<4>) - -> value_type_trait_of_t -{ - /* Common cofactors: */ - auto m_22_33_23_32 = M(2, 2) * M(3, 3) - M(2, 3) * M(3, 2); - auto m_23_30_20_33 = M(2, 3) * M(3, 0) - M(2, 0) * M(3, 3); - auto m_20_31_21_30 = M(2, 0) * M(3, 1) - M(2, 1) * M(3, 0); - auto m_21_32_22_31 = M(2, 1) * M(3, 2) - M(2, 2) * M(3, 1); - auto m_23_31_21_33 = M(2, 3) * M(3, 1) - M(2, 1) * M(3, 3); - auto m_20_32_22_30 = M(2, 0) * M(3, 2) - M(2, 2) * M(3, 0); - - auto d00 = M(0, 0) - * (M(1, 1) * m_22_33_23_32 + M(1, 2) * m_23_31_21_33 - + M(1, 3) * m_21_32_22_31); - - auto d01 = M(0, 1) - * (M(1, 0) * m_22_33_23_32 + M(1, 2) * m_23_30_20_33 - + M(1, 3) * m_20_32_22_30); - - auto d02 = M(0, 2) - * (M(1, 0) * -m_23_31_21_33 + M(1, 1) * m_23_30_20_33 - + M(1, 3) * m_20_31_21_30); - - auto d03 = M(0, 3) - * (M(1, 0) * m_21_32_22_31 + M(1, 1) * -m_20_32_22_30 - + M(1, 2) * m_20_31_21_30); - - return d00 - d01 + d02 - d03; -} - -/** Determinant implementation for statically-sized square matrices with - * dimension greater than 4, using a pivoting algorithm to compute the - * result. - * - * @note It is up to the caller to ensure @c M is a square matrix. - */ -template -inline auto -determinant(const readable_matrix& M, int_c) - -> value_type_trait_of_t -{ - temporary_of_t A(M); - std::array order; - int sign = lu_pivot_inplace(A, order); - - /* Compute the determinant from the diagonals: */ - return sign * diagonal_product(A); -} - -/** Determinant implementation for dynamically-sized matrices. This - * dispatches to a small matrix implementation when the dimension of @c M - * is no more than 4. Otherwise, the general pivoting implementation is - * used. - * - * @note It is up to the caller to ensure @c M is a square matrix. - */ -template -inline auto -determinant(const readable_matrix& M, int_c<-1>) - -> value_type_trait_of_t -{ - /* Size of matrix */ - int N = M.rows(); - - /* Use the small matrix determinant if possible: */ - switch(N) { - case 2: return determinant(M, int_c<2>()); break; - case 3: return determinant(M, int_c<3>()); break; - case 4: return determinant(M, int_c<4>()); break; - } - - temporary_of_t A(M); - std::vector order(A.rows()); - int sign = lu_pivot_inplace(A, order); - - /* Compute the determinant from the diagonals: */ - return sign * diagonal_product(A); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_DETAIL_DETERMINANT_TPP +# error "matrix/detail/determinant.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml::detail { +namespace { + +template +inline auto +diagonal_product(const Matrix& A) -> value_type_of_t +{ + auto D = A(0, 0); + for(int i = 1; i < A.rows(); ++i) D *= A(i, i); + return D; +} + +} // namespace + +/** 2x2 determinant implementation. */ +template +inline auto +determinant(const readable_matrix& M, int_c<2>) + -> value_type_trait_of_t +{ + return M(0, 0) * M(1, 1) - M(1, 0) * M(0, 1); +} + +/** 3x3 determinant implementation. */ +template +inline auto +determinant(const readable_matrix& M, int_c<3>) + -> value_type_trait_of_t +{ + return M(0, 0) * (M(1, 1) * M(2, 2) - M(1, 2) * M(2, 1)) + + M(0, 1) * (M(1, 2) * M(2, 0) - M(1, 0) * M(2, 2)) + + M(0, 2) * (M(1, 0) * M(2, 1) - M(1, 1) * M(2, 0)); +} + +/** 4x4 determinant implementation. */ +template +inline auto +determinant(const readable_matrix& M, int_c<4>) + -> value_type_trait_of_t +{ + /* Common cofactors: */ + auto m_22_33_23_32 = M(2, 2) * M(3, 3) - M(2, 3) * M(3, 2); + auto m_23_30_20_33 = M(2, 3) * M(3, 0) - M(2, 0) * M(3, 3); + auto m_20_31_21_30 = M(2, 0) * M(3, 1) - M(2, 1) * M(3, 0); + auto m_21_32_22_31 = M(2, 1) * M(3, 2) - M(2, 2) * M(3, 1); + auto m_23_31_21_33 = M(2, 3) * M(3, 1) - M(2, 1) * M(3, 3); + auto m_20_32_22_30 = M(2, 0) * M(3, 2) - M(2, 2) * M(3, 0); + + auto d00 = M(0, 0) + * (M(1, 1) * m_22_33_23_32 + M(1, 2) * m_23_31_21_33 + + M(1, 3) * m_21_32_22_31); + + auto d01 = M(0, 1) + * (M(1, 0) * m_22_33_23_32 + M(1, 2) * m_23_30_20_33 + + M(1, 3) * m_20_32_22_30); + + auto d02 = M(0, 2) + * (M(1, 0) * -m_23_31_21_33 + M(1, 1) * m_23_30_20_33 + + M(1, 3) * m_20_31_21_30); + + auto d03 = M(0, 3) + * (M(1, 0) * m_21_32_22_31 + M(1, 1) * -m_20_32_22_30 + + M(1, 2) * m_20_31_21_30); + + return d00 - d01 + d02 - d03; +} + +/** Determinant implementation for statically-sized square matrices with + * dimension greater than 4, using a pivoting algorithm to compute the + * result. + * + * @note It is up to the caller to ensure @c M is a square matrix. + */ +template +inline auto +determinant(const readable_matrix& M, int_c) + -> value_type_trait_of_t +{ + temporary_of_t A(M); + std::array order; + int sign = lu_pivot_inplace(A, order); + + /* Compute the determinant from the diagonals: */ + return sign * diagonal_product(A); +} + +/** Determinant implementation for dynamically-sized matrices. This + * dispatches to a small matrix implementation when the dimension of @c M + * is no more than 4. Otherwise, the general pivoting implementation is + * used. + * + * @note It is up to the caller to ensure @c M is a square matrix. + */ +template +inline auto +determinant(const readable_matrix& M, int_c<-1>) + -> value_type_trait_of_t +{ + /* Size of matrix */ + int N = M.rows(); + + /* Use the small matrix determinant if possible: */ + switch(N) { + case 2: return determinant(M, int_c<2>()); break; + case 3: return determinant(M, int_c<3>()); break; + case 4: return determinant(M, int_c<4>()); break; + } + + temporary_of_t A(M); + std::vector order(A.rows()); + int sign = lu_pivot_inplace(A, order); + + /* Compute the determinant from the diagonals: */ + return sign * diagonal_product(A); +} + +} diff --git a/cml/matrix/detail/generate.h b/cml/matrix/detail/generate.h index 0ada0bd..a2d84e9 100644 --- a/cml/matrix/detail/generate.h +++ b/cml/matrix/detail/generate.h @@ -1,35 +1,35 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml::detail { - -/** Assign the value of @c f(i,j) to the element @c (i,j) of row-major - * matrix @c left. - */ -template -inline void -generate(writable_matrix& left, F&& f, row_major) -{ - for(int i = 0; i < left.rows(); ++i) - for(int j = 0; j < left.cols(); ++j) - left.put(i, j, (std::forward(f))(i, j)); -} - -/** Assign the value of @c f(i,j) to the element @c (i,j) of column-major - * matrix @c left. - */ -template -inline void -generate(writable_matrix& left, F&& f, col_major) -{ - for(int j = 0; j < left.cols(); ++j) - for(int i = 0; i < left.rows(); ++i) - left.put(i, j, (std::forward(f))(i, j)); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml::detail { + +/** Assign the value of @c f(i,j) to the element @c (i,j) of row-major + * matrix @c left. + */ +template +inline void +generate(writable_matrix& left, F&& f, row_major) +{ + for(int i = 0; i < left.rows(); ++i) + for(int j = 0; j < left.cols(); ++j) + left.put(i, j, (std::forward(f))(i, j)); +} + +/** Assign the value of @c f(i,j) to the element @c (i,j) of column-major + * matrix @c left. + */ +template +inline void +generate(writable_matrix& left, F&& f, col_major) +{ + for(int j = 0; j < left.cols(); ++j) + for(int i = 0; i < left.rows(); ++i) + left.put(i, j, (std::forward(f))(i, j)); +} + +} diff --git a/cml/matrix/detail/get.h b/cml/matrix/detail/get.h index def74da..09bec60 100644 --- a/cml/matrix/detail/get.h +++ b/cml/matrix/detail/get.h @@ -4,6 +4,7 @@ #pragma once +#include #include namespace cml::detail { @@ -11,7 +12,8 @@ namespace cml::detail { /** Helper to return the passed-in value in response to a matrix index @c * (i,j). */ -template +template::value>> inline auto get(const Other& v, int, int) -> const Other& { @@ -20,8 +22,16 @@ get(const Other& v, int, int) -> const Other& /** Helper to return element @c (i,j) of @c array. */ template -inline const Other& -get(Other const (&array)[Rows][Cols], int i, int j) +inline auto +get(Other const (&array)[Rows][Cols], int i, int j) -> const Other& +{ + return array[i][j]; +} + +/** Helper to return element @c (i,j) of @c array. */ +template +inline auto +get(Other (&array)[Rows][Cols], int i, int j) -> Other& { return array[i][j]; } @@ -35,4 +45,12 @@ get(const readable_matrix& sub, int i, int j) -> return sub.get(i, j); } +template +inline auto +get(writable_matrix& sub, int i, int j) -> + typename matrix_traits::mutable_value +{ + return sub.get(i, j); } + +} // namespace cml::detail diff --git a/cml/matrix/detail/inverse.h b/cml/matrix/detail/inverse.h index 78a651d..04531be 100644 --- a/cml/matrix/detail/inverse.h +++ b/cml/matrix/detail/inverse.h @@ -1,280 +1,280 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml::detail { - -/** 2x2 inverse implementation. */ -template -inline void -inverse(writable_matrix& M, int_c<2>) -{ - /* Compute determinant and inverse: */ - auto M00 = M(0, 0), M01 = M(0, 1); - auto M10 = M(1, 0), M11 = M(1, 1); - auto D = (M00 * M11 - M01 * M10); - - /* Replace M: */ - M(0, 0) = M11 / D; - M(0, 1) = -M01 / D; - M(1, 0) = -M10 / D; - M(1, 1) = M00 / D; -} - -/** 3x3 inverse implementation. */ -template -inline void -inverse(writable_matrix& M, int_c<3>) -{ - /* Compute cofactors for each entry: */ - auto m_00 = M(1, 1) * M(2, 2) - M(1, 2) * M(2, 1); - auto m_01 = M(1, 2) * M(2, 0) - M(1, 0) * M(2, 2); - auto m_02 = M(1, 0) * M(2, 1) - M(1, 1) * M(2, 0); - - auto m_10 = M(0, 2) * M(2, 1) - M(0, 1) * M(2, 2); - auto m_11 = M(0, 0) * M(2, 2) - M(0, 2) * M(2, 0); - auto m_12 = M(0, 1) * M(2, 0) - M(0, 0) * M(2, 1); - - auto m_20 = M(0, 1) * M(1, 2) - M(0, 2) * M(1, 1); - auto m_21 = M(0, 2) * M(1, 0) - M(0, 0) * M(1, 2); - auto m_22 = M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0); - - /* Compute determinant from the minors: */ - auto D = (M(0, 0) * m_00 + M(0, 1) * m_01 + M(0, 2) * m_02); - - /* Assign the inverse as (1/D) * (cofactor matrix)^T: */ - M(0, 0) = m_00 / D; - M(0, 1) = m_10 / D; - M(0, 2) = m_20 / D; - M(1, 0) = m_01 / D; - M(1, 1) = m_11 / D; - M(1, 2) = m_21 / D; - M(2, 0) = m_02 / D; - M(2, 1) = m_12 / D; - M(2, 2) = m_22 / D; -} - -/** 4x4 inverse implementation. */ -template -inline void -inverse(writable_matrix& M, int_c<4>) -{ - /* Common cofactors, rows 0,1: */ - auto m_22_33_23_32 = M(2, 2) * M(3, 3) - M(2, 3) * M(3, 2); - auto m_23_30_20_33 = M(2, 3) * M(3, 0) - M(2, 0) * M(3, 3); - auto m_20_31_21_30 = M(2, 0) * M(3, 1) - M(2, 1) * M(3, 0); - auto m_21_32_22_31 = M(2, 1) * M(3, 2) - M(2, 2) * M(3, 1); - auto m_23_31_21_33 = M(2, 3) * M(3, 1) - M(2, 1) * M(3, 3); - auto m_20_32_22_30 = M(2, 0) * M(3, 2) - M(2, 2) * M(3, 0); - - /* Compute minors: */ - auto d00 = - M(1, 1) * m_22_33_23_32 + M(1, 2) * m_23_31_21_33 + M(1, 3) * m_21_32_22_31; - auto d01 = - M(1, 0) * m_22_33_23_32 + M(1, 2) * m_23_30_20_33 + M(1, 3) * m_20_32_22_30; - auto d02 = M(1, 0) * -m_23_31_21_33 + M(1, 1) * m_23_30_20_33 - + M(1, 3) * m_20_31_21_30; - auto d03 = M(1, 0) * m_21_32_22_31 + M(1, 1) * -m_20_32_22_30 - + M(1, 2) * m_20_31_21_30; - - /* Compute minors: */ - auto d10 = - M(0, 1) * m_22_33_23_32 + M(0, 2) * m_23_31_21_33 + M(0, 3) * m_21_32_22_31; - auto d11 = - M(0, 0) * m_22_33_23_32 + M(0, 2) * m_23_30_20_33 + M(0, 3) * m_20_32_22_30; - auto d12 = M(0, 0) * -m_23_31_21_33 + M(0, 1) * m_23_30_20_33 - + M(0, 3) * m_20_31_21_30; - auto d13 = M(0, 0) * m_21_32_22_31 + M(0, 1) * -m_20_32_22_30 - + M(0, 2) * m_20_31_21_30; - - /* Common cofactors, rows 2,3: */ - auto m_02_13_03_12 = M(0, 2) * M(1, 3) - M(0, 3) * M(1, 2); - auto m_03_10_00_13 = M(0, 3) * M(1, 0) - M(0, 0) * M(1, 3); - auto m_00_11_01_10 = M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0); - auto m_01_12_02_11 = M(0, 1) * M(1, 2) - M(0, 2) * M(1, 1); - auto m_03_11_01_13 = M(0, 3) * M(1, 1) - M(0, 1) * M(1, 3); - auto m_00_12_02_10 = M(0, 0) * M(1, 2) - M(0, 2) * M(1, 0); - - /* Compute minors (uses row 3 as the multipliers instead of row 0, - * which uses the same signs as row 0): - */ - auto d20 = - M(3, 1) * m_02_13_03_12 + M(3, 2) * m_03_11_01_13 + M(3, 3) * m_01_12_02_11; - auto d21 = - M(3, 0) * m_02_13_03_12 + M(3, 2) * m_03_10_00_13 + M(3, 3) * m_00_12_02_10; - auto d22 = M(3, 0) * -m_03_11_01_13 + M(3, 1) * m_03_10_00_13 - + M(3, 3) * m_00_11_01_10; - auto d23 = M(3, 0) * m_01_12_02_11 + M(3, 1) * -m_00_12_02_10 - + M(3, 2) * m_00_11_01_10; - - /* Compute minors: */ - auto d30 = - M(2, 1) * m_02_13_03_12 + M(2, 2) * m_03_11_01_13 + M(2, 3) * m_01_12_02_11; - auto d31 = - M(2, 0) * m_02_13_03_12 + M(2, 2) * m_03_10_00_13 + M(2, 3) * m_00_12_02_10; - auto d32 = M(2, 0) * -m_03_11_01_13 + M(2, 1) * m_03_10_00_13 - + M(2, 3) * m_00_11_01_10; - auto d33 = M(2, 0) * m_01_12_02_11 + M(2, 1) * -m_00_12_02_10 - + M(2, 2) * m_00_11_01_10; - - /* Finally, compute determinant from the minors, and assign the - * inverse as (1/D) * (cofactor matrix)^T: - */ - auto D = (M(0, 0) * d00 - M(0, 1) * d01 + M(0, 2) * d02 - M(0, 3) * d03); - M(0, 0) = +d00 / D; - M(0, 1) = -d10 / D; - M(0, 2) = +d20 / D; - M(0, 3) = -d30 / D; - M(1, 0) = -d01 / D; - M(1, 1) = +d11 / D; - M(1, 2) = -d21 / D; - M(1, 3) = +d31 / D; - M(2, 0) = +d02 / D; - M(2, 1) = -d12 / D; - M(2, 2) = +d22 / D; - M(2, 3) = -d32 / D; - M(3, 0) = -d03 / D; - M(3, 1) = +d13 / D; - M(3, 2) = -d23 / D; - M(3, 3) = +d33 / D; -} - -namespace { - -/** Internal NxN inverse implementation using pivoting. @c row_index, @c - * col_index, and @c pivoted should be an appropriately sized array (e.g. - * std::vector<> or std::array<>). - */ -template -inline void -inverse_pivot(writable_matrix& M, RowIndexArray& row_index, - ColIndexArray& col_index, Markers& pivoted) -{ - using value_type = value_type_trait_of_t; - using value_traits = traits_of_t; - - /* For each column */ - int N = M.rows(); - for(int i = 0; i < N; ++i) { - /* Find the pivot */ - int row = 0, col = 0; - auto pivot = value_traits::fabs(M(0, 0)); - for(int j = 0; j < N; ++j) { - if(pivoted[j]) continue; - - for(int k = 0; k < N; ++k) { - if(pivoted[k]) continue; - - value_type mag = value_traits::fabs(M(j, k)); - if(mag > pivot) { - pivot = mag; - row = j; - col = k; - } - } - } - - /* TODO: Check pivot against epsilon here to catch singularity */ - // cml_require(pivot >= epsilon, singular_matrix_error, /**/); - - row_index[i] = row; - col_index[i] = col; - - /* Swap rows if necessary */ - if(row != col) { - for(int j = 0; j < N; ++j) std::swap(M(row, j), M(col, j)); - } - - /* Process pivot row */ - pivoted[col] = true; - pivot = M(col, col); - M(col, col) = value_type(1); - value_type s = value_type(1) / pivot; - for(int j = 0; j < N; ++j) M(col, j) *= s; - - /* Process other rows */ - for(int j = 0; j < N; ++j) { - if(j == col) continue; - - value_type mult = -M(j, col); - M(j, col) = value_type(0); - for(int k = 0; k < N; ++k) M(j, k) += mult * M(col, k); - } - } - - /* Swap columns if necessary */ - for(int i = 0; i < N; ++i) { - if(row_index[i] == col_index[i]) continue; - - for(int j = 0; j < N; ++j) - std::swap(M(j, row_index[i]), M(j, col_index[i])); - } -} - -} // namespace - -/** Inverse implementation for statically-sized square matrices with - * dimension greater than 4, using a pivoting algorithm to compute the - * result. - * - * @note It is up to the caller to ensure @c M is a square matrix. - */ -template -inline void -inverse(writable_matrix& M, int_c) -{ - /* For tracking pivots */ - std::array row_index, col_index; - std::array pivoted; - pivoted.fill(false); - - /* Call the implementation: */ - inverse_pivot(M, row_index, col_index, pivoted); -} - -/** Inverse implementation for dynamically-sized square matrices. This - * dispatches to a small matrix implementation when the dimension of @c M - * is no more than 4. Otherwise, the general pivoting implementation is - * used. - * - * @note It is up to the caller to ensure @c M is a square matrix. - */ -template -inline void -inverse(writable_matrix& M, int_c<-1>) -{ - /* Use small matrix inverse if possible: */ - int N = M.rows(); - switch(N) { - case 2: - inverse(M, int_c<2>()); - return; - break; - case 3: - inverse(M, int_c<3>()); - return; - break; - case 4: - inverse(M, int_c<4>()); - return; - break; - } - - /* Otherwise, use the pivoting inverse: */ - - /* For tracking pivots */ - std::vector row_index(N), col_index(N); - std::vector pivoted(N, false); - - /* Call the implementation: */ - inverse_pivot(M, row_index, col_index, pivoted); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml::detail { + +/** 2x2 inverse implementation. */ +template +inline void +inverse(writable_matrix& M, int_c<2>) +{ + /* Compute determinant and inverse: */ + auto M00 = M(0, 0), M01 = M(0, 1); + auto M10 = M(1, 0), M11 = M(1, 1); + auto D = (M00 * M11 - M01 * M10); + + /* Replace M: */ + M(0, 0) = M11 / D; + M(0, 1) = -M01 / D; + M(1, 0) = -M10 / D; + M(1, 1) = M00 / D; +} + +/** 3x3 inverse implementation. */ +template +inline void +inverse(writable_matrix& M, int_c<3>) +{ + /* Compute cofactors for each entry: */ + auto m_00 = M(1, 1) * M(2, 2) - M(1, 2) * M(2, 1); + auto m_01 = M(1, 2) * M(2, 0) - M(1, 0) * M(2, 2); + auto m_02 = M(1, 0) * M(2, 1) - M(1, 1) * M(2, 0); + + auto m_10 = M(0, 2) * M(2, 1) - M(0, 1) * M(2, 2); + auto m_11 = M(0, 0) * M(2, 2) - M(0, 2) * M(2, 0); + auto m_12 = M(0, 1) * M(2, 0) - M(0, 0) * M(2, 1); + + auto m_20 = M(0, 1) * M(1, 2) - M(0, 2) * M(1, 1); + auto m_21 = M(0, 2) * M(1, 0) - M(0, 0) * M(1, 2); + auto m_22 = M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0); + + /* Compute determinant from the minors: */ + auto D = (M(0, 0) * m_00 + M(0, 1) * m_01 + M(0, 2) * m_02); + + /* Assign the inverse as (1/D) * (cofactor matrix)^T: */ + M(0, 0) = m_00 / D; + M(0, 1) = m_10 / D; + M(0, 2) = m_20 / D; + M(1, 0) = m_01 / D; + M(1, 1) = m_11 / D; + M(1, 2) = m_21 / D; + M(2, 0) = m_02 / D; + M(2, 1) = m_12 / D; + M(2, 2) = m_22 / D; +} + +/** 4x4 inverse implementation. */ +template +inline void +inverse(writable_matrix& M, int_c<4>) +{ + /* Common cofactors, rows 0,1: */ + auto m_22_33_23_32 = M(2, 2) * M(3, 3) - M(2, 3) * M(3, 2); + auto m_23_30_20_33 = M(2, 3) * M(3, 0) - M(2, 0) * M(3, 3); + auto m_20_31_21_30 = M(2, 0) * M(3, 1) - M(2, 1) * M(3, 0); + auto m_21_32_22_31 = M(2, 1) * M(3, 2) - M(2, 2) * M(3, 1); + auto m_23_31_21_33 = M(2, 3) * M(3, 1) - M(2, 1) * M(3, 3); + auto m_20_32_22_30 = M(2, 0) * M(3, 2) - M(2, 2) * M(3, 0); + + /* Compute minors: */ + auto d00 = + M(1, 1) * m_22_33_23_32 + M(1, 2) * m_23_31_21_33 + M(1, 3) * m_21_32_22_31; + auto d01 = + M(1, 0) * m_22_33_23_32 + M(1, 2) * m_23_30_20_33 + M(1, 3) * m_20_32_22_30; + auto d02 = M(1, 0) * -m_23_31_21_33 + M(1, 1) * m_23_30_20_33 + + M(1, 3) * m_20_31_21_30; + auto d03 = M(1, 0) * m_21_32_22_31 + M(1, 1) * -m_20_32_22_30 + + M(1, 2) * m_20_31_21_30; + + /* Compute minors: */ + auto d10 = + M(0, 1) * m_22_33_23_32 + M(0, 2) * m_23_31_21_33 + M(0, 3) * m_21_32_22_31; + auto d11 = + M(0, 0) * m_22_33_23_32 + M(0, 2) * m_23_30_20_33 + M(0, 3) * m_20_32_22_30; + auto d12 = M(0, 0) * -m_23_31_21_33 + M(0, 1) * m_23_30_20_33 + + M(0, 3) * m_20_31_21_30; + auto d13 = M(0, 0) * m_21_32_22_31 + M(0, 1) * -m_20_32_22_30 + + M(0, 2) * m_20_31_21_30; + + /* Common cofactors, rows 2,3: */ + auto m_02_13_03_12 = M(0, 2) * M(1, 3) - M(0, 3) * M(1, 2); + auto m_03_10_00_13 = M(0, 3) * M(1, 0) - M(0, 0) * M(1, 3); + auto m_00_11_01_10 = M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0); + auto m_01_12_02_11 = M(0, 1) * M(1, 2) - M(0, 2) * M(1, 1); + auto m_03_11_01_13 = M(0, 3) * M(1, 1) - M(0, 1) * M(1, 3); + auto m_00_12_02_10 = M(0, 0) * M(1, 2) - M(0, 2) * M(1, 0); + + /* Compute minors (uses row 3 as the multipliers instead of row 0, + * which uses the same signs as row 0): + */ + auto d20 = + M(3, 1) * m_02_13_03_12 + M(3, 2) * m_03_11_01_13 + M(3, 3) * m_01_12_02_11; + auto d21 = + M(3, 0) * m_02_13_03_12 + M(3, 2) * m_03_10_00_13 + M(3, 3) * m_00_12_02_10; + auto d22 = M(3, 0) * -m_03_11_01_13 + M(3, 1) * m_03_10_00_13 + + M(3, 3) * m_00_11_01_10; + auto d23 = M(3, 0) * m_01_12_02_11 + M(3, 1) * -m_00_12_02_10 + + M(3, 2) * m_00_11_01_10; + + /* Compute minors: */ + auto d30 = + M(2, 1) * m_02_13_03_12 + M(2, 2) * m_03_11_01_13 + M(2, 3) * m_01_12_02_11; + auto d31 = + M(2, 0) * m_02_13_03_12 + M(2, 2) * m_03_10_00_13 + M(2, 3) * m_00_12_02_10; + auto d32 = M(2, 0) * -m_03_11_01_13 + M(2, 1) * m_03_10_00_13 + + M(2, 3) * m_00_11_01_10; + auto d33 = M(2, 0) * m_01_12_02_11 + M(2, 1) * -m_00_12_02_10 + + M(2, 2) * m_00_11_01_10; + + /* Finally, compute determinant from the minors, and assign the + * inverse as (1/D) * (cofactor matrix)^T: + */ + auto D = (M(0, 0) * d00 - M(0, 1) * d01 + M(0, 2) * d02 - M(0, 3) * d03); + M(0, 0) = +d00 / D; + M(0, 1) = -d10 / D; + M(0, 2) = +d20 / D; + M(0, 3) = -d30 / D; + M(1, 0) = -d01 / D; + M(1, 1) = +d11 / D; + M(1, 2) = -d21 / D; + M(1, 3) = +d31 / D; + M(2, 0) = +d02 / D; + M(2, 1) = -d12 / D; + M(2, 2) = +d22 / D; + M(2, 3) = -d32 / D; + M(3, 0) = -d03 / D; + M(3, 1) = +d13 / D; + M(3, 2) = -d23 / D; + M(3, 3) = +d33 / D; +} + +namespace { + +/** Internal NxN inverse implementation using pivoting. @c row_index, @c + * col_index, and @c pivoted should be an appropriately sized array (e.g. + * std::vector<> or std::array<>). + */ +template +inline void +inverse_pivot(writable_matrix& M, RowIndexArray& row_index, + ColIndexArray& col_index, Markers& pivoted) +{ + using value_type = value_type_trait_of_t; + using value_traits = traits_of_t; + + /* For each column */ + int N = M.rows(); + for(int i = 0; i < N; ++i) { + /* Find the pivot */ + int row = 0, col = 0; + auto pivot = value_traits::fabs(M(0, 0)); + for(int j = 0; j < N; ++j) { + if(pivoted[j]) continue; + + for(int k = 0; k < N; ++k) { + if(pivoted[k]) continue; + + value_type mag = value_traits::fabs(M(j, k)); + if(mag > pivot) { + pivot = mag; + row = j; + col = k; + } + } + } + + /* TODO: Check pivot against epsilon here to catch singularity */ + // cml_require(pivot >= epsilon, singular_matrix_error, /**/); + + row_index[i] = row; + col_index[i] = col; + + /* Swap rows if necessary */ + if(row != col) { + for(int j = 0; j < N; ++j) std::swap(M(row, j), M(col, j)); + } + + /* Process pivot row */ + pivoted[col] = true; + pivot = M(col, col); + M(col, col) = value_type(1); + value_type s = value_type(1) / pivot; + for(int j = 0; j < N; ++j) M(col, j) *= s; + + /* Process other rows */ + for(int j = 0; j < N; ++j) { + if(j == col) continue; + + value_type mult = -M(j, col); + M(j, col) = value_type(0); + for(int k = 0; k < N; ++k) M(j, k) += mult * M(col, k); + } + } + + /* Swap columns if necessary */ + for(int i = 0; i < N; ++i) { + if(row_index[i] == col_index[i]) continue; + + for(int j = 0; j < N; ++j) + std::swap(M(j, row_index[i]), M(j, col_index[i])); + } +} + +} // namespace + +/** Inverse implementation for statically-sized square matrices with + * dimension greater than 4, using a pivoting algorithm to compute the + * result. + * + * @note It is up to the caller to ensure @c M is a square matrix. + */ +template +inline void +inverse(writable_matrix& M, int_c) +{ + /* For tracking pivots */ + std::array row_index, col_index; + std::array pivoted; + pivoted.fill(false); + + /* Call the implementation: */ + inverse_pivot(M, row_index, col_index, pivoted); +} + +/** Inverse implementation for dynamically-sized square matrices. This + * dispatches to a small matrix implementation when the dimension of @c M + * is no more than 4. Otherwise, the general pivoting implementation is + * used. + * + * @note It is up to the caller to ensure @c M is a square matrix. + */ +template +inline void +inverse(writable_matrix& M, int_c<-1>) +{ + /* Use small matrix inverse if possible: */ + int N = M.rows(); + switch(N) { + case 2: + inverse(M, int_c<2>()); + return; + break; + case 3: + inverse(M, int_c<3>()); + return; + break; + case 4: + inverse(M, int_c<4>()); + return; + break; + } + + /* Otherwise, use the pivoting inverse: */ + + /* For tracking pivots */ + std::vector row_index(N), col_index(N); + std::vector pivoted(N, false); + + /* Call the implementation: */ + inverse_pivot(M, row_index, col_index, pivoted); +} + +} diff --git a/cml/matrix/detail/lu.h b/cml/matrix/detail/lu.h index 52431e9..0d4f3b5 100644 --- a/cml/matrix/detail/lu.h +++ b/cml/matrix/detail/lu.h @@ -1,40 +1,40 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml::detail { - -/** In-place LU decomposition using Doolittle's method. - * - * @tparam Sub Derived output matrix type. - * - * @warning Without pivoting, this is numerically stable only for - * diagonally dominant matrices. - * - * @note It is up to the caller to ensure @c M is a square matrix. - */ -template inline void lu_inplace(writable_matrix& M); - -/** In-place LU decomposition using partial pivoting for non-singular - * square matrices. @c order contains the new row order after pivoting, - * and the diagonal elements are those of the upper matrix. This - * implements the algorithm from Cormen, Leiserson, Rivest, '96. - * - * @tparam Sub Derived output matrix type. - * @tparam order Row order array. - * - * @returns 1 if no pivots or an even number of pivots are performed, -1 if - * an odd number of pivots are performed, 0 if M is singular. - */ -template -inline int lu_pivot_inplace(writable_matrix& M, OrderArray& order); - -} - -#define __CML_MATRIX_DETAIL_LU_TPP -#include -#undef __CML_MATRIX_DETAIL_LU_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml::detail { + +/** In-place LU decomposition using Doolittle's method. + * + * @tparam Sub Derived output matrix type. + * + * @warning Without pivoting, this is numerically stable only for + * diagonally dominant matrices. + * + * @note It is up to the caller to ensure @c M is a square matrix. + */ +template inline void lu_inplace(writable_matrix& M); + +/** In-place LU decomposition using partial pivoting for non-singular + * square matrices. @c order contains the new row order after pivoting, + * and the diagonal elements are those of the upper matrix. This + * implements the algorithm from Cormen, Leiserson, Rivest, '96. + * + * @tparam Sub Derived output matrix type. + * @tparam order Row order array. + * + * @returns 1 if no pivots or an even number of pivots are performed, -1 if + * an odd number of pivots are performed, 0 if M is singular. + */ +template +inline int lu_pivot_inplace(writable_matrix& M, OrderArray& order); + +} + +#define __CML_MATRIX_DETAIL_LU_TPP +#include +#undef __CML_MATRIX_DETAIL_LU_TPP diff --git a/cml/matrix/detail/lu.tpp b/cml/matrix/detail/lu.tpp index fe3ae40..070f54b 100644 --- a/cml/matrix/detail/lu.tpp +++ b/cml/matrix/detail/lu.tpp @@ -1,84 +1,84 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_DETAIL_LU_TPP -# error "matrix/detail/lu.tpp not included correctly" -#endif - -#include - -namespace cml::detail { - -template -inline void -lu_inplace(writable_matrix& M) -{ - using value_type = value_type_trait_of_t; - - int N = M.rows(); - for(int k = 0; k < N; ++k) { - /* Compute the upper triangle: */ - for(int j = k; j < N; ++j) { - value_type sum(0); - for(int p = 0; p < k; ++p) sum += M(k, p) * M(p, j); - M(k, j) -= sum; - } - - /* Compute the lower triangle: */ - for(int i = k + 1; i < N; ++i) { - value_type sum(0); - for(int p = 0; p < k; ++p) sum += M(i, p) * M(p, k); - M(i, k) = (M(i, k) - sum) / M(k, k); - } - } -} - -template -inline int -lu_pivot_inplace(writable_matrix& M, OrderArray& order) -{ - using value_type = value_type_trait_of_t; - using value_traits = traits_of_t; - - /* Initialize the order: */ - int N = M.rows(); - for(int i = 0; i < N; ++i) order[i] = i; - - /* For each column: */ - int flag = 1; - for(int k = 0; k < N - 1; ++k) { - /* Find the next pivot row: */ - int row = k; - value_type max = M(k, k); - for(int i = k + 1; i < N; ++i) { - value_type mag = value_traits::fabs(M(i, k)); - if(mag > max) { - max = mag; - row = i; - } - } - - /* Check for a singular matrix: */ - if(max < value_traits::epsilon()) return 0; - // XXX should be configurable? - - /* Update order and swap rows: */ - if(row != k) { - std::swap(order[k], order[row]); - for(int i = 0; i < N; ++i) std::swap(M(k, i), M(row, i)); - flag = -flag; - } - - /* Compute the Schur complement: */ - for(int i = k + 1; i < N; ++i) { - M(i, k) /= M(k, k); - for(int j = k + 1; j < N; ++j) M(i, j) -= M(i, k) * M(k, j); - } - } - - /* Done: */ - return flag; -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_DETAIL_LU_TPP +# error "matrix/detail/lu.tpp not included correctly" +#endif + +#include + +namespace cml::detail { + +template +inline void +lu_inplace(writable_matrix& M) +{ + using value_type = value_type_trait_of_t; + + int N = M.rows(); + for(int k = 0; k < N; ++k) { + /* Compute the upper triangle: */ + for(int j = k; j < N; ++j) { + value_type sum(0); + for(int p = 0; p < k; ++p) sum += M(k, p) * M(p, j); + M(k, j) -= sum; + } + + /* Compute the lower triangle: */ + for(int i = k + 1; i < N; ++i) { + value_type sum(0); + for(int p = 0; p < k; ++p) sum += M(i, p) * M(p, k); + M(i, k) = (M(i, k) - sum) / M(k, k); + } + } +} + +template +inline int +lu_pivot_inplace(writable_matrix& M, OrderArray& order) +{ + using value_type = value_type_trait_of_t; + using value_traits = traits_of_t; + + /* Initialize the order: */ + int N = M.rows(); + for(int i = 0; i < N; ++i) order[i] = i; + + /* For each column: */ + int flag = 1; + for(int k = 0; k < N - 1; ++k) { + /* Find the next pivot row: */ + int row = k; + value_type max = M(k, k); + for(int i = k + 1; i < N; ++i) { + value_type mag = value_traits::fabs(M(i, k)); + if(mag > max) { + max = mag; + row = i; + } + } + + /* Check for a singular matrix: */ + if(max < value_traits::epsilon()) return 0; + // XXX should be configurable? + + /* Update order and swap rows: */ + if(row != k) { + std::swap(order[k], order[row]); + for(int i = 0; i < N; ++i) std::swap(M(k, i), M(row, i)); + flag = -flag; + } + + /* Compute the Schur complement: */ + for(int i = k + 1; i < N; ++i) { + M(i, k) /= M(k, k); + for(int j = k + 1; j < N; ++j) M(i, j) -= M(i, k) * M(k, j); + } + } + + /* Done: */ + return flag; +} + +} diff --git a/cml/matrix/detail/resize.h b/cml/matrix/detail/resize.h index 986326a..3333f30 100644 --- a/cml/matrix/detail/resize.h +++ b/cml/matrix/detail/resize.h @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml::detail { - -/** No-op for non-resizable matrices. */ -template -inline void -resize(readable_matrix&, int, int) -{} - -/** Resize matrices that implement resize(). */ -template -inline auto -resize(writable_matrix& sub, int rows, int cols) - -> decltype(sub.actual().resize(0, 0), void()) -{ - sub.actual().resize(rows, cols); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml::detail { + +/** No-op for non-resizable matrices. */ +template +inline void +resize(readable_matrix&, int, int) +{} + +/** Resize matrices that implement resize(). */ +template +inline auto +resize(writable_matrix& sub, int rows, int cols) + -> decltype(sub.actual().resize(0, 0), void()) +{ + sub.actual().resize(rows, cols); +} + +} diff --git a/cml/matrix/detail/transpose.h b/cml/matrix/detail/transpose.h index a37b07f..e2f5413 100644 --- a/cml/matrix/detail/transpose.h +++ b/cml/matrix/detail/transpose.h @@ -1,35 +1,35 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml::detail { - -/** Transpose a fixed-size square matrix. */ -template -inline void -transpose(writable_matrix& M, fixed_size_tag) -{ - static const int rows = array_rows_of_c::value; - static const int cols = array_cols_of_c::value; - static_assert(rows == cols, "non-square fixed-size matrix"); - for(int i = 1; i < rows; ++i) - for(int j = 0; j < i; ++j) std::swap(M.get(i, j), M.get(j, i)); -} - -/** Transpose a resizable matrix using a temporary. */ -template* = nullptr> -inline void -transpose(writable_matrix& M, dynamic_size_tag) -{ - temporary_of_t T(M); - M = cml::transpose(T); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml::detail { + +/** Transpose a fixed-size square matrix. */ +template +inline void +transpose(writable_matrix& M, fixed_size_tag) +{ + static const int rows = array_rows_of_c::value; + static const int cols = array_cols_of_c::value; + static_assert(rows == cols, "non-square fixed-size matrix"); + for(int i = 1; i < rows; ++i) + for(int j = 0; j < i; ++j) std::swap(M.get(i, j), M.get(j, i)); +} + +/** Transpose a resizable matrix using a temporary. */ +template* = nullptr> +inline void +transpose(writable_matrix& M, dynamic_size_tag) +{ + temporary_of_t T(M); + M = cml::transpose(T); +} + +} diff --git a/cml/matrix/determinant.h b/cml/matrix/determinant.h index 9b94bb2..cec8119 100644 --- a/cml/matrix/determinant.h +++ b/cml/matrix/determinant.h @@ -1,28 +1,28 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Compute the determinant of square matrix @c M. For matrices of - * dimension less than 4, the determinant is computed directly. For larger - * matrices, the determinant is computed from the LU decomposition with - * partial pivoting. - * - * @throws non_square_matrix_error at run-time if the matrix is - * dynamically-sized and not square. Fixed-size matrices are checked at - * compile-time. - */ -template -auto determinant(const readable_matrix& M) -> value_type_trait_of_t; - -} // namespace cml - -#define __CML_MATRIX_DETERMINANT_TPP -#include -#undef __CML_MATRIX_DETERMINANT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Compute the determinant of square matrix @c M. For matrices of + * dimension less than 4, the determinant is computed directly. For larger + * matrices, the determinant is computed from the LU decomposition with + * partial pivoting. + * + * @throws non_square_matrix_error at run-time if the matrix is + * dynamically-sized and not square. Fixed-size matrices are checked at + * compile-time. + */ +template +auto determinant(const readable_matrix& M) -> value_type_trait_of_t; + +} // namespace cml + +#define __CML_MATRIX_DETERMINANT_TPP +#include +#undef __CML_MATRIX_DETERMINANT_TPP diff --git a/cml/matrix/determinant.tpp b/cml/matrix/determinant.tpp index 99127d5..d5c9b5d 100644 --- a/cml/matrix/determinant.tpp +++ b/cml/matrix/determinant.tpp @@ -1,20 +1,20 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_DETERMINANT_TPP -# error "matrix/determinant.tpp not included correctly" -#endif - -#include - -namespace cml { - -template -inline auto -determinant(const readable_matrix& M) -> value_type_trait_of_t -{ - return M.determinant(); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_DETERMINANT_TPP +# error "matrix/determinant.tpp not included correctly" +#endif + +#include + +namespace cml { + +template +inline auto +determinant(const readable_matrix& M) -> value_type_trait_of_t +{ + return M.determinant(); +} + +} // namespace cml diff --git a/cml/matrix/dynamic.h b/cml/matrix/dynamic.h index f4d5939..ba1b2ec 100644 --- a/cml/matrix/dynamic.h +++ b/cml/matrix/dynamic.h @@ -1,7 +1,7 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include diff --git a/cml/matrix/dynamic_allocated.h b/cml/matrix/dynamic_allocated.h index 931a95d..53c7013 100644 --- a/cml/matrix/dynamic_allocated.h +++ b/cml/matrix/dynamic_allocated.h @@ -1,305 +1,305 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace cml { - -template -struct matrix_traits, BasisOrient, Layout>> -{ - /* The basis must be col_basis or row_basis: */ - static_assert(std::is_same::value - || std::is_same::value, - "invalid basis"); - - /* Traits and types for the matrix element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The matrix storage type: */ - using storage_type = rebind_t, matrix_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array rows (should be -1): */ - static const int array_rows = storage_type::array_rows; - static_assert(array_rows == -1, "invalid row size"); - - /* Array columns (should be -1): */ - static const int array_cols = storage_type::array_cols; - static_assert(array_cols == -1, "invalid column size"); - - /* Basis orientation: */ - using basis_tag = BasisOrient; - - /* Layout: */ - using layout_tag = Layout; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; -}; - -/** Fixed-size matrix. */ -template -class matrix, BasisOrient, Layout> -: public writable_matrix< - matrix, BasisOrient, Layout>> -{ - protected: - /** The real allocator type. */ - using allocator_type = cml::rebind_alloc_t; - - /** Allocator traits. */ - using allocator_traits = std::allocator_traits; - - /** Require a stateless allocator. */ - static_assert(std::is_empty::value, - "cannot use a stateful allocator for dynamic<> matrices"); - - - public: - using matrix_type = matrix, BasisOrient, Layout>; - using readable_type = readable_matrix; - using writable_type = writable_matrix; - using traits_type = matrix_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /* Include methods from writable_type: */ - using writable_type::operator(); - using writable_type::operator=; - - - public: - /** Constant containing the number of rows. */ - static const int array_rows = traits_type::array_rows; - - /** Constant containing the number of columns. */ - static const int array_cols = traits_type::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - - public: - /** Default constructor. - * - * @note The matrix has no elements. - */ - matrix(); - - /** Construct given a size. - * - * @throws std::invalid_argument if @c rows < 0 or @c cols < 0. - */ - matrix(int rows, int cols); - - /** Copy constructor. */ - matrix(const matrix_type& other); - - /** Move constructor. */ - matrix(matrix_type&& other); - - /** Construct from a readable_matrix. */ - template matrix(const readable_matrix& sub); - - /** Construct from at least 1 value. - * - * @note This overload is enabled only if all of the arguments are - * convertible to value_type. - */ - template::value - && std::is_integral::value - - /* Require compatible values: */ - && cml::are_convertible::value>* = nullptr> - - matrix(RowsT rows, ColsT cols, const E0& e0, const Elements&... eN) - // XXX Should be in matrix/dynamic_allocated.tpp, but VC++12 has - // brain-dead out-of-line template argument matching... - : m_data(0) - , m_rows(0) - , m_cols(0) - { - this->resize_fast(rows, cols); - this->assign_elements(e0, eN...); - } - - /** Construct from an array type. */ - template* = nullptr> - matrix(int rows, int cols, const Array& array); - - /** Construct from a C-array type. */ - template - matrix(Other const (&array)[Rows][Cols]); - - /** Construct from a pointer to an array. */ - template* = nullptr> - matrix(int rows, int cols, const Pointer& array); - - /** Construct from a pointer to an array. */ - template* = nullptr> - matrix(const Pointer& array, int rows, int cols); - - /** Destructor. */ - ~matrix(); - - - public: - /** Return access to the matrix data as a raw pointer. */ - pointer data(); - - /** Return const access to the matrix data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator over the elements as a 1D array. */ - const_pointer begin() const; - - /** Read-only iterator over the elements as a 1D array. */ - const_pointer end() const; - - /** Resize the matrix to the specified size. - * - * @note This will reallocate the array and copy existing elements, if - * any. - * - * @throws std::invalid_argument if @c rows or @c cols is negative. - */ - void resize(int rows, int cols); - - /** Resize the matrix to the specified size without copying the old - * elements. - * - * @throws std::invalid_argument if @c rows or @c cols is negative. - */ - void resize_fast(int rows, int cols); - - - public: - /** Copy assignment. */ - matrix_type& operator=(const matrix_type& other); - - /** Move assignment. */ - matrix_type& operator=(matrix_type&& other); - - - protected: - /** No-op for trivially destructible elements - * (is_trivially_destructible). - */ - void destruct(pointer, int, std::true_type); - - /** Invoke non-trivial destructors for @c n elements starting at @c - * data. - */ - void destruct(pointer data, int n, std::false_type); - - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the number of rows. */ - int i_rows() const; - - /** Return the number of columns. */ - int i_cols() const; - - /** Return matrix const element @c (i,j). */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** @name writeable_matrix Interface */ - /*@{*/ - - friend writable_type; - - /** Return matrix element @c (i,j). */ - mutable_value i_get(int i, int j); - - /** Set element @c i. */ - template matrix_type& i_put(int i, int j, const Other& v) &; - - /** Set element @c i on a temporary. */ - template matrix_type&& i_put(int i, int j, const Other& v) &&; - - /*@}*/ - - - protected: - /** Row-major access to const or non-const @c M. */ - template - inline static auto s_access(Matrix& M, int i, int j, row_major) - -> decltype(M.m_data[0]) - { - return M.m_data[i * M.m_cols + j]; - } - - /** Column-major access to const or non-const @c M. */ - template - inline static auto s_access(Matrix& M, int i, int j, col_major) - -> decltype(M.m_data[0]) - { - return M.m_data[j * M.m_rows + i]; - } - - - protected: - /** Dynamic storage. */ - pointer m_data; - - /** Matrix rows. */ - int m_rows; - - /** Matrix columns. */ - int m_cols; -}; - -} // namespace cml - -#define __CML_MATRIX_DYNAMIC_ALLOCATED_TPP -#include -#undef __CML_MATRIX_DYNAMIC_ALLOCATED_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace cml { + +template +struct matrix_traits, BasisOrient, Layout>> +{ + /* The basis must be col_basis or row_basis: */ + static_assert(std::is_same::value + || std::is_same::value, + "invalid basis"); + + /* Traits and types for the matrix element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The matrix storage type: */ + using storage_type = rebind_t, matrix_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array rows (should be -1): */ + static const int array_rows = storage_type::array_rows; + static_assert(array_rows == -1, "invalid row size"); + + /* Array columns (should be -1): */ + static const int array_cols = storage_type::array_cols; + static_assert(array_cols == -1, "invalid column size"); + + /* Basis orientation: */ + using basis_tag = BasisOrient; + + /* Layout: */ + using layout_tag = Layout; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; +}; + +/** Fixed-size matrix. */ +template +class matrix, BasisOrient, Layout> +: public writable_matrix< + matrix, BasisOrient, Layout>> +{ + protected: + /** The real allocator type. */ + using allocator_type = cml::rebind_alloc_t; + + /** Allocator traits. */ + using allocator_traits = std::allocator_traits; + + /** Require a stateless allocator. */ + static_assert(std::is_empty::value, + "cannot use a stateful allocator for dynamic<> matrices"); + + + public: + using matrix_type = matrix, BasisOrient, Layout>; + using readable_type = readable_matrix; + using writable_type = writable_matrix; + using traits_type = matrix_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /* Include methods from writable_type: */ + using writable_type::operator(); + using writable_type::operator=; + + + public: + /** Constant containing the number of rows. */ + static const int array_rows = traits_type::array_rows; + + /** Constant containing the number of columns. */ + static const int array_cols = traits_type::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + + public: + /** Default constructor. + * + * @note The matrix has no elements. + */ + matrix(); + + /** Construct given a size. + * + * @throws std::invalid_argument if @c rows < 0 or @c cols < 0. + */ + matrix(int rows, int cols); + + /** Copy constructor. */ + matrix(const matrix_type& other); + + /** Move constructor. */ + matrix(matrix_type&& other); + + /** Construct from a readable_matrix. */ + template matrix(const readable_matrix& sub); + + /** Construct from at least 1 value. + * + * @note This overload is enabled only if all of the arguments are + * convertible to value_type. + */ + template::value + && std::is_integral::value + + /* Require compatible values: */ + && cml::are_convertible::value>* = nullptr> + + matrix(RowsT rows, ColsT cols, const E0& e0, const Elements&... eN) + // XXX Should be in matrix/dynamic_allocated.tpp, but VC++12 has + // brain-dead out-of-line template argument matching... + : m_data(0) + , m_rows(0) + , m_cols(0) + { + this->resize_fast(rows, cols); + this->assign_elements(e0, eN...); + } + + /** Construct from an array type. */ + template* = nullptr> + matrix(int rows, int cols, const Array& array); + + /** Construct from a C-array type. */ + template + matrix(Other const (&array)[Rows][Cols]); + + /** Construct from a pointer to an array. */ + template* = nullptr> + matrix(int rows, int cols, const Pointer& array); + + /** Construct from a pointer to an array. */ + template* = nullptr> + matrix(const Pointer& array, int rows, int cols); + + /** Destructor. */ + ~matrix(); + + + public: + /** Return access to the matrix data as a raw pointer. */ + pointer data(); + + /** Return const access to the matrix data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator over the elements as a 1D array. */ + const_pointer begin() const; + + /** Read-only iterator over the elements as a 1D array. */ + const_pointer end() const; + + /** Resize the matrix to the specified size. + * + * @note This will reallocate the array and copy existing elements, if + * any. + * + * @throws std::invalid_argument if @c rows or @c cols is negative. + */ + void resize(int rows, int cols); + + /** Resize the matrix to the specified size without copying the old + * elements. + * + * @throws std::invalid_argument if @c rows or @c cols is negative. + */ + void resize_fast(int rows, int cols); + + + public: + /** Copy assignment. */ + matrix_type& operator=(const matrix_type& other); + + /** Move assignment. */ + matrix_type& operator=(matrix_type&& other); + + + protected: + /** No-op for trivially destructible elements + * (is_trivially_destructible). + */ + void destruct(pointer, int, std::true_type); + + /** Invoke non-trivial destructors for @c n elements starting at @c + * data. + */ + void destruct(pointer data, int n, std::false_type); + + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the number of rows. */ + int i_rows() const; + + /** Return the number of columns. */ + int i_cols() const; + + /** Return matrix const element @c (i,j). */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** @name writeable_matrix Interface */ + /*@{*/ + + friend writable_type; + + /** Return matrix element @c (i,j). */ + mutable_value i_get(int i, int j); + + /** Set element @c i. */ + template matrix_type& i_put(int i, int j, const Other& v) &; + + /** Set element @c i on a temporary. */ + template matrix_type&& i_put(int i, int j, const Other& v) &&; + + /*@}*/ + + + protected: + /** Row-major access to const or non-const @c M. */ + template + inline static auto s_access(Matrix& M, int i, int j, row_major) + -> decltype(M.m_data[0]) + { + return M.m_data[i * M.m_cols + j]; + } + + /** Column-major access to const or non-const @c M. */ + template + inline static auto s_access(Matrix& M, int i, int j, col_major) + -> decltype(M.m_data[0]) + { + return M.m_data[j * M.m_rows + i]; + } + + + protected: + /** Dynamic storage. */ + pointer m_data; + + /** Matrix rows. */ + int m_rows; + + /** Matrix columns. */ + int m_cols; +}; + +} // namespace cml + +#define __CML_MATRIX_DYNAMIC_ALLOCATED_TPP +#include +#undef __CML_MATRIX_DYNAMIC_ALLOCATED_TPP diff --git a/cml/matrix/dynamic_allocated.tpp b/cml/matrix/dynamic_allocated.tpp index ac3a5fb..0f87f6b 100644 --- a/cml/matrix/dynamic_allocated.tpp +++ b/cml/matrix/dynamic_allocated.tpp @@ -1,333 +1,333 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#ifndef __CML_MATRIX_DYNAMIC_ALLOCATED_TPP -# error "matrix/dynamic_allocated.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* dynamic 'structors: */ - -template -matrix, BO, L>::matrix() -: m_data(0) -, m_rows(0) -, m_cols(0) -{} - -template -matrix, BO, L>::matrix(int rows, int cols) -: m_data(0) -, m_rows(0) -, m_cols(0) -{ - this->resize_fast(rows, cols); -} - -template -matrix, BO, L>::matrix(const matrix_type& other) -: m_data(0) -, m_rows(0) -, m_cols(0) -{ - this->assign(other); -} - -template -matrix, BO, L>::matrix(matrix_type&& other) -: m_data(0) -, m_rows(0) -, m_cols(0) -{ - this->operator=(std::move(other)); -} - -template -template -matrix, BO, L>::matrix(const readable_matrix& sub) -: m_data(0) -, m_rows(0) -, m_cols(0) -{ - this->assign(sub); -} - -template -template*> -matrix, BO, L>::matrix(int rows, int cols, const Array& array) -: m_data(0) -, m_rows(0) -, m_cols(0) -{ - this->resize_fast(rows, cols); - this->assign(array); -} - -template -template -matrix, BO, L>::matrix(Other const (&array)[R][C]) -: m_data(0) -, m_rows(0) -, m_cols(0) -{ - this->assign(array); -} - -template -template*> -matrix, BO, L>::matrix(int rows, int cols, const Pointer& array) -: m_data(0) -, m_rows(0) -, m_cols(0) -{ - this->resize_fast(rows, cols); - this->assign(array); -} - -template -template*> -matrix, BO, L>::matrix(const Pointer& array, int rows, int cols) -: m_data(0) -, m_rows(0) -, m_cols(0) -{ - this->resize_fast(rows, cols); - this->assign(array); -} - -template -matrix, BO, L>::~matrix() -{ - using size_type = typename allocator_traits::size_type; - int n = this->m_rows * this->m_cols; - this->destruct(this->m_data, n, - typename std::is_trivially_destructible::type()); - - auto allocator = allocator_type(); - allocator_traits::deallocate(allocator, this->m_data, size_type(n)); -} - -/* Public methods: */ - -template -auto -matrix, BO, L>::data() -> pointer -{ - return this->m_data; -} - -template -auto -matrix, BO, L>::data() const -> const_pointer -{ - return this->m_data; -} - -template -auto -matrix, BO, L>::begin() const -> const_pointer -{ - return this->m_data; -} - -template -auto -matrix, BO, L>::end() const -> const_pointer -{ - return this->m_data + this->m_rows * this->m_cols; -} - -template -void -matrix, BO, L>::resize(int rows, int cols) -{ - cml_require(rows >= 0, std::invalid_argument, "rows < 0"); - cml_require(cols >= 0, std::invalid_argument, "cols < 0"); - - int n_old = this->m_rows * this->m_cols; - int n_new = rows * cols; - - /* Short-circuit same size: */ - if(n_new == n_old) { - this->m_rows = rows; - this->m_cols = cols; - return; - } - - /* Allocator to use: */ - auto allocator = allocator_type(); - - /* Allocate the new array: */ - pointer data = this->m_data; - pointer copy = allocator_traits::allocate(allocator, n_new); - try { - /* Destruct elements if necessary: */ - this->destruct(data, n_old, - typename std::is_trivially_destructible::type()); - - /* Copy elements to the new array if necessary: */ - if(data) { - int to = std::min(n_old, n_new); - for(pointer src = data, dst = copy; src < data + to; ++src, ++dst) { - allocator_traits::construct(allocator, dst, *src); - } - - /* Deallocate the old array: */ - allocator_traits::deallocate(allocator, data, n_old); - } - } catch(...) { - allocator_traits::deallocate(allocator, copy, n_new); - throw; - } - - /* Save the new array: */ - this->m_data = copy; - this->m_rows = rows; - this->m_cols = cols; -} - -template -void -matrix, BO, L>::resize_fast(int rows, int cols) -{ - cml_require(rows >= 0, std::invalid_argument, "rows < 0"); - cml_require(cols >= 0, std::invalid_argument, "cols < 0"); - - int n_old = this->m_rows * this->m_cols; - int n_new = rows * cols; - - /* Short-circuit same size: */ - if(n_new == n_old) { - this->m_rows = rows; - this->m_cols = cols; - return; - } - - /* Allocator to use: */ - auto allocator = allocator_type(); - - /* Allocate the new array: */ - pointer data = this->m_data; - pointer copy = allocator_traits::allocate(allocator, n_new); - try { - /* Destruct elements if necessary: */ - this->destruct(data, n_old, - typename std::is_trivially_destructible::type()); - - /* Deallocate the old array: */ - allocator_traits::deallocate(allocator, data, n_old); - } catch(...) { - allocator_traits::deallocate(allocator, copy, n_new); - throw; - } - - /* Save the new array: */ - this->m_data = copy; - this->m_rows = rows; - this->m_cols = cols; -} - -template -auto -matrix, BO, L>::operator=(const matrix_type& other) - -> matrix_type& -{ - return this->assign(other); -} - -template -auto -matrix, BO, L>::operator=(matrix_type&& other) -> matrix_type& -{ - /* Ensure deletion of the current array, if any: */ - std::swap(this->m_data, other.m_data); - std::swap(this->m_rows, other.m_rows); - std::swap(this->m_cols, other.m_cols); - /* Note: swap() can't throw here, so this is exception-safe. */ - - return *this; -} - -/* Internal methods: */ - -template -void -matrix, BO, L>::destruct(pointer, int, std::true_type) -{ - /* Nothing to do. */ -} - -template -void -matrix, BO, L>::destruct(pointer data, int n, std::false_type) -{ - /* Short-circuit null: */ - if(data == nullptr) return; - - /* Destruct each element: */ - else { - auto allocator = allocator_type(); - for(pointer e = data; e < data + n; ++e) - allocator_traits::destroy(allocator, e); - } -} - -/* readable_matrix interface: */ - -template -int -matrix, BO, L>::i_rows() const -{ - return this->m_rows; -} - -template -int -matrix, BO, L>::i_cols() const -{ - return this->m_cols; -} - -template -auto -matrix, BO, L>::i_get(int i, int j) const -> immutable_value -{ - return s_access(*this, i, j, layout_tag()); -} - -/* writable_matrix interface: */ - -template -auto -matrix, BO, L>::i_get(int i, int j) -> mutable_value -{ - return s_access(*this, i, j, layout_tag()); -} - -template -template -auto -matrix, BO, L>::i_put(int i, int j, - const Other& v) & -> matrix_type& -{ - s_access(*this, i, j, layout_tag()) = value_type(v); - return *this; -} - -template -template -auto -matrix, BO, L>::i_put(int i, int j, - const Other& v) && -> matrix_type&& -{ - s_access(*this, i, j, layout_tag()) = value_type(v); - return (matrix_type&&) *this; -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#ifndef __CML_MATRIX_DYNAMIC_ALLOCATED_TPP +# error "matrix/dynamic_allocated.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* dynamic 'structors: */ + +template +matrix, BO, L>::matrix() +: m_data(0) +, m_rows(0) +, m_cols(0) +{} + +template +matrix, BO, L>::matrix(int rows, int cols) +: m_data(0) +, m_rows(0) +, m_cols(0) +{ + this->resize_fast(rows, cols); +} + +template +matrix, BO, L>::matrix(const matrix_type& other) +: m_data(0) +, m_rows(0) +, m_cols(0) +{ + this->assign(other); +} + +template +matrix, BO, L>::matrix(matrix_type&& other) +: m_data(0) +, m_rows(0) +, m_cols(0) +{ + this->operator=(std::move(other)); +} + +template +template +matrix, BO, L>::matrix(const readable_matrix& sub) +: m_data(0) +, m_rows(0) +, m_cols(0) +{ + this->assign(sub); +} + +template +template*> +matrix, BO, L>::matrix(int rows, int cols, const Array& array) +: m_data(0) +, m_rows(0) +, m_cols(0) +{ + this->resize_fast(rows, cols); + this->assign(array); +} + +template +template +matrix, BO, L>::matrix(Other const (&array)[R][C]) +: m_data(0) +, m_rows(0) +, m_cols(0) +{ + this->assign(array); +} + +template +template*> +matrix, BO, L>::matrix(int rows, int cols, const Pointer& array) +: m_data(0) +, m_rows(0) +, m_cols(0) +{ + this->resize_fast(rows, cols); + this->assign(array); +} + +template +template*> +matrix, BO, L>::matrix(const Pointer& array, int rows, int cols) +: m_data(0) +, m_rows(0) +, m_cols(0) +{ + this->resize_fast(rows, cols); + this->assign(array); +} + +template +matrix, BO, L>::~matrix() +{ + using size_type = typename allocator_traits::size_type; + int n = this->m_rows * this->m_cols; + this->destruct(this->m_data, n, + typename std::is_trivially_destructible::type()); + + auto allocator = allocator_type(); + allocator_traits::deallocate(allocator, this->m_data, size_type(n)); +} + +/* Public methods: */ + +template +auto +matrix, BO, L>::data() -> pointer +{ + return this->m_data; +} + +template +auto +matrix, BO, L>::data() const -> const_pointer +{ + return this->m_data; +} + +template +auto +matrix, BO, L>::begin() const -> const_pointer +{ + return this->m_data; +} + +template +auto +matrix, BO, L>::end() const -> const_pointer +{ + return this->m_data + this->m_rows * this->m_cols; +} + +template +void +matrix, BO, L>::resize(int rows, int cols) +{ + cml_require(rows >= 0, std::invalid_argument, "rows < 0"); + cml_require(cols >= 0, std::invalid_argument, "cols < 0"); + + int n_old = this->m_rows * this->m_cols; + int n_new = rows * cols; + + /* Short-circuit same size: */ + if(n_new == n_old) { + this->m_rows = rows; + this->m_cols = cols; + return; + } + + /* Allocator to use: */ + auto allocator = allocator_type(); + + /* Allocate the new array: */ + pointer data = this->m_data; + pointer copy = allocator_traits::allocate(allocator, n_new); + try { + /* Destruct elements if necessary: */ + this->destruct(data, n_old, + typename std::is_trivially_destructible::type()); + + /* Copy elements to the new array if necessary: */ + if(data) { + int to = std::min(n_old, n_new); + for(pointer src = data, dst = copy; src < data + to; ++src, ++dst) { + allocator_traits::construct(allocator, dst, *src); + } + + /* Deallocate the old array: */ + allocator_traits::deallocate(allocator, data, n_old); + } + } catch(...) { + allocator_traits::deallocate(allocator, copy, n_new); + throw; + } + + /* Save the new array: */ + this->m_data = copy; + this->m_rows = rows; + this->m_cols = cols; +} + +template +void +matrix, BO, L>::resize_fast(int rows, int cols) +{ + cml_require(rows >= 0, std::invalid_argument, "rows < 0"); + cml_require(cols >= 0, std::invalid_argument, "cols < 0"); + + int n_old = this->m_rows * this->m_cols; + int n_new = rows * cols; + + /* Short-circuit same size: */ + if(n_new == n_old) { + this->m_rows = rows; + this->m_cols = cols; + return; + } + + /* Allocator to use: */ + auto allocator = allocator_type(); + + /* Allocate the new array: */ + pointer data = this->m_data; + pointer copy = allocator_traits::allocate(allocator, n_new); + try { + /* Destruct elements if necessary: */ + this->destruct(data, n_old, + typename std::is_trivially_destructible::type()); + + /* Deallocate the old array: */ + allocator_traits::deallocate(allocator, data, n_old); + } catch(...) { + allocator_traits::deallocate(allocator, copy, n_new); + throw; + } + + /* Save the new array: */ + this->m_data = copy; + this->m_rows = rows; + this->m_cols = cols; +} + +template +auto +matrix, BO, L>::operator=(const matrix_type& other) + -> matrix_type& +{ + return this->assign(other); +} + +template +auto +matrix, BO, L>::operator=(matrix_type&& other) -> matrix_type& +{ + /* Ensure deletion of the current array, if any: */ + std::swap(this->m_data, other.m_data); + std::swap(this->m_rows, other.m_rows); + std::swap(this->m_cols, other.m_cols); + /* Note: swap() can't throw here, so this is exception-safe. */ + + return *this; +} + +/* Internal methods: */ + +template +void +matrix, BO, L>::destruct(pointer, int, std::true_type) +{ + /* Nothing to do. */ +} + +template +void +matrix, BO, L>::destruct(pointer data, int n, std::false_type) +{ + /* Short-circuit null: */ + if(data == nullptr) return; + + /* Destruct each element: */ + else { + auto allocator = allocator_type(); + for(pointer e = data; e < data + n; ++e) + allocator_traits::destroy(allocator, e); + } +} + +/* readable_matrix interface: */ + +template +int +matrix, BO, L>::i_rows() const +{ + return this->m_rows; +} + +template +int +matrix, BO, L>::i_cols() const +{ + return this->m_cols; +} + +template +auto +matrix, BO, L>::i_get(int i, int j) const -> immutable_value +{ + return s_access(*this, i, j, layout_tag()); +} + +/* writable_matrix interface: */ + +template +auto +matrix, BO, L>::i_get(int i, int j) -> mutable_value +{ + return s_access(*this, i, j, layout_tag()); +} + +template +template +auto +matrix, BO, L>::i_put(int i, int j, + const Other& v) & -> matrix_type& +{ + s_access(*this, i, j, layout_tag()) = value_type(v); + return *this; +} + +template +template +auto +matrix, BO, L>::i_put(int i, int j, + const Other& v) && -> matrix_type&& +{ + s_access(*this, i, j, layout_tag()) = value_type(v); + return (matrix_type&&) *this; +} + +} // namespace cml diff --git a/cml/matrix/dynamic_external.h b/cml/matrix/dynamic_external.h index f7b3e06..8304e04 100644 --- a/cml/matrix/dynamic_external.h +++ b/cml/matrix/dynamic_external.h @@ -1,255 +1,255 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template -struct matrix_traits, BasisOrient, Layout>> -{ - /* The basis must be col_basis or row_basis: */ - static_assert(std::is_same::value - || std::is_same::value, - "invalid basis"); - - /* Traits and types for the matrix element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The matrix storage type: */ - using storage_type = rebind_t, matrix_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array rows (should be -1): */ - static const int array_rows = storage_type::array_rows; - static_assert(array_rows == -1, "invalid row size"); - - /* Array rows (should be -1): */ - static const int array_cols = storage_type::array_cols; - static_assert(array_cols == -1, "invalid column size"); - - /* Basis orientation: */ - using basis_tag = BasisOrient; - - /* Layout: */ - using layout_tag = Layout; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; -}; - -/** Fixed-size matrix. */ -template -class matrix, BasisOrient, Layout> -: public writable_matrix, BasisOrient, Layout>> -{ - // The basis must be col_basis or row_basis (NOT is_basis_tag!): - static_assert(std::is_same::value - || std::is_same::value, - "invalid basis"); - - // The layout must be col_major or row_major (NOT is_layout_tag!): - static_assert(std::is_same::value - || std::is_same::value, - "invalid layout"); - - public: - using matrix_type = matrix, BasisOrient, Layout>; - using readable_type = readable_matrix; - using writable_type = writable_matrix; - using traits_type = matrix_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /* Include methods from writable_type: */ - using writable_type::operator(); - using writable_type::operator=; - - - public: - /** Constant containing the number of rows. */ - static const int array_rows = traits_type::array_rows; - - /** Constant containing the number of columns. */ - static const int array_cols = traits_type::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - - public: - /** Default construct with a null pointer and 0 size (rows, cols). - * - * @warning The default constructor is enabled only if the compiler - * supports rvalue references from *this. - */ - matrix(); - - /** Construct from the wrapped pointer and the dimensions. - * - * @note @c data will be referenced using the assigned matrix layout. - * - * @note This is for compatibility with CML1. - */ - matrix(pointer data, int rows, int cols); - - /** Construct from the wrapped pointer and the dimensions. - * - * @note @c data will be referenced using the assigned matrix layout. - */ - matrix(int rows, int cols, pointer data); - - /** Construct from a wrapped pointer to a 2D array of values with - * dimensions N1xN2. - * - * @note The dimensions of @c array must take the matrix layout into - * account. For example, the C-array initializer for a 3x2 external - * matrix in row-major layout will have dimensions N1xN2 = [3][2], but - * the initializer for a column-major matrix will have dimensions N1xN2 - * = [2][3]. - */ - template matrix(Other (&array)[N1][N2]); - - /** Move constructor. */ - matrix(matrix_type&& other); - - - public: - /** Return access to the matrix data as a raw pointer. */ - pointer data(); - - /** Return const access to the matrix data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator over the elements as a 1D array. */ - const_pointer begin() const; - - /** Read-only iterator over the elements as a 1D array. */ - const_pointer end() const; - - /** Resize (reshape) the matrix to the specified size. - * - * @note The existing elements are not changed. - * - * @throws std::invalid_argument if @c rows or @c cols is negative. - * - * @throws matrix_size_error if the number of elements in the resized - * matrix would be different from the original. - */ - void resize(int rows, int cols); - - /** Reset the matrix to have no elements and no external pointer. */ - void reset(); - - - public: - /** Copy assignment. */ - matrix_type& operator=(const matrix_type& other); - - /** Move assignment. */ - matrix_type& operator=(matrix_type&& other); - - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the number of rows. */ - int i_rows() const; - - /** Return the number of columns. */ - int i_cols() const; - - /** Return matrix const element @c (i,j). */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** @name writeable_matrix Interface */ - /*@{*/ - - friend writable_type; - - /** Return matrix element @c (i,j). */ - mutable_value i_get(int i, int j); - - /** Set element @c i. */ - template - matrix_type& i_put(int i, int j, const Other& v) &; - - /** Set element @c i on a temporary. */ - template matrix_type&& i_put(int i, int j, const Other& v) &&; - - /*@}*/ - - - protected: - /** Row-major access to const or non-const @c M. */ - template - inline static auto s_access(Matrix& M, int i, int j, row_major) - -> decltype(M.m_data[0]) - { - return M.m_data[i * M.m_cols + j]; - } - - /** Column-major access to const or non-const @c M. */ - template - inline static auto s_access(Matrix& M, int i, int j, col_major) - -> decltype(M.m_data[0]) - { - return M.m_data[j * M.m_rows + i]; - } - - - protected: - /** Wrapped pointer. */ - pointer m_data; - - /** Row count. */ - int m_rows; - - /** Column count. */ - int m_cols; -}; - -} // namespace cml - -#define __CML_MATRIX_DYNAMIC_EXTERNAL_TPP -#include -#undef __CML_MATRIX_DYNAMIC_EXTERNAL_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template +struct matrix_traits, BasisOrient, Layout>> +{ + /* The basis must be col_basis or row_basis: */ + static_assert(std::is_same::value + || std::is_same::value, + "invalid basis"); + + /* Traits and types for the matrix element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The matrix storage type: */ + using storage_type = rebind_t, matrix_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array rows (should be -1): */ + static const int array_rows = storage_type::array_rows; + static_assert(array_rows == -1, "invalid row size"); + + /* Array rows (should be -1): */ + static const int array_cols = storage_type::array_cols; + static_assert(array_cols == -1, "invalid column size"); + + /* Basis orientation: */ + using basis_tag = BasisOrient; + + /* Layout: */ + using layout_tag = Layout; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; +}; + +/** Fixed-size matrix. */ +template +class matrix, BasisOrient, Layout> +: public writable_matrix, BasisOrient, Layout>> +{ + // The basis must be col_basis or row_basis (NOT is_basis_tag!): + static_assert(std::is_same::value + || std::is_same::value, + "invalid basis"); + + // The layout must be col_major or row_major (NOT is_layout_tag!): + static_assert(std::is_same::value + || std::is_same::value, + "invalid layout"); + + public: + using matrix_type = matrix, BasisOrient, Layout>; + using readable_type = readable_matrix; + using writable_type = writable_matrix; + using traits_type = matrix_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /* Include methods from writable_type: */ + using writable_type::operator(); + using writable_type::operator=; + + + public: + /** Constant containing the number of rows. */ + static const int array_rows = traits_type::array_rows; + + /** Constant containing the number of columns. */ + static const int array_cols = traits_type::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + + public: + /** Default construct with a null pointer and 0 size (rows, cols). + * + * @warning The default constructor is enabled only if the compiler + * supports rvalue references from *this. + */ + matrix(); + + /** Construct from the wrapped pointer and the dimensions. + * + * @note @c data will be referenced using the assigned matrix layout. + * + * @note This is for compatibility with CML1. + */ + matrix(pointer data, int rows, int cols); + + /** Construct from the wrapped pointer and the dimensions. + * + * @note @c data will be referenced using the assigned matrix layout. + */ + matrix(int rows, int cols, pointer data); + + /** Construct from a wrapped pointer to a 2D array of values with + * dimensions N1xN2. + * + * @note The dimensions of @c array must take the matrix layout into + * account. For example, the C-array initializer for a 3x2 external + * matrix in row-major layout will have dimensions N1xN2 = [3][2], but + * the initializer for a column-major matrix will have dimensions N1xN2 + * = [2][3]. + */ + template matrix(Other (&array)[N1][N2]); + + /** Move constructor. */ + matrix(matrix_type&& other); + + + public: + /** Return access to the matrix data as a raw pointer. */ + pointer data(); + + /** Return const access to the matrix data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator over the elements as a 1D array. */ + const_pointer begin() const; + + /** Read-only iterator over the elements as a 1D array. */ + const_pointer end() const; + + /** Resize (reshape) the matrix to the specified size. + * + * @note The existing elements are not changed. + * + * @throws std::invalid_argument if @c rows or @c cols is negative. + * + * @throws matrix_size_error if the number of elements in the resized + * matrix would be different from the original. + */ + void resize(int rows, int cols); + + /** Reset the matrix to have no elements and no external pointer. */ + void reset(); + + + public: + /** Copy assignment. */ + matrix_type& operator=(const matrix_type& other); + + /** Move assignment. */ + matrix_type& operator=(matrix_type&& other); + + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the number of rows. */ + int i_rows() const; + + /** Return the number of columns. */ + int i_cols() const; + + /** Return matrix const element @c (i,j). */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** @name writeable_matrix Interface */ + /*@{*/ + + friend writable_type; + + /** Return matrix element @c (i,j). */ + mutable_value i_get(int i, int j); + + /** Set element @c i. */ + template + matrix_type& i_put(int i, int j, const Other& v) &; + + /** Set element @c i on a temporary. */ + template matrix_type&& i_put(int i, int j, const Other& v) &&; + + /*@}*/ + + + protected: + /** Row-major access to const or non-const @c M. */ + template + inline static auto s_access(Matrix& M, int i, int j, row_major) + -> decltype(M.m_data[0]) + { + return M.m_data[i * M.m_cols + j]; + } + + /** Column-major access to const or non-const @c M. */ + template + inline static auto s_access(Matrix& M, int i, int j, col_major) + -> decltype(M.m_data[0]) + { + return M.m_data[j * M.m_rows + i]; + } + + + protected: + /** Wrapped pointer. */ + pointer m_data; + + /** Row count. */ + int m_rows; + + /** Column count. */ + int m_cols; +}; + +} // namespace cml + +#define __CML_MATRIX_DYNAMIC_EXTERNAL_TPP +#include +#undef __CML_MATRIX_DYNAMIC_EXTERNAL_TPP diff --git a/cml/matrix/dynamic_external.tpp b/cml/matrix/dynamic_external.tpp index b9ce319..a871fea 100644 --- a/cml/matrix/dynamic_external.tpp +++ b/cml/matrix/dynamic_external.tpp @@ -1,179 +1,179 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_DYNAMIC_EXTERNAL_TPP -# error "matrix/dynamic_external.tpp not included correctly" -#endif - -namespace cml { - -/* dynamic_external 'structors: */ - -template -matrix, BO, L>::matrix() -: m_data(0) -, m_rows(0) -, m_cols(0) -{ -} - -template -matrix, BO, L>::matrix(pointer data, int rows, int cols) -: m_data(data) -, m_rows(rows) -, m_cols(cols) -{ - cml_require(rows >= 0, std::invalid_argument, "rows < 0"); - cml_require(cols >= 0, std::invalid_argument, "cols < 0"); -} - -template -matrix, BO, L>::matrix(int rows, int cols, pointer data) -: m_data(data) -, m_rows(rows) -, m_cols(cols) -{ - cml_require(rows >= 0, std::invalid_argument, "rows < 0"); - cml_require(cols >= 0, std::invalid_argument, "cols < 0"); -} - -template -template -matrix, BO, L>::matrix(Other (&array)[N1][N2]) -: m_data(&array[0][0]) -, m_rows(array_layout == row_major_c ? N1 : N2) -, m_cols(array_layout == row_major_c ? N2 : N1) -{} - -template -matrix, BO, L>::matrix(matrix_type&& other) -{ - this->operator=(std::move(other)); -} - -/* Public methods: */ - -template -auto -matrix, BO, L>::data() -> pointer -{ - return this->m_data; -} - -template -auto -matrix, BO, L>::data() const -> const_pointer -{ - return this->m_data; -} - -template -auto -matrix, BO, L>::begin() const -> const_pointer -{ - return this->m_data; -} - -template -auto -matrix, BO, L>::end() const -> const_pointer -{ - return this->m_data + this->m_rows * this->m_cols; -} - -template -void -matrix, BO, L>::resize(int rows, int cols) -{ - cml_require(rows >= 0, std::invalid_argument, "rows < 0"); - cml_require(cols >= 0, std::invalid_argument, "cols < 0"); - cml::check_linear_size(*this, rows * cols); - this->m_rows = rows; - this->m_cols = cols; -} - -template -void -matrix, BO, L>::reset() -{ - this->m_rows = this->m_cols = 0; - this->m_data = nullptr; -} - -template -auto -matrix, BO, L>::operator=(const matrix_type& other) - -> matrix_type& -{ - return this->assign(other); -} - -template -auto -matrix, BO, L>::operator=(matrix_type&& other) -> matrix_type& -{ - this->m_data = other.m_data; - this->m_rows = other.m_rows; - this->m_cols = other.m_cols; - other.m_data = nullptr; - other.m_rows = 0; - other.m_cols = 0; - return *this; -} - -/* Internal methods: */ - -/* readable_matrix interface: */ - -template -int -matrix, BO, L>::i_rows() const -{ - return this->m_rows; -} - -template -int -matrix, BO, L>::i_cols() const -{ - return this->m_cols; -} - -template -auto -matrix, BO, L>::i_get(int i, int j) const -> immutable_value -{ - return s_access(*this, i, j, layout_tag()); -} - -/* writable_matrix interface: */ - -template -auto -matrix, BO, L>::i_get(int i, int j) -> mutable_value -{ - return s_access(*this, i, j, layout_tag()); -} - -template -template -auto -matrix, BO, L>::i_put(int i, int j, - const Other& v) & -> matrix_type& -{ - s_access(*this, i, j, layout_tag()) = value_type(v); - return *this; -} - -template -template -auto -matrix, BO, L>::i_put(int i, int j, - const Other& v) && -> matrix_type&& -{ - s_access(*this, i, j, layout_tag()) = value_type(v); - return (matrix_type&&) *this; -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_DYNAMIC_EXTERNAL_TPP +# error "matrix/dynamic_external.tpp not included correctly" +#endif + +namespace cml { + +/* dynamic_external 'structors: */ + +template +matrix, BO, L>::matrix() +: m_data(0) +, m_rows(0) +, m_cols(0) +{ +} + +template +matrix, BO, L>::matrix(pointer data, int rows, int cols) +: m_data(data) +, m_rows(rows) +, m_cols(cols) +{ + cml_require(rows >= 0, std::invalid_argument, "rows < 0"); + cml_require(cols >= 0, std::invalid_argument, "cols < 0"); +} + +template +matrix, BO, L>::matrix(int rows, int cols, pointer data) +: m_data(data) +, m_rows(rows) +, m_cols(cols) +{ + cml_require(rows >= 0, std::invalid_argument, "rows < 0"); + cml_require(cols >= 0, std::invalid_argument, "cols < 0"); +} + +template +template +matrix, BO, L>::matrix(Other (&array)[N1][N2]) +: m_data(&array[0][0]) +, m_rows(array_layout == row_major_c ? N1 : N2) +, m_cols(array_layout == row_major_c ? N2 : N1) +{} + +template +matrix, BO, L>::matrix(matrix_type&& other) +{ + this->operator=(std::move(other)); +} + +/* Public methods: */ + +template +auto +matrix, BO, L>::data() -> pointer +{ + return this->m_data; +} + +template +auto +matrix, BO, L>::data() const -> const_pointer +{ + return this->m_data; +} + +template +auto +matrix, BO, L>::begin() const -> const_pointer +{ + return this->m_data; +} + +template +auto +matrix, BO, L>::end() const -> const_pointer +{ + return this->m_data + this->m_rows * this->m_cols; +} + +template +void +matrix, BO, L>::resize(int rows, int cols) +{ + cml_require(rows >= 0, std::invalid_argument, "rows < 0"); + cml_require(cols >= 0, std::invalid_argument, "cols < 0"); + cml::check_linear_size(*this, rows * cols); + this->m_rows = rows; + this->m_cols = cols; +} + +template +void +matrix, BO, L>::reset() +{ + this->m_rows = this->m_cols = 0; + this->m_data = nullptr; +} + +template +auto +matrix, BO, L>::operator=(const matrix_type& other) + -> matrix_type& +{ + return this->assign(other); +} + +template +auto +matrix, BO, L>::operator=(matrix_type&& other) -> matrix_type& +{ + this->m_data = other.m_data; + this->m_rows = other.m_rows; + this->m_cols = other.m_cols; + other.m_data = nullptr; + other.m_rows = 0; + other.m_cols = 0; + return *this; +} + +/* Internal methods: */ + +/* readable_matrix interface: */ + +template +int +matrix, BO, L>::i_rows() const +{ + return this->m_rows; +} + +template +int +matrix, BO, L>::i_cols() const +{ + return this->m_cols; +} + +template +auto +matrix, BO, L>::i_get(int i, int j) const -> immutable_value +{ + return s_access(*this, i, j, layout_tag()); +} + +/* writable_matrix interface: */ + +template +auto +matrix, BO, L>::i_get(int i, int j) -> mutable_value +{ + return s_access(*this, i, j, layout_tag()); +} + +template +template +auto +matrix, BO, L>::i_put(int i, int j, + const Other& v) & -> matrix_type& +{ + s_access(*this, i, j, layout_tag()) = value_type(v); + return *this; +} + +template +template +auto +matrix, BO, L>::i_put(int i, int j, + const Other& v) && -> matrix_type&& +{ + s_access(*this, i, j, layout_tag()) = value_type(v); + return (matrix_type&&) *this; +} + +} // namespace cml diff --git a/cml/matrix/external.h b/cml/matrix/external.h index 680cb1f..1f4526d 100644 --- a/cml/matrix/external.h +++ b/cml/matrix/external.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/matrix/fixed.h b/cml/matrix/fixed.h index 526bb8e..f61717c 100644 --- a/cml/matrix/fixed.h +++ b/cml/matrix/fixed.h @@ -1,7 +1,7 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include diff --git a/cml/matrix/fixed_compiled.h b/cml/matrix/fixed_compiled.h index 43f36fe..ec7fdd0 100644 --- a/cml/matrix/fixed_compiled.h +++ b/cml/matrix/fixed_compiled.h @@ -1,246 +1,246 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template -struct matrix_traits, BasisOrient, Layout>> -{ - /* The basis must be col_basis or row_basis: */ - static_assert(std::is_same::value - || std::is_same::value, - "invalid basis"); - - /* Traits and types for the matrix element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The matrix storage type: */ - using storage_type = rebind_t, matrix_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array rows (should be positive): */ - static const int array_rows = storage_type::array_rows; - static_assert(array_rows > 0, "invalid row size"); - - /* Array columns (should be positive): */ - static const int array_cols = storage_type::array_cols; - static_assert(array_cols > 0, "invalid column size"); - - /* Basis orientation: */ - using basis_tag = BasisOrient; - - /* Layout: */ - using layout_tag = Layout; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; -}; - -/** Fixed-size matrix. */ -template -class matrix, BasisOrient, Layout> -: public writable_matrix< - matrix, BasisOrient, Layout>> -{ - public: - using matrix_type = matrix, BasisOrient, Layout>; - using readable_type = readable_matrix; - using writable_type = writable_matrix; - using traits_type = matrix_traits; - using storage_type = typename traits_type::storage_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /* Include methods from writable_matrix: */ - using writable_type::operator(); - using writable_type::operator=; - - - public: - /** Constant containing the number of rows. */ - static const int array_rows = traits_type::array_rows; - - /** Constant containing the number of columns. */ - static const int array_cols = traits_type::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - - public: - /** Compiler-default constructor. - * - * @note The matrix elements are uninitialized. - */ - matrix() = default; - - /** Compiler-default destructor. */ - ~matrix() = default; - - /** Compiler-default copy constructor. */ - matrix(const matrix_type& other) = default; - - /** Compiler-default move constructor. */ - matrix(matrix_type&& other) = default; - - /** Construct from a readable_matrix. */ - template matrix(const readable_matrix& sub); - - /** Construct from at least 1 value. - * - * @note This overload is enabled only if all of the arguments are - * convertible to value_type. - */ - template::type* = - nullptr> - matrix(const E0& e0, const Elements&... eN) - // XXX Should be in matrix/fixed.tpp, but VC++12 has brain-dead - // out-of-line template argument matching... - { - this->assign_elements(e0, eN...); - } - - /** Construct from an array type. */ - template* = nullptr> - matrix(const Array& array); - - /** Construct from a C-array type. */ - template - matrix(Other const (&array)[Rows2][Cols2]); - - /** Construct from a pointer to an array. */ - template* = nullptr> - matrix(const Pointer& array); - - /** Construct from std::initializer_list. */ - template matrix(std::initializer_list l); - - - public: - /** Return access to the matrix data as a raw pointer. */ - pointer data(); - - /** Return const access to the matrix data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator over the elements as a 1D array. */ - const_pointer begin() const; - - /** Read-only iterator over the elements as a 1D array. */ - const_pointer end() const; - - - public: - /** Copy assignment. */ - matrix_type& operator=(const matrix_type& other); - - /** Move assignment. */ - matrix_type& operator=(matrix_type&& other); - - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the number of rows. */ - int i_rows() const; - - /** Return the number of columns. */ - int i_cols() const; - - /** Return matrix const element @c (i,j). */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** @name writeable_matrix Interface */ - /*@{*/ - - friend writable_type; - - /** Return matrix element @c (i,j). */ - mutable_value i_get(int i, int j); - - /** Set element @c i. */ - template - matrix_type& i_put(int i, int j, const Other& v) &; - - /** Set element @c i on a temporary. */ - template matrix_type&& i_put(int i, int j, const Other& v) &&; - - /*@}*/ - - - protected: - /** Row-major access to const or non-const @c M. */ - template - inline static auto s_access(Matrix& M, int i, int j, row_major) - -> decltype(M.m_data[0][0]) - { - return M.m_data[i][j]; - } - - /** Column-major access to const or non-const @c M. */ - template - inline static auto s_access(Matrix& M, int i, int j, col_major) - -> decltype(M.m_data[0][0]) - { - return M.m_data[j][i]; - } - - - protected: - /** The matrix data type, depending upon the layout. */ - using matrix_data_type = if_t; - - /** Fixed-size array, based on the layout. */ - matrix_data_type m_data; -}; - -} // namespace cml - -#define __CML_MATRIX_FIXED_COMPILED_TPP -#include -#undef __CML_MATRIX_FIXED_COMPILED_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template +struct matrix_traits, BasisOrient, Layout>> +{ + /* The basis must be col_basis or row_basis: */ + static_assert(std::is_same::value + || std::is_same::value, + "invalid basis"); + + /* Traits and types for the matrix element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The matrix storage type: */ + using storage_type = rebind_t, matrix_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array rows (should be positive): */ + static const int array_rows = storage_type::array_rows; + static_assert(array_rows > 0, "invalid row size"); + + /* Array columns (should be positive): */ + static const int array_cols = storage_type::array_cols; + static_assert(array_cols > 0, "invalid column size"); + + /* Basis orientation: */ + using basis_tag = BasisOrient; + + /* Layout: */ + using layout_tag = Layout; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; +}; + +/** Fixed-size matrix. */ +template +class matrix, BasisOrient, Layout> +: public writable_matrix< + matrix, BasisOrient, Layout>> +{ + public: + using matrix_type = matrix, BasisOrient, Layout>; + using readable_type = readable_matrix; + using writable_type = writable_matrix; + using traits_type = matrix_traits; + using storage_type = typename traits_type::storage_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /* Include methods from writable_matrix: */ + using writable_type::operator(); + using writable_type::operator=; + + + public: + /** Constant containing the number of rows. */ + static const int array_rows = traits_type::array_rows; + + /** Constant containing the number of columns. */ + static const int array_cols = traits_type::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + + public: + /** Compiler-default constructor. + * + * @note The matrix elements are uninitialized. + */ + matrix() = default; + + /** Compiler-default destructor. */ + ~matrix() = default; + + /** Compiler-default copy constructor. */ + matrix(const matrix_type& other) = default; + + /** Compiler-default move constructor. */ + matrix(matrix_type&& other) = default; + + /** Construct from a readable_matrix. */ + template matrix(const readable_matrix& sub); + + /** Construct from at least 1 value. + * + * @note This overload is enabled only if all of the arguments are + * convertible to value_type. + */ + template::type* = + nullptr> + matrix(const E0& e0, const Elements&... eN) + // XXX Should be in matrix/fixed.tpp, but VC++12 has brain-dead + // out-of-line template argument matching... + { + this->assign_elements(e0, eN...); + } + + /** Construct from an array type. */ + template* = nullptr> + matrix(const Array& array); + + /** Construct from a C-array type. */ + template + matrix(Other const (&array)[Rows2][Cols2]); + + /** Construct from a pointer to an array. */ + template* = nullptr> + matrix(const Pointer& array); + + /** Construct from std::initializer_list. */ + template matrix(std::initializer_list l); + + + public: + /** Return access to the matrix data as a raw pointer. */ + pointer data(); + + /** Return const access to the matrix data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator over the elements as a 1D array. */ + const_pointer begin() const; + + /** Read-only iterator over the elements as a 1D array. */ + const_pointer end() const; + + + public: + /** Copy assignment. */ + matrix_type& operator=(const matrix_type& other); + + /** Move assignment. */ + matrix_type& operator=(matrix_type&& other); + + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the number of rows. */ + int i_rows() const; + + /** Return the number of columns. */ + int i_cols() const; + + /** Return matrix const element @c (i,j). */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** @name writeable_matrix Interface */ + /*@{*/ + + friend writable_type; + + /** Return matrix element @c (i,j). */ + mutable_value i_get(int i, int j); + + /** Set element @c i. */ + template + matrix_type& i_put(int i, int j, const Other& v) &; + + /** Set element @c i on a temporary. */ + template matrix_type&& i_put(int i, int j, const Other& v) &&; + + /*@}*/ + + + protected: + /** Row-major access to const or non-const @c M. */ + template + inline static auto s_access(Matrix& M, int i, int j, row_major) + -> decltype(M.m_data[0][0]) + { + return M.m_data[i][j]; + } + + /** Column-major access to const or non-const @c M. */ + template + inline static auto s_access(Matrix& M, int i, int j, col_major) + -> decltype(M.m_data[0][0]) + { + return M.m_data[j][i]; + } + + + protected: + /** The matrix data type, depending upon the layout. */ + using matrix_data_type = if_t; + + /** Fixed-size array, based on the layout. */ + matrix_data_type m_data; +}; + +} // namespace cml + +#define __CML_MATRIX_FIXED_COMPILED_TPP +#include +#undef __CML_MATRIX_FIXED_COMPILED_TPP diff --git a/cml/matrix/fixed_compiled.tpp b/cml/matrix/fixed_compiled.tpp index a6ff21a..0d327ff 100644 --- a/cml/matrix/fixed_compiled.tpp +++ b/cml/matrix/fixed_compiled.tpp @@ -1,151 +1,151 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_FIXED_COMPILED_TPP -# error "matrix/fixed_compiled.tpp not included correctly" -#endif - -namespace cml { - -/* fixed 'structors: */ - -template -template -matrix, BO, L>::matrix(const readable_matrix& sub) -{ - this->assign(sub); -} - -template -template*> -matrix, BO, L>::matrix(const Array& array) -{ - this->assign(array); -} - -template -template -matrix, BO, L>::matrix(Other const (&array)[R2][C2]) -{ - this->assign(array); -} - -template -template*> -matrix, BO, L>::matrix(const Pointer& array) -{ - this->assign(array); -} - -template -template -matrix, BO, L>::matrix(std::initializer_list l) -{ - this->assign(l); -} - -/* Public methods: */ - -template -auto -matrix, BO, L>::data() -> pointer -{ - return &this->m_data[0][0]; -} - -template -auto -matrix, BO, L>::data() const -> const_pointer -{ - return &this->m_data[0][0]; -} - -template -auto -matrix, BO, L>::begin() const -> const_pointer -{ - return &this->m_data[0][0]; -} - -template -auto -matrix, BO, L>::end() const -> const_pointer -{ - return (&this->m_data[0][0]) + R * C; -} - -template -auto -matrix, BO, L>::operator=(const matrix_type& other) - -> matrix_type& -{ - return this->assign(other); -} - -template -auto -matrix, BO, L>::operator=(matrix_type&& other) -> matrix_type& -{ - for(int i = 0; i < R; ++i) - for(int j = 0; j < C; ++j) - this->m_data[i][j] = std::move(other.m_data[i][j]); - /* Note: the layout doesn't matter here. */ - return *this; -} - -/* Internal methods: */ - -/* readable_matrix interface: */ - -template -int -matrix, BO, L>::i_rows() const -{ - return R; -} - -template -int -matrix, BO, L>::i_cols() const -{ - return C; -} - -template -auto -matrix, BO, L>::i_get(int i, int j) const -> immutable_value -{ - return s_access(*this, i, j, layout_tag()); -} - -/* writable_matrix interface: */ - -template -auto -matrix, BO, L>::i_get(int i, int j) -> mutable_value -{ - return s_access(*this, i, j, layout_tag()); -} - -template -template -auto -matrix, BO, L>::i_put(int i, int j, - const Other& v) &->matrix_type& -{ - s_access(*this, i, j, layout_tag()) = value_type(v); - return *this; -} - -template -template -auto -matrix, BO, L>::i_put(int i, int j, - const Other& v) && -> matrix_type&& -{ - s_access(*this, i, j, layout_tag()) = value_type(v); - return (matrix_type&&) *this; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_FIXED_COMPILED_TPP +# error "matrix/fixed_compiled.tpp not included correctly" +#endif + +namespace cml { + +/* fixed 'structors: */ + +template +template +matrix, BO, L>::matrix(const readable_matrix& sub) +{ + this->assign(sub); +} + +template +template*> +matrix, BO, L>::matrix(const Array& array) +{ + this->assign(array); +} + +template +template +matrix, BO, L>::matrix(Other const (&array)[R2][C2]) +{ + this->assign(array); +} + +template +template*> +matrix, BO, L>::matrix(const Pointer& array) +{ + this->assign(array); +} + +template +template +matrix, BO, L>::matrix(std::initializer_list l) +{ + this->assign(l); +} + +/* Public methods: */ + +template +auto +matrix, BO, L>::data() -> pointer +{ + return &this->m_data[0][0]; +} + +template +auto +matrix, BO, L>::data() const -> const_pointer +{ + return &this->m_data[0][0]; +} + +template +auto +matrix, BO, L>::begin() const -> const_pointer +{ + return &this->m_data[0][0]; +} + +template +auto +matrix, BO, L>::end() const -> const_pointer +{ + return (&this->m_data[0][0]) + R * C; +} + +template +auto +matrix, BO, L>::operator=(const matrix_type& other) + -> matrix_type& +{ + return this->assign(other); +} + +template +auto +matrix, BO, L>::operator=(matrix_type&& other) -> matrix_type& +{ + for(int i = 0; i < R; ++i) + for(int j = 0; j < C; ++j) + this->m_data[i][j] = std::move(other.m_data[i][j]); + /* Note: the layout doesn't matter here. */ + return *this; +} + +/* Internal methods: */ + +/* readable_matrix interface: */ + +template +int +matrix, BO, L>::i_rows() const +{ + return R; +} + +template +int +matrix, BO, L>::i_cols() const +{ + return C; +} + +template +auto +matrix, BO, L>::i_get(int i, int j) const -> immutable_value +{ + return s_access(*this, i, j, layout_tag()); +} + +/* writable_matrix interface: */ + +template +auto +matrix, BO, L>::i_get(int i, int j) -> mutable_value +{ + return s_access(*this, i, j, layout_tag()); +} + +template +template +auto +matrix, BO, L>::i_put(int i, int j, + const Other& v) &->matrix_type& +{ + s_access(*this, i, j, layout_tag()) = value_type(v); + return *this; +} + +template +template +auto +matrix, BO, L>::i_put(int i, int j, + const Other& v) && -> matrix_type&& +{ + s_access(*this, i, j, layout_tag()) = value_type(v); + return (matrix_type&&) *this; +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/fixed_external.h b/cml/matrix/fixed_external.h index cba9a40..918294c 100644 --- a/cml/matrix/fixed_external.h +++ b/cml/matrix/fixed_external.h @@ -1,225 +1,225 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template -struct matrix_traits, BasisOrient, Layout>> -{ - /* The basis must be col_basis or row_basis: */ - static_assert(std::is_same::value - || std::is_same::value, - "invalid basis"); - - /* Traits and types for the matrix element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The matrix storage type: */ - using storage_type = rebind_t, matrix_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array rows (should be positive): */ - static const int array_rows = storage_type::array_rows; - static_assert(array_rows > 0, "invalid row size"); - - /* Array columns (should be positive): */ - static const int array_cols = storage_type::array_cols; - static_assert(array_cols > 0, "invalid column size"); - - /* Basis orientation: */ - using basis_tag = BasisOrient; - - /* Layout: */ - using layout_tag = Layout; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; -}; - -/** Fixed-size matrix. */ -template -class matrix, BasisOrient, Layout> -: public writable_matrix< - matrix, BasisOrient, Layout>> -{ - public: - using matrix_type = matrix, BasisOrient, Layout>; - using readable_type = readable_matrix; - using writable_type = writable_matrix; - using traits_type = matrix_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /** The matrix data type, depending upon the layout. */ - using matrix_data_type = if_t; - - - public: - /* Include methods from writable_type: */ - using writable_type::operator(); - using writable_type::operator=; - - - public: - /** Constant containing the number of rows. */ - static const int array_rows = traits_type::array_rows; - - /** Constant containing the number of columns. */ - static const int array_cols = traits_type::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - - public: - /** Default construct with a null pointer. - * - * @warning The default constructor is enabled only if the compiler - * supports rvalue references from *this. - */ - matrix(); - - /** Construct from the wrapped pointer. - * - * @note @c data will be referenced using the assigned matrix layout. - */ - explicit matrix(pointer data); - - /** Construct from a wrapped pointer to a 2D array of values. - * - * @note The dimensions of @c array must match those of the matrix, - * taking the matrix layout into account. For example, the C-array - * initializer for a 3x2 external matrix in row-major layout will have - * dimensions [3][2], but the initializer for a column-major matrix - * will have dimensions [2][3]. - */ - matrix(matrix_data_type& array); - - /** Move constructor. */ - matrix(matrix_type&& other); - - - public: - /** Return access to the matrix data as a raw pointer. */ - pointer data(); - - /** Return const access to the matrix data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator over the elements as a 1D array. */ - const_pointer begin() const; - - /** Read-only iterator over the elements as a 1D array. */ - const_pointer end() const; - - - public: - /** Copy assignment. */ - matrix_type& operator=(const matrix_type& other); - - /** Move assignment. */ - matrix_type& operator=(matrix_type&& other); - - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the number of rows. */ - int i_rows() const; - - /** Return the number of columns. */ - int i_cols() const; - - /** Return matrix const element @c (i,j). */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** @name writeable_matrix Interface */ - /*@{*/ - - friend writable_type; - - /** Return matrix element @c (i,j). */ - mutable_value i_get(int i, int j); - - /** Set element @c i. */ - template - matrix_type& i_put(int i, int j, const Other& v) &; - - /** Set element @c i on a temporary. */ - template matrix_type&& i_put(int i, int j, const Other& v) &&; - - /*@}*/ - - - protected: - /** Row-major access to const or non-const @c M. */ - template - inline static auto s_access(Matrix& M, int i, int j, row_major) - -> decltype((*M.m_data)[0][0]) - { - return (*M.m_data)[i][j]; - } - - /** Column-major access to const or non-const @c M. */ - template - inline static auto s_access(Matrix& M, int i, int j, col_major) - -> decltype((*M.m_data)[0][0]) - { - return (*M.m_data)[j][i]; - } - - - protected: - /** Wrapped pointer. */ - matrix_data_type* m_data; -}; - -} // namespace cml - -#define __CML_MATRIX_FIXED_EXTERNAL_TPP -#include -#undef __CML_MATRIX_FIXED_EXTERNAL_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template +struct matrix_traits, BasisOrient, Layout>> +{ + /* The basis must be col_basis or row_basis: */ + static_assert(std::is_same::value + || std::is_same::value, + "invalid basis"); + + /* Traits and types for the matrix element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The matrix storage type: */ + using storage_type = rebind_t, matrix_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array rows (should be positive): */ + static const int array_rows = storage_type::array_rows; + static_assert(array_rows > 0, "invalid row size"); + + /* Array columns (should be positive): */ + static const int array_cols = storage_type::array_cols; + static_assert(array_cols > 0, "invalid column size"); + + /* Basis orientation: */ + using basis_tag = BasisOrient; + + /* Layout: */ + using layout_tag = Layout; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; +}; + +/** Fixed-size matrix. */ +template +class matrix, BasisOrient, Layout> +: public writable_matrix< + matrix, BasisOrient, Layout>> +{ + public: + using matrix_type = matrix, BasisOrient, Layout>; + using readable_type = readable_matrix; + using writable_type = writable_matrix; + using traits_type = matrix_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /** The matrix data type, depending upon the layout. */ + using matrix_data_type = if_t; + + + public: + /* Include methods from writable_type: */ + using writable_type::operator(); + using writable_type::operator=; + + + public: + /** Constant containing the number of rows. */ + static const int array_rows = traits_type::array_rows; + + /** Constant containing the number of columns. */ + static const int array_cols = traits_type::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + + public: + /** Default construct with a null pointer. + * + * @warning The default constructor is enabled only if the compiler + * supports rvalue references from *this. + */ + matrix(); + + /** Construct from the wrapped pointer. + * + * @note @c data will be referenced using the assigned matrix layout. + */ + explicit matrix(pointer data); + + /** Construct from a wrapped pointer to a 2D array of values. + * + * @note The dimensions of @c array must match those of the matrix, + * taking the matrix layout into account. For example, the C-array + * initializer for a 3x2 external matrix in row-major layout will have + * dimensions [3][2], but the initializer for a column-major matrix + * will have dimensions [2][3]. + */ + matrix(matrix_data_type& array); + + /** Move constructor. */ + matrix(matrix_type&& other); + + + public: + /** Return access to the matrix data as a raw pointer. */ + pointer data(); + + /** Return const access to the matrix data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator over the elements as a 1D array. */ + const_pointer begin() const; + + /** Read-only iterator over the elements as a 1D array. */ + const_pointer end() const; + + + public: + /** Copy assignment. */ + matrix_type& operator=(const matrix_type& other); + + /** Move assignment. */ + matrix_type& operator=(matrix_type&& other); + + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the number of rows. */ + int i_rows() const; + + /** Return the number of columns. */ + int i_cols() const; + + /** Return matrix const element @c (i,j). */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** @name writeable_matrix Interface */ + /*@{*/ + + friend writable_type; + + /** Return matrix element @c (i,j). */ + mutable_value i_get(int i, int j); + + /** Set element @c i. */ + template + matrix_type& i_put(int i, int j, const Other& v) &; + + /** Set element @c i on a temporary. */ + template matrix_type&& i_put(int i, int j, const Other& v) &&; + + /*@}*/ + + + protected: + /** Row-major access to const or non-const @c M. */ + template + inline static auto s_access(Matrix& M, int i, int j, row_major) + -> decltype((*M.m_data)[0][0]) + { + return (*M.m_data)[i][j]; + } + + /** Column-major access to const or non-const @c M. */ + template + inline static auto s_access(Matrix& M, int i, int j, col_major) + -> decltype((*M.m_data)[0][0]) + { + return (*M.m_data)[j][i]; + } + + + protected: + /** Wrapped pointer. */ + matrix_data_type* m_data; +}; + +} // namespace cml + +#define __CML_MATRIX_FIXED_EXTERNAL_TPP +#include +#undef __CML_MATRIX_FIXED_EXTERNAL_TPP diff --git a/cml/matrix/fixed_external.tpp b/cml/matrix/fixed_external.tpp index 9c020d0..4c1aaa0 100644 --- a/cml/matrix/fixed_external.tpp +++ b/cml/matrix/fixed_external.tpp @@ -1,136 +1,136 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_FIXED_EXTERNAL_TPP -# error "matrix/fixed_external.tpp not included correctly" -#endif - -namespace cml { - -/* fixed_external 'structors: */ - -template -matrix, BO, L>::matrix() -: m_data(0) -{ -} - -template -matrix, BO, L>::matrix(pointer data) -: m_data(reinterpret_cast(data)) -{} - -template -matrix, BO, L>::matrix(matrix_data_type& array) -: m_data(&array) -{} - -template -matrix, BO, L>::matrix(matrix_type&& other) -{ - this->operator=(std::move(other)); -} - -/* Public methods: */ - -template -auto -matrix, BO, L>::data() -> pointer -{ - return reinterpret_cast(this->m_data); -} - -template -auto -matrix, BO, L>::data() const -> const_pointer -{ - return reinterpret_cast(this->m_data); -} - -template -auto -matrix, BO, L>::begin() const -> const_pointer -{ - return reinterpret_cast(this->m_data); -} - -template -auto -matrix, BO, L>::end() const -> const_pointer -{ - return reinterpret_cast(this->m_data) + R * C; -} - -template -auto -matrix, BO, L>::operator=(const matrix_type& other) - -> matrix_type& -{ - return this->assign(other); -} - -template -auto -matrix, BO, L>::operator=(matrix_type&& other) -> matrix_type& -{ - this->m_data = other.m_data; - other.m_data = nullptr; - return *this; -} - -/* Internal methods: */ - -/* readable_matrix interface: */ - -template -int -matrix, BO, L>::i_rows() const -{ - return R; -} - -template -int -matrix, BO, L>::i_cols() const -{ - return C; -} - -template -auto -matrix, BO, L>::i_get(int i, int j) const -> immutable_value -{ - return s_access(*this, i, j, layout_tag()); -} - -/* writable_matrix interface: */ - -template -auto -matrix, BO, L>::i_get(int i, int j) -> mutable_value -{ - return s_access(*this, i, j, layout_tag()); -} - -template -template -auto -matrix, BO, L>::i_put(int i, int j, - const Other& v) &->matrix_type& -{ - s_access(*this, i, j, layout_tag()) = value_type(v); - return *this; -} - -template -template -auto -matrix, BO, L>::i_put(int i, int j, - const Other& v) && -> matrix_type&& -{ - s_access(*this, i, j, layout_tag()) = value_type(v); - return (matrix_type&&) *this; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_FIXED_EXTERNAL_TPP +# error "matrix/fixed_external.tpp not included correctly" +#endif + +namespace cml { + +/* fixed_external 'structors: */ + +template +matrix, BO, L>::matrix() +: m_data(0) +{ +} + +template +matrix, BO, L>::matrix(pointer data) +: m_data(reinterpret_cast(data)) +{} + +template +matrix, BO, L>::matrix(matrix_data_type& array) +: m_data(&array) +{} + +template +matrix, BO, L>::matrix(matrix_type&& other) +{ + this->operator=(std::move(other)); +} + +/* Public methods: */ + +template +auto +matrix, BO, L>::data() -> pointer +{ + return reinterpret_cast(this->m_data); +} + +template +auto +matrix, BO, L>::data() const -> const_pointer +{ + return reinterpret_cast(this->m_data); +} + +template +auto +matrix, BO, L>::begin() const -> const_pointer +{ + return reinterpret_cast(this->m_data); +} + +template +auto +matrix, BO, L>::end() const -> const_pointer +{ + return reinterpret_cast(this->m_data) + R * C; +} + +template +auto +matrix, BO, L>::operator=(const matrix_type& other) + -> matrix_type& +{ + return this->assign(other); +} + +template +auto +matrix, BO, L>::operator=(matrix_type&& other) -> matrix_type& +{ + this->m_data = other.m_data; + other.m_data = nullptr; + return *this; +} + +/* Internal methods: */ + +/* readable_matrix interface: */ + +template +int +matrix, BO, L>::i_rows() const +{ + return R; +} + +template +int +matrix, BO, L>::i_cols() const +{ + return C; +} + +template +auto +matrix, BO, L>::i_get(int i, int j) const -> immutable_value +{ + return s_access(*this, i, j, layout_tag()); +} + +/* writable_matrix interface: */ + +template +auto +matrix, BO, L>::i_get(int i, int j) -> mutable_value +{ + return s_access(*this, i, j, layout_tag()); +} + +template +template +auto +matrix, BO, L>::i_put(int i, int j, + const Other& v) &->matrix_type& +{ + s_access(*this, i, j, layout_tag()) = value_type(v); + return *this; +} + +template +template +auto +matrix, BO, L>::i_put(int i, int j, + const Other& v) && -> matrix_type&& +{ + s_access(*this, i, j, layout_tag()) = value_type(v); + return (matrix_type&&) *this; +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/functions.h b/cml/matrix/functions.h index 8b76b33..e2016ab 100644 --- a/cml/matrix/functions.h +++ b/cml/matrix/functions.h @@ -1,11 +1,11 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include diff --git a/cml/matrix/fwd.h b/cml/matrix/fwd.h index 44b60b1..ef0342d 100644 --- a/cml/matrix/fwd.h +++ b/cml/matrix/fwd.h @@ -1,12 +1,12 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -template class readable_matrix; -template class writable_matrix; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +template class readable_matrix; +template class writable_matrix; + +} // namespace cml diff --git a/cml/matrix/hadamard_product.h b/cml/matrix/hadamard_product.h index c9e9c8c..8f303d0 100644 --- a/cml/matrix/hadamard_product.h +++ b/cml/matrix/hadamard_product.h @@ -1,23 +1,23 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Elementwise (Hadamard) product of two matrixs. */ -template* = nullptr, - enable_if_matrix_t* = nullptr> -inline auto -hadamard(Sub1&& sub1, Sub2&& sub2) - -> decltype(make_matrix_binary_node>( - std::forward(sub1), std::forward(sub2))) -{ - return make_matrix_binary_node>( - std::forward(sub1), std::forward(sub2)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Elementwise (Hadamard) product of two matrixs. */ +template* = nullptr, + enable_if_matrix_t* = nullptr> +inline auto +hadamard(Sub1&& sub1, Sub2&& sub2) + -> decltype(make_matrix_binary_node>( + std::forward(sub1), std::forward(sub2))) +{ + return make_matrix_binary_node>( + std::forward(sub1), std::forward(sub2)); +} + +} // namespace cml diff --git a/cml/matrix/inverse.h b/cml/matrix/inverse.h index cd2f82b..6f467df 100644 --- a/cml/matrix/inverse.h +++ b/cml/matrix/inverse.h @@ -1,21 +1,21 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Compute the inverse of @c M and return the result in a temporary. */ -template -inline temporary_of_t -inverse(const readable_matrix& M) -{ - cml::check_square(M); - return temporary_of_t(M).inverse(); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Compute the inverse of @c M and return the result in a temporary. */ +template +inline temporary_of_t +inverse(const readable_matrix& M) +{ + cml::check_square(M); + return temporary_of_t(M).inverse(); +} + +} // namespace cml diff --git a/cml/matrix/lu.h b/cml/matrix/lu.h index 61ef404..4743d96 100644 --- a/cml/matrix/lu.h +++ b/cml/matrix/lu.h @@ -1,125 +1,125 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace cml { - -/** Sepcializable class to hold results from LU decomposition with partial - * pivoting. - */ -template struct lu_pivot_result; - -/** Results from partial-pivoting LU decomposition of a fixed-size matrix. */ -template -struct lu_pivot_result>> -{ - static const int N = array_rows_of_c>::value; - - Matrix lu; - std::array order; - int sign; - - explicit lu_pivot_result(const Matrix& M) - : lu(M) - , order() - {} -}; - -/** Results from partial-pivoting LU decomposition of a dynamic-size matrix. */ -template -struct lu_pivot_result>> -{ - Matrix lu; - std::vector order; - int sign; - - explicit lu_pivot_result(const Matrix& M) - : lu(M) - , order(M.rows()) - {} -}; - - -/** Compute the LU decomposition of M, with partial pivoting. The result - * is returned in an lu_pivot_result. - * - * @note if @c result.sign is 0, the input matrix is singular. - */ -template -auto lu_pivot(const readable_matrix& M) - -> lu_pivot_result>; - -/** In-place computation of the partial-pivoting LU decomposition of @c - * result.lu. - * - * @note if @c result.sign is 0, the input matrix is singular. - */ -template void lu_pivot(lu_pivot_result& result); - -/** Compute the LU decomposition of @c M using Doolittle's method, - * returning the result as a temporary matrix. - * - * @warning Without pivoting, this is numerically stable only for - * diagonally dominant matrices. - * - * @note This is for compatibility with CML1. - */ -template -auto lu(const readable_matrix& M) -> temporary_of_t; - - -/** Solve @c LUx = @c y for @c x, and return @c x as a temporary - * vector. @c LU must be a square LU decomposition, and @c y must have the - * same number of elements as @c LU has rows. - * - * @note This is for compatibility with CML1. - */ -template -auto lu_solve(const readable_matrix& LU, const readable_vector& y) - -> temporary_of_t; - -/** Solve @c LUx = @c b for @c x. @c LU must be a square LU - * decomposition, and @c y and @c x must have the same number of elements - * as @c LU has rows. - */ -template -void lu_solve(const readable_matrix& LU, writable_vector& x, - const readable_vector& b); - -/** Solve @c LUx = @c Pb for @c x, where the partial-pivot LU - * decomposition is provided as lu_pivot_result, and @c x is returned as a - * vector temporary. @c b must have the same number of elements as @c - * lup.lu has rows. - * - * @throws std::invalid_argument @c lup.sign is 0. - */ -template -auto lu_solve(const lu_pivot_result& lup, - const readable_vector& b) -> temporary_of_t; - -/** Solve @c LUx = @c Pb for @c x, where the partial-pivot LU - * decomposition is provided as lu_pivot_result. @c b and @c x must have - * the same number of elements as @c lup.lu has rows. - * - * @note @c x can be the same vector as @c b. - * - * @throws std::invalid_argument @c lup.sign is 0. - */ -template -void lu_solve(const lu_pivot_result& lup, writable_vector& x, - const readable_vector& b); - -} // namespace cml - -#define __CML_MATRIX_LU_TPP -#include -#undef __CML_MATRIX_LU_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Sepcializable class to hold results from LU decomposition with partial + * pivoting. + */ +template struct lu_pivot_result; + +/** Results from partial-pivoting LU decomposition of a fixed-size matrix. */ +template +struct lu_pivot_result>> +{ + static const int N = array_rows_of_c>::value; + + Matrix lu; + std::array order; + int sign; + + explicit lu_pivot_result(const Matrix& M) + : lu(M) + , order() + {} +}; + +/** Results from partial-pivoting LU decomposition of a dynamic-size matrix. */ +template +struct lu_pivot_result>> +{ + Matrix lu; + std::vector order; + int sign; + + explicit lu_pivot_result(const Matrix& M) + : lu(M) + , order(M.rows()) + {} +}; + + +/** Compute the LU decomposition of M, with partial pivoting. The result + * is returned in an lu_pivot_result. + * + * @note if @c result.sign is 0, the input matrix is singular. + */ +template +auto lu_pivot(const readable_matrix& M) + -> lu_pivot_result>; + +/** In-place computation of the partial-pivoting LU decomposition of @c + * result.lu. + * + * @note if @c result.sign is 0, the input matrix is singular. + */ +template void lu_pivot(lu_pivot_result& result); + +/** Compute the LU decomposition of @c M using Doolittle's method, + * returning the result as a temporary matrix. + * + * @warning Without pivoting, this is numerically stable only for + * diagonally dominant matrices. + * + * @note This is for compatibility with CML1. + */ +template +auto lu(const readable_matrix& M) -> temporary_of_t; + + +/** Solve @c LUx = @c y for @c x, and return @c x as a temporary + * vector. @c LU must be a square LU decomposition, and @c y must have the + * same number of elements as @c LU has rows. + * + * @note This is for compatibility with CML1. + */ +template +auto lu_solve(const readable_matrix& LU, const readable_vector& y) + -> temporary_of_t; + +/** Solve @c LUx = @c b for @c x. @c LU must be a square LU + * decomposition, and @c y and @c x must have the same number of elements + * as @c LU has rows. + */ +template +void lu_solve(const readable_matrix& LU, writable_vector& x, + const readable_vector& b); + +/** Solve @c LUx = @c Pb for @c x, where the partial-pivot LU + * decomposition is provided as lu_pivot_result, and @c x is returned as a + * vector temporary. @c b must have the same number of elements as @c + * lup.lu has rows. + * + * @throws std::invalid_argument @c lup.sign is 0. + */ +template +auto lu_solve(const lu_pivot_result& lup, + const readable_vector& b) -> temporary_of_t; + +/** Solve @c LUx = @c Pb for @c x, where the partial-pivot LU + * decomposition is provided as lu_pivot_result. @c b and @c x must have + * the same number of elements as @c lup.lu has rows. + * + * @note @c x can be the same vector as @c b. + * + * @throws std::invalid_argument @c lup.sign is 0. + */ +template +void lu_solve(const lu_pivot_result& lup, writable_vector& x, + const readable_vector& b); + +} // namespace cml + +#define __CML_MATRIX_LU_TPP +#include +#undef __CML_MATRIX_LU_TPP diff --git a/cml/matrix/lu.tpp b/cml/matrix/lu.tpp index 108d358..4e9eafb 100644 --- a/cml/matrix/lu.tpp +++ b/cml/matrix/lu.tpp @@ -1,142 +1,142 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_LU_TPP -# error "matrix/lu.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -template -inline auto -lu_pivot(const readable_matrix& M) -> lu_pivot_result> -{ - cml::check_square(M); - lu_pivot_result> result(M); - result.sign = detail::lu_pivot_inplace(result.lu, result.order); - return result; -} - -template -inline void -lu_pivot(lu_pivot_result& result) -{ - cml::check_square(result.lu); - result.sign = detail::lu_pivot_inplace(result.lu, result.order); -} - -template -inline auto -lu(const readable_matrix& M) -> temporary_of_t -{ - cml::check_square(M); - temporary_of_t LU(M); - detail::lu_inplace(LU); - return LU; -} - -template -inline auto -lu_solve(const readable_matrix& LU, const readable_vector& b) - -> temporary_of_t -{ - temporary_of_t x; - detail::check_or_resize(x, b); - lu_solve(LU, x, b); - return x; -} - -template -inline void -lu_solve(const readable_matrix& LU, writable_vector& x, - const readable_vector& b) -{ - using value_type = value_type_trait_of_t; - - cml::check_square(LU); - cml::check_same_inner_size(LU, x); - cml::check_same_inner_size(LU, b); - - int N = b.size(); - - /* Solve Ly = b for y by forward substitution. The entries below the - * diagonal of LU correspond to L, understood to be below a diagonal of - * 1's: - */ - temporary_of_t y; - detail::check_or_resize(y, b); - for(int i = 0; i < N; ++i) { - value_type sum(0); - for(int j = 0; j < i; ++j) sum += LU(i, j) * y[j]; - y[i] = b[i] - sum; - } - - /* Solve Ux = y for x by backward substitution. The entries at and above - * the diagonal of LU correspond to U: - */ - for(int i = N - 1; i >= 0; --i) { - value_type sum(0); - for(int j = i + 1; j < N; ++j) sum += LU(i, j) * x[j]; - x[i] = (y[i] - sum) / LU(i, i); - } - - /* Done. */ -} - -template -inline auto -lu_solve(const lu_pivot_result& lup, const readable_vector& b) - -> temporary_of_t -{ - temporary_of_t x; - detail::check_or_resize(x, b); - lu_solve(lup, x, b); - return x; -} - -template -inline void -lu_solve(const lu_pivot_result& lup, writable_vector& x, - const readable_vector& b) -{ - using value_type = value_type_trait_of_t; - - cml::check_same_inner_size(lup.lu, x); - cml::check_same_inner_size(lup.lu, b); - cml_require(lup.sign != 0, std::invalid_argument, - "lup.sign == 0 (singular matrix?)"); - - int N = b.size(); - const auto& LU = lup.lu; - const auto& P = lup.order; - - /* Solve Ly = Pb for c by forward substitution. The entries below the - * diagonal of LU correspond to L, understood to be below a diagonal of - * 1's: - */ - temporary_of_t y; - detail::check_or_resize(y, b); - for(int i = 0; i < N; ++i) { - value_type sum(0); - for(int j = 0; j < i; ++j) sum += LU(i, j) * y[j]; - y[i] = b[P[i]] - sum; - } - - /* Solve Ux = c for x by backward substitution. The entries at and above - * the diagonal of LU correspond to U: - */ - for(int i = N - 1; i >= 0; --i) { - value_type sum(0); - for(int j = i + 1; j < N; ++j) sum += LU(i, j) * x[j]; - x[i] = (y[i] - sum) / LU(i, i); - } - - /* Done. */ -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_LU_TPP +# error "matrix/lu.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +template +inline auto +lu_pivot(const readable_matrix& M) -> lu_pivot_result> +{ + cml::check_square(M); + lu_pivot_result> result(M); + result.sign = detail::lu_pivot_inplace(result.lu, result.order); + return result; +} + +template +inline void +lu_pivot(lu_pivot_result& result) +{ + cml::check_square(result.lu); + result.sign = detail::lu_pivot_inplace(result.lu, result.order); +} + +template +inline auto +lu(const readable_matrix& M) -> temporary_of_t +{ + cml::check_square(M); + temporary_of_t LU(M); + detail::lu_inplace(LU); + return LU; +} + +template +inline auto +lu_solve(const readable_matrix& LU, const readable_vector& b) + -> temporary_of_t +{ + temporary_of_t x; + detail::check_or_resize(x, b); + lu_solve(LU, x, b); + return x; +} + +template +inline void +lu_solve(const readable_matrix& LU, writable_vector& x, + const readable_vector& b) +{ + using value_type = value_type_trait_of_t; + + cml::check_square(LU); + cml::check_same_inner_size(LU, x); + cml::check_same_inner_size(LU, b); + + int N = b.size(); + + /* Solve Ly = b for y by forward substitution. The entries below the + * diagonal of LU correspond to L, understood to be below a diagonal of + * 1's: + */ + temporary_of_t y; + detail::check_or_resize(y, b); + for(int i = 0; i < N; ++i) { + value_type sum(0); + for(int j = 0; j < i; ++j) sum += LU(i, j) * y[j]; + y[i] = b[i] - sum; + } + + /* Solve Ux = y for x by backward substitution. The entries at and above + * the diagonal of LU correspond to U: + */ + for(int i = N - 1; i >= 0; --i) { + value_type sum(0); + for(int j = i + 1; j < N; ++j) sum += LU(i, j) * x[j]; + x[i] = (y[i] - sum) / LU(i, i); + } + + /* Done. */ +} + +template +inline auto +lu_solve(const lu_pivot_result& lup, const readable_vector& b) + -> temporary_of_t +{ + temporary_of_t x; + detail::check_or_resize(x, b); + lu_solve(lup, x, b); + return x; +} + +template +inline void +lu_solve(const lu_pivot_result& lup, writable_vector& x, + const readable_vector& b) +{ + using value_type = value_type_trait_of_t; + + cml::check_same_inner_size(lup.lu, x); + cml::check_same_inner_size(lup.lu, b); + cml_require(lup.sign != 0, std::invalid_argument, + "lup.sign == 0 (singular matrix?)"); + + int N = b.size(); + const auto& LU = lup.lu; + const auto& P = lup.order; + + /* Solve Ly = Pb for c by forward substitution. The entries below the + * diagonal of LU correspond to L, understood to be below a diagonal of + * 1's: + */ + temporary_of_t y; + detail::check_or_resize(y, b); + for(int i = 0; i < N; ++i) { + value_type sum(0); + for(int j = 0; j < i; ++j) sum += LU(i, j) * y[j]; + y[i] = b[P[i]] - sum; + } + + /* Solve Ux = c for x by backward substitution. The entries at and above + * the diagonal of LU correspond to U: + */ + for(int i = N - 1; i >= 0; --i) { + value_type sum(0); + for(int j = i + 1; j < N; ++j) sum += LU(i, j) * x[j]; + x[i] = (y[i] - sum) / LU(i, i); + } + + /* Done. */ +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/matrix.h b/cml/matrix/matrix.h index e934dfc..5d924c5 100644 --- a/cml/matrix/matrix.h +++ b/cml/matrix/matrix.h @@ -1,40 +1,40 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Specializable class for building vector types. - * - * This class encapsulates the notion of a matrix. - * - * @tparam Element The scalar type for matrix elements, with the following - * operators defined: +, -, *, /, <, >, ==, = (assign). - * - * @tparam StorageType Storage type to use for holding the 2D array of - * matrix elements. - * - * @tparam BasisOrient Encodes whether basis vectors for the matrix type - * lie along rows or columns. The default is col_basis, which is typical - * in mathematics expositions, and implies that transformation matrices - * pre-multiply vectors. The opposite, row_basis, appears most frequently - * in graphics, and implies that transformation matrices post-multiple - * vectors. - * - * @tparam Layout Encodes whether rows or columns are physically contiguous - * in memory. The default is row_major, which is equivalent to the layout - * of 2D arrays in C. The opposite, col_major, is equivalent to the layout - * of 2D arrays in Fortran. - * - * @sa scalar_traits - */ -template -class matrix; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Specializable class for building vector types. + * + * This class encapsulates the notion of a matrix. + * + * @tparam Element The scalar type for matrix elements, with the following + * operators defined: +, -, *, /, <, >, ==, = (assign). + * + * @tparam StorageType Storage type to use for holding the 2D array of + * matrix elements. + * + * @tparam BasisOrient Encodes whether basis vectors for the matrix type + * lie along rows or columns. The default is col_basis, which is typical + * in mathematics expositions, and implies that transformation matrices + * pre-multiply vectors. The opposite, row_basis, appears most frequently + * in graphics, and implies that transformation matrices post-multiple + * vectors. + * + * @tparam Layout Encodes whether rows or columns are physically contiguous + * in memory. The default is row_major, which is equivalent to the layout + * of 2D arrays in C. The opposite, col_major, is equivalent to the layout + * of 2D arrays in Fortran. + * + * @sa scalar_traits + */ +template +class matrix; + +} // namespace cml diff --git a/cml/matrix/matrix_product.h b/cml/matrix/matrix_product.h index 44f2869..9ee96fd 100644 --- a/cml/matrix/matrix_product.h +++ b/cml/matrix/matrix_product.h @@ -6,15 +6,15 @@ #include #include +#include namespace cml { -/** Multiply two matrices, and return the result as a temporary. */ -template* = nullptr, - enable_if_matrix_t* = nullptr> -auto operator*(Sub1&& sub1, Sub2&& sub2) - -> matrix_inner_product_promote_t, - actual_operand_type_of_t>; +/** Multiply two matrices and return the result as a temporary. */ +template, + typename = enable_if_matrix_t> +auto operator*(Sub1&& sub1, Sub2&& sub2) -> matrix_inner_product_promote_t< + actual_type_of_t, actual_type_of_t>; } // namespace cml diff --git a/cml/matrix/matrix_product.tpp b/cml/matrix/matrix_product.tpp index 959737b..2a0eb02 100644 --- a/cml/matrix/matrix_product.tpp +++ b/cml/matrix/matrix_product.tpp @@ -8,19 +8,17 @@ #include -namespace cml { +namespace cml::detail { -template*, - enable_if_matrix_t*> +/* Default matrix product. */ +template inline auto -operator*(Sub1&& sub1, Sub2&& sub2) - -> matrix_inner_product_promote_t, - actual_operand_type_of_t> +matrix_product(const Sub1& sub1, + const Sub2& sub2) -> matrix_inner_product_promote_t, + actual_type_of_t> { - using result_type = matrix_inner_product_promote_t< - actual_operand_type_of_t, - actual_operand_type_of_t>; - + using result_type = matrix_inner_product_promote_t, + actual_type_of_t>; cml::check_same_inner_size(sub1, sub2); result_type M; @@ -35,4 +33,226 @@ operator*(Sub1&& sub1, Sub2&& sub2) return M; } -} // namespace cml \ No newline at end of file +} // namespace cml::detail + +#ifndef CML_DISABLE_SIMD +# ifdef _MSC_VER +# include +# if defined(__AVX2__) +# define CML_SIMD_AVX2 +# endif +# endif +#endif + +#ifdef CML_SIMD_AVX2 +# include + +namespace cml::detail { + +/* AVX2 4x4 float row-major matrix product. */ +template +inline auto +matrix_product( + // clang-format off + const matrix, Basis1, row_major>& sub1, + const matrix, Basis2, row_major>& sub2 + // clang-format on + ) -> matrix, basis_tag_promote_t, + row_major> +{ + using result_type = matrix, + basis_tag_promote_t, row_major>; + + const auto* A = sub1.data(); + const auto* B = sub2.data(); + + /* Cache sub2: */ + const __m128 B0 = _mm_loadu_ps(B + (0 << 2)); + const __m128 B1 = _mm_loadu_ps(B + (1 << 2)); + const __m128 B2 = _mm_loadu_ps(B + (2 << 2)); + const __m128 B3 = _mm_loadu_ps(B + (3 << 2)); + + __m128 row[4]; + for(uint32_t i = 0; i < 4; ++i) { + /* row[0..3] = A[i][0] * B[0][0..3] */ + row[i] = _mm_mul_ps(_mm_broadcast_ss(A + (i << 2) + 0), B0); + + /* row[0..3] += A[i][1] * B[1][0..3] */ + row[i] = _mm_fmadd_ps(_mm_broadcast_ss(A + (i << 2) + 1), B1, row[i]); + + /* row[0..3] += A[i][2] * B[2][0..3] */ + row[i] = _mm_fmadd_ps(_mm_broadcast_ss(A + (i << 2) + 2), B2, row[i]); + + /* row[0..3] += A[i][3] * B[3][0..3] */ + row[i] = _mm_fmadd_ps(_mm_broadcast_ss(A + (i << 2) + 3), B3, row[i]); + } + + /* result[i] = row[i] */ + result_type result; + auto* M = result.data(); + for(uint32_t i = 0; i < 4; ++i) { + _mm_storeu_ps(M + (i << 2), row[i]); + } + + return result; +} + +/* AVX2 4x4 float col-major matrix product. */ +template +inline auto +matrix_product( + // clang-format off + const matrix, Basis1, col_major>& sub1, + const matrix, Basis2, col_major>& sub2 + // clang-format on + ) -> matrix, basis_tag_promote_t, + col_major> +{ + using result_type = matrix, + basis_tag_promote_t, col_major>; + + const auto* A = sub1.data(); + const auto* B = sub2.data(); + + /* Cache sub1: */ + const __m128 A0 = _mm_loadu_ps(A + (0 << 2)); + const __m128 A1 = _mm_loadu_ps(A + (1 << 2)); + const __m128 A2 = _mm_loadu_ps(A + (2 << 2)); + const __m128 A3 = _mm_loadu_ps(A + (3 << 2)); + + __m128 col[4]; + for(uint32_t j = 0; j < 4; ++j) { + /* col[0..3] = A[0..3][j] * B[j][0] */ + col[j] = _mm_mul_ps(A0, _mm_broadcast_ss(B + (j << 2) + 0)); + + /* col[0..3] += A[0..3][j] * B[j][1] */ + col[j] = _mm_fmadd_ps(A1, _mm_broadcast_ss(B + (j << 2) + 1), col[j]); + + /* col[0..3] += A[0..3][j] * B[j][2] */ + col[j] = _mm_fmadd_ps(A2, _mm_broadcast_ss(B + (j << 2) + 2), col[j]); + + /* col[0..3] += A[0..3][j] * B[j][3] */ + col[j] = _mm_fmadd_ps(A3, _mm_broadcast_ss(B + (j << 2) + 3), col[j]); + } + + /* result[j] = col[j] */ + result_type result; + auto* M = result.data(); + for(uint32_t j = 0; j < 4; ++j) { + _mm_storeu_ps(M + (j << 2), col[j]); + } + + return result; +} + +/* AVX2 4x4 double row-major matrix product. */ +template +inline auto +matrix_product( + // clang-format off + const matrix, Basis1, row_major>& sub1, + const matrix, Basis2, row_major>& sub2 + // clang-format on + ) -> matrix, basis_tag_promote_t, + row_major> +{ + using result_type = matrix, + basis_tag_promote_t, row_major>; + + const auto* A = sub1.data(); + const auto* B = sub2.data(); + + /* Cache sub2: */ + const __m256d B0 = _mm256_loadu_pd(B + (0 << 2)); + const __m256d B1 = _mm256_loadu_pd(B + (1 << 2)); + const __m256d B2 = _mm256_loadu_pd(B + (2 << 2)); + const __m256d B3 = _mm256_loadu_pd(B + (3 << 2)); + + __m256d row[4]; + for(uint32_t i = 0; i < 4; ++i) { + /* row[0..3] = A[i][0] * B[0][0..3] */ + row[i] = _mm256_mul_pd(_mm256_broadcast_sd(A + (i << 2) + 0), B0); + + /* row[0..3] += A[i][1] * B[1][0..3] */ + row[i] = _mm256_fmadd_pd(_mm256_broadcast_sd(A + (i << 2) + 1), B1, row[i]); + + /* row[0..3] += A[i][2] * B[2][0..3] */ + row[i] = _mm256_fmadd_pd(_mm256_broadcast_sd(A + (i << 2) + 2), B2, row[i]); + + /* row[0..3] += A[i][3] * B[3][0..3] */ + row[i] = _mm256_fmadd_pd(_mm256_broadcast_sd(A + (i << 2) + 3), B3, row[i]); + } + + /* result[i] = row[i] */ + result_type result; + auto* M = result.data(); + for(uint32_t i = 0; i < 4; ++i) { + _mm256_storeu_pd(M + (i << 2), row[i]); + } + + return result; +} + +/* AVX2 4x4 double col-major matrix product. */ +template +inline auto +matrix_product( + // clang-format off + const matrix, Basis1, col_major>& sub1, + const matrix, Basis2, col_major>& sub2 + // clang-format on + ) -> matrix, basis_tag_promote_t, + col_major> +{ + using result_type = matrix, + basis_tag_promote_t, col_major>; + + const auto* A = sub1.data(); + const auto* B = sub2.data(); + + /* Cache sub1: */ + const __m256d A0 = _mm256_loadu_pd(A + (0 << 2)); + const __m256d A1 = _mm256_loadu_pd(A + (1 << 2)); + const __m256d A2 = _mm256_loadu_pd(A + (2 << 2)); + const __m256d A3 = _mm256_loadu_pd(A + (3 << 2)); + + __m256d col[4]; + for(uint32_t j = 0; j < 4; ++j) { + /* col[0..3] = A[0..3][j] * B[j][0] */ + col[j] = _mm256_mul_pd(A0, _mm256_broadcast_sd(B + (j << 2) + 0)); + + /* col[0..3] += A[0..3][j] * B[j][1] */ + col[j] = _mm256_fmadd_pd(A1, _mm256_broadcast_sd(B + (j << 2) + 1), col[j]); + + /* col[0..3] += A[0..3][j] * B[j][2] */ + col[j] = _mm256_fmadd_pd(A2, _mm256_broadcast_sd(B + (j << 2) + 2), col[j]); + + /* col[0..3] += A[0..3][j] * B[j][3] */ + col[j] = _mm256_fmadd_pd(A3, _mm256_broadcast_sd(B + (j << 2) + 3), col[j]); + } + + /* result[j] = col[j] */ + result_type result; + auto* M = result.data(); + for(uint32_t j = 0; j < 4; ++j) { + _mm256_storeu_pd(M + (j << 2), col[j]); + } + + return result; +} + +} // namespace cml::detail +#endif + +namespace cml { + +template +inline auto +operator*(Sub1&& sub1, Sub2&& sub2) -> matrix_inner_product_promote_t< + actual_type_of_t, actual_type_of_t> +{ + return detail::matrix_product(std::forward(sub1), + std::forward(sub2)); +} + +} // namespace cml diff --git a/cml/matrix/ops.h b/cml/matrix/ops.h index 610ce06..4afc75b 100644 --- a/cml/matrix/ops.h +++ b/cml/matrix/ops.h @@ -1,9 +1,9 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include diff --git a/cml/matrix/promotion.h b/cml/matrix/promotion.h index 271f7e3..7b184b2 100644 --- a/cml/matrix/promotion.h +++ b/cml/matrix/promotion.h @@ -1,313 +1,313 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cml { - -/** Determine an appropriate storage type to use when combining matrix - * expressions via a pairwise binary operator. - * - * @note This can be specialized to accomodate user-defined storage types. - */ -template struct matrix_binary_storage_promote -{ - static_assert( - is_matrix_storage::value && is_matrix_storage::value, - "expected matrix storage types for binary promotion"); - - /* Determine the common unbound storage type: */ - using unbound_type = storage_promote_t; - - /* Determine the new row size: */ - static const int array_rows = Storage1::array_rows > Storage2::array_rows - ? Storage1::array_rows - : Storage2::array_rows; - - /* Determine the new column size: */ - static const int array_cols = Storage1::array_cols > Storage2::array_cols - ? Storage1::array_cols - : Storage2::array_cols; - - /* Resize: */ - using resized_type = reshape_storage_t; - - /* Rebind to a matrix storage type: */ - using type = rebind_matrix_storage_t; -}; - -/** Convenience alias for matrix_binary_storage_promote. */ -template -using matrix_binary_storage_promote_t = - typename matrix_binary_storage_promote::type; - - -/** Specializable class to determine a temporary type that can store the - * result of matrix/matrix or matrix/vector products. - */ -template -struct matrix_inner_product_promote; - -/** Determine a matrix temporary type that can hold the result of - * multiplying two matrix expressions @c Sub1 and @c Sub2. - */ -template -struct matrix_inner_product_promote::value - && is_matrix::value>::type> -{ - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = matrix_traits; - using right_traits = matrix_traits; - using left_value_type = value_type_of_t; - using right_value_type = value_type_of_t; - using left_storage_type = storage_type_of_t; - using right_storage_type = storage_type_of_t; - - /* Deduce the element type: */ - using value_type = value_type_trait_promote_t; - - /* Determine the common unbound storage type from the bound proxy types, - * preferring a dynamic-size type unless the resulting matrix can be - * fixed-size: - */ - using left_proxy_type = rebind_matrix_storage_t>; - using right_proxy_type = rebind_matrix_storage_t>; - static const int left_rows = left_proxy_type::array_rows; - static const int right_cols = right_proxy_type::array_cols; - static const bool is_fixed = left_rows > 0 && right_cols > 0; - using unbound_type = storage_promote_t; - - /* Determine the new matrix size: */ - static const int array_rows = is_fixed ? left_rows : -1; - static const int array_cols = is_fixed ? right_cols : -1; - - /* Determine the unbound proxy type: */ - using resized_type = reshape_storage_t; - using proxy_type = proxy_type_of_t>; - - /* Determine the common basis type: */ - using basis_tag = basis_tag_promote_t, - basis_tag_of_t>; - - /* Determine the common layout type: */ - using layout_tag = layout_tag_promote_t, - layout_tag_of_t>; - - /* Build the temporary: */ - using type = matrix; -}; - -/** Determine a matrix temporary type that can hold the result of - * multiplying two matrix expressions @c Sub1 and @c Sub2. - */ -template -struct matrix_inner_product_promote::value && is_matrix::value) - || (is_matrix::value && is_vector::value)>::type> -{ - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - - /* Figure out if pre- or post-multiplying: */ - static const bool left_is_vector = is_vector::value; - static const bool right_is_vector = is_vector::value; - static_assert(left_is_vector ^ right_is_vector, "unexpected expression"); - - /* Vector traits and types: */ - using vector_type = cml::if_t; - using vector_traits = traits_of_t; - using vector_value_type = value_type_of_t; - using vector_storage_type = storage_type_of_t; - - /* Matrix traits and types: */ - using matrix_type = cml::if_t; - using matrix_traits = traits_of_t; - using matrix_value_type = value_type_of_t; - using matrix_storage_type = storage_type_of_t; - - /* Deduce the element type: */ - using value_type = value_type_trait_promote_t; - - /* The resulting vector size comes from the bound matrix proxy rows or - * columns, depending on pre- or post-multiplication: - */ - using matrix_unbound_type = proxy_type_of_t; - using matrix_proxy_type = rebind_matrix_storage_t; - static const int array_size = left_is_vector - ? matrix_proxy_type::array_cols - : matrix_proxy_type::array_rows; - - /* Determine the unbound and bound vector proxy types by resizing the - * original vector storage type: - */ - using vector_resized_type = rebind_vector_storage_t< - resize_storage_t>; - using vector_unbound_type = proxy_type_of_t; - using vector_proxy_type = rebind_vector_storage_t; - /* Note: two rebinds are needed here, first to get the unbound proxy - * type, then to get the bound proxy type for sizing. - */ - - /* Determine the common unbound storage type from the bound proxy types, - * preferring a dynamic-size type unless the resulting vector can be - * fixed-size: - */ - static const bool is_fixed = array_size > 0; - using unbound_type = storage_promote_t; - using resized_type = resize_storage_t; - - /* Prefer the unbound vector proxy type when possible: */ - using proxy_type = cml::if_t< - /**/ (is_fixed&& is_fixed_size::value) - || (!is_fixed && is_dynamic_size::value), - vector_unbound_type, resized_type>; - - /* Build the temporary: */ - using type = vector; -}; - -/** Convenience alias for matrix_inner_product_promote. */ -template -using matrix_inner_product_promote_t = - typename matrix_inner_product_promote::type; - -template -struct matrix_outer_product_storage_promote -{ - static_assert( - is_vector_storage::value && is_vector_storage::value, - "expected vector storage types for outer product promotion"); - - /* Deduce the left matrix storage type from the vector storage: */ - static const int left_size = Storage1::array_size; - using left_unbound_type = reshape_storage_t; - using left_storage_type = rebind_matrix_storage_t; - - /* Deduce the right matrix storage type from the vector storage: */ - static const int right_size = Storage2::array_size; - using right_unbound_type = reshape_storage_t; - using right_storage_type = rebind_matrix_storage_t; - - /* Determine the common storage type, based on the storage types of its - * subexpressions: - */ - using type = matrix_binary_storage_promote_t; -}; - -/** Convenience alias for matrix_outer_product_promote. */ -template -using matrix_outer_product_storage_promote_t = - typename matrix_outer_product_storage_promote::type; - - -/** Specializable class to determine a temporary type that can store the - * result of vector outer products. - */ -template -struct matrix_outer_product_promote; - -/** Determine a matrix temporary type that can hold the result of the outer - * product of two vector expressions @c Sub1 and @c Sub2. - * - * @note The temporary will - */ -template -struct matrix_outer_product_promote::value - && is_vector::value)>::type> -{ - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = vector_traits; - using right_traits = vector_traits; - - /* Deduce the element type: */ - using value_type = value_type_promote_t; - - /* Determine the common storage type for the temporary, based on the - * storage types of its subexpressions: - */ - using left_storage_type = storage_type_of_t; - using right_storage_type = storage_type_of_t; - using storage_type = matrix_outer_product_storage_promote_t; - using proxy_type = proxy_type_of_t; - - /* Build the temporary: */ - using type = matrix; -}; - -/** Convenience alias for matrix_outer_product_promote. */ -template -using matrix_outer_product_promote_t = - typename matrix_outer_product_promote::type; - - -/** Determine the row vector temporary type for matrix type @c Sub. */ -template struct row_type_of; - -template -struct row_type_of::value>::type> -{ - /* Matrix traits and types: */ - using matrix_type = cml::unqualified_type_t; - using matrix_traits = cml::traits_of_t; - using matrix_storage_type = cml::storage_type_of_t; - using value_type = cml::value_type_of_t; - - /* The vector proxy type and size comes from the matrix proxy type: */ - using unbound_type = cml::proxy_type_of_t; - using proxy_type = cml::rebind_matrix_storage_t; - static const int array_size = proxy_type::array_cols; - using vector_type = cml::resize_storage_t; - - /* Build the temporary: */ - using type = cml::vector; -}; - -/** Convenience alias for row_type_of. */ -template using row_type_of_t = typename row_type_of::type; - - -/** Determine the column vector temporary type for matrix type @c Sub. */ -template struct col_type_of; - -template -struct col_type_of::value>::type> -{ - /* Matrix traits and types: */ - using matrix_type = cml::unqualified_type_t; - using matrix_traits = cml::traits_of_t; - using matrix_storage_type = cml::storage_type_of_t; - using value_type = cml::value_type_of_t; - - /* The vector proxy type and size comes from the matrix proxy type: */ - using unbound_type = cml::proxy_type_of_t; - using proxy_type = cml::rebind_matrix_storage_t; - static const int array_size = proxy_type::array_rows; - using vector_type = cml::resize_storage_t; - - /* Build the temporary: */ - using type = cml::vector; -}; - -/** Convenience alias for col_type_of. */ -template using col_type_of_t = typename col_type_of::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Determine an appropriate storage type to use when combining matrix + * expressions via a pairwise binary operator. + * + * @note This can be specialized to accomodate user-defined storage types. + */ +template struct matrix_binary_storage_promote +{ + static_assert( + is_matrix_storage::value && is_matrix_storage::value, + "expected matrix storage types for binary promotion"); + + /* Determine the common unbound storage type: */ + using unbound_type = storage_promote_t; + + /* Determine the new row size: */ + static const int array_rows = Storage1::array_rows > Storage2::array_rows + ? Storage1::array_rows + : Storage2::array_rows; + + /* Determine the new column size: */ + static const int array_cols = Storage1::array_cols > Storage2::array_cols + ? Storage1::array_cols + : Storage2::array_cols; + + /* Resize: */ + using resized_type = reshape_storage_t; + + /* Rebind to a matrix storage type: */ + using type = rebind_matrix_storage_t; +}; + +/** Convenience alias for matrix_binary_storage_promote. */ +template +using matrix_binary_storage_promote_t = + typename matrix_binary_storage_promote::type; + + +/** Specializable class to determine a temporary type that can store the + * result of matrix/matrix or matrix/vector products. + */ +template +struct matrix_inner_product_promote; + +/** Determine a matrix temporary type that can hold the result of + * multiplying two matrix expressions @c Sub1 and @c Sub2. + */ +template +struct matrix_inner_product_promote::value + && is_matrix::value>::type> +{ + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = matrix_traits; + using right_traits = matrix_traits; + using left_value_type = value_type_of_t; + using right_value_type = value_type_of_t; + using left_storage_type = storage_type_of_t; + using right_storage_type = storage_type_of_t; + + /* Deduce the element type: */ + using value_type = value_type_trait_promote_t; + + /* Determine the common unbound storage type from the bound proxy types, + * preferring a dynamic-size type unless the resulting matrix can be + * fixed-size: + */ + using left_proxy_type = rebind_matrix_storage_t>; + using right_proxy_type = rebind_matrix_storage_t>; + static const int left_rows = left_proxy_type::array_rows; + static const int right_cols = right_proxy_type::array_cols; + static const bool is_fixed = left_rows > 0 && right_cols > 0; + using unbound_type = storage_promote_t; + + /* Determine the new matrix size: */ + static const int array_rows = is_fixed ? left_rows : -1; + static const int array_cols = is_fixed ? right_cols : -1; + + /* Determine the unbound proxy type: */ + using resized_type = reshape_storage_t; + using proxy_type = proxy_type_of_t>; + + /* Determine the common basis type: */ + using basis_tag = basis_tag_promote_t, + basis_tag_of_t>; + + /* Determine the common layout type: */ + using layout_tag = layout_tag_promote_t, + layout_tag_of_t>; + + /* Build the temporary: */ + using type = matrix; +}; + +/** Determine a matrix temporary type that can hold the result of + * multiplying two matrix expressions @c Sub1 and @c Sub2. + */ +template +struct matrix_inner_product_promote::value && is_matrix::value) + || (is_matrix::value && is_vector::value)>::type> +{ + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + + /* Figure out if pre- or post-multiplying: */ + static const bool left_is_vector = is_vector::value; + static const bool right_is_vector = is_vector::value; + static_assert(left_is_vector ^ right_is_vector, "unexpected expression"); + + /* Vector traits and types: */ + using vector_type = cml::if_t; + using vector_traits = traits_of_t; + using vector_value_type = value_type_of_t; + using vector_storage_type = storage_type_of_t; + + /* Matrix traits and types: */ + using matrix_type = cml::if_t; + using matrix_traits = traits_of_t; + using matrix_value_type = value_type_of_t; + using matrix_storage_type = storage_type_of_t; + + /* Deduce the element type: */ + using value_type = value_type_trait_promote_t; + + /* The resulting vector size comes from the bound matrix proxy rows or + * columns, depending on pre- or post-multiplication: + */ + using matrix_unbound_type = proxy_type_of_t; + using matrix_proxy_type = rebind_matrix_storage_t; + static const int array_size = left_is_vector + ? matrix_proxy_type::array_cols + : matrix_proxy_type::array_rows; + + /* Determine the unbound and bound vector proxy types by resizing the + * original vector storage type: + */ + using vector_resized_type = rebind_vector_storage_t< + resize_storage_t>; + using vector_unbound_type = proxy_type_of_t; + using vector_proxy_type = rebind_vector_storage_t; + /* Note: two rebinds are needed here, first to get the unbound proxy + * type, then to get the bound proxy type for sizing. + */ + + /* Determine the common unbound storage type from the bound proxy types, + * preferring a dynamic-size type unless the resulting vector can be + * fixed-size: + */ + static const bool is_fixed = array_size > 0; + using unbound_type = storage_promote_t; + using resized_type = resize_storage_t; + + /* Prefer the unbound vector proxy type when possible: */ + using proxy_type = cml::if_t< + /**/ (is_fixed&& is_fixed_size::value) + || (!is_fixed && is_dynamic_size::value), + vector_unbound_type, resized_type>; + + /* Build the temporary: */ + using type = vector; +}; + +/** Convenience alias for matrix_inner_product_promote. */ +template +using matrix_inner_product_promote_t = + typename matrix_inner_product_promote::type; + +template +struct matrix_outer_product_storage_promote +{ + static_assert( + is_vector_storage::value && is_vector_storage::value, + "expected vector storage types for outer product promotion"); + + /* Deduce the left matrix storage type from the vector storage: */ + static const int left_size = Storage1::array_size; + using left_unbound_type = reshape_storage_t; + using left_storage_type = rebind_matrix_storage_t; + + /* Deduce the right matrix storage type from the vector storage: */ + static const int right_size = Storage2::array_size; + using right_unbound_type = reshape_storage_t; + using right_storage_type = rebind_matrix_storage_t; + + /* Determine the common storage type, based on the storage types of its + * subexpressions: + */ + using type = matrix_binary_storage_promote_t; +}; + +/** Convenience alias for matrix_outer_product_promote. */ +template +using matrix_outer_product_storage_promote_t = + typename matrix_outer_product_storage_promote::type; + + +/** Specializable class to determine a temporary type that can store the + * result of vector outer products. + */ +template +struct matrix_outer_product_promote; + +/** Determine a matrix temporary type that can hold the result of the outer + * product of two vector expressions @c Sub1 and @c Sub2. + * + * @note The temporary will + */ +template +struct matrix_outer_product_promote::value + && is_vector::value)>::type> +{ + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = vector_traits; + using right_traits = vector_traits; + + /* Deduce the element type: */ + using value_type = value_type_promote_t; + + /* Determine the common storage type for the temporary, based on the + * storage types of its subexpressions: + */ + using left_storage_type = storage_type_of_t; + using right_storage_type = storage_type_of_t; + using storage_type = matrix_outer_product_storage_promote_t; + using proxy_type = proxy_type_of_t; + + /* Build the temporary: */ + using type = matrix; +}; + +/** Convenience alias for matrix_outer_product_promote. */ +template +using matrix_outer_product_promote_t = + typename matrix_outer_product_promote::type; + + +/** Determine the row vector temporary type for matrix type @c Sub. */ +template struct row_type_of; + +template +struct row_type_of::value>::type> +{ + /* Matrix traits and types: */ + using matrix_type = cml::unqualified_type_t; + using matrix_traits = cml::traits_of_t; + using matrix_storage_type = cml::storage_type_of_t; + using value_type = cml::value_type_of_t; + + /* The vector proxy type and size comes from the matrix proxy type: */ + using unbound_type = cml::proxy_type_of_t; + using proxy_type = cml::rebind_matrix_storage_t; + static const int array_size = proxy_type::array_cols; + using vector_type = cml::resize_storage_t; + + /* Build the temporary: */ + using type = cml::vector; +}; + +/** Convenience alias for row_type_of. */ +template using row_type_of_t = typename row_type_of::type; + + +/** Determine the column vector temporary type for matrix type @c Sub. */ +template struct col_type_of; + +template +struct col_type_of::value>::type> +{ + /* Matrix traits and types: */ + using matrix_type = cml::unqualified_type_t; + using matrix_traits = cml::traits_of_t; + using matrix_storage_type = cml::storage_type_of_t; + using value_type = cml::value_type_of_t; + + /* The vector proxy type and size comes from the matrix proxy type: */ + using unbound_type = cml::proxy_type_of_t; + using proxy_type = cml::rebind_matrix_storage_t; + static const int array_size = proxy_type::array_rows; + using vector_type = cml::resize_storage_t; + + /* Build the temporary: */ + using type = cml::vector; +}; + +/** Convenience alias for col_type_of. */ +template using col_type_of_t = typename col_type_of::type; + +} // namespace cml diff --git a/cml/matrix/readable_matrix.h b/cml/matrix/readable_matrix.h index cf9a8ac..08f93af 100644 --- a/cml/matrix/readable_matrix.h +++ b/cml/matrix/readable_matrix.h @@ -1,133 +1,133 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml { - -/** Return type for readable_matrix<>::size(). */ -using matrix_size = std::pair; - -/** Base class for readable matrix types. Readable matrices support const - * access to its elements. - * - * DerivedT must implement: - * - * - int i_rows() const, returning the number of rows (even if static); - * - * - int i_cols() const, returning the number of columns (even if static); - * - * - i_get(int i, int j) const returning matrix element @c (i,j), where - * is the immutable_value type defined by matrix_traits. - * Note that immutable_value is not necessarily a reference or const type. - * - * - basis_element(int i, int j) const returning element @c j of basis - * vector @c i, where is the immutable_value type defined by - * matrix_traits. Note that immutable_value is not necessarily a - * reference or const type. - */ -template class readable_matrix -{ - public: - using matrix_type = DerivedT; - using traits_type = matrix_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /** Return a const reference to the matrix cast as DerivedT. */ - const DerivedT& actual() const; - - /** Return the number of rows. */ - int rows() const; - - /** Return the number of columns. */ - int cols() const; - - /** Returns the matrix size as a std::pair<>. */ - matrix_size size() const; - - /** Return const element at @c i, @c j. */ - immutable_value get(int i, int j) const; - - /** Return const element at @c i, @c j. */ - immutable_value operator()(int i, int j) const; - - /** Returns element @c j of basis vector @c i. The returned value - * depends upon the basis orientation. - */ - immutable_value basis_element(int i, int j) const; - - /** Returns the number of basis vectors. */ - int basis_count() const; - - /** Returns the number of elements in a basis vector. */ - int basis_size() const; - - /** Compute the determinant of the matrix. - * - * @throws non_square_matrix_error at run-time if the matrix is - * dynamically-sized and not square. Fixed-size matrices are checked - * at compile-time. - */ - value_type determinant() const; - - /** Compute the trace of the matrix. - * - * @throws non_square_matrix_error at run-time if the matrix is - * dynamically-sized and not square. Fixed-size matrices are checked - * at compile-time. - */ - value_type trace() const; - - - protected: - /** Return basis element @c (i,j) for a row-basis matrix. */ - immutable_value basis_element(int i, int j, row_basis) const; - - /** Return basis element @c (i,j) for a column-basis matrix. */ - immutable_value basis_element(int i, int j, col_basis) const; - - /** Return the number of basis vectors for a row_basis matrix. */ - int basis_count(row_basis) const; - - /** Return the number of basis vectors for a col_basis matrix. */ - int basis_count(col_basis) const; - - /** Return the number of elements in a basis vector for a row_basis - * matrix. - */ - int basis_size(row_basis) const; - - /** Return the number of elements in a basis vectors for a col_basis - * matrix. - */ - int basis_size(col_basis) const; - - - protected: - // Use the compiler-generated default constructor: - readable_matrix() = default; - - // Use the compiler-generated copy constructor: - readable_matrix(const readable_matrix&) = default; - - // Use the compiler-generated move constructor: - readable_matrix(readable_matrix&&) = default; -}; - -} // namespace cml - -#define __CML_MATRIX_READABLE_MATRIX_TPP -#include -#undef __CML_MATRIX_READABLE_MATRIX_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml { + +/** Return type for readable_matrix<>::size(). */ +using matrix_size = std::pair; + +/** Base class for readable matrix types. Readable matrices support const + * access to its elements. + * + * DerivedT must implement: + * + * - int i_rows() const, returning the number of rows (even if static); + * + * - int i_cols() const, returning the number of columns (even if static); + * + * - i_get(int i, int j) const returning matrix element @c (i,j), where + * is the immutable_value type defined by matrix_traits. + * Note that immutable_value is not necessarily a reference or const type. + * + * - basis_element(int i, int j) const returning element @c j of basis + * vector @c i, where is the immutable_value type defined by + * matrix_traits. Note that immutable_value is not necessarily a + * reference or const type. + */ +template class readable_matrix +{ + public: + using matrix_type = DerivedT; + using traits_type = matrix_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /** Return a const reference to the matrix cast as DerivedT. */ + const DerivedT& actual() const; + + /** Return the number of rows. */ + int rows() const; + + /** Return the number of columns. */ + int cols() const; + + /** Returns the matrix size as a std::pair<>. */ + matrix_size size() const; + + /** Return const element at @c i, @c j. */ + immutable_value get(int i, int j) const; + + /** Return const element at @c i, @c j. */ + immutable_value operator()(int i, int j) const; + + /** Returns element @c j of basis vector @c i. The returned value + * depends upon the basis orientation. + */ + immutable_value basis_element(int i, int j) const; + + /** Returns the number of basis vectors. */ + int basis_count() const; + + /** Returns the number of elements in a basis vector. */ + int basis_size() const; + + /** Compute the determinant of the matrix. + * + * @throws non_square_matrix_error at run-time if the matrix is + * dynamically-sized and not square. Fixed-size matrices are checked + * at compile-time. + */ + value_type determinant() const; + + /** Compute the trace of the matrix. + * + * @throws non_square_matrix_error at run-time if the matrix is + * dynamically-sized and not square. Fixed-size matrices are checked + * at compile-time. + */ + value_type trace() const; + + + protected: + /** Return basis element @c (i,j) for a row-basis matrix. */ + immutable_value basis_element(int i, int j, row_basis) const; + + /** Return basis element @c (i,j) for a column-basis matrix. */ + immutable_value basis_element(int i, int j, col_basis) const; + + /** Return the number of basis vectors for a row_basis matrix. */ + int basis_count(row_basis) const; + + /** Return the number of basis vectors for a col_basis matrix. */ + int basis_count(col_basis) const; + + /** Return the number of elements in a basis vector for a row_basis + * matrix. + */ + int basis_size(row_basis) const; + + /** Return the number of elements in a basis vectors for a col_basis + * matrix. + */ + int basis_size(col_basis) const; + + + protected: + // Use the compiler-generated default constructor: + readable_matrix() = default; + + // Use the compiler-generated copy constructor: + readable_matrix(const readable_matrix&) = default; + + // Use the compiler-generated move constructor: + readable_matrix(readable_matrix&&) = default; +}; + +} // namespace cml + +#define __CML_MATRIX_READABLE_MATRIX_TPP +#include +#undef __CML_MATRIX_READABLE_MATRIX_TPP diff --git a/cml/matrix/readable_matrix.tpp b/cml/matrix/readable_matrix.tpp index a9aa7a2..16f57b0 100644 --- a/cml/matrix/readable_matrix.tpp +++ b/cml/matrix/readable_matrix.tpp @@ -1,143 +1,143 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_READABLE_MATRIX_TPP -# error "matrix/readable_matrix.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -/* Public methods: */ - -template -const DT& -readable_matrix
::actual() const -{ - return (const DT&) *this; -} - -template -int -readable_matrix
::rows() const -{ - return this->actual().i_rows(); -} - -template -int -readable_matrix
::cols() const -{ - return this->actual().i_cols(); -} - -template -std::pair -readable_matrix
::size() const -{ - return std::make_pair(this->rows(), this->cols()); -} - -template -auto -readable_matrix
::get(int i, int j) const -> immutable_value -{ - return this->actual().i_get(i, j); -} - -template -auto -readable_matrix
::operator()(int i, int j) const -> immutable_value -{ - return this->get(i, j); -} - -template -auto -readable_matrix
::basis_element(int i, int j) const -> immutable_value -{ - return this->basis_element(i, j, basis_tag()); -} - -template -int -readable_matrix
::basis_count() const -{ - return this->basis_count(basis_tag()); -} - -template -int -readable_matrix
::basis_size() const -{ - return this->basis_size(basis_tag()); -} - -template -auto -readable_matrix
::determinant() const -> value_type -{ - cml::check_square(*this); - return detail::determinant(*this, cml::int_c()); -} - -template -auto -readable_matrix
::trace() const -> value_type -{ - cml::check_square(*this); - auto result = this->get(0, 0); - for(int i = 1; i < this->rows(); ++i) result += this->get(i, i); - return result; -} - -/* Internal methods: */ - -template -auto -readable_matrix
::basis_element(int i, int j, row_basis) const - -> immutable_value -{ - return this->get(i, j); -} - -template -auto -readable_matrix
::basis_element(int i, int j, col_basis) const - -> immutable_value -{ - return this->get(j, i); -} - -template -int -readable_matrix
::basis_count(row_basis) const -{ - return this->rows(); -} - -template -int -readable_matrix
::basis_count(col_basis) const -{ - return this->cols(); -} - -template -int -readable_matrix
::basis_size(row_basis) const -{ - return this->cols(); -} - -template -int -readable_matrix
::basis_size(col_basis) const -{ - return this->rows(); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_READABLE_MATRIX_TPP +# error "matrix/readable_matrix.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +/* Public methods: */ + +template +const DT& +readable_matrix
::actual() const +{ + return (const DT&) *this; +} + +template +int +readable_matrix
::rows() const +{ + return this->actual().i_rows(); +} + +template +int +readable_matrix
::cols() const +{ + return this->actual().i_cols(); +} + +template +std::pair +readable_matrix
::size() const +{ + return std::make_pair(this->rows(), this->cols()); +} + +template +auto +readable_matrix
::get(int i, int j) const -> immutable_value +{ + return this->actual().i_get(i, j); +} + +template +auto +readable_matrix
::operator()(int i, int j) const -> immutable_value +{ + return this->get(i, j); +} + +template +auto +readable_matrix
::basis_element(int i, int j) const -> immutable_value +{ + return this->basis_element(i, j, basis_tag()); +} + +template +int +readable_matrix
::basis_count() const +{ + return this->basis_count(basis_tag()); +} + +template +int +readable_matrix
::basis_size() const +{ + return this->basis_size(basis_tag()); +} + +template +auto +readable_matrix
::determinant() const -> value_type +{ + cml::check_square(*this); + return detail::determinant(*this, cml::int_c()); +} + +template +auto +readable_matrix
::trace() const -> value_type +{ + cml::check_square(*this); + auto result = this->get(0, 0); + for(int i = 1; i < this->rows(); ++i) result += this->get(i, i); + return result; +} + +/* Internal methods: */ + +template +auto +readable_matrix
::basis_element(int i, int j, row_basis) const + -> immutable_value +{ + return this->get(i, j); +} + +template +auto +readable_matrix
::basis_element(int i, int j, col_basis) const + -> immutable_value +{ + return this->get(j, i); +} + +template +int +readable_matrix
::basis_count(row_basis) const +{ + return this->rows(); +} + +template +int +readable_matrix
::basis_count(col_basis) const +{ + return this->cols(); +} + +template +int +readable_matrix
::basis_size(row_basis) const +{ + return this->cols(); +} + +template +int +readable_matrix
::basis_size(col_basis) const +{ + return this->rows(); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/row_col.h b/cml/matrix/row_col.h index b25f704..1b04edf 100644 --- a/cml/matrix/row_col.h +++ b/cml/matrix/row_col.h @@ -1,10 +1,10 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include diff --git a/cml/matrix/row_node.h b/cml/matrix/row_node.h index 245f8d3..3af7c77 100644 --- a/cml/matrix/row_node.h +++ b/cml/matrix/row_node.h @@ -1,120 +1,120 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template class matrix_row_node; - -/** matrix_row_node<> traits. */ -template struct vector_traits> -{ - using vector_type = matrix_row_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = matrix_traits; - using element_traits = typename sub_traits::element_traits; - using value_type = typename sub_traits::value_type; - using immutable_value = typename sub_traits::immutable_value; - - /* Propagate the column count from the subexpression: */ - static const int array_size = sub_traits::array_cols; - - /* Deduce the vector storage type: */ - using sub_storage_type = typename sub_traits::storage_type; - using sub_unbound_type = typename sub_storage_type::unbound_type; - using resized_type = resize_storage_t; - using storage_type = rebind_vector_storage_t; - - /* Take the size type from the storage type: */ - using size_tag = typename storage_type::size_tag; -}; - -/** Represents a read-only matrix row, specified at run-time by its index, - * as a node in an expression tree. - */ -template -class matrix_row_node -: public readable_vector> -{ - public: - using node_type = matrix_row_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** Constant containing the number of elements. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expression and the row index. @c - * sub must be an lvalue reference or rvalue reference type. - * - * @throws std::invalid_argument if @c row < 0. - */ - explicit matrix_row_node(Sub sub, int row); - - /** Move constructor. */ - matrix_row_node(node_type&& other); - - /** Copy constructor. */ - matrix_row_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Return element @c (row,j) of the matrix. */ - immutable_value i_get(int j) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using sub_wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - - protected: - /** The wrapped subexpression. */ - sub_wrap_type m_sub; - - /** The row index. */ - int m_row; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_MATRIX_ROW_NODE_TPP -#include -#undef __CML_MATRIX_ROW_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template class matrix_row_node; + +/** matrix_row_node<> traits. */ +template struct vector_traits> +{ + using vector_type = matrix_row_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = matrix_traits; + using element_traits = typename sub_traits::element_traits; + using value_type = typename sub_traits::value_type; + using immutable_value = typename sub_traits::immutable_value; + + /* Propagate the column count from the subexpression: */ + static const int array_size = sub_traits::array_cols; + + /* Deduce the vector storage type: */ + using sub_storage_type = typename sub_traits::storage_type; + using sub_unbound_type = typename sub_storage_type::unbound_type; + using resized_type = resize_storage_t; + using storage_type = rebind_vector_storage_t; + + /* Take the size type from the storage type: */ + using size_tag = typename storage_type::size_tag; +}; + +/** Represents a read-only matrix row, specified at run-time by its index, + * as a node in an expression tree. + */ +template +class matrix_row_node +: public readable_vector> +{ + public: + using node_type = matrix_row_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** Constant containing the number of elements. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expression and the row index. @c + * sub must be an lvalue reference or rvalue reference type. + * + * @throws std::invalid_argument if @c row < 0. + */ + explicit matrix_row_node(Sub sub, int row); + + /** Move constructor. */ + matrix_row_node(node_type&& other); + + /** Copy constructor. */ + matrix_row_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Return element @c (row,j) of the matrix. */ + immutable_value i_get(int j) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using sub_wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + + protected: + /** The wrapped subexpression. */ + sub_wrap_type m_sub; + + /** The row index. */ + int m_row; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_MATRIX_ROW_NODE_TPP +#include +#undef __CML_MATRIX_ROW_NODE_TPP diff --git a/cml/matrix/row_node.tpp b/cml/matrix/row_node.tpp index fd0efdc..28d1f92 100644 --- a/cml/matrix/row_node.tpp +++ b/cml/matrix/row_node.tpp @@ -1,52 +1,52 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_ROW_NODE_TPP -# error "matrix/row_node.tpp not included correctly" -#endif - -namespace cml { - -/* matrix_row_node 'structors: */ - -template -matrix_row_node::matrix_row_node(Sub sub, int row) -: m_sub(std::move(sub)) -, m_row(row) -{ - cml_require(row >= 0, std::invalid_argument, "row < 0"); -} - -template -matrix_row_node::matrix_row_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -, m_row(other.m_row) -{} - -template -matrix_row_node::matrix_row_node(const node_type& other) -: m_sub(other.m_sub) -, m_row(other.m_row) -{} - - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -matrix_row_node::i_size() const -{ - return this->m_sub.cols(); -} - -template -auto -matrix_row_node::i_get(int j) const -> immutable_value -{ - return this->m_sub.get(this->m_row, j); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_ROW_NODE_TPP +# error "matrix/row_node.tpp not included correctly" +#endif + +namespace cml { + +/* matrix_row_node 'structors: */ + +template +matrix_row_node::matrix_row_node(Sub sub, int row) +: m_sub(std::move(sub)) +, m_row(row) +{ + cml_require(row >= 0, std::invalid_argument, "row < 0"); +} + +template +matrix_row_node::matrix_row_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +, m_row(other.m_row) +{} + +template +matrix_row_node::matrix_row_node(const node_type& other) +: m_sub(other.m_sub) +, m_row(other.m_row) +{} + + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +matrix_row_node::i_size() const +{ + return this->m_sub.cols(); +} + +template +auto +matrix_row_node::i_get(int j) const -> immutable_value +{ + return this->m_sub.get(this->m_row, j); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/row_ops.h b/cml/matrix/row_ops.h index a907b78..ce63976 100644 --- a/cml/matrix/row_ops.h +++ b/cml/matrix/row_ops.h @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template* = nullptr> -inline auto -row(Sub&& sub, int row) - -> matrix_row_node, -1> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type"); - - /* Deduce the operand type of the subexpression (&, const&, &&): */ - using sub_type = actual_operand_type_of_t; - return matrix_row_node((sub_type) sub, row); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template* = nullptr> +inline auto +row(Sub&& sub, int row) + -> matrix_row_node, -1> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type"); + + /* Deduce the operand type of the subexpression (&, const&, &&): */ + using sub_type = actual_operand_type_of_t; + return matrix_row_node((sub_type) sub, row); +} + +} // namespace cml diff --git a/cml/matrix/scalar_node.h b/cml/matrix/scalar_node.h index 31923a9..6de7dc0 100644 --- a/cml/matrix/scalar_node.h +++ b/cml/matrix/scalar_node.h @@ -1,142 +1,142 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class matrix_scalar_node; - -/** matrix_scalar_node<> traits. */ -template -struct matrix_traits> -{ - using matrix_type = matrix_scalar_node; - using left_arg_type = Sub; - using right_arg_type = Scalar; - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = matrix_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - using storage_type = typename left_traits::storage_type; - using size_tag = typename left_traits::size_tag; - using basis_tag = typename left_traits::basis_tag; - using layout_tag = typename left_traits::layout_tag; - - /* Propagate the rows from the subexpression: */ - static const int array_rows = left_traits::array_rows; - - /* Propagate the columns from the subexpression: */ - static const int array_cols = left_traits::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; -}; - -/** Represents a binary matrix operation, where one operand is a scalar - * value, and the other is a matrix. - */ -template -class matrix_scalar_node -: public readable_matrix> -{ - public: - using node_type = matrix_scalar_node; - using readable_type = readable_matrix; - using traits_type = matrix_traits; - using left_arg_type = typename traits_type::left_arg_type; - using right_arg_type = typename traits_type::right_arg_type; - using left_type = typename traits_type::left_type; - using right_type = typename traits_type::right_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /** Take the array row size from the subexpression. */ - static const int array_rows = left_type::array_rows; - - /** Take the array column size from the subexpression. */ - static const int array_cols = left_type::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - - public: - /** Construct from the wrapped sub-expression and the scalar to apply. - * @c left and @c right must be lvalue or rvalue references. - */ - matrix_scalar_node(Sub left, Scalar right); - - /** Move constructor. */ - matrix_scalar_node(node_type&& other); - - /** Copy constructor. */ - matrix_scalar_node(const node_type& other); - - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the row size of the matrix expression. */ - int i_rows() const; - - /** Return the column size of the matrix expression. */ - int i_cols() const; - - /** Apply the operator to element @c (i,j) of the subexpressions and - * return the result. - */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** The type used to store the left subexpression. The expression is - * stored as a copy if Sub is an rvalue reference (temporary), or by - * const reference if Sub is an lvalue reference. - */ - using left_wrap_type = cml::if_t::value, const left_type&, - left_type>; - - - protected: - /** The matrix operand. */ - left_wrap_type m_left; - - /** The scalar operand. */ - right_type m_right; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_MATRIX_SCALAR_NODE_TPP -#include -#undef __CML_MATRIX_SCALAR_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class matrix_scalar_node; + +/** matrix_scalar_node<> traits. */ +template +struct matrix_traits> +{ + using matrix_type = matrix_scalar_node; + using left_arg_type = Sub; + using right_arg_type = Scalar; + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = matrix_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + using storage_type = typename left_traits::storage_type; + using size_tag = typename left_traits::size_tag; + using basis_tag = typename left_traits::basis_tag; + using layout_tag = typename left_traits::layout_tag; + + /* Propagate the rows from the subexpression: */ + static const int array_rows = left_traits::array_rows; + + /* Propagate the columns from the subexpression: */ + static const int array_cols = left_traits::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; +}; + +/** Represents a binary matrix operation, where one operand is a scalar + * value, and the other is a matrix. + */ +template +class matrix_scalar_node +: public readable_matrix> +{ + public: + using node_type = matrix_scalar_node; + using readable_type = readable_matrix; + using traits_type = matrix_traits; + using left_arg_type = typename traits_type::left_arg_type; + using right_arg_type = typename traits_type::right_arg_type; + using left_type = typename traits_type::left_type; + using right_type = typename traits_type::right_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /** Take the array row size from the subexpression. */ + static const int array_rows = left_type::array_rows; + + /** Take the array column size from the subexpression. */ + static const int array_cols = left_type::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + + public: + /** Construct from the wrapped sub-expression and the scalar to apply. + * @c left and @c right must be lvalue or rvalue references. + */ + matrix_scalar_node(Sub left, Scalar right); + + /** Move constructor. */ + matrix_scalar_node(node_type&& other); + + /** Copy constructor. */ + matrix_scalar_node(const node_type& other); + + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the row size of the matrix expression. */ + int i_rows() const; + + /** Return the column size of the matrix expression. */ + int i_cols() const; + + /** Apply the operator to element @c (i,j) of the subexpressions and + * return the result. + */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** The type used to store the left subexpression. The expression is + * stored as a copy if Sub is an rvalue reference (temporary), or by + * const reference if Sub is an lvalue reference. + */ + using left_wrap_type = cml::if_t::value, const left_type&, + left_type>; + + + protected: + /** The matrix operand. */ + left_wrap_type m_left; + + /** The scalar operand. */ + right_type m_right; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_MATRIX_SCALAR_NODE_TPP +#include +#undef __CML_MATRIX_SCALAR_NODE_TPP diff --git a/cml/matrix/scalar_node.tpp b/cml/matrix/scalar_node.tpp index 67595a2..e1f99b3 100644 --- a/cml/matrix/scalar_node.tpp +++ b/cml/matrix/scalar_node.tpp @@ -1,57 +1,57 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_SCALAR_NODE_TPP -# error "matrix/scalar_node.tpp not included correctly" -#endif - -namespace cml { - -/* matrix_scalar_node 'structors: */ - -template -matrix_scalar_node::matrix_scalar_node(Sub left, Scalar right) -: m_left(std::move(left)) -, m_right(std::move(right)) -{} - -template -matrix_scalar_node::matrix_scalar_node(node_type&& other) -: m_left(std::move(other.m_left)) -, m_right(std::move(other.m_right)) -{} - -template -matrix_scalar_node::matrix_scalar_node(const node_type& other) -: m_left(other.m_left) -, m_right(other.m_right) -{} - -/* Internal methods: */ - -/* readable_matrix interface: */ - -template -int -matrix_scalar_node::i_rows() const -{ - return this->m_left.rows(); -} - -template -int -matrix_scalar_node::i_cols() const -{ - return this->m_left.cols(); -} - -template -auto -matrix_scalar_node::i_get(int i, int j) const - -> immutable_value -{ - return Op().apply(this->m_left.get(i, j), this->m_right); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_SCALAR_NODE_TPP +# error "matrix/scalar_node.tpp not included correctly" +#endif + +namespace cml { + +/* matrix_scalar_node 'structors: */ + +template +matrix_scalar_node::matrix_scalar_node(Sub left, Scalar right) +: m_left(std::move(left)) +, m_right(std::move(right)) +{} + +template +matrix_scalar_node::matrix_scalar_node(node_type&& other) +: m_left(std::move(other.m_left)) +, m_right(std::move(other.m_right)) +{} + +template +matrix_scalar_node::matrix_scalar_node(const node_type& other) +: m_left(other.m_left) +, m_right(other.m_right) +{} + +/* Internal methods: */ + +/* readable_matrix interface: */ + +template +int +matrix_scalar_node::i_rows() const +{ + return this->m_left.rows(); +} + +template +int +matrix_scalar_node::i_cols() const +{ + return this->m_left.cols(); +} + +template +auto +matrix_scalar_node::i_get(int i, int j) const + -> immutable_value +{ + return Op().apply(this->m_left.get(i, j), this->m_right); +} + +} // namespace cml diff --git a/cml/matrix/scalar_ops.h b/cml/matrix/scalar_ops.h index 5ad3608..ad89da6 100644 --- a/cml/matrix/scalar_ops.h +++ b/cml/matrix/scalar_ops.h @@ -1,73 +1,73 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -/** Helper function to generate a matrix_scalar_node from a matrix type - * (i.e. derived from readable_matrix<>) and a scalar type. - */ -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -make_matrix_scalar_node(Sub&& sub, - Scalar&& v) -> matrix_scalar_node, - actual_operand_type_of_t, Op> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type (sub)"); - static_assert( - std::is_same(v))>::value, - "internal error: unexpected expression type (v)"); - - /* Deduce the operand types of the scalar and the subexpression (&, - * const&, &&): - */ - using sub_type = actual_operand_type_of_t; - using scalar_type = actual_operand_type_of_t; - return matrix_scalar_node((sub_type) sub, - (scalar_type) v); -} - -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -operator*(Sub&& sub, Scalar&& v) - -> decltype(make_matrix_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_matrix_scalar_node>( - std::forward(sub), std::forward(v)); -} - -template>* = nullptr, - enable_if_matrix_t* = nullptr> -inline auto -operator*(Scalar&& v, Sub&& sub) - -> decltype(make_matrix_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_matrix_scalar_node>( - std::forward(sub), std::forward(v)); -} - -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -operator/(Sub&& sub, Scalar&& v) - -> decltype(make_matrix_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_matrix_scalar_node>( - std::forward(sub), std::forward(v)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +/** Helper function to generate a matrix_scalar_node from a matrix type + * (i.e. derived from readable_matrix<>) and a scalar type. + */ +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +make_matrix_scalar_node(Sub&& sub, + Scalar&& v) -> matrix_scalar_node, + actual_operand_type_of_t, Op> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type (sub)"); + static_assert( + std::is_same(v))>::value, + "internal error: unexpected expression type (v)"); + + /* Deduce the operand types of the scalar and the subexpression (&, + * const&, &&): + */ + using sub_type = actual_operand_type_of_t; + using scalar_type = actual_operand_type_of_t; + return matrix_scalar_node((sub_type) sub, + (scalar_type) v); +} + +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +operator*(Sub&& sub, Scalar&& v) + -> decltype(make_matrix_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_matrix_scalar_node>( + std::forward(sub), std::forward(v)); +} + +template>* = nullptr, + enable_if_matrix_t* = nullptr> +inline auto +operator*(Scalar&& v, Sub&& sub) + -> decltype(make_matrix_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_matrix_scalar_node>( + std::forward(sub), std::forward(v)); +} + +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +operator/(Sub&& sub, Scalar&& v) + -> decltype(make_matrix_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_matrix_scalar_node>( + std::forward(sub), std::forward(v)); +} + +} // namespace cml diff --git a/cml/matrix/size_checking.h b/cml/matrix/size_checking.h index 0d5db22..791cf5e 100644 --- a/cml/matrix/size_checking.h +++ b/cml/matrix/size_checking.h @@ -1,418 +1,418 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace cml { - -/** Exception thrown when run-time size checking is enabled, and the - * operands of a matrix expression have incompatible sizes. - */ -struct incompatible_matrix_size_error : std::runtime_error -{ - incompatible_matrix_size_error() - : std::runtime_error("incompatible matrix expression sizes") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and the - * operand of a matrix expression does not meet a minimum size. - */ -struct minimum_matrix_size_error : std::runtime_error -{ - minimum_matrix_size_error() - : std::runtime_error("matrix expression too small") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and the - * operand of a matrix expression does not have the required size. - */ -struct matrix_size_error : std::runtime_error -{ - matrix_size_error() - : std::runtime_error("incorrect matrix expression size") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and the row - * size of a matrix operand does not match the (row) size of a second - * operand. - */ -struct incompatible_matrix_row_size_error : std::runtime_error -{ - incompatible_matrix_row_size_error() - : std::runtime_error("incompatible matrix row sizes") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and the column - * size of a matrix operand does not match the (row) size of a second - * operand. - */ -struct incompatible_matrix_col_size_error : std::runtime_error -{ - incompatible_matrix_col_size_error() - : std::runtime_error("incompatible matrix column sizes") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and the - * column size of a matrix operand does not match the row size of a second - * operand. - */ -struct incompatible_matrix_inner_size_error : std::runtime_error -{ - incompatible_matrix_inner_size_error() - : std::runtime_error("incompatible matrix inner product size") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and a matrix - * operand is not square. - */ -struct non_square_matrix_error : std::runtime_error -{ - non_square_matrix_error() - : std::runtime_error("non-square matrix") - {} -}; - - -/** Front-end for both compile-time and run-time matrix binary expression - * linear size checking. Both expressions must derive from - * readable_matrix. - * - * @tparam Sub1 the actual type of the first expression. - * @tparam Sub2 the actual type of the second expression. - * - * @param left First matrix expression. - * @param right Second matrix expression. - * - * @throws incompatible_matrix_size_error at run-time if either @c left or - * @c right is a dynamically-sized expression, and @c left.rows() * @c - * left.cols() != @c right.rows() * @c right.cols(). If @c left and @c - * right are fixed-size expressions, then the sizes are checked at compile - * time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_same_linear_size(const readable_matrix& left, - const readable_matrix& right); - -/** Front-end for both compile-time and run-time matrix binary expression - * size checking against a fixed-size array. The first expression must - * derive from readable_matrix, and std::is_array<>::value must be true for - * the second expression (e.g. double v[16]). - * - * @tparam Sub1 the actual type of the first expression. - * @tparam Sub2 the actual type of the second expression. - * - * @param left Matrix expression. - * @param right Fixed-length array. - * - * @throws incompatible_matrix_size_error at run-time if @c left is a - * dynamically-sized expression, and @c left.rows() * @c left.cols() != - * array_size_of(@c right). If @c left is a fixed-size expression, then the - * sizes are checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_same_linear_size(const readable_matrix& left, - const Sub2& right, enable_if_array_t* = 0); - -/** Front-end for run-time matrix binary expression length checking. The - * first expression must derive from readable_matrix, and the second must - * implement a size() method for this overload to be enabled. - * - * @tparam Sub1 the actual type of the first expression. - * @tparam Sub2 the actual type of the second expression. - * - * @param left First matrix expression. - * @param right Second expression. - * - * @throws incompatible_matrix_size_error if @c left.rows() * @c - * left.cols() != @c right.size(). - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -auto check_same_linear_size(const readable_matrix& left, - const Sub2& right) -> decltype(right.size(), void()); - - -/** Front-end for matrix expression size checking against a run-time linear - * size. The expression must derive from readable_matrix. - * - * @param left Matrix expression. - * @param N The linear size to check. - * - * @throws matrix_size_error if @c left.rows() * @c left.cols() != @c N. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_linear_size(const readable_matrix& left, int N); - -/** Front-end for compile-time and run-time matrix expression linear size - * checking against an integer constant via int_c. The expression - * must derive from readable_matrix. - * - * @param left Matrix expression. - * - * @throws matrix_size_error at run-time if @c left is a dynamically-sized - * expression and @c left.rows() * @c left.cols() != @c N. If @c left is a - * fixed-size expression, then the size is checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_linear_size(const readable_matrix& left, int_c); - -/** Front-end for both compile-time and run-time matrix binary expression - * size checking. Both expressions must derive from readable_matrix. - * - * @tparam Sub1 the actual type of the first expression. - * @tparam Sub2 the actual type of the second expression. - * - * @param left First matrix expression. - * @param right Second matrix expression. - * - * @throws incompatible_matrix_size_error at run-time if either @c left or - * @c right is a dynamically-sized expression, and @c left.size() != - * @c right.size(). If both are fixed-size expressions, then the sizes are - * checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_same_size(const readable_matrix& left, - const readable_matrix& right); - -/** Front-end for both compile-time and run-time matrix expression size - * checking against a 2D C-array. @c left must derive from - * readable_matrix. - * - * @tparam Sub the actual type of the first expression. - * @tparam Other the element type of the array. - * @tparam Rows the number of array rows. - * @tparam Cols the number of array cols. - * - * @param left First matrix expression. - * @param right The 2D C-array. - * - * @throws incompatible_matrix_size_error at run-time if @c left is a - * dynamically-sized expression and does not have the same number of rows - * and columns as the array. If @c left is a fixed-size expression, then the - * sizes are checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_same_size(const readable_matrix& left, - Other const (&array)[Rows][Cols]); - -/** Front-end for both compile-time and run-time matrix row size - * checking against a vector expression. @c left must derive from - * readable_matrix, and @c right must derived from readable_vector. - * - * @tparam Sub1 the actual type of the matrix expression. - * @tparam Sub2 the actual type of the vector expression. - * - * @param left Matrix expression. - * @param right Vector expression. - * - * @throws incompatible_matrix_row_size_error at run-time if @c left or @c - * right is dynamically-sized, and @c left does not have the same number of - * rows as @c right has elements. If both are fixed-size expressions, then - * the sizes are checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_same_row_size(const readable_matrix& left, - const readable_vector& right); - -/** Front-end for both compile-time and run-time matrix column size - * checking against a vector expression. @c left must derive from - * readable_matrix, and @c right must derived from readable_vector. - * - * @tparam Sub1 the actual type of the matrix expression. - * @tparam Sub2 the actual type of the vector expression. - * - * @param left Matrix expression. - * @param right Vector expression. - * - * @throws incompatible_matrix_col_size_error at run-time if @c left or @c - * right is dynamically-sized, and @c left does not have the same number - * of columns as @c right has elements. If both are fixed-size expressions, - * then the sizes are checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_same_col_size(const readable_matrix& left, - const readable_vector& right); - - -/** Front-end for both compile-time and run-time compatible inner product - * size checking. @c left and @c right must derive from readable_matrix. - * - * @tparam Sub1 the actual type of the first matrix expression. - * @tparam Sub2 the actual type of the second matrix expression. - * - * @param left First matrix expression. - * @param right Second matrix expression. - * - * @throws incompatible_matrix_inner_size_error at run-time if @c left or @c - * right is dynamically-sized, and @c left does not have the same number - * of columns as @c right has rows. If both are fixed-size expressions, - * then the sizes are checked at compile time. - */ -template -void check_same_inner_size(const readable_matrix& left, - const readable_matrix& right); - -/** Front-end for both compile-time and run-time compatible inner product - * size checking. @c left must derive from readable_matrix, and @c right - * must derive from readable_vector. - * - * @tparam Sub1 the actual type of the matrix expression. - * @tparam Sub2 the actual type of the vector expression. - * - * @param left Matrix expression. - * @param right Vector expression. - * - * @throws incompatible_matrix_inner_size_error at run-time if @c left or @c - * right is dynamically-sized, and @c left does not have the same number - * of columns as @c right has elements. If both are fixed-size expressions, - * then the sizes are checked at compile time. - */ -template -void check_same_inner_size(const readable_matrix& left, - const readable_vector& right); - -/** Front-end for both compile-time and run-time compatible inner product - * size checking. @c left must derive from readable_vector, and @c right - * must derive from readable_vector. - * - * @tparam Sub1 the actual type of the vector expression. - * @tparam Sub2 the actual type of the matrix expression. - * - * @param left Vector expression. - * @param right Matrix expression. - * - * @throws incompatible_matrix_inner_size_error at run-time if @c left or - * @c right is dynamically-sized, and @c left does not have the same number - * of elements as @c right has rows. If both are fixed-size expressions, - * then the sizes are checked at compile time. - */ -template -void check_same_inner_size(const readable_vector& left, - const readable_matrix& right); - - -/** Front-end for matrix expression size checking against a run-time - * size. The expression must derive from readable_matrix. - * - * @param left Matrix expression. - * @param R Row count to check. - * @param C Column count to check. - * - * @throws matrix_size_error at run-time if @c left is dynamically-sized, - * and if @c left.rows() != @c R or @c left.cols() != @c C. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_size(const readable_matrix& left, int R, int C); - -/** Front-end for compile-time and run-time matrix expression size checking - * against integer constants via int_c and int_c. The expression - * must derive from readable_matrix. - * - * @param left Matrix expression. - * - * @throws matrix_size_error at run-time if @c left is dynamically-sized, - * and if @c left.rows() != @c R or @c left.cols() != @c C. If @c left is a - * fixed-size expression, then the size is checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_size(const readable_matrix& left, cml::int_c, cml::int_c); - - -/** Front-end for matrix expression minimum size checking against a - * run-time size. The expression must derive from readable_matrix. - * - * @param left Matrix expression. - * @param R Minimum row count to check. - * @param C Minimum column count to check. - * - * @throws minimum_matrix_size_error at run-time if @c left is - * dynamically-sized, and if @c left.rows() < @c R or @c left.cols() < @c - * C. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_minimum_size(const readable_matrix& left, int R, int C); - -/** Front-end for compile-time and run-time matrix expression minimum size - * checking against integer constants via int_c and int_c. The - * expression must derive from readable_matrix. - * - * @param left Matrix expression. - * - * @throws minimum_matrix_size_error at run-time if @c left is - * dynamically-sized, and if @c left.rows() < @c R or @c left.cols() < - * @c C. If @c left is a fixed-size expression, then the size is checked - * at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template -void check_minimum_size(const readable_matrix& left, cml::int_c, - cml::int_c); - - -/** Front-end to check for a square matrix. - * - * @throws non_square_matrix_error at run-time if @c left is a - * dynamically-sized expression and @c left.rows() != @c left.cols(). If - * @c left is a fixed-size expression, then the size is checked at compile - * time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. - */ -template void check_square(const readable_matrix& left); - -} // namespace cml - -#define __CML_MATRIX_SIZE_CHECKING_TPP -#include -#undef __CML_MATRIX_SIZE_CHECKING_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace cml { + +/** Exception thrown when run-time size checking is enabled, and the + * operands of a matrix expression have incompatible sizes. + */ +struct incompatible_matrix_size_error : std::runtime_error +{ + incompatible_matrix_size_error() + : std::runtime_error("incompatible matrix expression sizes") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and the + * operand of a matrix expression does not meet a minimum size. + */ +struct minimum_matrix_size_error : std::runtime_error +{ + minimum_matrix_size_error() + : std::runtime_error("matrix expression too small") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and the + * operand of a matrix expression does not have the required size. + */ +struct matrix_size_error : std::runtime_error +{ + matrix_size_error() + : std::runtime_error("incorrect matrix expression size") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and the row + * size of a matrix operand does not match the (row) size of a second + * operand. + */ +struct incompatible_matrix_row_size_error : std::runtime_error +{ + incompatible_matrix_row_size_error() + : std::runtime_error("incompatible matrix row sizes") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and the column + * size of a matrix operand does not match the (row) size of a second + * operand. + */ +struct incompatible_matrix_col_size_error : std::runtime_error +{ + incompatible_matrix_col_size_error() + : std::runtime_error("incompatible matrix column sizes") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and the + * column size of a matrix operand does not match the row size of a second + * operand. + */ +struct incompatible_matrix_inner_size_error : std::runtime_error +{ + incompatible_matrix_inner_size_error() + : std::runtime_error("incompatible matrix inner product size") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and a matrix + * operand is not square. + */ +struct non_square_matrix_error : std::runtime_error +{ + non_square_matrix_error() + : std::runtime_error("non-square matrix") + {} +}; + + +/** Front-end for both compile-time and run-time matrix binary expression + * linear size checking. Both expressions must derive from + * readable_matrix. + * + * @tparam Sub1 the actual type of the first expression. + * @tparam Sub2 the actual type of the second expression. + * + * @param left First matrix expression. + * @param right Second matrix expression. + * + * @throws incompatible_matrix_size_error at run-time if either @c left or + * @c right is a dynamically-sized expression, and @c left.rows() * @c + * left.cols() != @c right.rows() * @c right.cols(). If @c left and @c + * right are fixed-size expressions, then the sizes are checked at compile + * time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_same_linear_size(const readable_matrix& left, + const readable_matrix& right); + +/** Front-end for both compile-time and run-time matrix binary expression + * size checking against a fixed-size array. The first expression must + * derive from readable_matrix, and std::is_array<>::value must be true for + * the second expression (e.g. double v[16]). + * + * @tparam Sub1 the actual type of the first expression. + * @tparam Sub2 the actual type of the second expression. + * + * @param left Matrix expression. + * @param right Fixed-length array. + * + * @throws incompatible_matrix_size_error at run-time if @c left is a + * dynamically-sized expression, and @c left.rows() * @c left.cols() != + * array_size_of(@c right). If @c left is a fixed-size expression, then the + * sizes are checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_same_linear_size(const readable_matrix& left, + const Sub2& right, enable_if_array_t* = 0); + +/** Front-end for run-time matrix binary expression length checking. The + * first expression must derive from readable_matrix, and the second must + * implement a size() method for this overload to be enabled. + * + * @tparam Sub1 the actual type of the first expression. + * @tparam Sub2 the actual type of the second expression. + * + * @param left First matrix expression. + * @param right Second expression. + * + * @throws incompatible_matrix_size_error if @c left.rows() * @c + * left.cols() != @c right.size(). + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +auto check_same_linear_size(const readable_matrix& left, + const Sub2& right) -> decltype(right.size(), void()); + + +/** Front-end for matrix expression size checking against a run-time linear + * size. The expression must derive from readable_matrix. + * + * @param left Matrix expression. + * @param N The linear size to check. + * + * @throws matrix_size_error if @c left.rows() * @c left.cols() != @c N. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_linear_size(const readable_matrix& left, int N); + +/** Front-end for compile-time and run-time matrix expression linear size + * checking against an integer constant via int_c. The expression + * must derive from readable_matrix. + * + * @param left Matrix expression. + * + * @throws matrix_size_error at run-time if @c left is a dynamically-sized + * expression and @c left.rows() * @c left.cols() != @c N. If @c left is a + * fixed-size expression, then the size is checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_linear_size(const readable_matrix& left, int_c); + +/** Front-end for both compile-time and run-time matrix binary expression + * size checking. Both expressions must derive from readable_matrix. + * + * @tparam Sub1 the actual type of the first expression. + * @tparam Sub2 the actual type of the second expression. + * + * @param left First matrix expression. + * @param right Second matrix expression. + * + * @throws incompatible_matrix_size_error at run-time if either @c left or + * @c right is a dynamically-sized expression, and @c left.size() != + * @c right.size(). If both are fixed-size expressions, then the sizes are + * checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_same_size(const readable_matrix& left, + const readable_matrix& right); + +/** Front-end for both compile-time and run-time matrix expression size + * checking against a 2D C-array. @c left must derive from + * readable_matrix. + * + * @tparam Sub the actual type of the first expression. + * @tparam Other the element type of the array. + * @tparam Rows the number of array rows. + * @tparam Cols the number of array cols. + * + * @param left First matrix expression. + * @param right The 2D C-array. + * + * @throws incompatible_matrix_size_error at run-time if @c left is a + * dynamically-sized expression and does not have the same number of rows + * and columns as the array. If @c left is a fixed-size expression, then the + * sizes are checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_same_size(const readable_matrix& left, + Other const (&array)[Rows][Cols]); + +/** Front-end for both compile-time and run-time matrix row size + * checking against a vector expression. @c left must derive from + * readable_matrix, and @c right must derived from readable_vector. + * + * @tparam Sub1 the actual type of the matrix expression. + * @tparam Sub2 the actual type of the vector expression. + * + * @param left Matrix expression. + * @param right Vector expression. + * + * @throws incompatible_matrix_row_size_error at run-time if @c left or @c + * right is dynamically-sized, and @c left does not have the same number of + * rows as @c right has elements. If both are fixed-size expressions, then + * the sizes are checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_same_row_size(const readable_matrix& left, + const readable_vector& right); + +/** Front-end for both compile-time and run-time matrix column size + * checking against a vector expression. @c left must derive from + * readable_matrix, and @c right must derived from readable_vector. + * + * @tparam Sub1 the actual type of the matrix expression. + * @tparam Sub2 the actual type of the vector expression. + * + * @param left Matrix expression. + * @param right Vector expression. + * + * @throws incompatible_matrix_col_size_error at run-time if @c left or @c + * right is dynamically-sized, and @c left does not have the same number + * of columns as @c right has elements. If both are fixed-size expressions, + * then the sizes are checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_same_col_size(const readable_matrix& left, + const readable_vector& right); + + +/** Front-end for both compile-time and run-time compatible inner product + * size checking. @c left and @c right must derive from readable_matrix. + * + * @tparam Sub1 the actual type of the first matrix expression. + * @tparam Sub2 the actual type of the second matrix expression. + * + * @param left First matrix expression. + * @param right Second matrix expression. + * + * @throws incompatible_matrix_inner_size_error at run-time if @c left or @c + * right is dynamically-sized, and @c left does not have the same number + * of columns as @c right has rows. If both are fixed-size expressions, + * then the sizes are checked at compile time. + */ +template +void check_same_inner_size(const readable_matrix& left, + const readable_matrix& right); + +/** Front-end for both compile-time and run-time compatible inner product + * size checking. @c left must derive from readable_matrix, and @c right + * must derive from readable_vector. + * + * @tparam Sub1 the actual type of the matrix expression. + * @tparam Sub2 the actual type of the vector expression. + * + * @param left Matrix expression. + * @param right Vector expression. + * + * @throws incompatible_matrix_inner_size_error at run-time if @c left or @c + * right is dynamically-sized, and @c left does not have the same number + * of columns as @c right has elements. If both are fixed-size expressions, + * then the sizes are checked at compile time. + */ +template +void check_same_inner_size(const readable_matrix& left, + const readable_vector& right); + +/** Front-end for both compile-time and run-time compatible inner product + * size checking. @c left must derive from readable_vector, and @c right + * must derive from readable_vector. + * + * @tparam Sub1 the actual type of the vector expression. + * @tparam Sub2 the actual type of the matrix expression. + * + * @param left Vector expression. + * @param right Matrix expression. + * + * @throws incompatible_matrix_inner_size_error at run-time if @c left or + * @c right is dynamically-sized, and @c left does not have the same number + * of elements as @c right has rows. If both are fixed-size expressions, + * then the sizes are checked at compile time. + */ +template +void check_same_inner_size(const readable_vector& left, + const readable_matrix& right); + + +/** Front-end for matrix expression size checking against a run-time + * size. The expression must derive from readable_matrix. + * + * @param left Matrix expression. + * @param R Row count to check. + * @param C Column count to check. + * + * @throws matrix_size_error at run-time if @c left is dynamically-sized, + * and if @c left.rows() != @c R or @c left.cols() != @c C. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_size(const readable_matrix& left, int R, int C); + +/** Front-end for compile-time and run-time matrix expression size checking + * against integer constants via int_c and int_c. The expression + * must derive from readable_matrix. + * + * @param left Matrix expression. + * + * @throws matrix_size_error at run-time if @c left is dynamically-sized, + * and if @c left.rows() != @c R or @c left.cols() != @c C. If @c left is a + * fixed-size expression, then the size is checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_size(const readable_matrix& left, cml::int_c, cml::int_c); + + +/** Front-end for matrix expression minimum size checking against a + * run-time size. The expression must derive from readable_matrix. + * + * @param left Matrix expression. + * @param R Minimum row count to check. + * @param C Minimum column count to check. + * + * @throws minimum_matrix_size_error at run-time if @c left is + * dynamically-sized, and if @c left.rows() < @c R or @c left.cols() < @c + * C. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_minimum_size(const readable_matrix& left, int R, int C); + +/** Front-end for compile-time and run-time matrix expression minimum size + * checking against integer constants via int_c and int_c. The + * expression must derive from readable_matrix. + * + * @param left Matrix expression. + * + * @throws minimum_matrix_size_error at run-time if @c left is + * dynamically-sized, and if @c left.rows() < @c R or @c left.cols() < + * @c C. If @c left is a fixed-size expression, then the size is checked + * at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template +void check_minimum_size(const readable_matrix& left, cml::int_c, + cml::int_c); + + +/** Front-end to check for a square matrix. + * + * @throws non_square_matrix_error at run-time if @c left is a + * dynamically-sized expression and @c left.rows() != @c left.cols(). If + * @c left is a fixed-size expression, then the size is checked at compile + * time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_MATRIX_SIZE_CHECKS at compile time. + */ +template void check_square(const readable_matrix& left); + +} // namespace cml + +#define __CML_MATRIX_SIZE_CHECKING_TPP +#include +#undef __CML_MATRIX_SIZE_CHECKING_TPP diff --git a/cml/matrix/size_checking.tpp b/cml/matrix/size_checking.tpp index b141925..9270b23 100644 --- a/cml/matrix/size_checking.tpp +++ b/cml/matrix/size_checking.tpp @@ -1,562 +1,562 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_SIZE_CHECKING_TPP -# error "matrix/size_checking.tpp not included correctly" -#endif - -#include -#include -#include -#include - -namespace cml { -namespace detail { - -/* For checking inner product sizes of vectors and/or matrices: */ -template struct inner_rows_of_c; -template struct inner_cols_of_c; - -/* Use the matrix row size for inner products: */ -template -struct inner_rows_of_c::value != 0>::type> -{ - static const int value = array_rows_of_c::value; -}; - -/* Use the matrix column size for inner products: */ -template -struct inner_cols_of_c::value != 0>::type> -{ - static const int value = array_cols_of_c::value; -}; - -/* The inner product row size for vectors is just the vector size: */ -template -struct inner_rows_of_c::value != 0>::type> -{ - static const int value = array_size_of_c::value; -}; - -/* The inner product column size for vectors is just the vector size: */ -template -struct inner_cols_of_c::value != 0>::type> -{ - static const int value = array_size_of_c::value; -}; - -/* Run-time matrix row size for inner products: */ -template -inline int -inner_rows_of(const readable_matrix& sub) -{ - return sub.rows(); -} - -/* Run-time matrix column size for inner products: */ -template -inline int -inner_cols_of(const readable_matrix& sub) -{ - return sub.cols(); -} - -/* Run-time row size for vectors is the vector size: */ -template -inline int -inner_rows_of(const readable_vector& sub) -{ - return sub.size(); -} - -/* Run-time column size for vectors is the vector size: */ -template -inline int -inner_cols_of(const readable_vector& sub) -{ - return sub.size(); -} - -/* No-op binary matrix expression linear size checking: */ -template -inline void -check_same_linear_size(const readable_matrix&, const Sub2&, any_size_tag) -{} - -/* Compile-time binary matrix expression linear size checking: */ -template -inline void -check_same_linear_size(const readable_matrix&, const Sub2&, - fixed_size_tag) -{ - static_assert(array_rows_of_c::value * array_cols_of_c::value - == array_size_of_c::value, - "incompatible matrix expression sizes"); -} - -/* Run-time binary matrix expression linear size checking: */ -template -inline void -check_same_linear_size(const readable_matrix& left, const Sub2& right, - dynamic_size_tag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require(array_rows_of(left) * array_cols_of(left) == array_size_of(right), - incompatible_matrix_size_error, - /**/); -#endif -} - -/* No-op matrix linear size checking. */ -template -inline void -check_linear_size(const readable_matrix&, int, any_size_tag) -{} - -/* Compile-time matrix linear size checking. */ -template -inline void -check_linear_size(const readable_matrix&, cml::int_c, fixed_size_tag) -{ - static_assert(array_rows_of_c::value * array_cols_of_c::value == N, - "incorrect matrix expression size"); -} - -/* Run-time matrix linear size checking. */ -template -inline void -check_linear_size(const readable_matrix& sub, int N, SizeTag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require(array_rows_of(sub) * array_cols_of(sub) == N, matrix_size_error, - /**/); -#endif -} - -/* No-op binary matrix expression size checking: */ -template -inline void -check_same_size(const readable_matrix&, const Sub2&, any_size_tag) -{} - -/* Compile-time binary matrix expression size checking: */ -template -inline void -check_same_size(const readable_matrix&, const Sub2&, fixed_size_tag) -{ - static_assert((array_rows_of_c::value == array_rows_of_c::value) - && (array_cols_of_c::value == array_cols_of_c::value), - "incompatible matrix expression sizes"); -} - -/* Run-time binary matrix expression size checking: */ -template -inline void -check_same_size(const readable_matrix& left, const Sub2& right, - dynamic_size_tag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require(array_size_of(left) == array_size_of(right), - incompatible_matrix_size_error, - /**/); -#endif -} - -/* Compile-time binary matrix expression size checking against a C-array: */ -template -inline void -check_same_size(const readable_matrix&, Other const (&)[R][C], - fixed_size_tag) -{ - static_assert( - (array_rows_of_c::value == R) && (array_cols_of_c::value == C), - "incompatible matrix expression sizes"); -} - -/* Run-time binary matrix expression size checking against a C-array: */ -template -inline void -check_same_size(const readable_matrix& left, Other const (&)[R][C], - dynamic_size_tag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require((array_rows_of(left) == R && array_cols_of(left) == C), - incompatible_matrix_size_error, - /**/); -#endif -} - -/* No-op binary matrix expression row size checking: */ -template -inline void -check_same_row_size(const readable_matrix&, const Sub2&, any_size_tag) -{} - -/* Compile-time binary matrix expression row size checking against a - * fixed-size readable_vector: - */ -template -inline void -check_same_row_size(const readable_matrix&, const readable_vector&, - fixed_size_tag) -{ - static_assert(array_rows_of_c::value == array_size_of_c::value, - "incompatible matrix row sizes"); -} - -/* Run-time binary matrix expression row size checking against a - * dynamic-size readable_vector: - */ -template -inline void -check_same_row_size(const readable_matrix& left, - const readable_vector& right, dynamic_size_tag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require(array_rows_of(left) == array_size_of(right), - incompatible_matrix_row_size_error, - /**/); -#endif -} - -/* No-op binary matrix expression column size checking: */ -template -inline void -check_same_col_size(const readable_matrix&, const Sub2&, any_size_tag) -{} - -/* Compile-time binary matrix expression column size checking against a - * fixed-size readable_vector: - */ -template -inline void -check_same_col_size(const readable_matrix&, const readable_vector&, - fixed_size_tag) -{ - static_assert(array_cols_of_c::value == array_size_of_c::value, - "incompatible matrix row sizes"); -} - -/* Run-time binary matrix expression column size checking against a - * dynamic-size readable_vector: - */ -template -inline void -check_same_col_size(const readable_matrix& left, - const readable_vector& right, dynamic_size_tag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require(array_cols_of(left) == array_size_of(right), - incompatible_matrix_col_size_error, - /**/); -#endif -} - -/* No-op matrix inner product size checking: */ -template -inline void -check_same_inner_size(const Sub1&, const Sub2&, any_size_tag) -{} - -/* Compile-time matrix inner product size checking: */ -template -inline void -check_same_inner_size(const Sub1&, const Sub2&, fixed_size_tag) -{ - using left_traits = traits_of_t; - using right_traits = traits_of_t; - static_assert( - (inner_cols_of_c::value - == inner_rows_of_c::value), - "incompatible matrix inner product size"); -} - -/* Run-time matrix inner product size checking: */ -template -inline void -check_same_inner_size(const Sub1& left, const Sub2& right, dynamic_size_tag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require(inner_cols_of(left) == inner_rows_of(right), - incompatible_matrix_inner_size_error, - /**/); -#endif -} - -/* No-op matrix size checking. */ -template -inline void -check_size(const readable_matrix&, int, int, any_size_tag) -{} - -/* Compile-time checking against constant row and column sizes. */ -template -inline void -check_size(const readable_matrix&, cml::int_c, cml::int_c, - fixed_size_tag) -{ - static_assert( - (array_rows_of_c::value == R) && (array_cols_of_c::value == C), - "incorrect matrix expression size"); -} - -/* Run-time matrix size checking. */ -template -inline void -check_size(const readable_matrix& sub, int R, int C, SizeTag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require((array_rows_of(sub) == R) && (array_cols_of(sub) == C), - matrix_size_error, - /**/); -#endif -} - -/* No-op minimum matrix size checking. */ -template -inline void -check_minimum_size(const readable_matrix&, int, int, any_size_tag) -{} - -/* Compile-time minimum size checking against constant row and column - * sizes. - */ -template -inline void -check_minimum_size(const readable_matrix&, cml::int_c, cml::int_c, - fixed_size_tag) -{ - static_assert( - (array_rows_of_c::value >= R) && (array_cols_of_c::value >= C), - "matrix expression too small"); -} - -/* Run-time minimum matrix size checking. */ -template -inline void -check_minimum_size(const readable_matrix& sub, int R, int C, SizeTag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require((array_rows_of(sub) >= R) && (array_cols_of(sub) >= C), - minimum_matrix_size_error, - /**/); -#endif -} - -/* No-op square matrix checking. */ -template -inline void -check_square(const readable_matrix&, any_size_tag) -{} - -/* Compile-time square matrix checking. */ -template -inline void -check_square(const readable_matrix&, fixed_size_tag) -{ - static_assert((array_rows_of_c::value == array_cols_of_c::value), - "non-square matrix"); -} - -/* Run-time square matrix checking. */ -template -inline void -check_square(const readable_matrix& sub, SizeTag) -{ -#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS - cml_require( - (array_rows_of(sub) == array_cols_of(sub)), non_square_matrix_error, /**/); -#endif -} - -} // namespace detail - -/* check_same_linear_size: */ - -template -inline void -check_same_linear_size(const readable_matrix& left, - const readable_matrix& right) -{ - using tag1 = size_tag_of_t; - using tag2 = size_tag_of_t; - detail::check_same_linear_size(left, right.actual(), - size_check_promote_t()); -} - -template -inline void -check_same_linear_size(const readable_matrix& left, const Sub2& right, - enable_if_array_t*) -{ - using tag1 = size_tag_of_t; - using tag2 = tag1; // dynamic/dynamic or fixed/fixed. - detail::check_same_linear_size(left, right, - size_check_promote_t()); -} - -template -inline auto -check_same_linear_size(const readable_matrix& left, const Sub2& right) - -> decltype(right.size(), void()) -{ - using tag1 = size_tag_of_t; - using tag2 = dynamic_size_tag; // dynamic/dynamic or fixed/dynamic. - detail::check_same_linear_size(left, right, - size_check_promote_t()); -} - -/* check_linear_size: */ - -template -inline void -check_linear_size(const readable_matrix& left, int n) -{ - using tag = size_tag_of_t; - detail::check_linear_size(left, n, tag()); -} - -template -inline void -check_linear_size(const readable_matrix& left, cml::int_c) -{ - using tag = size_tag_of_t; - detail::check_linear_size(left, cml::int_c(), tag()); -} - -/* check_same_size: */ - -template -inline void -check_same_size(const readable_matrix& left, - const readable_matrix& right) -{ - using tag1 = size_tag_of_t; - using tag2 = size_tag_of_t; - detail::check_same_size(left, right.actual(), - size_check_promote_t()); -} - -template -inline void -check_same_size(const readable_matrix& left, Other const (&array)[R][C]) -{ - using tag1 = size_tag_of_t; - using tag2 = fixed_size_tag; - detail::check_same_size(left, array, size_check_promote_t()); -} - -/* check_same_row_size: */ - -template -inline void -check_same_row_size(const readable_matrix& left, - const readable_vector& right) -{ - using tag1 = size_tag_of_t; - using tag2 = size_tag_of_t; - detail::check_same_row_size(left, right.actual(), - size_check_promote_t()); -} - -/* check_same_col_size: */ - -template -inline void -check_same_col_size(const readable_matrix& left, - const readable_vector& right) -{ - using tag1 = size_tag_of_t; - using tag2 = size_tag_of_t; - detail::check_same_col_size(left, right.actual(), - size_check_promote_t()); -} - -/* check_same_inner_size: */ - -template -inline void -check_same_inner_size(const readable_matrix& left, - const readable_matrix& right) -{ - using tag1 = size_tag_of_t; - using tag2 = size_tag_of_t; - detail::check_same_inner_size(left.actual(), right.actual(), - size_check_promote_t()); -} - -template -inline void -check_same_inner_size(const readable_matrix& left, - const readable_vector& right) -{ - using tag1 = size_tag_of_t; - using tag2 = size_tag_of_t; - detail::check_same_inner_size(left.actual(), right.actual(), - size_check_promote_t()); -} - -template -inline void -check_same_inner_size(const readable_vector& left, - const readable_matrix& right) -{ - using tag1 = size_tag_of_t; - using tag2 = size_tag_of_t; - detail::check_same_inner_size(left.actual(), right.actual(), - size_check_promote_t()); -} - -/* check_size: */ - -template -inline void -check_size(const readable_matrix& left, int R, int C) -{ - using tag = size_tag_of_t; - detail::check_size(left, R, C, tag()); -} - -template -inline void -check_size(const readable_matrix& left, cml::int_c, cml::int_c) -{ - using tag = size_tag_of_t; - detail::check_size(left, cml::int_c(), cml::int_c(), tag()); -} - -/* check_minimum_size: */ - -template -inline void -check_minimum_size(const readable_matrix& left, int R, int C) -{ - using tag = size_tag_of_t; - detail::check_minimum_size(left, R, C, tag()); -} - -template -inline void -check_minimum_size(const readable_matrix& left, cml::int_c, - cml::int_c) -{ - using tag = size_tag_of_t; - detail::check_minimum_size(left, cml::int_c(), cml::int_c(), tag()); -} - -/* check_square: */ - -template -inline void -check_square(const readable_matrix& left) -{ - using tag = size_tag_of_t; - detail::check_square(left, tag()); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_SIZE_CHECKING_TPP +# error "matrix/size_checking.tpp not included correctly" +#endif + +#include +#include +#include +#include + +namespace cml { +namespace detail { + +/* For checking inner product sizes of vectors and/or matrices: */ +template struct inner_rows_of_c; +template struct inner_cols_of_c; + +/* Use the matrix row size for inner products: */ +template +struct inner_rows_of_c::value != 0>::type> +{ + static const int value = array_rows_of_c::value; +}; + +/* Use the matrix column size for inner products: */ +template +struct inner_cols_of_c::value != 0>::type> +{ + static const int value = array_cols_of_c::value; +}; + +/* The inner product row size for vectors is just the vector size: */ +template +struct inner_rows_of_c::value != 0>::type> +{ + static const int value = array_size_of_c::value; +}; + +/* The inner product column size for vectors is just the vector size: */ +template +struct inner_cols_of_c::value != 0>::type> +{ + static const int value = array_size_of_c::value; +}; + +/* Run-time matrix row size for inner products: */ +template +inline int +inner_rows_of(const readable_matrix& sub) +{ + return sub.rows(); +} + +/* Run-time matrix column size for inner products: */ +template +inline int +inner_cols_of(const readable_matrix& sub) +{ + return sub.cols(); +} + +/* Run-time row size for vectors is the vector size: */ +template +inline int +inner_rows_of(const readable_vector& sub) +{ + return sub.size(); +} + +/* Run-time column size for vectors is the vector size: */ +template +inline int +inner_cols_of(const readable_vector& sub) +{ + return sub.size(); +} + +/* No-op binary matrix expression linear size checking: */ +template +inline void +check_same_linear_size(const readable_matrix&, const Sub2&, any_size_tag) +{} + +/* Compile-time binary matrix expression linear size checking: */ +template +inline void +check_same_linear_size(const readable_matrix&, const Sub2&, + fixed_size_tag) +{ + static_assert(array_rows_of_c::value * array_cols_of_c::value + == array_size_of_c::value, + "incompatible matrix expression sizes"); +} + +/* Run-time binary matrix expression linear size checking: */ +template +inline void +check_same_linear_size(const readable_matrix& left, const Sub2& right, + dynamic_size_tag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require(array_rows_of(left) * array_cols_of(left) == array_size_of(right), + incompatible_matrix_size_error, + /**/); +#endif +} + +/* No-op matrix linear size checking. */ +template +inline void +check_linear_size(const readable_matrix&, int, any_size_tag) +{} + +/* Compile-time matrix linear size checking. */ +template +inline void +check_linear_size(const readable_matrix&, cml::int_c, fixed_size_tag) +{ + static_assert(array_rows_of_c::value * array_cols_of_c::value == N, + "incorrect matrix expression size"); +} + +/* Run-time matrix linear size checking. */ +template +inline void +check_linear_size(const readable_matrix& sub, int N, SizeTag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require(array_rows_of(sub) * array_cols_of(sub) == N, matrix_size_error, + /**/); +#endif +} + +/* No-op binary matrix expression size checking: */ +template +inline void +check_same_size(const readable_matrix&, const Sub2&, any_size_tag) +{} + +/* Compile-time binary matrix expression size checking: */ +template +inline void +check_same_size(const readable_matrix&, const Sub2&, fixed_size_tag) +{ + static_assert((array_rows_of_c::value == array_rows_of_c::value) + && (array_cols_of_c::value == array_cols_of_c::value), + "incompatible matrix expression sizes"); +} + +/* Run-time binary matrix expression size checking: */ +template +inline void +check_same_size(const readable_matrix& left, const Sub2& right, + dynamic_size_tag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require(array_size_of(left) == array_size_of(right), + incompatible_matrix_size_error, + /**/); +#endif +} + +/* Compile-time binary matrix expression size checking against a C-array: */ +template +inline void +check_same_size(const readable_matrix&, Other const (&)[R][C], + fixed_size_tag) +{ + static_assert( + (array_rows_of_c::value == R) && (array_cols_of_c::value == C), + "incompatible matrix expression sizes"); +} + +/* Run-time binary matrix expression size checking against a C-array: */ +template +inline void +check_same_size(const readable_matrix& left, Other const (&)[R][C], + dynamic_size_tag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require((array_rows_of(left) == R && array_cols_of(left) == C), + incompatible_matrix_size_error, + /**/); +#endif +} + +/* No-op binary matrix expression row size checking: */ +template +inline void +check_same_row_size(const readable_matrix&, const Sub2&, any_size_tag) +{} + +/* Compile-time binary matrix expression row size checking against a + * fixed-size readable_vector: + */ +template +inline void +check_same_row_size(const readable_matrix&, const readable_vector&, + fixed_size_tag) +{ + static_assert(array_rows_of_c::value == array_size_of_c::value, + "incompatible matrix row sizes"); +} + +/* Run-time binary matrix expression row size checking against a + * dynamic-size readable_vector: + */ +template +inline void +check_same_row_size(const readable_matrix& left, + const readable_vector& right, dynamic_size_tag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require(array_rows_of(left) == array_size_of(right), + incompatible_matrix_row_size_error, + /**/); +#endif +} + +/* No-op binary matrix expression column size checking: */ +template +inline void +check_same_col_size(const readable_matrix&, const Sub2&, any_size_tag) +{} + +/* Compile-time binary matrix expression column size checking against a + * fixed-size readable_vector: + */ +template +inline void +check_same_col_size(const readable_matrix&, const readable_vector&, + fixed_size_tag) +{ + static_assert(array_cols_of_c::value == array_size_of_c::value, + "incompatible matrix row sizes"); +} + +/* Run-time binary matrix expression column size checking against a + * dynamic-size readable_vector: + */ +template +inline void +check_same_col_size(const readable_matrix& left, + const readable_vector& right, dynamic_size_tag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require(array_cols_of(left) == array_size_of(right), + incompatible_matrix_col_size_error, + /**/); +#endif +} + +/* No-op matrix inner product size checking: */ +template +inline void +check_same_inner_size(const Sub1&, const Sub2&, any_size_tag) +{} + +/* Compile-time matrix inner product size checking: */ +template +inline void +check_same_inner_size(const Sub1&, const Sub2&, fixed_size_tag) +{ + using left_traits = traits_of_t; + using right_traits = traits_of_t; + static_assert( + (inner_cols_of_c::value + == inner_rows_of_c::value), + "incompatible matrix inner product size"); +} + +/* Run-time matrix inner product size checking: */ +template +inline void +check_same_inner_size(const Sub1& left, const Sub2& right, dynamic_size_tag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require(inner_cols_of(left) == inner_rows_of(right), + incompatible_matrix_inner_size_error, + /**/); +#endif +} + +/* No-op matrix size checking. */ +template +inline void +check_size(const readable_matrix&, int, int, any_size_tag) +{} + +/* Compile-time checking against constant row and column sizes. */ +template +inline void +check_size(const readable_matrix&, cml::int_c, cml::int_c, + fixed_size_tag) +{ + static_assert( + (array_rows_of_c::value == R) && (array_cols_of_c::value == C), + "incorrect matrix expression size"); +} + +/* Run-time matrix size checking. */ +template +inline void +check_size(const readable_matrix& sub, int R, int C, SizeTag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require((array_rows_of(sub) == R) && (array_cols_of(sub) == C), + matrix_size_error, + /**/); +#endif +} + +/* No-op minimum matrix size checking. */ +template +inline void +check_minimum_size(const readable_matrix&, int, int, any_size_tag) +{} + +/* Compile-time minimum size checking against constant row and column + * sizes. + */ +template +inline void +check_minimum_size(const readable_matrix&, cml::int_c, cml::int_c, + fixed_size_tag) +{ + static_assert( + (array_rows_of_c::value >= R) && (array_cols_of_c::value >= C), + "matrix expression too small"); +} + +/* Run-time minimum matrix size checking. */ +template +inline void +check_minimum_size(const readable_matrix& sub, int R, int C, SizeTag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require((array_rows_of(sub) >= R) && (array_cols_of(sub) >= C), + minimum_matrix_size_error, + /**/); +#endif +} + +/* No-op square matrix checking. */ +template +inline void +check_square(const readable_matrix&, any_size_tag) +{} + +/* Compile-time square matrix checking. */ +template +inline void +check_square(const readable_matrix&, fixed_size_tag) +{ + static_assert((array_rows_of_c::value == array_cols_of_c::value), + "non-square matrix"); +} + +/* Run-time square matrix checking. */ +template +inline void +check_square(const readable_matrix& sub, SizeTag) +{ +#ifndef CML_NO_RUNTIME_MATRIX_SIZE_CHECKS + cml_require( + (array_rows_of(sub) == array_cols_of(sub)), non_square_matrix_error, /**/); +#endif +} + +} // namespace detail + +/* check_same_linear_size: */ + +template +inline void +check_same_linear_size(const readable_matrix& left, + const readable_matrix& right) +{ + using tag1 = size_tag_of_t; + using tag2 = size_tag_of_t; + detail::check_same_linear_size(left, right.actual(), + size_check_promote_t()); +} + +template +inline void +check_same_linear_size(const readable_matrix& left, const Sub2& right, + enable_if_array_t*) +{ + using tag1 = size_tag_of_t; + using tag2 = tag1; // dynamic/dynamic or fixed/fixed. + detail::check_same_linear_size(left, right, + size_check_promote_t()); +} + +template +inline auto +check_same_linear_size(const readable_matrix& left, const Sub2& right) + -> decltype(right.size(), void()) +{ + using tag1 = size_tag_of_t; + using tag2 = dynamic_size_tag; // dynamic/dynamic or fixed/dynamic. + detail::check_same_linear_size(left, right, + size_check_promote_t()); +} + +/* check_linear_size: */ + +template +inline void +check_linear_size(const readable_matrix& left, int n) +{ + using tag = size_tag_of_t; + detail::check_linear_size(left, n, tag()); +} + +template +inline void +check_linear_size(const readable_matrix& left, cml::int_c) +{ + using tag = size_tag_of_t; + detail::check_linear_size(left, cml::int_c(), tag()); +} + +/* check_same_size: */ + +template +inline void +check_same_size(const readable_matrix& left, + const readable_matrix& right) +{ + using tag1 = size_tag_of_t; + using tag2 = size_tag_of_t; + detail::check_same_size(left, right.actual(), + size_check_promote_t()); +} + +template +inline void +check_same_size(const readable_matrix& left, Other const (&array)[R][C]) +{ + using tag1 = size_tag_of_t; + using tag2 = fixed_size_tag; + detail::check_same_size(left, array, size_check_promote_t()); +} + +/* check_same_row_size: */ + +template +inline void +check_same_row_size(const readable_matrix& left, + const readable_vector& right) +{ + using tag1 = size_tag_of_t; + using tag2 = size_tag_of_t; + detail::check_same_row_size(left, right.actual(), + size_check_promote_t()); +} + +/* check_same_col_size: */ + +template +inline void +check_same_col_size(const readable_matrix& left, + const readable_vector& right) +{ + using tag1 = size_tag_of_t; + using tag2 = size_tag_of_t; + detail::check_same_col_size(left, right.actual(), + size_check_promote_t()); +} + +/* check_same_inner_size: */ + +template +inline void +check_same_inner_size(const readable_matrix& left, + const readable_matrix& right) +{ + using tag1 = size_tag_of_t; + using tag2 = size_tag_of_t; + detail::check_same_inner_size(left.actual(), right.actual(), + size_check_promote_t()); +} + +template +inline void +check_same_inner_size(const readable_matrix& left, + const readable_vector& right) +{ + using tag1 = size_tag_of_t; + using tag2 = size_tag_of_t; + detail::check_same_inner_size(left.actual(), right.actual(), + size_check_promote_t()); +} + +template +inline void +check_same_inner_size(const readable_vector& left, + const readable_matrix& right) +{ + using tag1 = size_tag_of_t; + using tag2 = size_tag_of_t; + detail::check_same_inner_size(left.actual(), right.actual(), + size_check_promote_t()); +} + +/* check_size: */ + +template +inline void +check_size(const readable_matrix& left, int R, int C) +{ + using tag = size_tag_of_t; + detail::check_size(left, R, C, tag()); +} + +template +inline void +check_size(const readable_matrix& left, cml::int_c, cml::int_c) +{ + using tag = size_tag_of_t; + detail::check_size(left, cml::int_c(), cml::int_c(), tag()); +} + +/* check_minimum_size: */ + +template +inline void +check_minimum_size(const readable_matrix& left, int R, int C) +{ + using tag = size_tag_of_t; + detail::check_minimum_size(left, R, C, tag()); +} + +template +inline void +check_minimum_size(const readable_matrix& left, cml::int_c, + cml::int_c) +{ + using tag = size_tag_of_t; + detail::check_minimum_size(left, cml::int_c(), cml::int_c(), tag()); +} + +/* check_square: */ + +template +inline void +check_square(const readable_matrix& left) +{ + using tag = size_tag_of_t; + detail::check_square(left, tag()); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/temporary.h b/cml/matrix/temporary.h index 72a3a60..abb53db 100644 --- a/cml/matrix/temporary.h +++ b/cml/matrix/temporary.h @@ -1,35 +1,35 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace cml { - -/** Deduce a temporary for a matrix expression. */ -template -struct temporary_of> -{ - using matrix_type = cml::unqualified_type_t; - - /* Propagate the element type of the original matrix: */ - using traits_type = matrix_traits; - using value_type = typename traits_type::value_type; - using storage_type = typename traits_type::storage_type; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - /* Need the proxy for the storage type: */ - using proxy_type = typename storage_type::proxy_type; - - /* Build the temporary: */ - using type = matrix; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace cml { + +/** Deduce a temporary for a matrix expression. */ +template +struct temporary_of> +{ + using matrix_type = cml::unqualified_type_t; + + /* Propagate the element type of the original matrix: */ + using traits_type = matrix_traits; + using value_type = typename traits_type::value_type; + using storage_type = typename traits_type::storage_type; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + /* Need the proxy for the storage type: */ + using proxy_type = typename storage_type::proxy_type; + + /* Build the temporary: */ + using type = matrix; +}; + +} // namespace cml diff --git a/cml/matrix/trace.h b/cml/matrix/trace.h index 1d38490..b006c5a 100644 --- a/cml/matrix/trace.h +++ b/cml/matrix/trace.h @@ -1,25 +1,25 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Compute the trace of square matrix @c M. - * - * @throws non_square_matrix_error at run-time if the matrix is - * dynamically-sized and not square. Fixed-size matrices are checked at - * compile-time. - */ -template -auto trace(const readable_matrix& M) -> value_type_trait_of_t; - -} // namespace cml - -#define __CML_MATRIX_TRACE_TPP -#include -#undef __CML_MATRIX_TRACE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Compute the trace of square matrix @c M. + * + * @throws non_square_matrix_error at run-time if the matrix is + * dynamically-sized and not square. Fixed-size matrices are checked at + * compile-time. + */ +template +auto trace(const readable_matrix& M) -> value_type_trait_of_t; + +} // namespace cml + +#define __CML_MATRIX_TRACE_TPP +#include +#undef __CML_MATRIX_TRACE_TPP diff --git a/cml/matrix/trace.tpp b/cml/matrix/trace.tpp index 60f115c..6eb1143 100644 --- a/cml/matrix/trace.tpp +++ b/cml/matrix/trace.tpp @@ -1,20 +1,20 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_TRACE_TPP -# error "matrix/trace.tpp not included correctly" -#endif - -#include - -namespace cml { - -template -inline auto -trace(const readable_matrix& M) -> value_type_trait_of_t -{ - return M.trace(); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_TRACE_TPP +# error "matrix/trace.tpp not included correctly" +#endif + +#include + +namespace cml { + +template +inline auto +trace(const readable_matrix& M) -> value_type_trait_of_t +{ + return M.trace(); +} + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/traits.h b/cml/matrix/traits.h index ae3324e..b312dea 100644 --- a/cml/matrix/traits.h +++ b/cml/matrix/traits.h @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Specializable class wrapping traits for matrix<> types. This class - * is used to simplify static polymorphism by providing a polymorphic base - * class the types used by a particular derived class. - * - * @tparam Matrix The matrix<> type the traits correspond to. - */ -template struct matrix_traits; - -/** traits_of for matrix types. */ -template struct traits_of> -{ - using type = matrix_traits; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Specializable class wrapping traits for matrix<> types. This class + * is used to simplify static polymorphism by providing a polymorphic base + * class the types used by a particular derived class. + * + * @tparam Matrix The matrix<> type the traits correspond to. + */ +template struct matrix_traits; + +/** traits_of for matrix types. */ +template struct traits_of> +{ + using type = matrix_traits; +}; + +} // namespace cml diff --git a/cml/matrix/transpose.h b/cml/matrix/transpose.h index 18b54ee..0288ab7 100644 --- a/cml/matrix/transpose.h +++ b/cml/matrix/transpose.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/matrix/transpose_node.h b/cml/matrix/transpose_node.h index 3ea2351..2a5b20e 100644 --- a/cml/matrix/transpose_node.h +++ b/cml/matrix/transpose_node.h @@ -1,135 +1,135 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class matrix_transpose_node; - -/** matrix_transpose_node<> traits. */ -template struct matrix_traits> -{ - using matrix_type = matrix_transpose_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = matrix_traits; - using element_traits = typename sub_traits::element_traits; - using value_type = typename sub_traits::value_type; - using immutable_value = typename sub_traits::immutable_value; - using storage_type = typename sub_traits::storage_type; - using size_tag = typename sub_traits::size_tag; - using basis_tag = typename sub_traits::basis_tag; - using layout_tag = typename sub_traits::layout_tag; - -#if 0 - /* Flip the layout: */ - typedef typename sub_traits::layout_tag sub_layout; - typedef typename sub_layout::transposed_tag layout_tag; -#endif - - /* Propagate the rows from the subexpression: */ - static const int array_rows = sub_traits::array_cols; - - /* Propagate the columns from the subexpression: */ - static const int array_cols = sub_traits::array_rows; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; -}; - -/** Represents a transpose matrix operation in an expression tree. */ -template -class matrix_transpose_node : public readable_matrix> -{ - public: - using node_type = matrix_transpose_node; - using readable_type = readable_matrix; - using traits_type = matrix_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /** Constant containing the number of rows. */ - static const int array_rows = traits_type::array_rows; - - /** Constant containing the number of columns. */ - static const int array_cols = traits_type::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - - public: - /** Construct from the wrapped sub-expression. @c sub must be an - * lvalue reference or rvalue reference type. - */ - matrix_transpose_node(Sub sub); - - /** Move constructor. */ - matrix_transpose_node(node_type&& other); - - /** Copy constructor. */ - matrix_transpose_node(const node_type& other); - - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the row size of the transposed matrix expression. */ - int i_rows() const; - - /** Return the column size of the transposed matrix expression. */ - int i_cols() const; - - /** Return element @c (j,i) of the subexpression. */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using sub_wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - - protected: - /** The wrapped subexpression. */ - sub_wrap_type m_sub; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_MATRIX_TRANSPOSE_NODE_TPP -#include -#undef __CML_MATRIX_TRANSPOSE_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class matrix_transpose_node; + +/** matrix_transpose_node<> traits. */ +template struct matrix_traits> +{ + using matrix_type = matrix_transpose_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = matrix_traits; + using element_traits = typename sub_traits::element_traits; + using value_type = typename sub_traits::value_type; + using immutable_value = typename sub_traits::immutable_value; + using storage_type = typename sub_traits::storage_type; + using size_tag = typename sub_traits::size_tag; + using basis_tag = typename sub_traits::basis_tag; + using layout_tag = typename sub_traits::layout_tag; + +#if 0 + /* Flip the layout: */ + typedef typename sub_traits::layout_tag sub_layout; + typedef typename sub_layout::transposed_tag layout_tag; +#endif + + /* Propagate the rows from the subexpression: */ + static const int array_rows = sub_traits::array_cols; + + /* Propagate the columns from the subexpression: */ + static const int array_cols = sub_traits::array_rows; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; +}; + +/** Represents a transpose matrix operation in an expression tree. */ +template +class matrix_transpose_node : public readable_matrix> +{ + public: + using node_type = matrix_transpose_node; + using readable_type = readable_matrix; + using traits_type = matrix_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /** Constant containing the number of rows. */ + static const int array_rows = traits_type::array_rows; + + /** Constant containing the number of columns. */ + static const int array_cols = traits_type::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + + public: + /** Construct from the wrapped sub-expression. @c sub must be an + * lvalue reference or rvalue reference type. + */ + matrix_transpose_node(Sub sub); + + /** Move constructor. */ + matrix_transpose_node(node_type&& other); + + /** Copy constructor. */ + matrix_transpose_node(const node_type& other); + + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the row size of the transposed matrix expression. */ + int i_rows() const; + + /** Return the column size of the transposed matrix expression. */ + int i_cols() const; + + /** Return element @c (j,i) of the subexpression. */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using sub_wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + + protected: + /** The wrapped subexpression. */ + sub_wrap_type m_sub; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_MATRIX_TRANSPOSE_NODE_TPP +#include +#undef __CML_MATRIX_TRANSPOSE_NODE_TPP diff --git a/cml/matrix/transpose_node.tpp b/cml/matrix/transpose_node.tpp index 56c4f07..51e31ee 100644 --- a/cml/matrix/transpose_node.tpp +++ b/cml/matrix/transpose_node.tpp @@ -1,53 +1,53 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_TRANSPOSE_NODE_TPP -# error "matrix/transpose_node.tpp not included correctly" -#endif - -namespace cml { - -/* matrix_transpose_node 'structors: */ - -template -matrix_transpose_node::matrix_transpose_node(Sub sub) -: m_sub(std::move(sub)) -{} - -template -matrix_transpose_node::matrix_transpose_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -{} - -template -matrix_transpose_node::matrix_transpose_node(const node_type& other) -: m_sub(other.m_sub) -{} - -/* Internal methods: */ - -/* readable_matrix interface: */ - -template -int -matrix_transpose_node::i_rows() const -{ - return this->m_sub.cols(); -} - -template -int -matrix_transpose_node::i_cols() const -{ - return this->m_sub.rows(); -} - -template -auto -matrix_transpose_node::i_get(int i, int j) const -> immutable_value -{ - return this->m_sub.get(j, i); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_TRANSPOSE_NODE_TPP +# error "matrix/transpose_node.tpp not included correctly" +#endif + +namespace cml { + +/* matrix_transpose_node 'structors: */ + +template +matrix_transpose_node::matrix_transpose_node(Sub sub) +: m_sub(std::move(sub)) +{} + +template +matrix_transpose_node::matrix_transpose_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +{} + +template +matrix_transpose_node::matrix_transpose_node(const node_type& other) +: m_sub(other.m_sub) +{} + +/* Internal methods: */ + +/* readable_matrix interface: */ + +template +int +matrix_transpose_node::i_rows() const +{ + return this->m_sub.cols(); +} + +template +int +matrix_transpose_node::i_cols() const +{ + return this->m_sub.rows(); +} + +template +auto +matrix_transpose_node::i_get(int i, int j) const -> immutable_value +{ + return this->m_sub.get(j, i); +} + +} // namespace cml diff --git a/cml/matrix/transpose_ops.h b/cml/matrix/transpose_ops.h index e5ac618..e66e457 100644 --- a/cml/matrix/transpose_ops.h +++ b/cml/matrix/transpose_ops.h @@ -1,36 +1,36 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Helper function to generate a matrix_unary_node from a matrix type - * (i.e. derived from readable_matrix<>). - */ -template* = nullptr> -inline auto -make_matrix_transpose_node(Sub&& sub) - -> matrix_transpose_node> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type"); - - /* Deduce the operand type of the subexpression (&, const&, &&): */ - using sub_type = actual_operand_type_of_t; - return matrix_transpose_node((sub_type) sub); -} - -template* = nullptr> -inline auto -transpose(Sub&& sub) - -> decltype(make_matrix_transpose_node(std::forward(sub))) -{ - return make_matrix_transpose_node(std::forward(sub)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Helper function to generate a matrix_unary_node from a matrix type + * (i.e. derived from readable_matrix<>). + */ +template* = nullptr> +inline auto +make_matrix_transpose_node(Sub&& sub) + -> matrix_transpose_node> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type"); + + /* Deduce the operand type of the subexpression (&, const&, &&): */ + using sub_type = actual_operand_type_of_t; + return matrix_transpose_node((sub_type) sub); +} + +template* = nullptr> +inline auto +transpose(Sub&& sub) + -> decltype(make_matrix_transpose_node(std::forward(sub))) +{ + return make_matrix_transpose_node(std::forward(sub)); +} + +} // namespace cml diff --git a/cml/matrix/type_util.h b/cml/matrix/type_util.h index e0af138..eaea555 100644 --- a/cml/matrix/type_util.h +++ b/cml/matrix/type_util.h @@ -1,48 +1,48 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Defines typedef @c type as std::true_type if @c T is statically - * polymorphic and derived from @c readable_matrix, or std::false_type - * otherwise. The static bool @c value is set to true or false to match @c - * type. - */ -template struct is_matrix -{ - private: - /* Strip const, volatile, and reference from T to get the type to test: */ - using naked_type = cml::unqualified_type_t; - - /* Deduce the derived type (fails if T is not statically polymorphic): */ - using derived_type = actual_type_of_t; - - - public: - /* std::true_type if T is derived from readable_matrix<>, std::false_type - * otherwise: - */ - using type = std::is_base_of, naked_type>; - - /* True or false, depending upon 'type': */ - static const bool value = type::value; -}; - -/** Wrapper for enable_if to detect matrix types (derived from - * readable_matrix). - */ -template -struct enable_if_matrix : std::enable_if::value> -{}; - -/** Convenience alias for enable_if_matrix. */ -template -using enable_if_matrix_t = typename enable_if_matrix::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Defines typedef @c type as std::true_type if @c T is statically + * polymorphic and derived from @c readable_matrix, or std::false_type + * otherwise. The static bool @c value is set to true or false to match @c + * type. + */ +template struct is_matrix +{ + private: + /* Strip const, volatile, and reference from T to get the type to test: */ + using naked_type = cml::unqualified_type_t; + + /* Deduce the derived type (fails if T is not statically polymorphic): */ + using derived_type = actual_type_of_t; + + + public: + /* std::true_type if T is derived from readable_matrix<>, std::false_type + * otherwise: + */ + using type = std::is_base_of, naked_type>; + + /* True or false, depending upon 'type': */ + static const bool value = type::value; +}; + +/** Wrapper for enable_if to detect matrix types (derived from + * readable_matrix). + */ +template +struct enable_if_matrix : std::enable_if::value> +{}; + +/** Convenience alias for enable_if_matrix. */ +template +using enable_if_matrix_t = typename enable_if_matrix::type; + +} // namespace cml diff --git a/cml/matrix/types.h b/cml/matrix/types.h index 70810df..497c921 100644 --- a/cml/matrix/types.h +++ b/cml/matrix/types.h @@ -1,140 +1,140 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** @defgroup matrix_types Predefined Matrix Types */ -/*@{*/ - -// Column-basis, row-major: -using matrix22i = matrix>; -using matrix33i = matrix>; -using matrix44i = matrix>; -using matrix23i = matrix>; -using matrix34i = matrix>; -using matrixi = matrix>; -using external22i = matrix>; -using external33i = matrix>; -using external44i = matrix>; -using external23i = matrix>; -using external34i = matrix>; -using externalmni = matrix>; - -using matrix22f = matrix>; -using matrix33f = matrix>; -using matrix44f = matrix>; -using matrix32f = matrix>; -using matrix34f = matrix>; -using matrixf = matrix>; -using external22f = matrix>; -using external33f = matrix>; -using external44f = matrix>; -using external23f = matrix>; -using external34f = matrix>; -using externalmnf = matrix>; - -using matrix22d = matrix>; -using matrix33d = matrix>; -using matrix44d = matrix>; -using matrix23d = matrix>; -using matrix34d = matrix>; -using matrixd = matrix>; -using external22d = matrix>; -using external33d = matrix>; -using external44d = matrix>; -using external23d = matrix>; -using external34d = matrix>; -using externalmnd = matrix>; - - -// Row-basis, row-major: -using matrix22i_r = matrix, row_basis, row_major>; -using matrix33i_r = matrix, row_basis, row_major>; -using matrix44i_r = matrix, row_basis, row_major>; -using matrix32i_r = matrix, row_basis, row_major>; -using matrix43i_r = matrix, row_basis, row_major>; -using matrixi_r = matrix, row_basis, row_major>; -using external22i_r = matrix, row_basis, row_major>; -using external33i_r = matrix, row_basis, row_major>; -using external44i_r = matrix, row_basis, row_major>; -using external32i_r = matrix, row_basis, row_major>; -using external43i_r = matrix, row_basis, row_major>; -using externalmni_r = matrix, row_basis, row_major>; - - -using matrix22f_r = matrix, row_basis, row_major>; -using matrix33f_r = matrix, row_basis, row_major>; -using matrix44f_r = matrix, row_basis, row_major>; -using matrix32f_r = matrix, row_basis, row_major>; -using matrix43f_r = matrix, row_basis, row_major>; -using matrixf_r = matrix, row_basis, row_major>; -using external22f_r = matrix, row_basis, row_major>; -using external33f_r = matrix, row_basis, row_major>; -using external44f_r = matrix, row_basis, row_major>; -using external32f_r = matrix, row_basis, row_major>; -using external43f_r = matrix, row_basis, row_major>; -using externalmnf_r = matrix, row_basis, row_major>; - -using matrix22d_r = matrix, row_basis, row_major>; -using matrix33d_r = matrix, row_basis, row_major>; -using matrix44d_r = matrix, row_basis, row_major>; -using matrix32d_r = matrix, row_basis, row_major>; -using matrix43d_r = matrix, row_basis, row_major>; -using matrixd_r = matrix, row_basis, row_major>; -using external22d_r = matrix, row_basis, row_major>; -using external33d_r = matrix, row_basis, row_major>; -using external44d_r = matrix, row_basis, row_major>; -using external32d_r = matrix, row_basis, row_major>; -using external43d_r = matrix, row_basis, row_major>; -using externalmnd_r = matrix, row_basis, row_major>; - - -// Column-basis, column-major: -using matrix22i_c = matrix, col_basis, col_major>; -using matrix33i_c = matrix, col_basis, col_major>; -using matrix44i_c = matrix, col_basis, col_major>; -using matrix23i_c = matrix, col_basis, col_major>; -using matrix34i_c = matrix, col_basis, col_major>; -using matrixi_c = matrix, col_basis, col_major>; -using external22i_c = matrix, col_basis, col_major>; -using external33i_c = matrix, col_basis, col_major>; -using external44i_c = matrix, col_basis, col_major>; -using external23i_c = matrix, col_basis, col_major>; -using external34i_c = matrix, col_basis, col_major>; -using externalmni_c = matrix, col_basis, col_major>; - -using matrix22f_c = matrix, col_basis, col_major>; -using matrix33f_c = matrix, col_basis, col_major>; -using matrix44f_c = matrix, col_basis, col_major>; -using matrix23f_c = matrix, col_basis, col_major>; -using matrix34f_c = matrix, col_basis, col_major>; -using matrixf_c = matrix, col_basis, col_major>; -using external22f_c = matrix, col_basis, col_major>; -using external33f_c = matrix, col_basis, col_major>; -using external44f_c = matrix, col_basis, col_major>; -using external23f_c = matrix, col_basis, col_major>; -using external34f_c = matrix, col_basis, col_major>; -using externalmnf_c = matrix, col_basis, col_major>; - -using matrix22d_c = matrix, col_basis, col_major>; -using matrix33d_c = matrix, col_basis, col_major>; -using matrix44d_c = matrix, col_basis, col_major>; -using matrix23d_c = matrix, col_basis, col_major>; -using matrix34d_c = matrix, col_basis, col_major>; -using matrixd_c = matrix, col_basis, col_major>; -using external22d_c = matrix, col_basis, col_major>; -using external33d_c = matrix, col_basis, col_major>; -using external44d_c = matrix, col_basis, col_major>; -using external23d_c = matrix, col_basis, col_major>; -using external34d_c = matrix, col_basis, col_major>; -using externalmnd_c = matrix, col_basis, col_major>; - -/*@}*/ - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** @defgroup matrix_types Predefined Matrix Types */ +/*@{*/ + +// Column-basis, row-major: +using matrix22i = matrix>; +using matrix33i = matrix>; +using matrix44i = matrix>; +using matrix23i = matrix>; +using matrix34i = matrix>; +using matrixi = matrix>; +using external22i = matrix>; +using external33i = matrix>; +using external44i = matrix>; +using external23i = matrix>; +using external34i = matrix>; +using externalmni = matrix>; + +using matrix22f = matrix>; +using matrix33f = matrix>; +using matrix44f = matrix>; +using matrix32f = matrix>; +using matrix34f = matrix>; +using matrixf = matrix>; +using external22f = matrix>; +using external33f = matrix>; +using external44f = matrix>; +using external23f = matrix>; +using external34f = matrix>; +using externalmnf = matrix>; + +using matrix22d = matrix>; +using matrix33d = matrix>; +using matrix44d = matrix>; +using matrix23d = matrix>; +using matrix34d = matrix>; +using matrixd = matrix>; +using external22d = matrix>; +using external33d = matrix>; +using external44d = matrix>; +using external23d = matrix>; +using external34d = matrix>; +using externalmnd = matrix>; + + +// Row-basis, row-major: +using matrix22i_r = matrix, row_basis, row_major>; +using matrix33i_r = matrix, row_basis, row_major>; +using matrix44i_r = matrix, row_basis, row_major>; +using matrix32i_r = matrix, row_basis, row_major>; +using matrix43i_r = matrix, row_basis, row_major>; +using matrixi_r = matrix, row_basis, row_major>; +using external22i_r = matrix, row_basis, row_major>; +using external33i_r = matrix, row_basis, row_major>; +using external44i_r = matrix, row_basis, row_major>; +using external32i_r = matrix, row_basis, row_major>; +using external43i_r = matrix, row_basis, row_major>; +using externalmni_r = matrix, row_basis, row_major>; + + +using matrix22f_r = matrix, row_basis, row_major>; +using matrix33f_r = matrix, row_basis, row_major>; +using matrix44f_r = matrix, row_basis, row_major>; +using matrix32f_r = matrix, row_basis, row_major>; +using matrix43f_r = matrix, row_basis, row_major>; +using matrixf_r = matrix, row_basis, row_major>; +using external22f_r = matrix, row_basis, row_major>; +using external33f_r = matrix, row_basis, row_major>; +using external44f_r = matrix, row_basis, row_major>; +using external32f_r = matrix, row_basis, row_major>; +using external43f_r = matrix, row_basis, row_major>; +using externalmnf_r = matrix, row_basis, row_major>; + +using matrix22d_r = matrix, row_basis, row_major>; +using matrix33d_r = matrix, row_basis, row_major>; +using matrix44d_r = matrix, row_basis, row_major>; +using matrix32d_r = matrix, row_basis, row_major>; +using matrix43d_r = matrix, row_basis, row_major>; +using matrixd_r = matrix, row_basis, row_major>; +using external22d_r = matrix, row_basis, row_major>; +using external33d_r = matrix, row_basis, row_major>; +using external44d_r = matrix, row_basis, row_major>; +using external32d_r = matrix, row_basis, row_major>; +using external43d_r = matrix, row_basis, row_major>; +using externalmnd_r = matrix, row_basis, row_major>; + + +// Column-basis, column-major: +using matrix22i_c = matrix, col_basis, col_major>; +using matrix33i_c = matrix, col_basis, col_major>; +using matrix44i_c = matrix, col_basis, col_major>; +using matrix23i_c = matrix, col_basis, col_major>; +using matrix34i_c = matrix, col_basis, col_major>; +using matrixi_c = matrix, col_basis, col_major>; +using external22i_c = matrix, col_basis, col_major>; +using external33i_c = matrix, col_basis, col_major>; +using external44i_c = matrix, col_basis, col_major>; +using external23i_c = matrix, col_basis, col_major>; +using external34i_c = matrix, col_basis, col_major>; +using externalmni_c = matrix, col_basis, col_major>; + +using matrix22f_c = matrix, col_basis, col_major>; +using matrix33f_c = matrix, col_basis, col_major>; +using matrix44f_c = matrix, col_basis, col_major>; +using matrix23f_c = matrix, col_basis, col_major>; +using matrix34f_c = matrix, col_basis, col_major>; +using matrixf_c = matrix, col_basis, col_major>; +using external22f_c = matrix, col_basis, col_major>; +using external33f_c = matrix, col_basis, col_major>; +using external44f_c = matrix, col_basis, col_major>; +using external23f_c = matrix, col_basis, col_major>; +using external34f_c = matrix, col_basis, col_major>; +using externalmnf_c = matrix, col_basis, col_major>; + +using matrix22d_c = matrix, col_basis, col_major>; +using matrix33d_c = matrix, col_basis, col_major>; +using matrix44d_c = matrix, col_basis, col_major>; +using matrix23d_c = matrix, col_basis, col_major>; +using matrix34d_c = matrix, col_basis, col_major>; +using matrixd_c = matrix, col_basis, col_major>; +using external22d_c = matrix, col_basis, col_major>; +using external33d_c = matrix, col_basis, col_major>; +using external44d_c = matrix, col_basis, col_major>; +using external23d_c = matrix, col_basis, col_major>; +using external34d_c = matrix, col_basis, col_major>; +using externalmnd_c = matrix, col_basis, col_major>; + +/*@}*/ + +} // namespace cml diff --git a/cml/matrix/unary_node.h b/cml/matrix/unary_node.h index 855c624..85dd135 100644 --- a/cml/matrix/unary_node.h +++ b/cml/matrix/unary_node.h @@ -1,131 +1,131 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class matrix_unary_node; - -/** matrix_unary_node<> traits. */ -template struct matrix_traits> -{ - using matrix_type = matrix_unary_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = matrix_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - using storage_type = typename sub_traits::storage_type; - using size_tag = typename sub_traits::size_tag; - using basis_tag = typename sub_traits::basis_tag; - using layout_tag = typename sub_traits::layout_tag; - - /* Propagate the rows from the subexpression: */ - static const int array_rows = sub_traits::array_rows; - - /* Propagate the columns from the subexpression: */ - static const int array_cols = sub_traits::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; -}; - -/** Represents a unary matrix operation in an expression tree. */ -template -class matrix_unary_node : public readable_matrix> -{ - public: - using node_type = matrix_unary_node; - using readable_type = readable_matrix; - using traits_type = matrix_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /** Constant containing the number of rows. */ - static const int array_rows = traits_type::array_rows; - - /** Constant containing the number of columns. */ - static const int array_cols = traits_type::array_cols; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - - public: - /** Construct from the wrapped sub-expression. @c sub must be an - * lvalue reference or rvalue reference type. - */ - explicit matrix_unary_node(Sub sub); - - /** Move constructor. */ - matrix_unary_node(node_type&& other); - - /** Copy constructor. */ - matrix_unary_node(const node_type& other); - - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the row size of the matrix expression. */ - int i_rows() const; - - /** Return the column size of the matrix expression. */ - int i_cols() const; - - /** Apply the operator to element @c (i,j) of the subexpressions and - * return the result. - */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using sub_wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - - protected: - /** The wrapped subexpression. */ - sub_wrap_type m_sub; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_MATRIX_UNARY_NODE_TPP -#include -#undef __CML_MATRIX_UNARY_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class matrix_unary_node; + +/** matrix_unary_node<> traits. */ +template struct matrix_traits> +{ + using matrix_type = matrix_unary_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = matrix_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + using storage_type = typename sub_traits::storage_type; + using size_tag = typename sub_traits::size_tag; + using basis_tag = typename sub_traits::basis_tag; + using layout_tag = typename sub_traits::layout_tag; + + /* Propagate the rows from the subexpression: */ + static const int array_rows = sub_traits::array_rows; + + /* Propagate the columns from the subexpression: */ + static const int array_cols = sub_traits::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; +}; + +/** Represents a unary matrix operation in an expression tree. */ +template +class matrix_unary_node : public readable_matrix> +{ + public: + using node_type = matrix_unary_node; + using readable_type = readable_matrix; + using traits_type = matrix_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /** Constant containing the number of rows. */ + static const int array_rows = traits_type::array_rows; + + /** Constant containing the number of columns. */ + static const int array_cols = traits_type::array_cols; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + + public: + /** Construct from the wrapped sub-expression. @c sub must be an + * lvalue reference or rvalue reference type. + */ + explicit matrix_unary_node(Sub sub); + + /** Move constructor. */ + matrix_unary_node(node_type&& other); + + /** Copy constructor. */ + matrix_unary_node(const node_type& other); + + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the row size of the matrix expression. */ + int i_rows() const; + + /** Return the column size of the matrix expression. */ + int i_cols() const; + + /** Apply the operator to element @c (i,j) of the subexpressions and + * return the result. + */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using sub_wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + + protected: + /** The wrapped subexpression. */ + sub_wrap_type m_sub; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_MATRIX_UNARY_NODE_TPP +#include +#undef __CML_MATRIX_UNARY_NODE_TPP diff --git a/cml/matrix/unary_node.tpp b/cml/matrix/unary_node.tpp index 4bb98cf..f672819 100644 --- a/cml/matrix/unary_node.tpp +++ b/cml/matrix/unary_node.tpp @@ -1,53 +1,53 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_UNARY_NODE_TPP -# error "matrix/unary_node.tpp not included correctly" -#endif - -namespace cml { - -/* matrix_unary_node 'structors: */ - -template -matrix_unary_node::matrix_unary_node(Sub sub) -: m_sub(std::move(sub)) -{} - -template -matrix_unary_node::matrix_unary_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -{} - -template -matrix_unary_node::matrix_unary_node(const node_type& other) -: m_sub(other.m_sub) -{} - -/* Internal methods: */ - -/* readable_matrix interface: */ - -template -int -matrix_unary_node::i_rows() const -{ - return this->m_sub.rows(); -} - -template -int -matrix_unary_node::i_cols() const -{ - return this->m_sub.cols(); -} - -template -auto -matrix_unary_node::i_get(int i, int j) const -> immutable_value -{ - return Op().apply(this->m_sub.get(i, j)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_UNARY_NODE_TPP +# error "matrix/unary_node.tpp not included correctly" +#endif + +namespace cml { + +/* matrix_unary_node 'structors: */ + +template +matrix_unary_node::matrix_unary_node(Sub sub) +: m_sub(std::move(sub)) +{} + +template +matrix_unary_node::matrix_unary_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +{} + +template +matrix_unary_node::matrix_unary_node(const node_type& other) +: m_sub(other.m_sub) +{} + +/* Internal methods: */ + +/* readable_matrix interface: */ + +template +int +matrix_unary_node::i_rows() const +{ + return this->m_sub.rows(); +} + +template +int +matrix_unary_node::i_cols() const +{ + return this->m_sub.cols(); +} + +template +auto +matrix_unary_node::i_get(int i, int j) const -> immutable_value +{ + return Op().apply(this->m_sub.get(i, j)); +} + +} // namespace cml diff --git a/cml/matrix/unary_ops.h b/cml/matrix/unary_ops.h index 46f594e..08fa078 100644 --- a/cml/matrix/unary_ops.h +++ b/cml/matrix/unary_ops.h @@ -1,45 +1,45 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Helper function to generate a matrix_unary_node from a matrix type - * (i.e. derived from readable_matrix<>). - */ -template* = nullptr> -inline auto -make_matrix_unary_node(Sub&& sub) - -> matrix_unary_node, Op> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type"); - - /* Deduce the operand type of the subexpression (&, const&, &&): */ - using sub_type = actual_operand_type_of_t; - return matrix_unary_node((sub_type) sub); -} - -template* = nullptr> -inline auto -operator-(Sub&& sub) -> decltype(make_matrix_unary_node>( - std::forward(sub))) -{ - return make_matrix_unary_node>(std::forward(sub)); -} - -template* = nullptr> -inline auto -operator+(Sub&& sub) - -> decltype(make_matrix_unary_node>(std::forward(sub))) -{ - return make_matrix_unary_node>(std::forward(sub)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Helper function to generate a matrix_unary_node from a matrix type + * (i.e. derived from readable_matrix<>). + */ +template* = nullptr> +inline auto +make_matrix_unary_node(Sub&& sub) + -> matrix_unary_node, Op> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type"); + + /* Deduce the operand type of the subexpression (&, const&, &&): */ + using sub_type = actual_operand_type_of_t; + return matrix_unary_node((sub_type) sub); +} + +template* = nullptr> +inline auto +operator-(Sub&& sub) -> decltype(make_matrix_unary_node>( + std::forward(sub))) +{ + return make_matrix_unary_node>(std::forward(sub)); +} + +template* = nullptr> +inline auto +operator+(Sub&& sub) + -> decltype(make_matrix_unary_node>(std::forward(sub))) +{ + return make_matrix_unary_node>(std::forward(sub)); +} + +} // namespace cml diff --git a/cml/matrix/vector_product.h b/cml/matrix/vector_product.h index 160a40b..728eef5 100644 --- a/cml/matrix/vector_product.h +++ b/cml/matrix/vector_product.h @@ -1,33 +1,33 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Multiply a vector by a matrix, and return the vector result as a - * temporary. - */ -template* = nullptr, - enable_if_vector_t* = nullptr> -auto operator*(Sub1&& sub1, Sub2&& sub2) - -> matrix_inner_product_promote_t, - actual_operand_type_of_t>; - -/** Multiply a matrix by a vector, and return the vector result as a - * temporary. - */ -template* = nullptr, - enable_if_matrix_t* = nullptr> -auto operator*(Sub1&& sub1, Sub2&& sub2) - -> matrix_inner_product_promote_t, - actual_operand_type_of_t>; - -} // namespace cml - -#define __CML_MATRIX_VECTOR_PRODUCT_TPP -#include -#undef __CML_MATRIX_VECTOR_PRPDUCT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Multiply a vector by a matrix, and return the vector result as a + * temporary. + */ +template* = nullptr, + enable_if_vector_t* = nullptr> +auto operator*(Sub1&& sub1, Sub2&& sub2) + -> matrix_inner_product_promote_t, + actual_operand_type_of_t>; + +/** Multiply a matrix by a vector, and return the vector result as a + * temporary. + */ +template* = nullptr, + enable_if_matrix_t* = nullptr> +auto operator*(Sub1&& sub1, Sub2&& sub2) + -> matrix_inner_product_promote_t, + actual_operand_type_of_t>; + +} // namespace cml + +#define __CML_MATRIX_VECTOR_PRODUCT_TPP +#include +#undef __CML_MATRIX_VECTOR_PRPDUCT_TPP diff --git a/cml/matrix/vector_product.tpp b/cml/matrix/vector_product.tpp index e62e96f..45bb005 100644 --- a/cml/matrix/vector_product.tpp +++ b/cml/matrix/vector_product.tpp @@ -1,64 +1,64 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_VECTOR_PRODUCT_TPP -# error "matrix/vector_product.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -template*, - enable_if_vector_t*> -inline auto -operator*(Sub1&& sub1, Sub2&& sub2) - -> matrix_inner_product_promote_t, - actual_operand_type_of_t> -{ - using result_type = matrix_inner_product_promote_t< - actual_operand_type_of_t, - actual_operand_type_of_t>; - - cml::check_same_inner_size(sub1, sub2); - - result_type v; - detail::resize(v, array_rows_of(sub1)); - for(int i = 0; i < sub1.rows(); ++i) { - auto m = sub1(i, 0) * sub2[0]; - for(int k = 1; k < sub2.size(); ++k) m += sub1(i, k) * sub2[k]; - v[i] = m; - } - return v; -} - -template*, - enable_if_matrix_t*> -inline auto -operator*(Sub1&& sub1, Sub2&& sub2) - -> matrix_inner_product_promote_t, - actual_operand_type_of_t> -{ - using result_type = matrix_inner_product_promote_t< - actual_operand_type_of_t, - actual_operand_type_of_t>; - - cml::check_same_inner_size(sub1, sub2); - - result_type v; - detail::resize(v, array_cols_of(sub2)); - for(int j = 0; j < sub2.cols(); ++j) { - auto m = sub1[0] * sub2(0, j); - for(int k = 1; k < sub1.size(); ++k) m += sub1[k] * sub2(k, j); - v[j] = m; - } - return v; -} - -// TODO Both of these can (and should) be refactored to return a vector -// expression node. This requires automatic temporary generation within -// the expression tree first, though. - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_VECTOR_PRODUCT_TPP +# error "matrix/vector_product.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +template*, + enable_if_vector_t*> +inline auto +operator*(Sub1&& sub1, Sub2&& sub2) + -> matrix_inner_product_promote_t, + actual_operand_type_of_t> +{ + using result_type = matrix_inner_product_promote_t< + actual_operand_type_of_t, + actual_operand_type_of_t>; + + cml::check_same_inner_size(sub1, sub2); + + result_type v; + detail::resize(v, array_rows_of(sub1)); + for(int i = 0; i < sub1.rows(); ++i) { + auto m = sub1(i, 0) * sub2[0]; + for(int k = 1; k < sub2.size(); ++k) m += sub1(i, k) * sub2[k]; + v[i] = m; + } + return v; +} + +template*, + enable_if_matrix_t*> +inline auto +operator*(Sub1&& sub1, Sub2&& sub2) + -> matrix_inner_product_promote_t, + actual_operand_type_of_t> +{ + using result_type = matrix_inner_product_promote_t< + actual_operand_type_of_t, + actual_operand_type_of_t>; + + cml::check_same_inner_size(sub1, sub2); + + result_type v; + detail::resize(v, array_cols_of(sub2)); + for(int j = 0; j < sub2.cols(); ++j) { + auto m = sub1[0] * sub2(0, j); + for(int k = 1; k < sub1.size(); ++k) m += sub1[k] * sub2(k, j); + v[j] = m; + } + return v; +} + +// TODO Both of these can (and should) be refactored to return a vector +// expression node. This requires automatic temporary generation within +// the expression tree first, though. + } // namespace cml \ No newline at end of file diff --git a/cml/matrix/writable_matrix.h b/cml/matrix/writable_matrix.h index 631dc77..b326f02 100644 --- a/cml/matrix/writable_matrix.h +++ b/cml/matrix/writable_matrix.h @@ -1,415 +1,415 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace cml { - -/** Base class for writable matrix types. Writable matrices support - * non-const read-write access to its elements, in addition to read-only - * access via readable_matrix. - * - * In addition to the requirements of readable_matrix, DerivedT must - * implement: - * - * - i_get(int i, int j) returning element @c (i,j) as a mutable value, - * where is the mutable_value type defined by matrix_traits - * - * - template DerivedT& i_put(int i, int j, const T&) - * - * for compilers without support for rvalue reference from *this; and - * - * template DerivedT& i_put(int i, int j, const T&) & - * template DerivedT&& i_put(int i, int j, const T&) && - * - * for compilers with support for rvalue reference from this. - * - * Note that mutable_value need not be a reference type. - */ -template -class writable_matrix : public readable_matrix -{ - public: - using matrix_type = DerivedT; - using readable_type = readable_matrix; - using traits_type = matrix_traits; - using value_type = typename traits_type::value_type; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /* Disambiguate readable_matrix<> methods: */ - using readable_type::actual; - using readable_type::get; - using readable_type::operator(); - - - public: - /** Return a mutable reference to the matrix cast as DerivedT. */ - DerivedT& actual(); - - /** Set element @c (i,j). */ - template DerivedT& put(int i, int j, const Other& v) &; - - /** Set element @c (i,j) on a temporary. */ - template DerivedT&& put(int i, int j, const Other& v) &&; - - /** Return mutable element @c (i,j). */ - mutable_value get(int i, int j); - - /** Return a mutable reference to element @c (i,j). */ - mutable_value operator()(int i, int j); - - - public: - /** Set element @c j of basis vector @c i. */ - template - DerivedT& set_basis_element(int i, int j, const Other& v) &; - - /** Set element @c j of basis vector @c i on a temporary. */ - template - DerivedT&& set_basis_element(int i, int j, const Other& v) &&; - - /** Copy @c v to row @c i of the matrix. - * - * @throws cml::incompatible_matrix_col_size_error if the matrix is - * dynamic and the number of columns does not match the size of - * @c v. The sizes are checked at compile time otherwise. - */ - template DerivedT& set_row(int i, const readable_vector& v) &; - - /** Copy @c v to row @c i of a temporary matrix. - * - * @throws cml::incompatible_matrix_col_size_error if the matrix is - * dynamic and the number of columns does not match the size of - * @c v. The sizes are checked at compile time otherwise. - */ - template - DerivedT&& set_row(int i, const readable_vector& v) &&; - - /** Copy @c v to column @c j of the matrix. - * - * @throws cml::incompatible_matrix_row_size_error if the matrix is - * dynamic and the number of rows does not match the size of @c v. The - * sizes are checked at compile time otherwise. - */ - template DerivedT& set_col(int j, const readable_vector& v) &; - - /** Copy @c v to column @c j of a temporary matrix. - * - * @throws cml::incompatible_matrix_row_size_error if the matrix is - * dynamic and the number of rows does not match the size of @c v. The - * sizes are checked at compile time otherwise. - */ - template - DerivedT&& set_col(int j, const readable_vector& v) &&; - - /** Zero the matrix elements. */ - DerivedT& zero() &; - - /** Zero the matrix elements of a temporary. */ - DerivedT&& zero() &&; - - /** Set the matrix to the identity. */ - DerivedT& identity() &; - - /** Set a temporary matrix to the identity. */ - DerivedT&& identity() &&; - - /** Set elements to random values in the range @c[low,high]. */ - DerivedT& random(const_reference low, const_reference high) &; - - /** Set elements of a temporary to random values in the range - * @c[low,high]. - */ - DerivedT&& random(const_reference low, const_reference high) &&; - - /** Set all elements to a specific value. */ - DerivedT& fill(const_reference v) &; - - /** Set all elements of a temporary to a specific value. */ - DerivedT&& fill(const_reference v) &&; - - /** Set the matrix to its inverse. - * - * @throws non_square_matrix_error at run-time if the matrix is - * dynamically sized and not square. - */ - DerivedT& inverse() &; - - /** Set a temporary matrix to its inverse. - * - * @throws non_square_matrix_error at run-time if the matrix is - * dynamically sized and not square. - */ - DerivedT&& inverse() &&; - - /** Set the matrix to its transpose. - * - * @note This will raise a compile time error if the matrix is - * fixed-size and non-square. Dynamic-size matrices will be assigned - * from a temporary. - */ - DerivedT& transpose() &; - - /** Set a temporary matrix to its inverse. - * - * @note This will raise a compile time error if the matrix is - * fixed-size and non-square. Dynamic-size matrices will be assigned - * from a temporary. - */ - DerivedT&& transpose() &&; - - - public: - /** Assign from a readable_matrix. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is not - * resizable, and if @c other.size() != this->size(). If both are - * fixed-size, then the size is checked at compile time. - */ - template - DerivedT& operator=(const readable_matrix& other) &; - - /** Assign a temporary from a readable_matrix. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is not - * resizable, and if @c other.size() != this->size(). If both are - * fixed-size, then the size is checked at compile time. - */ - template - DerivedT&& operator=(const readable_matrix& other) &&; - - /** Assign from a fixed-length array type. - * - * @throws incompatible_matrix_size_error at run-time if @c - * array_size_of_c::value != this->rows()*this->cols(). If both - * are fixed-size, then the size is checked at compile time. - */ - template* = nullptr> - DerivedT& operator=(const Array& array) &; - - /** Assign a temporary from a fixed-length array type. - * - * @throws incompatible_matrix_size_error at run-time if @c - * array_size_of_c::value != this->rows()*this->cols(). If both - * are fixed-size, then the size is checked at compile time. - */ - template* = nullptr> - DerivedT&& operator=(const Array& array) &&; - - /** Assign from a 2D C-array. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * not resizable and does not have the same size as @c array. If both - * are fixed-size, then the size is checked at compile time. - */ - template - DerivedT& operator=(Other const (&array)[Rows][Cols]) &; - - /** Assign a temporary from a fixed-length array type. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * not resizable and does not have the same size as @c array. If both - * are fixed-size, then the size is checked at compile time. - */ - template - DerivedT& operator=(Other const (&array)[Rows][Cols]) &&; - - /** Assign from initializer list. - * - * @throws incompatible_matrix_size_error if the matrix is not - * resizable, and if @c l.size() != this->size(). - */ - template DerivedT& operator=(std::initializer_list l) &; - - /** Assign a temporary from initializer list. - * - * @throws incompatible_matrix_size_error if the matrix is not - * resizable, and if @c l.size() != this->size(). - */ - template DerivedT&& operator=(std::initializer_list l) &&; - - /** Modify the matrix by addition of another matrix. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * dynamically-sized, and if @c other.size() != this->size(). If both - * are fixed-size expressions, then the size is checked at compile - * time. - */ - template - DerivedT& operator+=(const readable_matrix& other) &; - - /** Modify a temporary matrix by addition of another matrix. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * dynamically-sized, and if @c other.size() != this->size(). If both - * are fixed-size expressions, then the size is checked at compile - * time. - */ - template - DerivedT&& operator+=(const readable_matrix& other) &&; - - /** Modify the matrix by subtraction of another matrix. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * dynamically-sized, and if @c other.size() != this->size(). If both - * are fixed-size expressions, then the size is checked at compile - * time. - */ - template - DerivedT& operator-=(const readable_matrix& other) &; - - /** Modify a temporary matrix by subtraction of another matrix. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * dynamically-sized, and if @c other.size() != this->size(). If both - * are fixed-size expressions, then the size is checked at compile - * time. - */ - template - DerivedT&& operator-=(const readable_matrix& other) &&; - - /** Multiply the matrix by a scalar convertible to its value_type. */ - template::type* = nullptr> - DerivedT& operator*=(const ScalarT& v) &; - - /** Multiply the matrix temporary by a scalar convertible to its - * value_type. - */ - template::type* = nullptr> - DerivedT&& operator*=(const ScalarT& v) &&; - - /** Divide the matrix by a scalar convertible to its value_type. */ - template::type* = nullptr> - DerivedT& operator/=(const ScalarT& v) &; - - /** Divide a temporary matrix by a scalar. - * - * @note This depends upon implicit conversion of @c v to the - * matrix value_type. - */ - template::type* = nullptr> - DerivedT&& operator/=(const ScalarT& v) &&; - - - protected: - /** Assign from a readable_matrix. - * - * @note This depends upon implicit conversion of the source matrix - * elements to the matrix value_type. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is not - * resizable, and if @c other.size() != this->size(). If both are - * fixed-size expressions, then the size is checked at compile time. - */ - template - DerivedT& assign(const readable_matrix& other); - - /** Assign from an array type. - * - * @note This depends upon implicit conversion of the array elements to - * the matrix value_type. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * not resizable, and if @c array_size_of_c::value != - * this->rows()*this->cols(). If both are fixed-size, then the size is - * checked at compile time. - */ - template* = nullptr> - DerivedT& assign(const Array& array); - - /** Assign from a 2D C-array type. - * - * @note This depends upon implicit conversion of the array elements to - * the matrix value_type. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * not resizable and does not have the same size as @c array. If both - * are fixed-size, then the size is checked at compile time. - */ - template - DerivedT& assign(Other const (&array)[Rows][Cols]); - - /** Assign from a pointer to an array. - * - * @note This depends upon implicit conversion of the array elements to - * the matrix value_type. - * - * @note The number of elements read from @c array depends upon the - * current size of the matrix. - */ - template* = nullptr> - DerivedT& assign(const Pointer& array); - - /** Assign from an initializer_list. - * - * @note This depends upon implicit conversion of @c Other to the - * matrix value_type. - * - * @throws incompatible_matrix_size_error if the matrix is not resizable, - * and if @c l.size() != this->rows()*this->cols(). - */ - template DerivedT& assign(const std::initializer_list& l); - - /** Construct from a variable list of values. If the matrix has more - * elements than the variable argument list, the remaining elements are - * set to value_type(0). - * - * @note For fixed-size matrices, the number of arguments is checked - * against the number of matrix elements at compile time. - * - * @note This depends upon implicit conversions of the elements to the - * matrix value_type. - * - * @throws incompatible_matrix_size_error at run-time if the matrix is - * not fixed-sized, and if @c sizeof...(eN) > @c (rows()*cols()). If - * the matrix is fixed-size, then the size is checked at compile time. - */ - template DerivedT& assign_elements(const Elements&... eN); - - - protected: - /** Set basis element @c (i,j) for a row-basis matrix. */ - template - void set_basis_element(int i, int j, const Other& v, row_basis); - - /** Set basis element @c (i,j) for a column-basis matrix. */ - template - void set_basis_element(int i, int j, const Other& v, col_basis); - - - protected: - // Use the compiler-generated default constructor: - writable_matrix() = default; - - // Use the compiler-generated copy constructor: - writable_matrix(const writable_matrix&) = default; - - // Use the compiler-generated move constructor: - writable_matrix(writable_matrix&&) = default; - - // Force assignment through operator=(readable_matrix<>): - writable_matrix& operator=(const writable_matrix&) = delete; -}; - -} // namespace cml - -#define __CML_MATRIX_WRITABLE_MATRIX_TPP -#include -#undef __CML_MATRIX_WRITABLE_MATRIX_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Base class for writable matrix types. Writable matrices support + * non-const read-write access to its elements, in addition to read-only + * access via readable_matrix. + * + * In addition to the requirements of readable_matrix, DerivedT must + * implement: + * + * - i_get(int i, int j) returning element @c (i,j) as a mutable value, + * where is the mutable_value type defined by matrix_traits + * + * - template DerivedT& i_put(int i, int j, const T&) + * + * for compilers without support for rvalue reference from *this; and + * + * template DerivedT& i_put(int i, int j, const T&) & + * template DerivedT&& i_put(int i, int j, const T&) && + * + * for compilers with support for rvalue reference from this. + * + * Note that mutable_value need not be a reference type. + */ +template +class writable_matrix : public readable_matrix +{ + public: + using matrix_type = DerivedT; + using readable_type = readable_matrix; + using traits_type = matrix_traits; + using value_type = typename traits_type::value_type; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /* Disambiguate readable_matrix<> methods: */ + using readable_type::actual; + using readable_type::get; + using readable_type::operator(); + + + public: + /** Return a mutable reference to the matrix cast as DerivedT. */ + DerivedT& actual(); + + /** Set element @c (i,j). */ + template DerivedT& put(int i, int j, const Other& v) &; + + /** Set element @c (i,j) on a temporary. */ + template DerivedT&& put(int i, int j, const Other& v) &&; + + /** Return mutable element @c (i,j). */ + mutable_value get(int i, int j); + + /** Return a mutable reference to element @c (i,j). */ + mutable_value operator()(int i, int j); + + + public: + /** Set element @c j of basis vector @c i. */ + template + DerivedT& set_basis_element(int i, int j, const Other& v) &; + + /** Set element @c j of basis vector @c i on a temporary. */ + template + DerivedT&& set_basis_element(int i, int j, const Other& v) &&; + + /** Copy @c v to row @c i of the matrix. + * + * @throws cml::incompatible_matrix_col_size_error if the matrix is + * dynamic and the number of columns does not match the size of + * @c v. The sizes are checked at compile time otherwise. + */ + template DerivedT& set_row(int i, const readable_vector& v) &; + + /** Copy @c v to row @c i of a temporary matrix. + * + * @throws cml::incompatible_matrix_col_size_error if the matrix is + * dynamic and the number of columns does not match the size of + * @c v. The sizes are checked at compile time otherwise. + */ + template + DerivedT&& set_row(int i, const readable_vector& v) &&; + + /** Copy @c v to column @c j of the matrix. + * + * @throws cml::incompatible_matrix_row_size_error if the matrix is + * dynamic and the number of rows does not match the size of @c v. The + * sizes are checked at compile time otherwise. + */ + template DerivedT& set_col(int j, const readable_vector& v) &; + + /** Copy @c v to column @c j of a temporary matrix. + * + * @throws cml::incompatible_matrix_row_size_error if the matrix is + * dynamic and the number of rows does not match the size of @c v. The + * sizes are checked at compile time otherwise. + */ + template + DerivedT&& set_col(int j, const readable_vector& v) &&; + + /** Zero the matrix elements. */ + DerivedT& zero() &; + + /** Zero the matrix elements of a temporary. */ + DerivedT&& zero() &&; + + /** Set the matrix to the identity. */ + DerivedT& identity() &; + + /** Set a temporary matrix to the identity. */ + DerivedT&& identity() &&; + + /** Set elements to random values in the range @c[low,high]. */ + DerivedT& random(const_reference low, const_reference high) &; + + /** Set elements of a temporary to random values in the range + * @c[low,high]. + */ + DerivedT&& random(const_reference low, const_reference high) &&; + + /** Set all elements to a specific value. */ + DerivedT& fill(const_reference v) &; + + /** Set all elements of a temporary to a specific value. */ + DerivedT&& fill(const_reference v) &&; + + /** Set the matrix to its inverse. + * + * @throws non_square_matrix_error at run-time if the matrix is + * dynamically sized and not square. + */ + DerivedT& inverse() &; + + /** Set a temporary matrix to its inverse. + * + * @throws non_square_matrix_error at run-time if the matrix is + * dynamically sized and not square. + */ + DerivedT&& inverse() &&; + + /** Set the matrix to its transpose. + * + * @note This will raise a compile time error if the matrix is + * fixed-size and non-square. Dynamic-size matrices will be assigned + * from a temporary. + */ + DerivedT& transpose() &; + + /** Set a temporary matrix to its inverse. + * + * @note This will raise a compile time error if the matrix is + * fixed-size and non-square. Dynamic-size matrices will be assigned + * from a temporary. + */ + DerivedT&& transpose() &&; + + + public: + /** Assign from a readable_matrix. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is not + * resizable, and if @c other.size() != this->size(). If both are + * fixed-size, then the size is checked at compile time. + */ + template + DerivedT& operator=(const readable_matrix& other) &; + + /** Assign a temporary from a readable_matrix. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is not + * resizable, and if @c other.size() != this->size(). If both are + * fixed-size, then the size is checked at compile time. + */ + template + DerivedT&& operator=(const readable_matrix& other) &&; + + /** Assign from a fixed-length array type. + * + * @throws incompatible_matrix_size_error at run-time if @c + * array_size_of_c::value != this->rows()*this->cols(). If both + * are fixed-size, then the size is checked at compile time. + */ + template* = nullptr> + DerivedT& operator=(const Array& array) &; + + /** Assign a temporary from a fixed-length array type. + * + * @throws incompatible_matrix_size_error at run-time if @c + * array_size_of_c::value != this->rows()*this->cols(). If both + * are fixed-size, then the size is checked at compile time. + */ + template* = nullptr> + DerivedT&& operator=(const Array& array) &&; + + /** Assign from a 2D C-array. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * not resizable and does not have the same size as @c array. If both + * are fixed-size, then the size is checked at compile time. + */ + template + DerivedT& operator=(Other const (&array)[Rows][Cols]) &; + + /** Assign a temporary from a fixed-length array type. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * not resizable and does not have the same size as @c array. If both + * are fixed-size, then the size is checked at compile time. + */ + template + DerivedT& operator=(Other const (&array)[Rows][Cols]) &&; + + /** Assign from initializer list. + * + * @throws incompatible_matrix_size_error if the matrix is not + * resizable, and if @c l.size() != this->size(). + */ + template DerivedT& operator=(std::initializer_list l) &; + + /** Assign a temporary from initializer list. + * + * @throws incompatible_matrix_size_error if the matrix is not + * resizable, and if @c l.size() != this->size(). + */ + template DerivedT&& operator=(std::initializer_list l) &&; + + /** Modify the matrix by addition of another matrix. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * dynamically-sized, and if @c other.size() != this->size(). If both + * are fixed-size expressions, then the size is checked at compile + * time. + */ + template + DerivedT& operator+=(const readable_matrix& other) &; + + /** Modify a temporary matrix by addition of another matrix. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * dynamically-sized, and if @c other.size() != this->size(). If both + * are fixed-size expressions, then the size is checked at compile + * time. + */ + template + DerivedT&& operator+=(const readable_matrix& other) &&; + + /** Modify the matrix by subtraction of another matrix. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * dynamically-sized, and if @c other.size() != this->size(). If both + * are fixed-size expressions, then the size is checked at compile + * time. + */ + template + DerivedT& operator-=(const readable_matrix& other) &; + + /** Modify a temporary matrix by subtraction of another matrix. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * dynamically-sized, and if @c other.size() != this->size(). If both + * are fixed-size expressions, then the size is checked at compile + * time. + */ + template + DerivedT&& operator-=(const readable_matrix& other) &&; + + /** Multiply the matrix by a scalar convertible to its value_type. */ + template::type* = nullptr> + DerivedT& operator*=(const ScalarT& v) &; + + /** Multiply the matrix temporary by a scalar convertible to its + * value_type. + */ + template::type* = nullptr> + DerivedT&& operator*=(const ScalarT& v) &&; + + /** Divide the matrix by a scalar convertible to its value_type. */ + template::type* = nullptr> + DerivedT& operator/=(const ScalarT& v) &; + + /** Divide a temporary matrix by a scalar. + * + * @note This depends upon implicit conversion of @c v to the + * matrix value_type. + */ + template::type* = nullptr> + DerivedT&& operator/=(const ScalarT& v) &&; + + + protected: + /** Assign from a readable_matrix. + * + * @note This depends upon implicit conversion of the source matrix + * elements to the matrix value_type. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is not + * resizable, and if @c other.size() != this->size(). If both are + * fixed-size expressions, then the size is checked at compile time. + */ + template + DerivedT& assign(const readable_matrix& other); + + /** Assign from an array type. + * + * @note This depends upon implicit conversion of the array elements to + * the matrix value_type. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * not resizable, and if @c array_size_of_c::value != + * this->rows()*this->cols(). If both are fixed-size, then the size is + * checked at compile time. + */ + template* = nullptr> + DerivedT& assign(const Array& array); + + /** Assign from a 2D C-array type. + * + * @note This depends upon implicit conversion of the array elements to + * the matrix value_type. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * not resizable and does not have the same size as @c array. If both + * are fixed-size, then the size is checked at compile time. + */ + template + DerivedT& assign(Other const (&array)[Rows][Cols]); + + /** Assign from a pointer to an array. + * + * @note This depends upon implicit conversion of the array elements to + * the matrix value_type. + * + * @note The number of elements read from @c array depends upon the + * current size of the matrix. + */ + template* = nullptr> + DerivedT& assign(const Pointer& array); + + /** Assign from an initializer_list. + * + * @note This depends upon implicit conversion of @c Other to the + * matrix value_type. + * + * @throws incompatible_matrix_size_error if the matrix is not resizable, + * and if @c l.size() != this->rows()*this->cols(). + */ + template DerivedT& assign(const std::initializer_list& l); + + /** Construct from a variable list of values. If the matrix has more + * elements than the variable argument list, the remaining elements are + * set to value_type(0). + * + * @note For fixed-size matrices, the number of arguments is checked + * against the number of matrix elements at compile time. + * + * @note This depends upon implicit conversions of the elements to the + * matrix value_type. + * + * @throws incompatible_matrix_size_error at run-time if the matrix is + * not fixed-sized, and if @c sizeof...(eN) > @c (rows()*cols()). If + * the matrix is fixed-size, then the size is checked at compile time. + */ + template DerivedT& assign_elements(const Elements&... eN); + + + protected: + /** Set basis element @c (i,j) for a row-basis matrix. */ + template + void set_basis_element(int i, int j, const Other& v, row_basis); + + /** Set basis element @c (i,j) for a column-basis matrix. */ + template + void set_basis_element(int i, int j, const Other& v, col_basis); + + + protected: + // Use the compiler-generated default constructor: + writable_matrix() = default; + + // Use the compiler-generated copy constructor: + writable_matrix(const writable_matrix&) = default; + + // Use the compiler-generated move constructor: + writable_matrix(writable_matrix&&) = default; + + // Force assignment through operator=(readable_matrix<>): + writable_matrix& operator=(const writable_matrix&) = delete; +}; + +} // namespace cml + +#define __CML_MATRIX_WRITABLE_MATRIX_TPP +#include +#undef __CML_MATRIX_WRITABLE_MATRIX_TPP diff --git a/cml/matrix/writable_matrix.tpp b/cml/matrix/writable_matrix.tpp index 078f119..10114c4 100644 --- a/cml/matrix/writable_matrix.tpp +++ b/cml/matrix/writable_matrix.tpp @@ -1,503 +1,503 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_MATRIX_WRITABLE_MATRIX_TPP -# error "matrix/writable_matrix.tpp not included correctly" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cml { -namespace detail { - -/* Terminate the assignment recursion at the final element. */ -template -inline void -assign_elements(writable_matrix& sub, const E0& e0) -{ - sub.put(I / sub.cols(), I % sub.cols(), e0); -} - -/* Set element (I/cols(),I%cols()) of sub to e0, then assign the remainder - * of the elements starting from I+1. - */ -template -inline void -assign_elements(writable_matrix& sub, const E0& e0, const Es&... eN) -{ - sub.put(I / sub.cols(), I % sub.cols(), e0); - assign_elements(sub, eN...); -} - -/* Assign elements of @c sub from @c eN, assuming @c eN is given in - * row-major order. - */ -template -inline void -assign_elements(writable_matrix& sub, const Es&... eN) -{ - assign_elements<0>(sub, eN...); -} - -} // namespace detail - -/* Public methods: */ - -template -DT& -writable_matrix
::actual() -{ - return (DT&) *this; -} - -template -auto -writable_matrix
::get(int i, int j) -> mutable_value -{ - return this->actual().i_get(i, j); -} - -template -template -DT& -writable_matrix
::put(int i, int j, const Other& v) & -{ - return this->actual().i_put(i, j, v); -} - -template -template -DT&& -writable_matrix
::put(int i, int j, const Other& v) && -{ - this->put(i, j, v); // Forward to put(...) & - return (DT&&) *this; -} - -template -auto -writable_matrix
::operator()(int i, int j) -> mutable_value -{ - return this->get(i, j); -} - -template -template -DT& -writable_matrix
::set_basis_element(int i, int j, const Other& v) & -{ - this->set_basis_element(i, j, v, basis_tag()); - return this->actual(); -} - -template -template -DT&& -writable_matrix
::set_basis_element(int i, int j, const Other& v) && -{ - this->set_basis_element(i, j, v); // Forward to set_basis_element(...) & - return (DT&&) *this; -} - - -template -template -DT& -writable_matrix
::set_row(int i, const readable_vector& v) & -{ - cml::check_same_col_size(*this, v); - for(int j = 0; j < this->cols(); ++j) this->put(i, j, v.get(j)); - return this->actual(); -} - -template -template -DT&& -writable_matrix
::set_row(int i, const readable_vector& v) && -{ - this->set_row(i, v); - return (DT&&) *this; -} - -template -template -DT& -writable_matrix
::set_col(int j, const readable_vector& v) & -{ - cml::check_same_row_size(*this, v); - for(int i = 0; i < this->rows(); ++i) this->put(i, j, v.get(i)); - return this->actual(); -} - -template -template -DT&& -writable_matrix
::set_col(int j, const readable_vector& v) && -{ - this->set_col(j, v); - return (DT&&) *this; -} - - -template -DT& -writable_matrix
::zero() & -{ - auto zero_f = [](int, int) { return value_type(0); }; - detail::generate(*this, zero_f, layout_tag()); - return this->actual(); -} - -template -DT&& -writable_matrix
::zero() && -{ - this->zero(); // Forward to zero & - return (DT&&) *this; -} - - -template -DT& -writable_matrix
::identity() & -{ - auto identity_f = [](int i, int j) { return value_type(i == j); }; - detail::generate(*this, identity_f, layout_tag()); - return this->actual(); -} - -template -DT&& -writable_matrix
::identity() && -{ - this->identity(); // Forward to zero & - return (DT&&) *this; -} - -template -DT& -writable_matrix
::random(const_reference low, const_reference high) & -{ - using distribution_type = if_t::value, - std::uniform_int_distribution, - std::uniform_real_distribution>; - - std::random_device rd; // Non-deterministic seed, if supported. - std::default_random_engine gen(rd()); - distribution_type d(low, high); - auto random_f = [&d, &gen](int, int) { return d(gen); }; - detail::generate(*this, random_f, layout_tag()); - return this->actual(); -} - -template -DT&& -writable_matrix
::random(const_reference low, const_reference high) && -{ - this->random(low, high); - return (DT&&) *this; -} - -template -DT& -writable_matrix
::fill(const_reference v) & -{ - detail::generate( - *this, [&v](int, int) { return v; }, layout_tag()); - return this->actual(); -} - -template -DT&& -writable_matrix
::fill(const_reference v) && -{ - this->fill(v); - return (DT&&) *this; -} - -template -DT& -writable_matrix
::inverse() & -{ - cml::check_square(*this); - detail::inverse(*this, cml::int_c()); - return this->actual(); -} - -template -DT&& -writable_matrix
::inverse() && -{ - this->inverse(); - return (DT&&) *this; -} - -template -DT& -writable_matrix
::transpose() & -{ - using tag = size_tag_of_t; - detail::transpose(*this, tag()); - return this->actual(); -} - -template -DT&& -writable_matrix
::transpose() && -{ - this->transpose(); - return (DT&&) *this; -} - - -template -template -DT& -writable_matrix
::operator=(const readable_matrix& other) & -{ - return this->assign(other); -} - -template -template -DT&& -writable_matrix
::operator=(const readable_matrix& other) && -{ - this->operator=(other); - return (DT&&) *this; -} - -template -template*> -DT& -writable_matrix
::operator=(const Array& array) & -{ - return this->assign(array); -} - -template -template*> -DT&& -writable_matrix
::operator=(const Array& array) && -{ - this->operator=(array); - return (DT&&) *this; -} - -template -template -DT& -writable_matrix
::operator=(Other const (&array)[Rows][Cols]) & -{ - return this->assign(array); -} - -template -template -DT& -writable_matrix
::operator=(Other const (&array)[Rows][Cols]) && -{ - this->operator=(array); - return (DT&&) *this; -} - -template -template -DT& -writable_matrix
::operator=(std::initializer_list l) & -{ - return this->assign(l); -} - -template -template -DT&& -writable_matrix
::operator=(std::initializer_list l) && -{ - return this->assign(l); -} - -template -template -DT& -writable_matrix
::operator+=(const readable_matrix& other) & -{ - detail::check_or_resize(*this, other); - detail::apply>(*this, other, layout_tag()); - return this->actual(); -} - -template -template -DT&& -writable_matrix
::operator+=(const readable_matrix& other) && -{ - this->operator+=(other); - return (DT&&) *this; -} - -template -template -DT& -writable_matrix
::operator-=(const readable_matrix& other) & -{ - detail::check_or_resize(*this, other); - detail::apply>(*this, other, layout_tag()); - return this->actual(); -} - -template -template -DT&& -writable_matrix
::operator-=(const readable_matrix& other) && -{ - this->operator-=(other); - return (DT&&) *this; -} - - -template -template::value_type, - ScalarT>::type*> -DT& -writable_matrix
::operator*=(const ScalarT& v) & -{ - detail::apply>(*this, v, layout_tag()); - return this->actual(); -} - -template -template::value_type, - ScalarT>::type*> -DT&& -writable_matrix
::operator*=(const ScalarT& v) && -{ - this->operator*=(v); - return (DT&&) *this; -} - -template -template::value_type, - ScalarT>::type*> -DT& -writable_matrix
::operator/=(const ScalarT& v) & -{ - detail::apply>(*this, v, layout_tag()); - return this->actual(); -} - -template -template::value_type, - ScalarT>::type*> -DT&& -writable_matrix
::operator/=(const ScalarT& v) && -{ - this->operator/=(v); - return (DT&&) *this; -} - - -/* Internal methods: */ - -template -template -DT& -writable_matrix
::assign(const readable_matrix& other) -{ - detail::check_or_resize(*this, other); - detail::copy(*this, other, layout_tag()); - return this->actual(); -} - -template -template*> -DT& -writable_matrix
::assign(const Array& array) -{ - cml::check_same_linear_size(*this, array); - int cols = this->cols(); - for(int i = 0; i < array_size_of_c::value; ++i) { - this->put(i / cols, i % cols, array[i]); - } - return this->actual(); -} - -template -template -DT& -writable_matrix
::assign(Other const (&array)[R][C]) -{ - detail::check_or_resize(*this, array); - detail::copy(*this, array, layout_tag()); - return this->actual(); -} - -template -template*> -DT& -writable_matrix
::assign(const Pointer& array) -{ - int rows = this->rows(), cols = this->cols(); - for(int i = 0; i < rows * cols; ++i) this->put(i / cols, i % cols, array[i]); - return this->actual(); -} - -template -template -DT& -writable_matrix
::assign(const std::initializer_list& l) -{ - cml::check_same_linear_size(*this, l); - int cols = this->cols(), i = 0; - for(Other v : l) { - this->put(i / cols, i % cols, v); - ++i; - } - return this->actual(); -} - -template -template -DT& -writable_matrix
::assign_elements(const Es&... eN) -{ - static const int N = int(sizeof...(eN)); - cml::check_linear_size(*this, cml::int_c()); - - /* Assign elements: */ - detail::assign_elements(*this, eN...); - - /* Done: */ - return this->actual(); -} - -template -template -void -writable_matrix
::set_basis_element(int i, int j, const Other& v, row_basis) -{ - this->put(i, j, v); -} - -template -template -void -writable_matrix
::set_basis_element(int i, int j, const Other& v, col_basis) -{ - this->put(j, i, v); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_MATRIX_WRITABLE_MATRIX_TPP +# error "matrix/writable_matrix.tpp not included correctly" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cml { +namespace detail { + +/* Terminate the assignment recursion at the final element. */ +template +inline void +assign_elements(writable_matrix& sub, const E0& e0) +{ + sub.put(I / sub.cols(), I % sub.cols(), e0); +} + +/* Set element (I/cols(),I%cols()) of sub to e0, then assign the remainder + * of the elements starting from I+1. + */ +template +inline void +assign_elements(writable_matrix& sub, const E0& e0, const Es&... eN) +{ + sub.put(I / sub.cols(), I % sub.cols(), e0); + assign_elements(sub, eN...); +} + +/* Assign elements of @c sub from @c eN, assuming @c eN is given in + * row-major order. + */ +template +inline void +assign_elements(writable_matrix& sub, const Es&... eN) +{ + assign_elements<0>(sub, eN...); +} + +} // namespace detail + +/* Public methods: */ + +template +DT& +writable_matrix
::actual() +{ + return (DT&) *this; +} + +template +auto +writable_matrix
::get(int i, int j) -> mutable_value +{ + return this->actual().i_get(i, j); +} + +template +template +DT& +writable_matrix
::put(int i, int j, const Other& v) & +{ + return this->actual().i_put(i, j, v); +} + +template +template +DT&& +writable_matrix
::put(int i, int j, const Other& v) && +{ + this->put(i, j, v); // Forward to put(...) & + return (DT&&) *this; +} + +template +auto +writable_matrix
::operator()(int i, int j) -> mutable_value +{ + return this->get(i, j); +} + +template +template +DT& +writable_matrix
::set_basis_element(int i, int j, const Other& v) & +{ + this->set_basis_element(i, j, v, basis_tag()); + return this->actual(); +} + +template +template +DT&& +writable_matrix
::set_basis_element(int i, int j, const Other& v) && +{ + this->set_basis_element(i, j, v); // Forward to set_basis_element(...) & + return (DT&&) *this; +} + + +template +template +DT& +writable_matrix
::set_row(int i, const readable_vector& v) & +{ + cml::check_same_col_size(*this, v); + for(int j = 0; j < this->cols(); ++j) this->put(i, j, v.get(j)); + return this->actual(); +} + +template +template +DT&& +writable_matrix
::set_row(int i, const readable_vector& v) && +{ + this->set_row(i, v); + return (DT&&) *this; +} + +template +template +DT& +writable_matrix
::set_col(int j, const readable_vector& v) & +{ + cml::check_same_row_size(*this, v); + for(int i = 0; i < this->rows(); ++i) this->put(i, j, v.get(i)); + return this->actual(); +} + +template +template +DT&& +writable_matrix
::set_col(int j, const readable_vector& v) && +{ + this->set_col(j, v); + return (DT&&) *this; +} + + +template +DT& +writable_matrix
::zero() & +{ + auto zero_f = [](int, int) { return value_type(0); }; + detail::generate(*this, zero_f, layout_tag()); + return this->actual(); +} + +template +DT&& +writable_matrix
::zero() && +{ + this->zero(); // Forward to zero & + return (DT&&) *this; +} + + +template +DT& +writable_matrix
::identity() & +{ + auto identity_f = [](int i, int j) { return value_type(i == j); }; + detail::generate(*this, identity_f, layout_tag()); + return this->actual(); +} + +template +DT&& +writable_matrix
::identity() && +{ + this->identity(); // Forward to zero & + return (DT&&) *this; +} + +template +DT& +writable_matrix
::random(const_reference low, const_reference high) & +{ + using distribution_type = if_t::value, + std::uniform_int_distribution, + std::uniform_real_distribution>; + + std::random_device rd; // Non-deterministic seed, if supported. + std::default_random_engine gen(rd()); + distribution_type d(low, high); + auto random_f = [&d, &gen](int, int) { return d(gen); }; + detail::generate(*this, random_f, layout_tag()); + return this->actual(); +} + +template +DT&& +writable_matrix
::random(const_reference low, const_reference high) && +{ + this->random(low, high); + return (DT&&) *this; +} + +template +DT& +writable_matrix
::fill(const_reference v) & +{ + detail::generate( + *this, [&v](int, int) { return v; }, layout_tag()); + return this->actual(); +} + +template +DT&& +writable_matrix
::fill(const_reference v) && +{ + this->fill(v); + return (DT&&) *this; +} + +template +DT& +writable_matrix
::inverse() & +{ + cml::check_square(*this); + detail::inverse(*this, cml::int_c()); + return this->actual(); +} + +template +DT&& +writable_matrix
::inverse() && +{ + this->inverse(); + return (DT&&) *this; +} + +template +DT& +writable_matrix
::transpose() & +{ + using tag = size_tag_of_t; + detail::transpose(*this, tag()); + return this->actual(); +} + +template +DT&& +writable_matrix
::transpose() && +{ + this->transpose(); + return (DT&&) *this; +} + + +template +template +DT& +writable_matrix
::operator=(const readable_matrix& other) & +{ + return this->assign(other); +} + +template +template +DT&& +writable_matrix
::operator=(const readable_matrix& other) && +{ + this->operator=(other); + return (DT&&) *this; +} + +template +template*> +DT& +writable_matrix
::operator=(const Array& array) & +{ + return this->assign(array); +} + +template +template*> +DT&& +writable_matrix
::operator=(const Array& array) && +{ + this->operator=(array); + return (DT&&) *this; +} + +template +template +DT& +writable_matrix
::operator=(Other const (&array)[Rows][Cols]) & +{ + return this->assign(array); +} + +template +template +DT& +writable_matrix
::operator=(Other const (&array)[Rows][Cols]) && +{ + this->operator=(array); + return (DT&&) *this; +} + +template +template +DT& +writable_matrix
::operator=(std::initializer_list l) & +{ + return this->assign(l); +} + +template +template +DT&& +writable_matrix
::operator=(std::initializer_list l) && +{ + return this->assign(l); +} + +template +template +DT& +writable_matrix
::operator+=(const readable_matrix& other) & +{ + detail::check_or_resize(*this, other); + detail::apply>(*this, other, layout_tag()); + return this->actual(); +} + +template +template +DT&& +writable_matrix
::operator+=(const readable_matrix& other) && +{ + this->operator+=(other); + return (DT&&) *this; +} + +template +template +DT& +writable_matrix
::operator-=(const readable_matrix& other) & +{ + detail::check_or_resize(*this, other); + detail::apply>(*this, other, layout_tag()); + return this->actual(); +} + +template +template +DT&& +writable_matrix
::operator-=(const readable_matrix& other) && +{ + this->operator-=(other); + return (DT&&) *this; +} + + +template +template::value_type, + ScalarT>::type*> +DT& +writable_matrix
::operator*=(const ScalarT& v) & +{ + detail::apply>(*this, v, layout_tag()); + return this->actual(); +} + +template +template::value_type, + ScalarT>::type*> +DT&& +writable_matrix
::operator*=(const ScalarT& v) && +{ + this->operator*=(v); + return (DT&&) *this; +} + +template +template::value_type, + ScalarT>::type*> +DT& +writable_matrix
::operator/=(const ScalarT& v) & +{ + detail::apply>(*this, v, layout_tag()); + return this->actual(); +} + +template +template::value_type, + ScalarT>::type*> +DT&& +writable_matrix
::operator/=(const ScalarT& v) && +{ + this->operator/=(v); + return (DT&&) *this; +} + + +/* Internal methods: */ + +template +template +DT& +writable_matrix
::assign(const readable_matrix& other) +{ + detail::check_or_resize(*this, other); + detail::copy(*this, other, layout_tag()); + return this->actual(); +} + +template +template*> +DT& +writable_matrix
::assign(const Array& array) +{ + cml::check_same_linear_size(*this, array); + int cols = this->cols(); + for(int i = 0; i < array_size_of_c::value; ++i) { + this->put(i / cols, i % cols, array[i]); + } + return this->actual(); +} + +template +template +DT& +writable_matrix
::assign(Other const (&array)[R][C]) +{ + detail::check_or_resize(*this, array); + detail::copy(*this, array, layout_tag()); + return this->actual(); +} + +template +template*> +DT& +writable_matrix
::assign(const Pointer& array) +{ + int rows = this->rows(), cols = this->cols(); + for(int i = 0; i < rows * cols; ++i) this->put(i / cols, i % cols, array[i]); + return this->actual(); +} + +template +template +DT& +writable_matrix
::assign(const std::initializer_list& l) +{ + cml::check_same_linear_size(*this, l); + int cols = this->cols(), i = 0; + for(Other v : l) { + this->put(i / cols, i % cols, v); + ++i; + } + return this->actual(); +} + +template +template +DT& +writable_matrix
::assign_elements(const Es&... eN) +{ + static const int N = int(sizeof...(eN)); + cml::check_linear_size(*this, cml::int_c()); + + /* Assign elements: */ + detail::assign_elements(*this, eN...); + + /* Done: */ + return this->actual(); +} + +template +template +void +writable_matrix
::set_basis_element(int i, int j, const Other& v, row_basis) +{ + this->put(i, j, v); +} + +template +template +void +writable_matrix
::set_basis_element(int i, int j, const Other& v, col_basis) +{ + this->put(j, i, v); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion.h b/cml/quaternion.h index c7d107e..ebc974e 100644 --- a/cml/quaternion.h +++ b/cml/quaternion.h @@ -1,17 +1,17 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/cml/quaternion/binary_node.h b/cml/quaternion/binary_node.h index 91c6dd0..58182ad 100644 --- a/cml/quaternion/binary_node.h +++ b/cml/quaternion/binary_node.h @@ -1,142 +1,142 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class quaternion_binary_node; - -/** quaternion_binary_node<> traits. */ -template -struct quaternion_traits> -{ - using quaternion_type = quaternion_binary_node; - using left_arg_type = Sub1; - using right_arg_type = Sub2; - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = quaternion_traits; - using right_traits = quaternion_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - - /* Determine the common storage type for the node, based on the storage - * types of its subexpressions: - */ - using storage_type = quaternion_binary_storage_promote_t, - storage_type_of_t>; - using size_tag = typename storage_type::size_tag; - static_assert(cml::is_fixed_size::value, "invalid size tag"); - - /* Array size: */ - static const int array_size = storage_type::array_size; - static_assert(array_size == 4, "invalid quaternion size"); - - /* Determine the common order type: */ - using order_type = order_type_promote_t, - order_type_of_t>; - - /* Determine the common cross type: */ - using cross_type = cross_type_promote_t, - cross_type_of_t>; -}; - -/** Represents a binary quaternion operation in an expression tree. */ -template -class quaternion_binary_node -: public readable_quaternion> -{ - public: - using node_type = quaternion_binary_node; - using readable_type = readable_quaternion; - using traits_type = quaternion_traits; - using left_arg_type = typename traits_type::left_arg_type; - using right_arg_type = typename traits_type::right_arg_type; - using left_type = typename traits_type::left_type; - using right_type = typename traits_type::right_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using order_type = typename traits_type::order_type; - using cross_type = typename traits_type::cross_type; - - - public: - /** Constant containing the array size. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be - * lvalue reference or rvalue reference types. - * - * @throws incompatible_quaternion_size_error at run-time if either Sub1 or - * Sub2 is a dynamically-sized quaternion, and sub1.size() != sub2.size(). - * If both Sub1 and Sub2 are fixed-size expressions, then the sizes are - * checked at compile time. - */ - quaternion_binary_node(Sub1 left, Sub2 right); - - /** Move constructor. */ - quaternion_binary_node(node_type&& other); - - /** Copy constructor. */ - quaternion_binary_node(const node_type& other); - - - protected: - /** @name readable_quaternion Interface */ - /*@{*/ - - friend readable_type; - - /** Apply the operator to element @c i of the subexpressions and return - * the result. - */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the left subexpression. The expression is - * stored as a copy if Sub1 is an rvalue reference (temporary), or by - * const reference if Sub1 is an lvalue reference. - */ - using left_wrap_type = cml::if_t::value, const left_type&, - left_type>; - - /** The type used to store the right subexpression. The expression is - * stored as a copy if Sub2 is an rvalue reference (temporary), or by - * const reference if Sub2 is an lvalue reference. - */ - using right_wrap_type = cml::if_t::value, const right_type&, - right_type>; - - - protected: - /** The wrapped left subexpression. */ - left_wrap_type m_left; - - /** The wrapped right subexpression. */ - right_wrap_type m_right; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_QUATERNION_BINARY_NODE_TPP -#include -#undef __CML_QUATERNION_BINARY_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class quaternion_binary_node; + +/** quaternion_binary_node<> traits. */ +template +struct quaternion_traits> +{ + using quaternion_type = quaternion_binary_node; + using left_arg_type = Sub1; + using right_arg_type = Sub2; + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = quaternion_traits; + using right_traits = quaternion_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + + /* Determine the common storage type for the node, based on the storage + * types of its subexpressions: + */ + using storage_type = quaternion_binary_storage_promote_t, + storage_type_of_t>; + using size_tag = typename storage_type::size_tag; + static_assert(cml::is_fixed_size::value, "invalid size tag"); + + /* Array size: */ + static const int array_size = storage_type::array_size; + static_assert(array_size == 4, "invalid quaternion size"); + + /* Determine the common order type: */ + using order_type = order_type_promote_t, + order_type_of_t>; + + /* Determine the common cross type: */ + using cross_type = cross_type_promote_t, + cross_type_of_t>; +}; + +/** Represents a binary quaternion operation in an expression tree. */ +template +class quaternion_binary_node +: public readable_quaternion> +{ + public: + using node_type = quaternion_binary_node; + using readable_type = readable_quaternion; + using traits_type = quaternion_traits; + using left_arg_type = typename traits_type::left_arg_type; + using right_arg_type = typename traits_type::right_arg_type; + using left_type = typename traits_type::left_type; + using right_type = typename traits_type::right_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using order_type = typename traits_type::order_type; + using cross_type = typename traits_type::cross_type; + + + public: + /** Constant containing the array size. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be + * lvalue reference or rvalue reference types. + * + * @throws incompatible_quaternion_size_error at run-time if either Sub1 or + * Sub2 is a dynamically-sized quaternion, and sub1.size() != sub2.size(). + * If both Sub1 and Sub2 are fixed-size expressions, then the sizes are + * checked at compile time. + */ + quaternion_binary_node(Sub1 left, Sub2 right); + + /** Move constructor. */ + quaternion_binary_node(node_type&& other); + + /** Copy constructor. */ + quaternion_binary_node(const node_type& other); + + + protected: + /** @name readable_quaternion Interface */ + /*@{*/ + + friend readable_type; + + /** Apply the operator to element @c i of the subexpressions and return + * the result. + */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the left subexpression. The expression is + * stored as a copy if Sub1 is an rvalue reference (temporary), or by + * const reference if Sub1 is an lvalue reference. + */ + using left_wrap_type = cml::if_t::value, const left_type&, + left_type>; + + /** The type used to store the right subexpression. The expression is + * stored as a copy if Sub2 is an rvalue reference (temporary), or by + * const reference if Sub2 is an lvalue reference. + */ + using right_wrap_type = cml::if_t::value, const right_type&, + right_type>; + + + protected: + /** The wrapped left subexpression. */ + left_wrap_type m_left; + + /** The wrapped right subexpression. */ + right_wrap_type m_right; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_QUATERNION_BINARY_NODE_TPP +#include +#undef __CML_QUATERNION_BINARY_NODE_TPP diff --git a/cml/quaternion/binary_node.tpp b/cml/quaternion/binary_node.tpp index 096e4ff..404b0aa 100644 --- a/cml/quaternion/binary_node.tpp +++ b/cml/quaternion/binary_node.tpp @@ -1,46 +1,46 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_BINARY_NODE_TPP -# error "quaternion/binary_node.tpp not included correctly" -#endif - -namespace cml { - -/* quaternion_binary_node 'structors: */ - -template -quaternion_binary_node::quaternion_binary_node(Sub1 left, - Sub2 right) -: m_left(std::move(left)) -, m_right(std::move(right)) -{} - -template -quaternion_binary_node::quaternion_binary_node( - node_type&& other) -: m_left(std::move(other.m_left)) -, m_right(std::move(other.m_right)) -{} - -template -quaternion_binary_node::quaternion_binary_node( - const node_type& other) -: m_left(other.m_left) -, m_right(other.m_right) -{} - - -/* Internal methods: */ - -/* readable_quaternion interface: */ - -template -auto -quaternion_binary_node::i_get(int i) const -> immutable_value -{ - return Op().apply(this->m_left.get(i), this->m_right.get(i)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_BINARY_NODE_TPP +# error "quaternion/binary_node.tpp not included correctly" +#endif + +namespace cml { + +/* quaternion_binary_node 'structors: */ + +template +quaternion_binary_node::quaternion_binary_node(Sub1 left, + Sub2 right) +: m_left(std::move(left)) +, m_right(std::move(right)) +{} + +template +quaternion_binary_node::quaternion_binary_node( + node_type&& other) +: m_left(std::move(other.m_left)) +, m_right(std::move(other.m_right)) +{} + +template +quaternion_binary_node::quaternion_binary_node( + const node_type& other) +: m_left(other.m_left) +, m_right(other.m_right) +{} + + +/* Internal methods: */ + +/* readable_quaternion interface: */ + +template +auto +quaternion_binary_node::i_get(int i) const -> immutable_value +{ + return Op().apply(this->m_left.get(i), this->m_right.get(i)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/binary_ops.h b/cml/quaternion/binary_ops.h index 02f3c07..721b4d6 100644 --- a/cml/quaternion/binary_ops.h +++ b/cml/quaternion/binary_ops.h @@ -1,59 +1,59 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Helper function to generate a quaternion_binary_node from two - * quaternion types (i.e. derived from readable_quaternion<>). - */ -template* = nullptr, - enable_if_quaternion_t* = nullptr> -inline auto -make_quaternion_binary_node(Sub1&& sub1, Sub2&& sub2) - -> quaternion_binary_node, - actual_operand_type_of_t, Op> -{ - static_assert( - std::is_same(sub1))>::value, - "internal error: unexpected expression type (sub1)"); - static_assert( - std::is_same(sub2))>::value, - "internal error: unexpected expression type (sub2)"); - - /* Deduce the operand types of the subexpressions (&, const&, &&): */ - using sub1_type = actual_operand_type_of_t; - using sub2_type = actual_operand_type_of_t; - return quaternion_binary_node((sub1_type) sub1, - (sub2_type) sub2); -} - -template* = nullptr, - enable_if_quaternion_t* = nullptr> -inline auto -operator-(Sub1&& sub1, Sub2&& sub2) - -> decltype(make_quaternion_binary_node>( - std::forward(sub1), std::forward(sub2))) -{ - return make_quaternion_binary_node>( - std::forward(sub1), std::forward(sub2)); -} - -template* = nullptr, - enable_if_quaternion_t* = nullptr> -inline auto -operator+(Sub1&& sub1, Sub2&& sub2) - -> decltype(make_quaternion_binary_node>( - std::forward(sub1), std::forward(sub2))) -{ - return make_quaternion_binary_node>( - std::forward(sub1), std::forward(sub2)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Helper function to generate a quaternion_binary_node from two + * quaternion types (i.e. derived from readable_quaternion<>). + */ +template* = nullptr, + enable_if_quaternion_t* = nullptr> +inline auto +make_quaternion_binary_node(Sub1&& sub1, Sub2&& sub2) + -> quaternion_binary_node, + actual_operand_type_of_t, Op> +{ + static_assert( + std::is_same(sub1))>::value, + "internal error: unexpected expression type (sub1)"); + static_assert( + std::is_same(sub2))>::value, + "internal error: unexpected expression type (sub2)"); + + /* Deduce the operand types of the subexpressions (&, const&, &&): */ + using sub1_type = actual_operand_type_of_t; + using sub2_type = actual_operand_type_of_t; + return quaternion_binary_node((sub1_type) sub1, + (sub2_type) sub2); +} + +template* = nullptr, + enable_if_quaternion_t* = nullptr> +inline auto +operator-(Sub1&& sub1, Sub2&& sub2) + -> decltype(make_quaternion_binary_node>( + std::forward(sub1), std::forward(sub2))) +{ + return make_quaternion_binary_node>( + std::forward(sub1), std::forward(sub2)); +} + +template* = nullptr, + enable_if_quaternion_t* = nullptr> +inline auto +operator+(Sub1&& sub1, Sub2&& sub2) + -> decltype(make_quaternion_binary_node>( + std::forward(sub1), std::forward(sub2))) +{ + return make_quaternion_binary_node>( + std::forward(sub1), std::forward(sub2)); +} + +} // namespace cml diff --git a/cml/quaternion/comparison.h b/cml/quaternion/comparison.h index 96ab96a..821fdfc 100644 --- a/cml/quaternion/comparison.h +++ b/cml/quaternion/comparison.h @@ -1,53 +1,53 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Returns true if @c left is lexicographically less than @c right. */ -template -bool operator<(const readable_quaternion& left, - const readable_quaternion& right); - -/** Returns true if @c left is lexicographically less than or equal to @c - * right. - */ -template -bool operator<=(const readable_quaternion& left, - const readable_quaternion& right); - -/** Returns true if @c left is lexicographically greater than @c right. */ -template -bool operator>(const readable_quaternion& left, - const readable_quaternion& right); - -/** Returns true if @c left is lexicographically greater than or equal to - * @c right. - */ -template -bool operator>=(const readable_quaternion& left, - const readable_quaternion& right); - -/** Returns true if the elements of @c left are all equal to the elements - * of @c right. - */ -template -bool operator==(const readable_quaternion& left, - const readable_quaternion& right); - -/** Returns true if some element of @c left is not equal to the - * corresponding element of @c right. - */ -template -bool operator!=(const readable_quaternion& left, - const readable_quaternion& right); - -} // namespace cml - -#define __CML_QUATERNION_COMPARISON_TPP -#include -#undef __CML_QUATERNION_COMPARISON_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Returns true if @c left is lexicographically less than @c right. */ +template +bool operator<(const readable_quaternion& left, + const readable_quaternion& right); + +/** Returns true if @c left is lexicographically less than or equal to @c + * right. + */ +template +bool operator<=(const readable_quaternion& left, + const readable_quaternion& right); + +/** Returns true if @c left is lexicographically greater than @c right. */ +template +bool operator>(const readable_quaternion& left, + const readable_quaternion& right); + +/** Returns true if @c left is lexicographically greater than or equal to + * @c right. + */ +template +bool operator>=(const readable_quaternion& left, + const readable_quaternion& right); + +/** Returns true if the elements of @c left are all equal to the elements + * of @c right. + */ +template +bool operator==(const readable_quaternion& left, + const readable_quaternion& right); + +/** Returns true if some element of @c left is not equal to the + * corresponding element of @c right. + */ +template +bool operator!=(const readable_quaternion& left, + const readable_quaternion& right); + +} // namespace cml + +#define __CML_QUATERNION_COMPARISON_TPP +#include +#undef __CML_QUATERNION_COMPARISON_TPP diff --git a/cml/quaternion/comparison.tpp b/cml/quaternion/comparison.tpp index 4445461..85f5762 100644 --- a/cml/quaternion/comparison.tpp +++ b/cml/quaternion/comparison.tpp @@ -1,92 +1,92 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_COMPARISON_TPP -# error "quaternion/comparison.tpp not included correctly" -#endif - -#include - -namespace cml { - -template -inline bool -operator<(const readable_quaternion& left, - const readable_quaternion& right) -{ - static_assert( - std::is_same, - order_type_trait_of_t>::value, - "cannot compare quaternions with different orders"); - for(int i = 0; i < 4; i++) { - /**/ if(left[i] < right[i]) - return true; // Strictly less. - else if(left[i] > right[i]) return false; // Strictly greater. - else continue; // Equal. - } - - /* Equal. */ - return false; -} - -template -inline bool -operator>(const readable_quaternion& left, - const readable_quaternion& right) -{ - static_assert( - std::is_same, - order_type_trait_of_t>::value, - "cannot compare quaternions with different orders"); - for(int i = 0; i < 4; i++) { - /**/ if(left[i] > right[i]) - return true; // Strictly greater. - else if(left[i] < right[i]) return false; // Strictly less. - else continue; // Equal. - } - - /* Equal. */ - return false; -} - -template -inline bool -operator==(const readable_quaternion& left, - const readable_quaternion& right) -{ - static_assert( - std::is_same, - order_type_trait_of_t>::value, - "cannot compare quaternions with different orders"); - for(int i = 0; i < 4; i++) { - if(!(left[i] == right[i])) return false; // Not equal. - } - return true; -} - -template -inline bool -operator<=(const readable_quaternion& left, - const readable_quaternion& right) -{ - return !(left > right); -} - -template -inline bool -operator>=(const readable_quaternion& left, - const readable_quaternion& right) -{ - return !(left < right); -} - -template -inline bool -operator!=(const readable_quaternion& left, - const readable_quaternion& right) -{ - return !(left == right); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_COMPARISON_TPP +# error "quaternion/comparison.tpp not included correctly" +#endif + +#include + +namespace cml { + +template +inline bool +operator<(const readable_quaternion& left, + const readable_quaternion& right) +{ + static_assert( + std::is_same, + order_type_trait_of_t>::value, + "cannot compare quaternions with different orders"); + for(int i = 0; i < 4; i++) { + /**/ if(left[i] < right[i]) + return true; // Strictly less. + else if(left[i] > right[i]) return false; // Strictly greater. + else continue; // Equal. + } + + /* Equal. */ + return false; +} + +template +inline bool +operator>(const readable_quaternion& left, + const readable_quaternion& right) +{ + static_assert( + std::is_same, + order_type_trait_of_t>::value, + "cannot compare quaternions with different orders"); + for(int i = 0; i < 4; i++) { + /**/ if(left[i] > right[i]) + return true; // Strictly greater. + else if(left[i] < right[i]) return false; // Strictly less. + else continue; // Equal. + } + + /* Equal. */ + return false; +} + +template +inline bool +operator==(const readable_quaternion& left, + const readable_quaternion& right) +{ + static_assert( + std::is_same, + order_type_trait_of_t>::value, + "cannot compare quaternions with different orders"); + for(int i = 0; i < 4; i++) { + if(!(left[i] == right[i])) return false; // Not equal. + } + return true; +} + +template +inline bool +operator<=(const readable_quaternion& left, + const readable_quaternion& right) +{ + return !(left > right); +} + +template +inline bool +operator>=(const readable_quaternion& left, + const readable_quaternion& right) +{ + return !(left < right); +} + +template +inline bool +operator!=(const readable_quaternion& left, + const readable_quaternion& right) +{ + return !(left == right); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/conjugate.h b/cml/quaternion/conjugate.h index 84ea247..8835bfd 100644 --- a/cml/quaternion/conjugate.h +++ b/cml/quaternion/conjugate.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/quaternion/conjugate_node.h b/cml/quaternion/conjugate_node.h index 909096d..e344f61 100644 --- a/cml/quaternion/conjugate_node.h +++ b/cml/quaternion/conjugate_node.h @@ -1,106 +1,106 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -template class conjugate_node; - -/** conjugate_node<> traits. */ -template struct quaternion_traits> -{ - /* Figure out the basic type of Sub: */ - using quaternion_type = conjugate_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = quaternion_traits; - using element_traits = scalar_traits>; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - using storage_type = typename sub_traits::storage_type; - - using size_tag = typename sub_traits::size_tag; - static_assert(cml::is_fixed_size::value, "invalid size tag"); - - /* Array size: */ - static const int array_size = storage_type::array_size; - static_assert(array_size == 4, "invalid quaternion size"); - - /* Order and cross taken from the sub-expression: */ - using order_type = typename sub_traits::order_type; - using cross_type = typename sub_traits::cross_type; -}; - -/** Represents the conjugate of a quaternion subexpression. */ -template -class conjugate_node : public readable_quaternion> -{ - public: - using node_type = conjugate_node; - using readable_type = readable_quaternion; - using traits_type = quaternion_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** The array size constant depends upon the subexpression size. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped quaternion expression. @c sub must be - * an lvalue reference or rvalue reference. - */ - explicit conjugate_node(Sub sub); - - /** Move constructor. */ - conjugate_node(node_type&& other); - - /** Copy constructor. */ - conjugate_node(const node_type& other); - - - protected: - /** @name readable_quaternion Interface */ - /*@{*/ - - friend readable_type; - - /** Apply the operator to element @c i and return the result. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - /** The wrapped subexpression. */ - wrap_type m_sub; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_QUATERNION_CONJUGATE_NODE_TPP -#include -#undef __CML_QUATERNION_CONJUGATE_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +template class conjugate_node; + +/** conjugate_node<> traits. */ +template struct quaternion_traits> +{ + /* Figure out the basic type of Sub: */ + using quaternion_type = conjugate_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = quaternion_traits; + using element_traits = scalar_traits>; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + using storage_type = typename sub_traits::storage_type; + + using size_tag = typename sub_traits::size_tag; + static_assert(cml::is_fixed_size::value, "invalid size tag"); + + /* Array size: */ + static const int array_size = storage_type::array_size; + static_assert(array_size == 4, "invalid quaternion size"); + + /* Order and cross taken from the sub-expression: */ + using order_type = typename sub_traits::order_type; + using cross_type = typename sub_traits::cross_type; +}; + +/** Represents the conjugate of a quaternion subexpression. */ +template +class conjugate_node : public readable_quaternion> +{ + public: + using node_type = conjugate_node; + using readable_type = readable_quaternion; + using traits_type = quaternion_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** The array size constant depends upon the subexpression size. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped quaternion expression. @c sub must be + * an lvalue reference or rvalue reference. + */ + explicit conjugate_node(Sub sub); + + /** Move constructor. */ + conjugate_node(node_type&& other); + + /** Copy constructor. */ + conjugate_node(const node_type& other); + + + protected: + /** @name readable_quaternion Interface */ + /*@{*/ + + friend readable_type; + + /** Apply the operator to element @c i and return the result. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + /** The wrapped subexpression. */ + wrap_type m_sub; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_QUATERNION_CONJUGATE_NODE_TPP +#include +#undef __CML_QUATERNION_CONJUGATE_NODE_TPP diff --git a/cml/quaternion/conjugate_node.tpp b/cml/quaternion/conjugate_node.tpp index 9c72241..1e5161a 100644 --- a/cml/quaternion/conjugate_node.tpp +++ b/cml/quaternion/conjugate_node.tpp @@ -1,44 +1,44 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_CONJUGATE_NODE_TPP -# error "quaternion/conjugate_node.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* conjugate_node 'structors: */ - -template -conjugate_node::conjugate_node(Sub sub) -: m_sub(std::move(sub)) -{} - -template -conjugate_node::conjugate_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -{} - -template -conjugate_node::conjugate_node(const node_type& other) -: m_sub(other.m_sub) -{} - - -/* Internal methods: */ - -/* readable_quaternion interface: */ - -template -auto -conjugate_node::i_get(int i) const -> immutable_value -{ - using order_type = order_type_trait_of_t; - return (i == order_type::W) ? this->m_sub.get(i) : -this->m_sub.get(i); - /* Note: W is either 0 (conjugate_first) or 3 (real_first). */ -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_CONJUGATE_NODE_TPP +# error "quaternion/conjugate_node.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* conjugate_node 'structors: */ + +template +conjugate_node::conjugate_node(Sub sub) +: m_sub(std::move(sub)) +{} + +template +conjugate_node::conjugate_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +{} + +template +conjugate_node::conjugate_node(const node_type& other) +: m_sub(other.m_sub) +{} + + +/* Internal methods: */ + +/* readable_quaternion interface: */ + +template +auto +conjugate_node::i_get(int i) const -> immutable_value +{ + using order_type = order_type_trait_of_t; + return (i == order_type::W) ? this->m_sub.get(i) : -this->m_sub.get(i); + /* Note: W is either 0 (conjugate_first) or 3 (real_first). */ +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/conjugate_ops.h b/cml/quaternion/conjugate_ops.h index ed63122..c46123d 100644 --- a/cml/quaternion/conjugate_ops.h +++ b/cml/quaternion/conjugate_ops.h @@ -1,27 +1,27 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Return an expression node for the conjugate part of @c q. @c q is - * stored by const reference in the node. - */ -template -auto conjugate(const readable_quaternion& q) -> conjugate_node; - -/** Return an expression node for conjugate part of the temporary - * subexpression @c q. @c q is stored by value in the node (via std::move). - */ -template -auto conjugate(readable_quaternion&& q) -> conjugate_node; - -} // namespace cml - -#define __CML_QUATERNION_CONJUGATE_OPS_TPP -#include -#undef __CML_QUATERNION_CONJUGATE_OPS_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Return an expression node for the conjugate part of @c q. @c q is + * stored by const reference in the node. + */ +template +auto conjugate(const readable_quaternion& q) -> conjugate_node; + +/** Return an expression node for conjugate part of the temporary + * subexpression @c q. @c q is stored by value in the node (via std::move). + */ +template +auto conjugate(readable_quaternion&& q) -> conjugate_node; + +} // namespace cml + +#define __CML_QUATERNION_CONJUGATE_OPS_TPP +#include +#undef __CML_QUATERNION_CONJUGATE_OPS_TPP diff --git a/cml/quaternion/conjugate_ops.tpp b/cml/quaternion/conjugate_ops.tpp index ca29fbd..262f00f 100644 --- a/cml/quaternion/conjugate_ops.tpp +++ b/cml/quaternion/conjugate_ops.tpp @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - - -#ifndef __CML_QUATERNION_CONJUGATE_OPS_TPP -# error "quaternion/conjugate_ops.tpp not included correctly" -#endif - -namespace cml { - -template -inline auto -conjugate(const readable_quaternion& q) -> conjugate_node -{ - return conjugate_node(q.actual()); -} - -template -inline auto -conjugate(readable_quaternion&& q) -> conjugate_node -{ - return conjugate_node((Sub&&) q); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + + +#ifndef __CML_QUATERNION_CONJUGATE_OPS_TPP +# error "quaternion/conjugate_ops.tpp not included correctly" +#endif + +namespace cml { + +template +inline auto +conjugate(const readable_quaternion& q) -> conjugate_node +{ + return conjugate_node(q.actual()); +} + +template +inline auto +conjugate(readable_quaternion&& q) -> conjugate_node +{ + return conjugate_node((Sub&&) q); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/cross_tags.h b/cml/quaternion/cross_tags.h index 9f6bc96..c30e75a 100644 --- a/cml/quaternion/cross_tags.h +++ b/cml/quaternion/cross_tags.h @@ -1,69 +1,69 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -/** Helper to specify v1^v2 multiplication cross. */ -struct positive_cross -{}; - -/** Helper to specify v2^v1 multiplication cross. */ -struct negative_cross -{}; - -/** Detect valid cross types. */ -template struct is_cross_type -{ - static const bool value = std::is_same::value - || std::is_same::value; -}; - -/** Templated helper to determine the cross type of an expression that - * defines the cross_type type. - */ -template struct cross_type_of -{ - using type = typename T::cross_type; - static_assert(is_cross_type::value, "invalid cross type"); -}; - -/** Convenience alias for cross_type_of. */ -template using cross_type_of_t = typename cross_type_of::type; - -/** Retrieve the cross_type of @c T via traits. */ -template struct cross_type_trait_of -{ - using type = typename traits_of::type::cross_type; - static_assert(is_cross_type::value, "invalid cross type"); -}; - -/** Convenience alias for cross_type_trait_of. */ -template -using cross_type_trait_of_t = typename cross_type_trait_of::type; - -/** Deduce the default cross tag needed to promote the result of combining - * two expressions having crosss @c Tag1 and @c Tag2. By default: - * - * - both imaginary_first: imaginary_first - * - both real_first: real_first - * - otherwise: compile-time error - */ -template struct cross_type_promote -{ - static_assert(is_cross_type::value, "invalid quaternion cross type"); - static_assert(is_cross_type::value, "invalid quaternion cross type"); - static_assert(std::is_same::value, - "mismatched quaternion cross types"); - - /* The tags are the same, so use the common type: */ - using type = Tag1; -}; - -/** Convenience alias for cross_type_promote. */ -template -using cross_type_promote_t = typename cross_type_promote::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +/** Helper to specify v1^v2 multiplication cross. */ +struct positive_cross +{}; + +/** Helper to specify v2^v1 multiplication cross. */ +struct negative_cross +{}; + +/** Detect valid cross types. */ +template struct is_cross_type +{ + static const bool value = std::is_same::value + || std::is_same::value; +}; + +/** Templated helper to determine the cross type of an expression that + * defines the cross_type type. + */ +template struct cross_type_of +{ + using type = typename T::cross_type; + static_assert(is_cross_type::value, "invalid cross type"); +}; + +/** Convenience alias for cross_type_of. */ +template using cross_type_of_t = typename cross_type_of::type; + +/** Retrieve the cross_type of @c T via traits. */ +template struct cross_type_trait_of +{ + using type = typename traits_of::type::cross_type; + static_assert(is_cross_type::value, "invalid cross type"); +}; + +/** Convenience alias for cross_type_trait_of. */ +template +using cross_type_trait_of_t = typename cross_type_trait_of::type; + +/** Deduce the default cross tag needed to promote the result of combining + * two expressions having crosss @c Tag1 and @c Tag2. By default: + * + * - both imaginary_first: imaginary_first + * - both real_first: real_first + * - otherwise: compile-time error + */ +template struct cross_type_promote +{ + static_assert(is_cross_type::value, "invalid quaternion cross type"); + static_assert(is_cross_type::value, "invalid quaternion cross type"); + static_assert(std::is_same::value, + "mismatched quaternion cross types"); + + /* The tags are the same, so use the common type: */ + using type = Tag1; +}; + +/** Convenience alias for cross_type_promote. */ +template +using cross_type_promote_t = typename cross_type_promote::type; + +} // namespace cml diff --git a/cml/quaternion/dot.h b/cml/quaternion/dot.h index 74be7dc..28a5556 100644 --- a/cml/quaternion/dot.h +++ b/cml/quaternion/dot.h @@ -1,29 +1,29 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Compute the dot-product of two quaternions. - * - * @note Currently, the result is computed immediately, even if it appears - * as a term in an expression. - * - * @note Compilation will fail if @c Sub1 and @c Sub2 have different - * quaternion orders. - */ -template -auto dot(const readable_quaternion& left, - const readable_quaternion& right) - -> value_type_trait_promote_t; - -} // namespace cml - -#define __CML_QUATERNION_DOT_TPP -#include -#undef __CML_QUATERNION_DOT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Compute the dot-product of two quaternions. + * + * @note Currently, the result is computed immediately, even if it appears + * as a term in an expression. + * + * @note Compilation will fail if @c Sub1 and @c Sub2 have different + * quaternion orders. + */ +template +auto dot(const readable_quaternion& left, + const readable_quaternion& right) + -> value_type_trait_promote_t; + +} // namespace cml + +#define __CML_QUATERNION_DOT_TPP +#include +#undef __CML_QUATERNION_DOT_TPP diff --git a/cml/quaternion/dot.tpp b/cml/quaternion/dot.tpp index 2907266..7cd5123 100644 --- a/cml/quaternion/dot.tpp +++ b/cml/quaternion/dot.tpp @@ -1,30 +1,30 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_DOT_TPP -# error "quaternion/dot.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -template -inline auto -dot(const readable_quaternion& left, - const readable_quaternion& right) - -> value_type_trait_promote_t -{ - using value_type = value_type_trait_promote_t; - - static_assert( - std::is_same, - order_type_trait_of_t>::value, - "mismatched quaternion order types"); - return value_type(left.get(0) * right.get(0) + left.get(1) * right.get(1) - + left.get(2) * right.get(2) + left.get(3) * right.get(3)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_DOT_TPP +# error "quaternion/dot.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +template +inline auto +dot(const readable_quaternion& left, + const readable_quaternion& right) + -> value_type_trait_promote_t +{ + using value_type = value_type_trait_promote_t; + + static_assert( + std::is_same, + order_type_trait_of_t>::value, + "mismatched quaternion order types"); + return value_type(left.get(0) * right.get(0) + left.get(1) * right.get(1) + + left.get(2) * right.get(2) + left.get(3) * right.get(3)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/fixed.h b/cml/quaternion/fixed.h index aa00622..ca978de 100644 --- a/cml/quaternion/fixed.h +++ b/cml/quaternion/fixed.h @@ -1,7 +1,7 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include diff --git a/cml/quaternion/fixed_compiled.h b/cml/quaternion/fixed_compiled.h index c8a3eb4..032c0c6 100644 --- a/cml/quaternion/fixed_compiled.h +++ b/cml/quaternion/fixed_compiled.h @@ -1,245 +1,245 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template -struct quaternion_traits, Order, Cross>> -{ - /* Traits and types for the quaternion element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The quaternion storage type: */ - using storage_type = rebind_t, quaternion_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array size (should be positive): */ - static const int array_size = storage_type::array_size; - static_assert(array_size == 4, "invalid quaternion size"); - - /** Quaternion order. */ - using order_type = Order; - - /** Quaternion cross type. */ - using cross_type = Cross; -}; - -/** Fixed-length quaternion. */ -template -class quaternion, Order, Cross> -: public writable_quaternion, Order, Cross>> -{ - public: - using quaternion_type = quaternion, Order, Cross>; - using readable_type = readable_quaternion; - using writable_type = writable_quaternion; - using traits_type = quaternion_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using order_type = typename traits_type::order_type; - using cross_type = typename traits_type::cross_type; - - - public: - /* Include methods from writable_type: */ - using writable_type::W; - using writable_type::X; - using writable_type::Y; - using writable_type::Z; - using writable_type::operator=; - - - public: - /** Constant containing the array size. */ - static const int array_size = traits_type::array_size; - - /** The dimension (same as array_size). */ - static const int dimension = array_size; - - - public: - /** Compiler-default constructor. - * - * @note The quaternion elements are uninitialized. - */ - quaternion() = default; - - /** Compiler-default destructor. */ - ~quaternion() = default; - - /** Compiler-default copy constructor. */ - quaternion(const quaternion_type& other) = default; - - /** Compiler-default move constructor. */ - quaternion(quaternion_type&& other) = default; - - /** Construct from a readable_quaternion. */ - template quaternion(const readable_quaternion& sub); - - /** Construct from 4 values. - * - * @note This overload is enabled only if all of the arguments are - * convertible to value_type. - */ - template* = nullptr> - quaternion(const E0& e0, const E1& e1, const E2& e2, const E3& e3) - // XXX Should be in quaternion/fixed_compiled.tpp, but VC++12 has - // brain-dead out-of-line template argument matching... - { - this->assign_elements(e0, e1, e2, e3); - } - - /** Construct from a 3D readable_vector and one additional element. - * - * @note Although the imaginary part is specified first, the proper - * coefficient order is maintained. - * - * @note This overload is enabled only if the value_type of @c sub and - * the scalar argument are convertible to value_type. - */ - template, E0>* = - nullptr> - quaternion(const readable_vector& sub, const E0& e0) - // XXX Should be in quaternion/fixed_compiled.tpp, but VC++12 has - // brain-dead out-of-line template argument matching... - { - this->assign(sub, e0); - } - - /** Construct from one additional element and a 3D readable_vector. - * - * @note Although the imaginary part is specified second, the proper - * coefficient order is maintained. - * - * @note This overload is enabled only if the value_type of @c sub and - * the scalar argument are convertible to value_type. - */ - template, E0>* = - nullptr> - quaternion(const E0& e0, const readable_vector& sub) - // XXX Should be in quaternion/fixed_compiled.tpp, but VC++12 has - // brain-dead out-of-line template argument matching... - { - this->assign(sub, e0); - } - - /** Construct from a 3-element array and one additional element. - * - * @note Although the imaginary part is specified first, the proper - * coefficient order is maintained. - */ - template* = nullptr> - quaternion(const Array& array, const E1& e1); - - /** Construct from one additional element and a 3-element array. - * - * @note Although the imaginary part is specified second, the proper - * coefficient order is maintained. - */ - template* = nullptr> - quaternion(const E0& e0, const Array& array); - - /** Construct from an array type. */ - template* = nullptr> - quaternion(const Array& array); - - /** Construct from a pointer to an array. */ - template* = nullptr> - quaternion(const Pointer& array); - - /** Construct from std::initializer_list. */ - template quaternion(std::initializer_list l); - - - public: - /** Return the length of the quaternion. */ - int size() const; - - /** Return access to the quaternion data as a raw pointer. */ - pointer data(); - - /** Return const access to the quaternion data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator. */ - const_pointer begin() const; - - /** Read-only iterator. */ - const_pointer end() const; - - - public: - /** Copy assignment. */ - quaternion_type& operator=(const quaternion_type& other); - - /** Move assignment. */ - quaternion_type& operator=(quaternion_type&& other); - - - protected: - /** @name readable_quaternion Interface */ - /*@{*/ - - friend readable_type; - - /** Return quaternion const element @c i. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** @name writable_quaternion Interface */ - /*@{*/ - - friend writable_type; - - /** Return quaternion element @c i. */ - mutable_value i_get(int i); - - /** Set element @c i. */ - template quaternion_type& i_put(int i, const Other& v) &; - - /** Set element @c i on a temporary. */ - template quaternion_type&& i_put(int i, const Other& v) &&; - - /*@}*/ - - - protected: - /** Fixed-length array. */ - value_type m_data[4]; -}; - -} // namespace cml - -#define __CML_QUATERNION_FIXED_COMPILED_TPP -#include -#undef __CML_QUATERNION_FIXED_COMPILED_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template +struct quaternion_traits, Order, Cross>> +{ + /* Traits and types for the quaternion element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The quaternion storage type: */ + using storage_type = rebind_t, quaternion_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array size (should be positive): */ + static const int array_size = storage_type::array_size; + static_assert(array_size == 4, "invalid quaternion size"); + + /** Quaternion order. */ + using order_type = Order; + + /** Quaternion cross type. */ + using cross_type = Cross; +}; + +/** Fixed-length quaternion. */ +template +class quaternion, Order, Cross> +: public writable_quaternion, Order, Cross>> +{ + public: + using quaternion_type = quaternion, Order, Cross>; + using readable_type = readable_quaternion; + using writable_type = writable_quaternion; + using traits_type = quaternion_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using order_type = typename traits_type::order_type; + using cross_type = typename traits_type::cross_type; + + + public: + /* Include methods from writable_type: */ + using writable_type::W; + using writable_type::X; + using writable_type::Y; + using writable_type::Z; + using writable_type::operator=; + + + public: + /** Constant containing the array size. */ + static const int array_size = traits_type::array_size; + + /** The dimension (same as array_size). */ + static const int dimension = array_size; + + + public: + /** Compiler-default constructor. + * + * @note The quaternion elements are uninitialized. + */ + quaternion() = default; + + /** Compiler-default destructor. */ + ~quaternion() = default; + + /** Compiler-default copy constructor. */ + quaternion(const quaternion_type& other) = default; + + /** Compiler-default move constructor. */ + quaternion(quaternion_type&& other) = default; + + /** Construct from a readable_quaternion. */ + template quaternion(const readable_quaternion& sub); + + /** Construct from 4 values. + * + * @note This overload is enabled only if all of the arguments are + * convertible to value_type. + */ + template* = nullptr> + quaternion(const E0& e0, const E1& e1, const E2& e2, const E3& e3) + // XXX Should be in quaternion/fixed_compiled.tpp, but VC++12 has + // brain-dead out-of-line template argument matching... + { + this->assign_elements(e0, e1, e2, e3); + } + + /** Construct from a 3D readable_vector and one additional element. + * + * @note Although the imaginary part is specified first, the proper + * coefficient order is maintained. + * + * @note This overload is enabled only if the value_type of @c sub and + * the scalar argument are convertible to value_type. + */ + template, E0>* = + nullptr> + quaternion(const readable_vector& sub, const E0& e0) + // XXX Should be in quaternion/fixed_compiled.tpp, but VC++12 has + // brain-dead out-of-line template argument matching... + { + this->assign(sub, e0); + } + + /** Construct from one additional element and a 3D readable_vector. + * + * @note Although the imaginary part is specified second, the proper + * coefficient order is maintained. + * + * @note This overload is enabled only if the value_type of @c sub and + * the scalar argument are convertible to value_type. + */ + template, E0>* = + nullptr> + quaternion(const E0& e0, const readable_vector& sub) + // XXX Should be in quaternion/fixed_compiled.tpp, but VC++12 has + // brain-dead out-of-line template argument matching... + { + this->assign(sub, e0); + } + + /** Construct from a 3-element array and one additional element. + * + * @note Although the imaginary part is specified first, the proper + * coefficient order is maintained. + */ + template* = nullptr> + quaternion(const Array& array, const E1& e1); + + /** Construct from one additional element and a 3-element array. + * + * @note Although the imaginary part is specified second, the proper + * coefficient order is maintained. + */ + template* = nullptr> + quaternion(const E0& e0, const Array& array); + + /** Construct from an array type. */ + template* = nullptr> + quaternion(const Array& array); + + /** Construct from a pointer to an array. */ + template* = nullptr> + quaternion(const Pointer& array); + + /** Construct from std::initializer_list. */ + template quaternion(std::initializer_list l); + + + public: + /** Return the length of the quaternion. */ + int size() const; + + /** Return access to the quaternion data as a raw pointer. */ + pointer data(); + + /** Return const access to the quaternion data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator. */ + const_pointer begin() const; + + /** Read-only iterator. */ + const_pointer end() const; + + + public: + /** Copy assignment. */ + quaternion_type& operator=(const quaternion_type& other); + + /** Move assignment. */ + quaternion_type& operator=(quaternion_type&& other); + + + protected: + /** @name readable_quaternion Interface */ + /*@{*/ + + friend readable_type; + + /** Return quaternion const element @c i. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** @name writable_quaternion Interface */ + /*@{*/ + + friend writable_type; + + /** Return quaternion element @c i. */ + mutable_value i_get(int i); + + /** Set element @c i. */ + template quaternion_type& i_put(int i, const Other& v) &; + + /** Set element @c i on a temporary. */ + template quaternion_type&& i_put(int i, const Other& v) &&; + + /*@}*/ + + + protected: + /** Fixed-length array. */ + value_type m_data[4]; +}; + +} // namespace cml + +#define __CML_QUATERNION_FIXED_COMPILED_TPP +#include +#undef __CML_QUATERNION_FIXED_COMPILED_TPP diff --git a/cml/quaternion/fixed_compiled.tpp b/cml/quaternion/fixed_compiled.tpp index 119e7ec..7ff5e81 100644 --- a/cml/quaternion/fixed_compiled.tpp +++ b/cml/quaternion/fixed_compiled.tpp @@ -1,152 +1,152 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_FIXED_COMPILED_TPP -# error "quaternion/fixed_compiled.tpp not included correctly" -#endif - -namespace cml { - -/* fixed 'structors: */ - -template -template -quaternion, O, C>::quaternion(const readable_quaternion& sub) -{ - this->assign(sub); -} - -template -template*> -quaternion, O, C>::quaternion(const Array& array) -{ - this->assign(array); -} - -template -template*> -quaternion, O, C>::quaternion(const Pointer& array) -{ - this->assign(array); -} - -template -template*> -quaternion, O, C>::quaternion(const E0& e0, const Array& array) -{ - this->assign(array, e0); -} - -template -template*> -quaternion, O, C>::quaternion(const Array& array, const E1& e1) -{ - this->assign(array, e1); -} - -template -template -quaternion, O, C>::quaternion(std::initializer_list l) -{ - this->assign(l); -} - -/* Public methods: */ - -template -int -quaternion, O, C>::size() const -{ - return 4; -} - -template -auto -quaternion, O, C>::data() -> pointer -{ - return &this->m_data[0]; -} - -template -auto -quaternion, O, C>::data() const -> const_pointer -{ - return &this->m_data[0]; -} - -template -auto -quaternion, O, C>::begin() const -> const_pointer -{ - return &this->m_data[0]; -} - -template -auto -quaternion, O, C>::end() const -> const_pointer -{ - return (&this->m_data[0]) + 4; -} - -template -auto -quaternion, O, C>::operator=(const quaternion_type& other) - -> quaternion_type& -{ - return this->assign(other); -} - -template -auto -quaternion, O, C>::operator=(quaternion_type&& other) - -> quaternion_type& -{ - this->m_data[W] = std::move(other.m_data[W]); - this->m_data[X] = std::move(other.m_data[X]); - this->m_data[Y] = std::move(other.m_data[Y]); - this->m_data[Z] = std::move(other.m_data[Z]); - return *this; -} - -/* Internal methods: */ - -/* readable_quaternion interface: */ - -template -auto -quaternion, O, C>::i_get(int i) const -> immutable_value -{ - return this->m_data[i]; -} - -/* writable_quaternion interface: */ - -template -auto -quaternion, O, C>::i_get(int i) -> mutable_value -{ - return this->m_data[i]; -} - -template -template -auto -quaternion, O, C>::i_put(int i, - const Other& v) &->quaternion_type& -{ - this->m_data[i] = value_type(v); - return *this; -} - -template -template -auto -quaternion, O, C>::i_put(int i, - const Other& v) && -> quaternion_type&& -{ - this->m_data[i] = value_type(v); - return (quaternion_type&&) *this; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_FIXED_COMPILED_TPP +# error "quaternion/fixed_compiled.tpp not included correctly" +#endif + +namespace cml { + +/* fixed 'structors: */ + +template +template +quaternion, O, C>::quaternion(const readable_quaternion& sub) +{ + this->assign(sub); +} + +template +template*> +quaternion, O, C>::quaternion(const Array& array) +{ + this->assign(array); +} + +template +template*> +quaternion, O, C>::quaternion(const Pointer& array) +{ + this->assign(array); +} + +template +template*> +quaternion, O, C>::quaternion(const E0& e0, const Array& array) +{ + this->assign(array, e0); +} + +template +template*> +quaternion, O, C>::quaternion(const Array& array, const E1& e1) +{ + this->assign(array, e1); +} + +template +template +quaternion, O, C>::quaternion(std::initializer_list l) +{ + this->assign(l); +} + +/* Public methods: */ + +template +int +quaternion, O, C>::size() const +{ + return 4; +} + +template +auto +quaternion, O, C>::data() -> pointer +{ + return &this->m_data[0]; +} + +template +auto +quaternion, O, C>::data() const -> const_pointer +{ + return &this->m_data[0]; +} + +template +auto +quaternion, O, C>::begin() const -> const_pointer +{ + return &this->m_data[0]; +} + +template +auto +quaternion, O, C>::end() const -> const_pointer +{ + return (&this->m_data[0]) + 4; +} + +template +auto +quaternion, O, C>::operator=(const quaternion_type& other) + -> quaternion_type& +{ + return this->assign(other); +} + +template +auto +quaternion, O, C>::operator=(quaternion_type&& other) + -> quaternion_type& +{ + this->m_data[W] = std::move(other.m_data[W]); + this->m_data[X] = std::move(other.m_data[X]); + this->m_data[Y] = std::move(other.m_data[Y]); + this->m_data[Z] = std::move(other.m_data[Z]); + return *this; +} + +/* Internal methods: */ + +/* readable_quaternion interface: */ + +template +auto +quaternion, O, C>::i_get(int i) const -> immutable_value +{ + return this->m_data[i]; +} + +/* writable_quaternion interface: */ + +template +auto +quaternion, O, C>::i_get(int i) -> mutable_value +{ + return this->m_data[i]; +} + +template +template +auto +quaternion, O, C>::i_put(int i, + const Other& v) &->quaternion_type& +{ + this->m_data[i] = value_type(v); + return *this; +} + +template +template +auto +quaternion, O, C>::i_put(int i, + const Other& v) && -> quaternion_type&& +{ + this->m_data[i] = value_type(v); + return (quaternion_type&&) *this; +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/functions.h b/cml/quaternion/functions.h index 43c5751..80f07af 100644 --- a/cml/quaternion/functions.h +++ b/cml/quaternion/functions.h @@ -1,54 +1,54 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Return the real part of quaternion @c q. */ -template -auto real(const readable_quaternion& q) - -> value_type_trait_of_t; - -/** Return the squared length of @c q. */ -template -auto length_squared(const readable_quaternion& q) - -> value_type_trait_of_t; - -/** Return the length of @c q. */ -template -auto length(const readable_quaternion& q) - -> value_type_trait_of_t; - -/** Return the Cayley norm (squared length) of @c q. */ -template -auto norm(const readable_quaternion& q) - -> value_type_trait_of_t; - -/** Return a normalized copy of @c q. */ -template -auto normalize(const readable_quaternion& q) - -> temporary_of_t; - -/** Return the multiplicative identity of quaternion @c q. */ -template -auto identity(const readable_quaternion& q) - -> temporary_of_t; - -/** Return the log of @c q. */ -template -auto log(const readable_quaternion& q) -> temporary_of_t; - -/** Return the exponential of @c q. */ -template -auto exp(const readable_quaternion& q) -> temporary_of_t; - -} // namespace cml - -#define __CML_QUATERNION_FUNCTIONS_TPP -#include -#undef __CML_QUATERNION_FUNCTIONS_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Return the real part of quaternion @c q. */ +template +auto real(const readable_quaternion& q) + -> value_type_trait_of_t; + +/** Return the squared length of @c q. */ +template +auto length_squared(const readable_quaternion& q) + -> value_type_trait_of_t; + +/** Return the length of @c q. */ +template +auto length(const readable_quaternion& q) + -> value_type_trait_of_t; + +/** Return the Cayley norm (squared length) of @c q. */ +template +auto norm(const readable_quaternion& q) + -> value_type_trait_of_t; + +/** Return a normalized copy of @c q. */ +template +auto normalize(const readable_quaternion& q) + -> temporary_of_t; + +/** Return the multiplicative identity of quaternion @c q. */ +template +auto identity(const readable_quaternion& q) + -> temporary_of_t; + +/** Return the log of @c q. */ +template +auto log(const readable_quaternion& q) -> temporary_of_t; + +/** Return the exponential of @c q. */ +template +auto exp(const readable_quaternion& q) -> temporary_of_t; + +} // namespace cml + +#define __CML_QUATERNION_FUNCTIONS_TPP +#include +#undef __CML_QUATERNION_FUNCTIONS_TPP diff --git a/cml/quaternion/functions.tpp b/cml/quaternion/functions.tpp index f48b234..250c419 100644 --- a/cml/quaternion/functions.tpp +++ b/cml/quaternion/functions.tpp @@ -1,75 +1,75 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_FUNCTIONS_TPP -# error "quaternion/functions.tpp not included correctly" -#endif - -#include - -namespace cml { - -template -inline auto -real(const readable_quaternion
& q) -> value_type_trait_of_t
-{ - return q.real(); -} - -template -inline auto -length_squared(const readable_quaternion
& q) -> value_type_trait_of_t
-{ - return q.length_squared(); -} - -template -inline auto -length(const readable_quaternion
& q) -> value_type_trait_of_t
-{ - return q.length(); -} - -template -inline auto -norm(const readable_quaternion
& q) -> value_type_trait_of_t
-{ - return q.norm(); -} - -template -inline auto -normalize(const readable_quaternion& q) -> temporary_of_t -{ - return q.normalize(); -} - -template -inline auto -identity(const readable_quaternion& q) -> temporary_of_t -{ - temporary_of_t result(q); - result.identity(); - return result; -} - -template -inline auto -log(const readable_quaternion& q) -> temporary_of_t -{ - temporary_of_t result(q); - result.log(); - return result; -} - -template -inline auto -exp(const readable_quaternion& q) -> temporary_of_t -{ - temporary_of_t result(q); - result.exp(); - return result; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_FUNCTIONS_TPP +# error "quaternion/functions.tpp not included correctly" +#endif + +#include + +namespace cml { + +template +inline auto +real(const readable_quaternion
& q) -> value_type_trait_of_t
+{ + return q.real(); +} + +template +inline auto +length_squared(const readable_quaternion
& q) -> value_type_trait_of_t
+{ + return q.length_squared(); +} + +template +inline auto +length(const readable_quaternion
& q) -> value_type_trait_of_t
+{ + return q.length(); +} + +template +inline auto +norm(const readable_quaternion
& q) -> value_type_trait_of_t
+{ + return q.norm(); +} + +template +inline auto +normalize(const readable_quaternion& q) -> temporary_of_t +{ + return q.normalize(); +} + +template +inline auto +identity(const readable_quaternion& q) -> temporary_of_t +{ + temporary_of_t result(q); + result.identity(); + return result; +} + +template +inline auto +log(const readable_quaternion& q) -> temporary_of_t +{ + temporary_of_t result(q); + result.log(); + return result; +} + +template +inline auto +exp(const readable_quaternion& q) -> temporary_of_t +{ + temporary_of_t result(q); + result.exp(); + return result; +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/fwd.h b/cml/quaternion/fwd.h index bd62245..95bb6d7 100644 --- a/cml/quaternion/fwd.h +++ b/cml/quaternion/fwd.h @@ -1,12 +1,12 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -template class readable_quaternion; -template class writable_quaternion; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +template class readable_quaternion; +template class writable_quaternion; + +} // namespace cml diff --git a/cml/quaternion/imaginary.h b/cml/quaternion/imaginary.h index 62b7c7a..b372410 100644 --- a/cml/quaternion/imaginary.h +++ b/cml/quaternion/imaginary.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/quaternion/imaginary_node.h b/cml/quaternion/imaginary_node.h index 824e1f3..9851900 100644 --- a/cml/quaternion/imaginary_node.h +++ b/cml/quaternion/imaginary_node.h @@ -1,118 +1,118 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class imaginary_node; - -/** imaginary_node<> traits. */ -template struct vector_traits> -{ - /* Figure out the basic type of Sub: */ - using vector_type = imaginary_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = quaternion_traits; - using element_traits = typename sub_traits::element_traits; - using value_type = typename sub_traits::value_type; - using immutable_value = typename sub_traits::immutable_value; - - /* Resize the *unbound* storage type of the quaternion subexpression to a - * vector storage type: - */ - using bound_storage_type = typename sub_traits::storage_type; - using unbound_storage_type = typename bound_storage_type::unbound_type; - using resized_type = resize_storage_t; - - /* Rebind to vector storage: */ - using storage_type = rebind_t; - - /* Traits and types for the new storage: */ - using size_tag = typename storage_type::size_tag; - static_assert(cml::is_fixed_size::value, "invalid size tag"); - - /* Array size: */ - static const int array_size = storage_type::array_size; - static_assert(array_size == 3, "invalid imaginary vector size"); -}; - -/** Represents the imaginary part of a quaternion subexpression as a - * 3-element vector expression. - */ -template -class imaginary_node : public readable_vector> -{ - public: - using node_type = imaginary_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** The array size constant depends upon the subexpression size. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped quaternion expression. @c sub must be - * an lvalue reference or rvalue reference. - */ - explicit imaginary_node(Sub sub); - - /** Move constructor. */ - imaginary_node(node_type&& other); - - /** Copy constructor. */ - imaginary_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Apply the operator to element @c i and return the result. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using wrap_type = - cml::if_t::value, const sub_type&, sub_type>; - - /** The wrapped subexpression. */ - wrap_type m_sub; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_QUATERNION_IMAGINARY_NODE_TPP -#include -#undef __CML_QUATERNION_IMAGINARY_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class imaginary_node; + +/** imaginary_node<> traits. */ +template struct vector_traits> +{ + /* Figure out the basic type of Sub: */ + using vector_type = imaginary_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = quaternion_traits; + using element_traits = typename sub_traits::element_traits; + using value_type = typename sub_traits::value_type; + using immutable_value = typename sub_traits::immutable_value; + + /* Resize the *unbound* storage type of the quaternion subexpression to a + * vector storage type: + */ + using bound_storage_type = typename sub_traits::storage_type; + using unbound_storage_type = typename bound_storage_type::unbound_type; + using resized_type = resize_storage_t; + + /* Rebind to vector storage: */ + using storage_type = rebind_t; + + /* Traits and types for the new storage: */ + using size_tag = typename storage_type::size_tag; + static_assert(cml::is_fixed_size::value, "invalid size tag"); + + /* Array size: */ + static const int array_size = storage_type::array_size; + static_assert(array_size == 3, "invalid imaginary vector size"); +}; + +/** Represents the imaginary part of a quaternion subexpression as a + * 3-element vector expression. + */ +template +class imaginary_node : public readable_vector> +{ + public: + using node_type = imaginary_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** The array size constant depends upon the subexpression size. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped quaternion expression. @c sub must be + * an lvalue reference or rvalue reference. + */ + explicit imaginary_node(Sub sub); + + /** Move constructor. */ + imaginary_node(node_type&& other); + + /** Copy constructor. */ + imaginary_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Apply the operator to element @c i and return the result. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using wrap_type = + cml::if_t::value, const sub_type&, sub_type>; + + /** The wrapped subexpression. */ + wrap_type m_sub; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_QUATERNION_IMAGINARY_NODE_TPP +#include +#undef __CML_QUATERNION_IMAGINARY_NODE_TPP diff --git a/cml/quaternion/imaginary_node.tpp b/cml/quaternion/imaginary_node.tpp index b385bb9..ac5cea3 100644 --- a/cml/quaternion/imaginary_node.tpp +++ b/cml/quaternion/imaginary_node.tpp @@ -1,50 +1,50 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_IMAGINARY_NODE_TPP -# error "quaternion/imaginary_node.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* imaginary_node 'structors: */ - -template -imaginary_node::imaginary_node(Sub sub) -: m_sub(std::move(sub)) -{} - -template -imaginary_node::imaginary_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -{} - -template -imaginary_node::imaginary_node(const node_type& other) -: m_sub(other.m_sub) -{} - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -imaginary_node::i_size() const -{ - return 3; -} - -template -auto -imaginary_node::i_get(int i) const -> immutable_value -{ - using order_type = order_type_trait_of_t; - return this->m_sub.get(order_type::X + i); - /* Note: X is either 0 (imaginary_first) or 1 (real_first). */ -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_IMAGINARY_NODE_TPP +# error "quaternion/imaginary_node.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* imaginary_node 'structors: */ + +template +imaginary_node::imaginary_node(Sub sub) +: m_sub(std::move(sub)) +{} + +template +imaginary_node::imaginary_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +{} + +template +imaginary_node::imaginary_node(const node_type& other) +: m_sub(other.m_sub) +{} + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +imaginary_node::i_size() const +{ + return 3; +} + +template +auto +imaginary_node::i_get(int i) const -> immutable_value +{ + using order_type = order_type_trait_of_t; + return this->m_sub.get(order_type::X + i); + /* Note: X is either 0 (imaginary_first) or 1 (real_first). */ +} + +} // namespace cml diff --git a/cml/quaternion/imaginary_ops.h b/cml/quaternion/imaginary_ops.h index 7a5b10b..029dd3b 100644 --- a/cml/quaternion/imaginary_ops.h +++ b/cml/quaternion/imaginary_ops.h @@ -1,27 +1,27 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Return an expression node for the imaginary part of @c q. @c q is - * stored by const reference in the node. - */ -template -auto imaginary(const readable_quaternion& q) -> imaginary_node; - -/** Return an expression node for imaginary part of the temporary - * subexpression @c q. @c q is stored by value in the node (via std::move). - */ -template -auto imaginary(readable_quaternion&& q) -> imaginary_node; - -} // namespace cml - -#define __CML_QUATERNION_IMAGINARY_OPS_TPP -#include -#undef __CML_QUATERNION_IMAGINARY_OPS_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Return an expression node for the imaginary part of @c q. @c q is + * stored by const reference in the node. + */ +template +auto imaginary(const readable_quaternion& q) -> imaginary_node; + +/** Return an expression node for imaginary part of the temporary + * subexpression @c q. @c q is stored by value in the node (via std::move). + */ +template +auto imaginary(readable_quaternion&& q) -> imaginary_node; + +} // namespace cml + +#define __CML_QUATERNION_IMAGINARY_OPS_TPP +#include +#undef __CML_QUATERNION_IMAGINARY_OPS_TPP diff --git a/cml/quaternion/imaginary_ops.tpp b/cml/quaternion/imaginary_ops.tpp index e2e8912..ad3464b 100644 --- a/cml/quaternion/imaginary_ops.tpp +++ b/cml/quaternion/imaginary_ops.tpp @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - - -#ifndef __CML_QUATERNION_IMAGINARY_OPS_TPP -# error "quaternion/imaginary_ops.tpp not included correctly" -#endif - -namespace cml { - -template -inline auto -imaginary(const readable_quaternion& q) -> imaginary_node -{ - return imaginary_node(q.actual()); -} - -template -inline auto -imaginary(readable_quaternion&& q) -> imaginary_node -{ - return imaginary_node((Sub&&) q); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + + +#ifndef __CML_QUATERNION_IMAGINARY_OPS_TPP +# error "quaternion/imaginary_ops.tpp not included correctly" +#endif + +namespace cml { + +template +inline auto +imaginary(const readable_quaternion& q) -> imaginary_node +{ + return imaginary_node(q.actual()); +} + +template +inline auto +imaginary(readable_quaternion&& q) -> imaginary_node +{ + return imaginary_node((Sub&&) q); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/inverse.h b/cml/quaternion/inverse.h index 1414cbf..205baa6 100644 --- a/cml/quaternion/inverse.h +++ b/cml/quaternion/inverse.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/quaternion/inverse_node.h b/cml/quaternion/inverse_node.h index eaced90..143a4fa 100644 --- a/cml/quaternion/inverse_node.h +++ b/cml/quaternion/inverse_node.h @@ -1,109 +1,109 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -template class inverse_node; - -/** inverse_node<> traits. */ -template struct quaternion_traits> -{ - /* Figure out the basic type of Sub: */ - using quaternion_type = inverse_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = quaternion_traits; - using element_traits = scalar_traits>; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - using storage_type = typename sub_traits::storage_type; - - using size_tag = typename sub_traits::size_tag; - static_assert(cml::is_fixed_size::value, "invalid size tag"); - - /* Array size: */ - static const int array_size = storage_type::array_size; - static_assert(array_size == 4, "invalid quaternion size"); - - /* Order and cross taken from the sub-expression: */ - using order_type = typename sub_traits::order_type; - using cross_type = typename sub_traits::cross_type; -}; - -/** Represents the inverse of a quaternion subexpression. */ -template -class inverse_node : public readable_quaternion> -{ - public: - using node_type = inverse_node; - using readable_type = readable_quaternion; - using traits_type = quaternion_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** The array size constant depends upon the subexpression size. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped quaternion expression. @c sub must be - * an lvalue reference or rvalue reference. - */ - explicit inverse_node(Sub sub); - - /** Move constructor. */ - inverse_node(node_type&& other); - - /** Copy constructor. */ - inverse_node(const node_type& other); - - - protected: - /** @name readable_quaternion Interface */ - /*@{*/ - - friend readable_type; - - /** Apply the operator to element @c i and return the result. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using wrap_type = - cml::if_t::value, const sub_type&, sub_type>; - - /** The wrapped subexpression. */ - wrap_type m_sub; - - /** The reciprocal of the subexpression norm. */ - value_type m_inv_norm; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_QUATERNION_INVERSE_NODE_TPP -#include -#undef __CML_QUATERNION_INVERSE_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +template class inverse_node; + +/** inverse_node<> traits. */ +template struct quaternion_traits> +{ + /* Figure out the basic type of Sub: */ + using quaternion_type = inverse_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = quaternion_traits; + using element_traits = scalar_traits>; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + using storage_type = typename sub_traits::storage_type; + + using size_tag = typename sub_traits::size_tag; + static_assert(cml::is_fixed_size::value, "invalid size tag"); + + /* Array size: */ + static const int array_size = storage_type::array_size; + static_assert(array_size == 4, "invalid quaternion size"); + + /* Order and cross taken from the sub-expression: */ + using order_type = typename sub_traits::order_type; + using cross_type = typename sub_traits::cross_type; +}; + +/** Represents the inverse of a quaternion subexpression. */ +template +class inverse_node : public readable_quaternion> +{ + public: + using node_type = inverse_node; + using readable_type = readable_quaternion; + using traits_type = quaternion_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** The array size constant depends upon the subexpression size. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped quaternion expression. @c sub must be + * an lvalue reference or rvalue reference. + */ + explicit inverse_node(Sub sub); + + /** Move constructor. */ + inverse_node(node_type&& other); + + /** Copy constructor. */ + inverse_node(const node_type& other); + + + protected: + /** @name readable_quaternion Interface */ + /*@{*/ + + friend readable_type; + + /** Apply the operator to element @c i and return the result. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using wrap_type = + cml::if_t::value, const sub_type&, sub_type>; + + /** The wrapped subexpression. */ + wrap_type m_sub; + + /** The reciprocal of the subexpression norm. */ + value_type m_inv_norm; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_QUATERNION_INVERSE_NODE_TPP +#include +#undef __CML_QUATERNION_INVERSE_NODE_TPP diff --git a/cml/quaternion/inverse_node.tpp b/cml/quaternion/inverse_node.tpp index 7ec0884..d929315 100644 --- a/cml/quaternion/inverse_node.tpp +++ b/cml/quaternion/inverse_node.tpp @@ -1,47 +1,47 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_INVERSE_NODE_TPP -# error "quaternion/inverse_node.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* inverse_node 'structors: */ - -template -inverse_node::inverse_node(Sub sub) -: m_sub(std::move(sub)) -, m_inv_norm(value_type(1) / sub.norm()) -{} - -template -inverse_node::inverse_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -, m_inv_norm(std::move(other.m_inv_norm)) -{} - -template -inverse_node::inverse_node(const node_type& other) -: m_sub(other.m_sub) -, m_inv_norm(other.m_inv_norm) -{} - -/* Internal methods: */ - -/* readable_quaternion interface: */ - -template -auto -inverse_node::i_get(int i) const -> immutable_value -{ - using order_type = order_type_trait_of_t; - return this->m_inv_norm - * ((i == order_type::W) ? this->m_sub.get(i) : -this->m_sub.get(i)); - /* Note: W is either 0 (inverse_first) or 3 (real_first). */ -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_INVERSE_NODE_TPP +# error "quaternion/inverse_node.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* inverse_node 'structors: */ + +template +inverse_node::inverse_node(Sub sub) +: m_sub(std::move(sub)) +, m_inv_norm(value_type(1) / sub.norm()) +{} + +template +inverse_node::inverse_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +, m_inv_norm(std::move(other.m_inv_norm)) +{} + +template +inverse_node::inverse_node(const node_type& other) +: m_sub(other.m_sub) +, m_inv_norm(other.m_inv_norm) +{} + +/* Internal methods: */ + +/* readable_quaternion interface: */ + +template +auto +inverse_node::i_get(int i) const -> immutable_value +{ + using order_type = order_type_trait_of_t; + return this->m_inv_norm + * ((i == order_type::W) ? this->m_sub.get(i) : -this->m_sub.get(i)); + /* Note: W is either 0 (inverse_first) or 3 (real_first). */ +} + +} // namespace cml diff --git a/cml/quaternion/inverse_ops.h b/cml/quaternion/inverse_ops.h index c92cd12..8252923 100644 --- a/cml/quaternion/inverse_ops.h +++ b/cml/quaternion/inverse_ops.h @@ -1,27 +1,27 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Return an expression node for the inverse part of @c q. @c q is - * stored by const reference in the node. - */ -template -auto inverse(const readable_quaternion& q) -> inverse_node; - -/** Return an expression node for inverse part of the temporary - * subexpression @c q. @c q is stored by value in the node (via std::move). - */ -template -auto inverse(readable_quaternion&& q) -> inverse_node; - -} // namespace cml - -#define __CML_QUATERNION_INVERSE_OPS_TPP -#include -#undef __CML_QUATERNION_INVERSE_OPS_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Return an expression node for the inverse part of @c q. @c q is + * stored by const reference in the node. + */ +template +auto inverse(const readable_quaternion& q) -> inverse_node; + +/** Return an expression node for inverse part of the temporary + * subexpression @c q. @c q is stored by value in the node (via std::move). + */ +template +auto inverse(readable_quaternion&& q) -> inverse_node; + +} // namespace cml + +#define __CML_QUATERNION_INVERSE_OPS_TPP +#include +#undef __CML_QUATERNION_INVERSE_OPS_TPP diff --git a/cml/quaternion/inverse_ops.tpp b/cml/quaternion/inverse_ops.tpp index 224619e..daa1637 100644 --- a/cml/quaternion/inverse_ops.tpp +++ b/cml/quaternion/inverse_ops.tpp @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - - -#ifndef __CML_QUATERNION_INVERSE_OPS_TPP -# error "quaternion/inverse_ops.tpp not included correctly" -#endif - -namespace cml { - -template -inline auto -inverse(const readable_quaternion& q) -> inverse_node -{ - return inverse_node(q.actual()); -} - -template -inline auto -inverse(readable_quaternion&& q) -> inverse_node -{ - return inverse_node((Sub&&) q); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + + +#ifndef __CML_QUATERNION_INVERSE_OPS_TPP +# error "quaternion/inverse_ops.tpp not included correctly" +#endif + +namespace cml { + +template +inline auto +inverse(const readable_quaternion& q) -> inverse_node +{ + return inverse_node(q.actual()); +} + +template +inline auto +inverse(readable_quaternion&& q) -> inverse_node +{ + return inverse_node((Sub&&) q); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/ops.h b/cml/quaternion/ops.h index 546b15d..78965e8 100644 --- a/cml/quaternion/ops.h +++ b/cml/quaternion/ops.h @@ -1,9 +1,9 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include diff --git a/cml/quaternion/order_tags.h b/cml/quaternion/order_tags.h index 5ba8eb1..114d2d3 100644 --- a/cml/quaternion/order_tags.h +++ b/cml/quaternion/order_tags.h @@ -1,94 +1,94 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Helper to specify real-first quaternion element ordering. */ -struct real_first -{ - enum - { - W = 0, - X = 1, - Y = 2, - Z = 3 - }; -}; - -/** Helper to specify imaginary-first quaternion element ordering. */ -struct imaginary_first -{ - enum - { - X = 0, - Y = 1, - Z = 2, - W = 3 - }; -}; - -/** Detect valid order types. */ -template struct is_order_type -{ - static const bool value = std::is_same::value - || std::is_same::value; -}; - -/** Templated helper to determine the order type of an expression that - * defines the order_type type. - */ -template struct order_type_of -{ - using type = typename T::order_type; - static_assert(is_order_type::value, "invalid order type"); -}; - -/** Convenience alias for order_type_of. */ -template using order_type_of_t = typename order_type_of::type; - -/** Retrieve the order_type of @c T via traits. */ -template struct order_type_trait_of -{ - using type = typename traits_of::type::order_type; - static_assert(is_order_type::value, "invalid order type"); -}; - -/** Convenience alias for order_type_trait_of. */ -template -using order_type_trait_of_t = typename order_type_trait_of::type; - -/** Deduce the default order tag needed to promote the result of combining - * two expressions having orders @c Tag1 and @c Tag2. By default: - * - * - both imaginary_first: imaginary_first - * - both real_first: real_first - * - otherwise: compile-time error - */ -template struct order_type_promote -{ - static_assert(is_order_type::value, "invalid quaternion order type"); - static_assert(is_order_type::value, "invalid quaternion order type"); - static_assert(std::is_same::value, - "mismatched quaternion order types"); - - /* The tags are the same, so use the common type: */ - using type = Tag1; -}; - -/** Convenience alias for order_type_promote. */ -template -using order_type_promote_t = typename order_type_promote::type; - - -/** For CML1 compatibility. */ -using scalar_first = real_first; - -/** For CML1 compatibility. */ -using vector_first = imaginary_first; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Helper to specify real-first quaternion element ordering. */ +struct real_first +{ + enum + { + W = 0, + X = 1, + Y = 2, + Z = 3 + }; +}; + +/** Helper to specify imaginary-first quaternion element ordering. */ +struct imaginary_first +{ + enum + { + X = 0, + Y = 1, + Z = 2, + W = 3 + }; +}; + +/** Detect valid order types. */ +template struct is_order_type +{ + static const bool value = std::is_same::value + || std::is_same::value; +}; + +/** Templated helper to determine the order type of an expression that + * defines the order_type type. + */ +template struct order_type_of +{ + using type = typename T::order_type; + static_assert(is_order_type::value, "invalid order type"); +}; + +/** Convenience alias for order_type_of. */ +template using order_type_of_t = typename order_type_of::type; + +/** Retrieve the order_type of @c T via traits. */ +template struct order_type_trait_of +{ + using type = typename traits_of::type::order_type; + static_assert(is_order_type::value, "invalid order type"); +}; + +/** Convenience alias for order_type_trait_of. */ +template +using order_type_trait_of_t = typename order_type_trait_of::type; + +/** Deduce the default order tag needed to promote the result of combining + * two expressions having orders @c Tag1 and @c Tag2. By default: + * + * - both imaginary_first: imaginary_first + * - both real_first: real_first + * - otherwise: compile-time error + */ +template struct order_type_promote +{ + static_assert(is_order_type::value, "invalid quaternion order type"); + static_assert(is_order_type::value, "invalid quaternion order type"); + static_assert(std::is_same::value, + "mismatched quaternion order types"); + + /* The tags are the same, so use the common type: */ + using type = Tag1; +}; + +/** Convenience alias for order_type_promote. */ +template +using order_type_promote_t = typename order_type_promote::type; + + +/** For CML1 compatibility. */ +using scalar_first = real_first; + +/** For CML1 compatibility. */ +using vector_first = imaginary_first; + +} // namespace cml diff --git a/cml/quaternion/product.h b/cml/quaternion/product.h index 06cf62c..b21c7f3 100644 --- a/cml/quaternion/product.h +++ b/cml/quaternion/product.h @@ -1,23 +1,23 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Multiply two quaternions, and return the result as a temporary. */ -template* = nullptr, - enable_if_quaternion_t* = nullptr> -auto operator*(Sub1&& sub1, - Sub2&& sub2) -> quaternion_promote_t, - actual_operand_type_of_t>; - -} // namespace cml - -#define __CML_QUATERNION_PRODUCT_TPP -#include -#undef __CML_QUATERNION_PRODUCT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Multiply two quaternions, and return the result as a temporary. */ +template* = nullptr, + enable_if_quaternion_t* = nullptr> +auto operator*(Sub1&& sub1, + Sub2&& sub2) -> quaternion_promote_t, + actual_operand_type_of_t>; + +} // namespace cml + +#define __CML_QUATERNION_PRODUCT_TPP +#include +#undef __CML_QUATERNION_PRODUCT_TPP diff --git a/cml/quaternion/product.tpp b/cml/quaternion/product.tpp index b7a5c75..e4ac341 100644 --- a/cml/quaternion/product.tpp +++ b/cml/quaternion/product.tpp @@ -1,55 +1,55 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_PRODUCT_TPP -# error "quaternion/product.tpp not included correctly" -#endif - -#include -#include -#include -#include - -namespace cml { - -template*, - enable_if_quaternion_t*> -inline auto -operator*(Sub1&& sub1, - Sub2&& sub2) -> quaternion_promote_t, - actual_operand_type_of_t> -{ - using result_type = quaternion_promote_t, - actual_operand_type_of_t>; - using order_type = order_type_trait_of_t; - using cross_type = cross_type_trait_of_t; - - /* Local enum for the order: */ - enum - { - W = order_type::W, - X = order_type::X, - Y = order_type::Y, - Z = order_type::Z - }; - - /* If sub1 = (w1, v1) and sub2 = (w2, v2), where w is the real part and - * v is the imaginary part of the quaternion, then - * - * sub1 * sub2 = (w1*w2 - dot(v1,v2), w1*v2 + w2*v1 {+/-} cross(v1,v2)) - * - * {+/-} is determined by cross_type: - */ - auto real = sub1[W] * sub2[W] - cml::dot(sub1.imaginary(), sub2.imaginary()); - auto cross = std::is_same::value - ? cml::cross(sub1.imaginary(), sub2.imaginary()) - : cml::cross(sub2.imaginary(), sub1.imaginary()); - auto imaginary = - sub1[W] * sub2.imaginary() + sub2[W] * sub1.imaginary() + cross; - - /* Done: */ - return result_type(real, imaginary); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_PRODUCT_TPP +# error "quaternion/product.tpp not included correctly" +#endif + +#include +#include +#include +#include + +namespace cml { + +template*, + enable_if_quaternion_t*> +inline auto +operator*(Sub1&& sub1, + Sub2&& sub2) -> quaternion_promote_t, + actual_operand_type_of_t> +{ + using result_type = quaternion_promote_t, + actual_operand_type_of_t>; + using order_type = order_type_trait_of_t; + using cross_type = cross_type_trait_of_t; + + /* Local enum for the order: */ + enum + { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + /* If sub1 = (w1, v1) and sub2 = (w2, v2), where w is the real part and + * v is the imaginary part of the quaternion, then + * + * sub1 * sub2 = (w1*w2 - dot(v1,v2), w1*v2 + w2*v1 {+/-} cross(v1,v2)) + * + * {+/-} is determined by cross_type: + */ + auto real = sub1[W] * sub2[W] - cml::dot(sub1.imaginary(), sub2.imaginary()); + auto cross = std::is_same::value + ? cml::cross(sub1.imaginary(), sub2.imaginary()) + : cml::cross(sub2.imaginary(), sub1.imaginary()); + auto imaginary = + sub1[W] * sub2.imaginary() + sub2[W] * sub1.imaginary() + cross; + + /* Done: */ + return result_type(real, imaginary); +} + +} // namespace cml diff --git a/cml/quaternion/promotion.h b/cml/quaternion/promotion.h index e7a5ff7..abfbc67 100644 --- a/cml/quaternion/promotion.h +++ b/cml/quaternion/promotion.h @@ -1,88 +1,88 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cml { - -/** Determine an appropriate storage type to use when combining quaternion - * expressions via a pairwise binary operator. - * - * @note This can be specialized to accomodate user-defined storage types. - */ -template -struct quaternion_binary_storage_promote -{ - static_assert(is_quaternion_storage::value - && is_quaternion_storage::value, - "expected quaternion storage types for binary promotion"); - - /* Determine the common unbound storage type: */ - using unbound_type = storage_promote_t; - - /* Resize: */ - using resized_type = resize_storage_t; - - /* Rebind to a quaternion storage type: */ - using type = rebind_quaternion_storage_t; -}; - -/** Convenience alias for quaternion_binary_storage_promote. */ -template -using quaternion_binary_storage_promote_t = - typename quaternion_binary_storage_promote::type; - - -/** Helper to deduce a reasonable quaternion type from two quaternion - * subexpression types. This can be specialized for non-default behavior. - */ -template struct quaternion_promote; - -template -struct quaternion_promote::value - && is_quaternion::value>::type> -{ - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = quaternion_traits; - using right_traits = quaternion_traits; - - /* Deduce the new quaternion element type: */ - using value_type = value_type_promote_t; - - /* Determine the new storage type: */ - using storage_type = quaternion_binary_storage_promote_t, - storage_type_of_t>; - - /* Use the proxy type for the temporary: */ - using proxy_type = proxy_type_of_t; - - /* Determine the common order type: */ - using order_type = order_type_promote_t, - order_type_of_t>; - - /* Determine the common cross type: */ - using cross_type = cross_type_promote_t, - cross_type_of_t>; - - /* Build the quaternion type: */ - using type = quaternion; -}; - -/** Convenience alias for quaternion_promote<>. */ -template -using quaternion_promote_t = typename quaternion_promote::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Determine an appropriate storage type to use when combining quaternion + * expressions via a pairwise binary operator. + * + * @note This can be specialized to accomodate user-defined storage types. + */ +template +struct quaternion_binary_storage_promote +{ + static_assert(is_quaternion_storage::value + && is_quaternion_storage::value, + "expected quaternion storage types for binary promotion"); + + /* Determine the common unbound storage type: */ + using unbound_type = storage_promote_t; + + /* Resize: */ + using resized_type = resize_storage_t; + + /* Rebind to a quaternion storage type: */ + using type = rebind_quaternion_storage_t; +}; + +/** Convenience alias for quaternion_binary_storage_promote. */ +template +using quaternion_binary_storage_promote_t = + typename quaternion_binary_storage_promote::type; + + +/** Helper to deduce a reasonable quaternion type from two quaternion + * subexpression types. This can be specialized for non-default behavior. + */ +template struct quaternion_promote; + +template +struct quaternion_promote::value + && is_quaternion::value>::type> +{ + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = quaternion_traits; + using right_traits = quaternion_traits; + + /* Deduce the new quaternion element type: */ + using value_type = value_type_promote_t; + + /* Determine the new storage type: */ + using storage_type = quaternion_binary_storage_promote_t, + storage_type_of_t>; + + /* Use the proxy type for the temporary: */ + using proxy_type = proxy_type_of_t; + + /* Determine the common order type: */ + using order_type = order_type_promote_t, + order_type_of_t>; + + /* Determine the common cross type: */ + using cross_type = cross_type_promote_t, + cross_type_of_t>; + + /* Build the quaternion type: */ + using type = quaternion; +}; + +/** Convenience alias for quaternion_promote<>. */ +template +using quaternion_promote_t = typename quaternion_promote::type; + +} // namespace cml diff --git a/cml/quaternion/quaternion.h b/cml/quaternion/quaternion.h index a945851..75c6027 100644 --- a/cml/quaternion/quaternion.h +++ b/cml/quaternion/quaternion.h @@ -1,36 +1,36 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -/** Specializable class for building quaternions. - * - * This class encapsulates the notion of a quaternion. - * - * @note Quaternions with two different orders cannot be used in the same - * expression. - * - * @tparam Element The scalar type for quaternion elements, with the - * following operators defined: +, -, *, /, <, >, ==, = (assign). - * - * @tparam StorageType Storage type to use for holding the array of quaternion - * elements. - * - * @tparam Order Specifies the position of the scalar and imaginary - * elements when accessed like a vector. - * - * @tparam Cross Specifies whether the cross product of two quaternions is - * left-handed (negative_cross) or right-handed (positive_cross). - */ -template, - class Order = imaginary_first, class Cross = positive_cross> -class quaternion; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +/** Specializable class for building quaternions. + * + * This class encapsulates the notion of a quaternion. + * + * @note Quaternions with two different orders cannot be used in the same + * expression. + * + * @tparam Element The scalar type for quaternion elements, with the + * following operators defined: +, -, *, /, <, >, ==, = (assign). + * + * @tparam StorageType Storage type to use for holding the array of quaternion + * elements. + * + * @tparam Order Specifies the position of the scalar and imaginary + * elements when accessed like a vector. + * + * @tparam Cross Specifies whether the cross product of two quaternions is + * left-handed (negative_cross) or right-handed (positive_cross). + */ +template, + class Order = imaginary_first, class Cross = positive_cross> +class quaternion; + +} // namespace cml diff --git a/cml/quaternion/readable_quaternion.h b/cml/quaternion/readable_quaternion.h index 15c8d62..36b2f3b 100644 --- a/cml/quaternion/readable_quaternion.h +++ b/cml/quaternion/readable_quaternion.h @@ -1,142 +1,142 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/* Forward declarations: */ -template class quaternion_scalar_node; -template class imaginary_node; -template class conjugate_node; -template class inverse_node; - -/** Base class for readable quaternion types. Readable quaternions support - * const access to its elements. - * - * DerivedT must implement: - * - * - i_get(int i) const, where is the immutable_value type defined - * by quaternion_traits. Note that immutable_value is not - * necessarily a reference or const type. - */ -template class readable_quaternion -{ - public: - using quaternion_type = DerivedT; - using traits_type = quaternion_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using order_type = typename traits_type::order_type; - using cross_type = typename traits_type::cross_type; - - - public: - /** Localize the ordering as an enum. */ - enum - { - W = order_type::W, - X = order_type::X, - Y = order_type::Y, - Z = order_type::Z - }; - - - public: - /** Return a const reference to the quaternion cast as DerivedT. */ - const DerivedT& actual() const; - - /** Return const element @c i. */ - immutable_value get(int i) const; - - /** Return const element @c i. */ - immutable_value operator[](int i) const; - - /** Return a const reference to the real part of the quaternion. */ - immutable_value w() const; - - /** Return a const reference to the imaginary i coordinate */ - immutable_value x() const; - - /** Return a const reference to the imaginary j coordinate */ - immutable_value y() const; - - /** Return a const reference to the imaginary k coordinate */ - immutable_value z() const; - - - public: - /** Return the array size. This is always 4. */ - int size() const; - - /** Return the real part of the quaternion. */ - immutable_value real() const; - - /** Return the imaginary part of the quaternion as a vector expression. - */ - imaginary_node imaginary() const&; - - /** Return the imaginary part of the quaternion as a vector expression, - * moving the source into the node. - */ - imaginary_node imaginary() const&&; - - /** Return the squared length of the quaternion. */ - value_type length_squared() const; - - /** Return the length of the quaternion. */ - value_type length() const; - - /** Return the Cayley norm of the quaternion. */ - value_type norm() const; - - /** Return the normalized quaternion as an expression node. */ - quaternion_scalar_node> - normalize() const&; - - /** Return the normalized quaternion as an expression node, moving the - * source into the node. - */ - quaternion_scalar_node> - normalize() const&&; - - /** Return the conjugate as an expression node. */ - conjugate_node conjugate() const&; - - /** Return the conjugate as an expression node, moving the source into - * the node. - */ - conjugate_node conjugate() const&&; - - /** Return the inverse as an expression node. */ - inverse_node inverse() const&; - - /** Return the inverse as an expression node, moving the source into - * the node. - */ - inverse_node inverse() const&&; - - - protected: - // Use the compiler-generated default constructor: - readable_quaternion() = default; - - // Use the compiler-generated copy constructor: - readable_quaternion(const readable_quaternion&) = default; - - // Use the compiler-generated move constructor: - readable_quaternion(readable_quaternion&&) = default; -}; - -} // namespace cml - -#define __CML_QUATERNION_READABLE_QUATERNION_TPP -#include -#undef __CML_QUATERNION_READABLE_QUATERNION_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/* Forward declarations: */ +template class quaternion_scalar_node; +template class imaginary_node; +template class conjugate_node; +template class inverse_node; + +/** Base class for readable quaternion types. Readable quaternions support + * const access to its elements. + * + * DerivedT must implement: + * + * - i_get(int i) const, where is the immutable_value type defined + * by quaternion_traits. Note that immutable_value is not + * necessarily a reference or const type. + */ +template class readable_quaternion +{ + public: + using quaternion_type = DerivedT; + using traits_type = quaternion_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using order_type = typename traits_type::order_type; + using cross_type = typename traits_type::cross_type; + + + public: + /** Localize the ordering as an enum. */ + enum + { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + + public: + /** Return a const reference to the quaternion cast as DerivedT. */ + const DerivedT& actual() const; + + /** Return const element @c i. */ + immutable_value get(int i) const; + + /** Return const element @c i. */ + immutable_value operator[](int i) const; + + /** Return a const reference to the real part of the quaternion. */ + immutable_value w() const; + + /** Return a const reference to the imaginary i coordinate */ + immutable_value x() const; + + /** Return a const reference to the imaginary j coordinate */ + immutable_value y() const; + + /** Return a const reference to the imaginary k coordinate */ + immutable_value z() const; + + + public: + /** Return the array size. This is always 4. */ + int size() const; + + /** Return the real part of the quaternion. */ + immutable_value real() const; + + /** Return the imaginary part of the quaternion as a vector expression. + */ + imaginary_node imaginary() const&; + + /** Return the imaginary part of the quaternion as a vector expression, + * moving the source into the node. + */ + imaginary_node imaginary() const&&; + + /** Return the squared length of the quaternion. */ + value_type length_squared() const; + + /** Return the length of the quaternion. */ + value_type length() const; + + /** Return the Cayley norm of the quaternion. */ + value_type norm() const; + + /** Return the normalized quaternion as an expression node. */ + quaternion_scalar_node> + normalize() const&; + + /** Return the normalized quaternion as an expression node, moving the + * source into the node. + */ + quaternion_scalar_node> + normalize() const&&; + + /** Return the conjugate as an expression node. */ + conjugate_node conjugate() const&; + + /** Return the conjugate as an expression node, moving the source into + * the node. + */ + conjugate_node conjugate() const&&; + + /** Return the inverse as an expression node. */ + inverse_node inverse() const&; + + /** Return the inverse as an expression node, moving the source into + * the node. + */ + inverse_node inverse() const&&; + + + protected: + // Use the compiler-generated default constructor: + readable_quaternion() = default; + + // Use the compiler-generated copy constructor: + readable_quaternion(const readable_quaternion&) = default; + + // Use the compiler-generated move constructor: + readable_quaternion(readable_quaternion&&) = default; +}; + +} // namespace cml + +#define __CML_QUATERNION_READABLE_QUATERNION_TPP +#include +#undef __CML_QUATERNION_READABLE_QUATERNION_TPP diff --git a/cml/quaternion/readable_quaternion.tpp b/cml/quaternion/readable_quaternion.tpp index 47ec69e..2e2c230 100644 --- a/cml/quaternion/readable_quaternion.tpp +++ b/cml/quaternion/readable_quaternion.tpp @@ -1,165 +1,165 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_READABLE_QUATERNION_TPP -# error "quaternion/readable_quaternion.tpp not included correctly" -#endif - -#include -#include -#include -#include - -namespace cml { - -/* Public methods: */ - -template -const DT& -readable_quaternion
::actual() const -{ - return (const DT&) *this; -} - -template -auto -readable_quaternion
::get(int i) const -> immutable_value -{ - return this->actual().i_get(i); -} - -template -auto -readable_quaternion
::operator[](int i) const -> immutable_value -{ - return this->get(i); -} - -template -auto -readable_quaternion
::w() const -> immutable_value -{ - return this->get(order_type::W); -} - -template -auto -readable_quaternion
::x() const -> immutable_value -{ - return this->get(order_type::X); -} - -template -auto -readable_quaternion
::y() const -> immutable_value -{ - return this->get(order_type::Y); -} - -template -auto -readable_quaternion
::z() const -> immutable_value -{ - return this->get(order_type::Z); -} - -template -int -readable_quaternion
::size() const -{ - return 4; -} - -template -auto -readable_quaternion
::real() const -> immutable_value -{ - return this->get(order_type::W); -} - -template -auto -readable_quaternion
::imaginary() const& -> imaginary_node -{ - return imaginary_node((const DT&) *this); -} - -template -auto -readable_quaternion
::imaginary() const&& -> imaginary_node -{ - return imaginary_node((DT&&) *this); -} - -template -auto -readable_quaternion
::length_squared() const -> value_type -{ - value_type accum = cml::sqr(this->get(0)); - for(int i = 1; i < 4; ++i) accum += cml::sqr(this->get(i)); - return accum; -} - -template -auto -readable_quaternion
::length() const -> value_type -{ - return element_traits::sqrt(this->length_squared()); -} - -template -auto -readable_quaternion
::norm() const -> value_type -{ - return this->length_squared(); -} - -template -auto -readable_quaternion
::normalize() const& -> quaternion_scalar_node> -{ - return quaternion_scalar_node>((const DT&) *this, - this->length()); -} - -template -auto -readable_quaternion
::normalize() const&& -> quaternion_scalar_node> -{ - return quaternion_scalar_node>((DT&&) *this, this->length()); -} - -template -auto -readable_quaternion
::conjugate() const& -> conjugate_node -{ - return conjugate_node((const DT&) *this); -} - -template -auto -readable_quaternion
::conjugate() const&& -> conjugate_node -{ - return conjugate_node((DT&&) *this); -} - -template -auto -readable_quaternion
::inverse() const& -> inverse_node -{ - return inverse_node((const DT&) *this); -} - -template -auto -readable_quaternion
::inverse() const&& -> inverse_node -{ - return inverse_node((DT&&) *this); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_READABLE_QUATERNION_TPP +# error "quaternion/readable_quaternion.tpp not included correctly" +#endif + +#include +#include +#include +#include + +namespace cml { + +/* Public methods: */ + +template +const DT& +readable_quaternion
::actual() const +{ + return (const DT&) *this; +} + +template +auto +readable_quaternion
::get(int i) const -> immutable_value +{ + return this->actual().i_get(i); +} + +template +auto +readable_quaternion
::operator[](int i) const -> immutable_value +{ + return this->get(i); +} + +template +auto +readable_quaternion
::w() const -> immutable_value +{ + return this->get(order_type::W); +} + +template +auto +readable_quaternion
::x() const -> immutable_value +{ + return this->get(order_type::X); +} + +template +auto +readable_quaternion
::y() const -> immutable_value +{ + return this->get(order_type::Y); +} + +template +auto +readable_quaternion
::z() const -> immutable_value +{ + return this->get(order_type::Z); +} + +template +int +readable_quaternion
::size() const +{ + return 4; +} + +template +auto +readable_quaternion
::real() const -> immutable_value +{ + return this->get(order_type::W); +} + +template +auto +readable_quaternion
::imaginary() const& -> imaginary_node +{ + return imaginary_node((const DT&) *this); +} + +template +auto +readable_quaternion
::imaginary() const&& -> imaginary_node +{ + return imaginary_node((DT&&) *this); +} + +template +auto +readable_quaternion
::length_squared() const -> value_type +{ + value_type accum = cml::sqr(this->get(0)); + for(int i = 1; i < 4; ++i) accum += cml::sqr(this->get(i)); + return accum; +} + +template +auto +readable_quaternion
::length() const -> value_type +{ + return element_traits::sqrt(this->length_squared()); +} + +template +auto +readable_quaternion
::norm() const -> value_type +{ + return this->length_squared(); +} + +template +auto +readable_quaternion
::normalize() const& -> quaternion_scalar_node> +{ + return quaternion_scalar_node>((const DT&) *this, + this->length()); +} + +template +auto +readable_quaternion
::normalize() const&& -> quaternion_scalar_node> +{ + return quaternion_scalar_node>((DT&&) *this, this->length()); +} + +template +auto +readable_quaternion
::conjugate() const& -> conjugate_node +{ + return conjugate_node((const DT&) *this); +} + +template +auto +readable_quaternion
::conjugate() const&& -> conjugate_node +{ + return conjugate_node((DT&&) *this); +} + +template +auto +readable_quaternion
::inverse() const& -> inverse_node +{ + return inverse_node((const DT&) *this); +} + +template +auto +readable_quaternion
::inverse() const&& -> inverse_node +{ + return inverse_node((DT&&) *this); +} + +} // namespace cml diff --git a/cml/quaternion/scalar_node.h b/cml/quaternion/scalar_node.h index fd8fc53..c1820e5 100644 --- a/cml/quaternion/scalar_node.h +++ b/cml/quaternion/scalar_node.h @@ -1,124 +1,124 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class quaternion_scalar_node; - -/** quaternion_scalar_node<> traits. */ -template -struct quaternion_traits> -{ - /* Figure out the basic types of Sub and Scalar: */ - using quaternion_type = quaternion_scalar_node; - using left_arg_type = Sub; - using right_arg_type = Scalar; - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = quaternion_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - using storage_type = typename left_traits::storage_type; - - using size_tag = typename left_traits::size_tag; - static_assert(cml::is_fixed_size::value, "invalid size tag"); - - /* Array size: */ - static const int array_size = storage_type::array_size; - static_assert(array_size == 4, "invalid quaternion size"); - - /* Order and cross taken from the sub-expression: */ - using order_type = typename left_traits::order_type; - using cross_type = typename left_traits::cross_type; -}; - -/** Represents a binary quaternion operation, where one operand is a scalar - * value, and the other is a quaternion. - */ -template -class quaternion_scalar_node -: public readable_quaternion> -{ - public: - using node_type = quaternion_scalar_node; - using readable_type = readable_quaternion; - using traits_type = quaternion_traits; - using left_arg_type = typename traits_type::left_arg_type; - using right_arg_type = typename traits_type::right_arg_type; - using left_type = typename traits_type::left_type; - using right_type = typename traits_type::right_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using order_type = typename traits_type::order_type; - using cross_type = typename traits_type::cross_type; - - - public: - /** The array size constant is the same as the subexpression. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expression and the scalar to apply. - * @c left must be an lvalue reference or rvalue reference. - */ - quaternion_scalar_node(Sub left, const right_type& right); - - /** Move constructor. */ - quaternion_scalar_node(node_type&& other); - - /** Copy constructor. */ - quaternion_scalar_node(const node_type& other); - - - protected: - /** @name readable_quaternion Interface */ - /*@{*/ - - friend readable_type; - - /** Apply the scalar operator to element @c i of the subexpression and - * return the result. - */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the left subexpression. The expression is - * stored as a copy if Sub is an rvalue reference (temporary), or by - * const reference if Sub is an lvalue reference. - */ - using left_wrap_type = cml::if_t::value, const left_type&, - left_type>; - - - protected: - /** The quaternion operand. */ - left_wrap_type m_left; - - /** The scalar operand. */ - right_type m_right; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_QUATERNION_SCALAR_NODE_TPP -#include -#undef __CML_QUATERNION_SCALAR_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class quaternion_scalar_node; + +/** quaternion_scalar_node<> traits. */ +template +struct quaternion_traits> +{ + /* Figure out the basic types of Sub and Scalar: */ + using quaternion_type = quaternion_scalar_node; + using left_arg_type = Sub; + using right_arg_type = Scalar; + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = quaternion_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + using storage_type = typename left_traits::storage_type; + + using size_tag = typename left_traits::size_tag; + static_assert(cml::is_fixed_size::value, "invalid size tag"); + + /* Array size: */ + static const int array_size = storage_type::array_size; + static_assert(array_size == 4, "invalid quaternion size"); + + /* Order and cross taken from the sub-expression: */ + using order_type = typename left_traits::order_type; + using cross_type = typename left_traits::cross_type; +}; + +/** Represents a binary quaternion operation, where one operand is a scalar + * value, and the other is a quaternion. + */ +template +class quaternion_scalar_node +: public readable_quaternion> +{ + public: + using node_type = quaternion_scalar_node; + using readable_type = readable_quaternion; + using traits_type = quaternion_traits; + using left_arg_type = typename traits_type::left_arg_type; + using right_arg_type = typename traits_type::right_arg_type; + using left_type = typename traits_type::left_type; + using right_type = typename traits_type::right_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using order_type = typename traits_type::order_type; + using cross_type = typename traits_type::cross_type; + + + public: + /** The array size constant is the same as the subexpression. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expression and the scalar to apply. + * @c left must be an lvalue reference or rvalue reference. + */ + quaternion_scalar_node(Sub left, const right_type& right); + + /** Move constructor. */ + quaternion_scalar_node(node_type&& other); + + /** Copy constructor. */ + quaternion_scalar_node(const node_type& other); + + + protected: + /** @name readable_quaternion Interface */ + /*@{*/ + + friend readable_type; + + /** Apply the scalar operator to element @c i of the subexpression and + * return the result. + */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the left subexpression. The expression is + * stored as a copy if Sub is an rvalue reference (temporary), or by + * const reference if Sub is an lvalue reference. + */ + using left_wrap_type = cml::if_t::value, const left_type&, + left_type>; + + + protected: + /** The quaternion operand. */ + left_wrap_type m_left; + + /** The scalar operand. */ + right_type m_right; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_QUATERNION_SCALAR_NODE_TPP +#include +#undef __CML_QUATERNION_SCALAR_NODE_TPP diff --git a/cml/quaternion/scalar_node.tpp b/cml/quaternion/scalar_node.tpp index 32a2269..dfe8a41 100644 --- a/cml/quaternion/scalar_node.tpp +++ b/cml/quaternion/scalar_node.tpp @@ -1,46 +1,46 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_SCALAR_NODE_TPP -# error "quaternion/scalar_node.tpp not included correctly" -#endif - -namespace cml { - -/* quaternion_scalar_node 'structors: */ - -template -quaternion_scalar_node::quaternion_scalar_node(Sub left, - const right_type& right) -: m_left(std::move(left)) -, m_right(right) -{} - -template -quaternion_scalar_node::quaternion_scalar_node( - node_type&& other) -: m_left(std::move(other.m_left)) -, m_right(std::move(other.m_right)) -{} - -template -quaternion_scalar_node::quaternion_scalar_node( - const node_type& other) -: m_left(other.m_left) -, m_right(other.m_right) -{} - - -/* Internal methods: */ - -/* readable_quaternion interface: */ - -template -auto -quaternion_scalar_node::i_get(int i) const -> immutable_value -{ - return Op().apply(this->m_left.get(i), this->m_right); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_SCALAR_NODE_TPP +# error "quaternion/scalar_node.tpp not included correctly" +#endif + +namespace cml { + +/* quaternion_scalar_node 'structors: */ + +template +quaternion_scalar_node::quaternion_scalar_node(Sub left, + const right_type& right) +: m_left(std::move(left)) +, m_right(right) +{} + +template +quaternion_scalar_node::quaternion_scalar_node( + node_type&& other) +: m_left(std::move(other.m_left)) +, m_right(std::move(other.m_right)) +{} + +template +quaternion_scalar_node::quaternion_scalar_node( + const node_type& other) +: m_left(other.m_left) +, m_right(other.m_right) +{} + + +/* Internal methods: */ + +/* readable_quaternion interface: */ + +template +auto +quaternion_scalar_node::i_get(int i) const -> immutable_value +{ + return Op().apply(this->m_left.get(i), this->m_right); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/scalar_ops.h b/cml/quaternion/scalar_ops.h index c33adfc..6f419b3 100644 --- a/cml/quaternion/scalar_ops.h +++ b/cml/quaternion/scalar_ops.h @@ -1,74 +1,74 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -/** Helper function to generate a quaternion_scalar_node from a quaternion - * type (i.e. derived from readable_quaternion<>) and a scalar type. - */ -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -make_quaternion_scalar_node(Sub&& sub, - Scalar&& v) -> quaternion_scalar_node, - actual_operand_type_of_t, Op> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type (sub)"); - static_assert( - std::is_same(v))>::value, - "internal error: unexpected expression type (v)"); - - /* Deduce the operand types of the scalar and the subexpression (&, - * const&, &&): - */ - using sub_type = actual_operand_type_of_t; - using scalar_type = actual_operand_type_of_t; - return quaternion_scalar_node((sub_type) sub, - (scalar_type) v); -} - -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -operator*(Sub&& sub, Scalar&& v) - -> decltype(make_quaternion_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_quaternion_scalar_node>( - std::forward(sub), std::forward(v)); -} - -template>* = nullptr, - enable_if_quaternion_t* = nullptr> -inline auto -operator*(Scalar&& v, Sub&& sub) - -> decltype(make_quaternion_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_quaternion_scalar_node>( - std::forward(sub), std::forward(v)); -} - -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -operator/(Sub&& sub, Scalar&& v) - -> decltype(make_quaternion_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_quaternion_scalar_node>( - std::forward(sub), std::forward(v)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +/** Helper function to generate a quaternion_scalar_node from a quaternion + * type (i.e. derived from readable_quaternion<>) and a scalar type. + */ +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +make_quaternion_scalar_node(Sub&& sub, + Scalar&& v) -> quaternion_scalar_node, + actual_operand_type_of_t, Op> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type (sub)"); + static_assert( + std::is_same(v))>::value, + "internal error: unexpected expression type (v)"); + + /* Deduce the operand types of the scalar and the subexpression (&, + * const&, &&): + */ + using sub_type = actual_operand_type_of_t; + using scalar_type = actual_operand_type_of_t; + return quaternion_scalar_node((sub_type) sub, + (scalar_type) v); +} + +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +operator*(Sub&& sub, Scalar&& v) + -> decltype(make_quaternion_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_quaternion_scalar_node>( + std::forward(sub), std::forward(v)); +} + +template>* = nullptr, + enable_if_quaternion_t* = nullptr> +inline auto +operator*(Scalar&& v, Sub&& sub) + -> decltype(make_quaternion_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_quaternion_scalar_node>( + std::forward(sub), std::forward(v)); +} + +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +operator/(Sub&& sub, Scalar&& v) + -> decltype(make_quaternion_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_quaternion_scalar_node>( + std::forward(sub), std::forward(v)); +} + +} // namespace cml diff --git a/cml/quaternion/size_checking.h b/cml/quaternion/size_checking.h index 4b6dd8a..d76d0cc 100644 --- a/cml/quaternion/size_checking.h +++ b/cml/quaternion/size_checking.h @@ -1,27 +1,27 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml { - -/** Exception thrown when run-time size checking is enabled, and the - * operand of a quaternion expression does not have 4 elements. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_QUATERNION_SIZE_CHECKS at compile time. - */ -struct quaternion_size_error : std::runtime_error -{ - quaternion_size_error() - : std::runtime_error("incorrect quaternion expression size") - {} -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml { + +/** Exception thrown when run-time size checking is enabled, and the + * operand of a quaternion expression does not have 4 elements. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_QUATERNION_SIZE_CHECKS at compile time. + */ +struct quaternion_size_error : std::runtime_error +{ + quaternion_size_error() + : std::runtime_error("incorrect quaternion expression size") + {} +}; + +} // namespace cml diff --git a/cml/quaternion/temporary.h b/cml/quaternion/temporary.h index 715a963..2752049 100644 --- a/cml/quaternion/temporary.h +++ b/cml/quaternion/temporary.h @@ -1,35 +1,35 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace cml { - -/** Deduce a temporary for a quaternion expression. */ -template -struct temporary_of> -{ - using quaternion_type = cml::unqualified_type_t; - - /* Propagate the element type of the original quaternion: */ - using traits_type = quaternion_traits; - using value_type = typename traits_type::value_type; - using storage_type = typename traits_type::storage_type; - using order_type = typename traits_type::order_type; - using cross_type = typename traits_type::cross_type; - - /* Need the proxy for the storage type: */ - using proxy_type = proxy_type_of_t; - - /* Build the temporary: */ - using type = quaternion; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace cml { + +/** Deduce a temporary for a quaternion expression. */ +template +struct temporary_of> +{ + using quaternion_type = cml::unqualified_type_t; + + /* Propagate the element type of the original quaternion: */ + using traits_type = quaternion_traits; + using value_type = typename traits_type::value_type; + using storage_type = typename traits_type::storage_type; + using order_type = typename traits_type::order_type; + using cross_type = typename traits_type::cross_type; + + /* Need the proxy for the storage type: */ + using proxy_type = proxy_type_of_t; + + /* Build the temporary: */ + using type = quaternion; +}; + +} // namespace cml diff --git a/cml/quaternion/traits.h b/cml/quaternion/traits.h index ec883de..f7917e2 100644 --- a/cml/quaternion/traits.h +++ b/cml/quaternion/traits.h @@ -1,27 +1,27 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Specializable class wrapping traits for quaternion<> types. This class - * is used to simplify static polymorphism by providing a base class the - * types used by a particular derived class. - * - * @tparam Quaternion The quaternion<> type the traits correspond to. - */ -template struct quaternion_traits; - -/** traits_of for quaternion types. */ -template -struct traits_of> -{ - using type = quaternion_traits; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Specializable class wrapping traits for quaternion<> types. This class + * is used to simplify static polymorphism by providing a base class the + * types used by a particular derived class. + * + * @tparam Quaternion The quaternion<> type the traits correspond to. + */ +template struct quaternion_traits; + +/** traits_of for quaternion types. */ +template +struct traits_of> +{ + using type = quaternion_traits; +}; + +} // namespace cml diff --git a/cml/quaternion/type_util.h b/cml/quaternion/type_util.h index c1eec0d..afc809b 100644 --- a/cml/quaternion/type_util.h +++ b/cml/quaternion/type_util.h @@ -1,48 +1,48 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Defines typedef @c type as std::true_type if @c T is statically - * polymorphic and derived from @c readable_quaternion, or std::false_type - * otherwise. The static bool @c value is set to true or false to match @c - * type. - */ -template struct is_quaternion -{ - private: - /* Strip const, volatile, and reference from T to get the type to test: */ - using naked_type = cml::unqualified_type_t; - - /* Deduce the derived type (fails if T is not statically polymorphic): */ - using derived_type = actual_type_of_t; - - - public: - /* std::true_type if T is derived from readable_quaternion<>, std::false_type - * otherwise: - */ - using type = std::is_base_of, naked_type>; - - /* True or false, depending upon 'type': */ - static const bool value = type::value; -}; - -/** Wrapper for enable_if to detect quaternion types (derived from - * readable_quaternion). - */ -template -struct enable_if_quaternion : std::enable_if::value> -{}; - -/** Convenience alias for enable_if_quaternion. */ -template -using enable_if_quaternion_t = typename enable_if_quaternion::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Defines typedef @c type as std::true_type if @c T is statically + * polymorphic and derived from @c readable_quaternion, or std::false_type + * otherwise. The static bool @c value is set to true or false to match @c + * type. + */ +template struct is_quaternion +{ + private: + /* Strip const, volatile, and reference from T to get the type to test: */ + using naked_type = cml::unqualified_type_t; + + /* Deduce the derived type (fails if T is not statically polymorphic): */ + using derived_type = actual_type_of_t; + + + public: + /* std::true_type if T is derived from readable_quaternion<>, std::false_type + * otherwise: + */ + using type = std::is_base_of, naked_type>; + + /* True or false, depending upon 'type': */ + static const bool value = type::value; +}; + +/** Wrapper for enable_if to detect quaternion types (derived from + * readable_quaternion). + */ +template +struct enable_if_quaternion : std::enable_if::value> +{}; + +/** Convenience alias for enable_if_quaternion. */ +template +using enable_if_quaternion_t = typename enable_if_quaternion::type; + +} // namespace cml diff --git a/cml/quaternion/types.h b/cml/quaternion/types.h index 776ce50..ea8dd94 100644 --- a/cml/quaternion/types.h +++ b/cml/quaternion/types.h @@ -1,44 +1,44 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** @defgroup quaternion_types Predefined Quaternion Types */ -/*@{*/ - -// Imaginary first, positive cross: -using quaternionf_ip = quaternion, imaginary_first, positive_cross>; -using quaternionf_p = quaternion, imaginary_first, positive_cross>; -using quaternionf = quaternion; - -using quaterniond_ip = quaternion, imaginary_first, positive_cross>; -using quaterniond_p = quaternion, imaginary_first, positive_cross>; -using quaterniond = quaternion; - - -// Imaginary first, negative cross: -using quaternionf_in = quaternion, imaginary_first, negative_cross>; -using quaternionf_n = quaternion, imaginary_first, negative_cross>; - -using quaterniond_in = quaternion, imaginary_first, negative_cross>; -using quaterniond_n = quaternion, imaginary_first, negative_cross>; - - -// Real first, positive cross: -using quaternionf_rp = quaternion, real_first, positive_cross>; -using quaterniond_rp = quaternion, real_first, positive_cross>; - - -// Real first, negative cross: -using quaternionf_rn = quaternion, real_first, negative_cross>; -using quaterniond_rn = quaternion, real_first, negative_cross>; - -/*@}*/ - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** @defgroup quaternion_types Predefined Quaternion Types */ +/*@{*/ + +// Imaginary first, positive cross: +using quaternionf_ip = quaternion, imaginary_first, positive_cross>; +using quaternionf_p = quaternion, imaginary_first, positive_cross>; +using quaternionf = quaternion; + +using quaterniond_ip = quaternion, imaginary_first, positive_cross>; +using quaterniond_p = quaternion, imaginary_first, positive_cross>; +using quaterniond = quaternion; + + +// Imaginary first, negative cross: +using quaternionf_in = quaternion, imaginary_first, negative_cross>; +using quaternionf_n = quaternion, imaginary_first, negative_cross>; + +using quaterniond_in = quaternion, imaginary_first, negative_cross>; +using quaterniond_n = quaternion, imaginary_first, negative_cross>; + + +// Real first, positive cross: +using quaternionf_rp = quaternion, real_first, positive_cross>; +using quaterniond_rp = quaternion, real_first, positive_cross>; + + +// Real first, negative cross: +using quaternionf_rn = quaternion, real_first, negative_cross>; +using quaterniond_rn = quaternion, real_first, negative_cross>; + +/*@}*/ + +} // namespace cml diff --git a/cml/quaternion/unary_node.h b/cml/quaternion/unary_node.h index acedd45..65b06c6 100644 --- a/cml/quaternion/unary_node.h +++ b/cml/quaternion/unary_node.h @@ -1,115 +1,115 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class quaternion_unary_node; - -/** quaternion_unary_node<> traits. */ -template -struct quaternion_traits> -{ - /* Figure out the basic types of Sub: */ - using quaternion_type = quaternion_unary_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = quaternion_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - using storage_type = typename sub_traits::storage_type; - - using size_tag = typename sub_traits::size_tag; - static_assert(cml::is_fixed_size::value, "invalid size tag"); - - /* Array size: */ - static const int array_size = storage_type::array_size; - static_assert(array_size == 4, "invalid quaternion size"); - - /* Order and cross taken from the sub-expression: */ - using order_type = typename sub_traits::order_type; - using cross_type = typename sub_traits::cross_type; -}; - -/** Represents a unary quaternion operation. */ -template -class quaternion_unary_node -: public readable_quaternion> -{ - public: - using node_type = quaternion_unary_node; - using readable_type = readable_quaternion; - using traits_type = quaternion_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using order_type = typename traits_type::order_type; - using cross_type = typename traits_type::cross_type; - - - public: - /** The array size constant is the same as the subexpression. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expression. @c sub must be an - * lvalue reference or rvalue reference. - */ - quaternion_unary_node(Sub sub); - - /** Move constructor. */ - quaternion_unary_node(node_type&& other); - - /** Copy constructor. */ - quaternion_unary_node(const node_type& other); - - - protected: - /** @name readable_quaternion Interface */ - /*@{*/ - - friend readable_type; - - /** Apply the unary operator to element @c i of the subexpression and - * return the result. - */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using sub_wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - - protected: - /** The subexpression. */ - sub_wrap_type m_sub; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_QUATERNION_UNARY_NODE_TPP -#include -#undef __CML_QUATERNION_UNARY_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class quaternion_unary_node; + +/** quaternion_unary_node<> traits. */ +template +struct quaternion_traits> +{ + /* Figure out the basic types of Sub: */ + using quaternion_type = quaternion_unary_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = quaternion_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + using storage_type = typename sub_traits::storage_type; + + using size_tag = typename sub_traits::size_tag; + static_assert(cml::is_fixed_size::value, "invalid size tag"); + + /* Array size: */ + static const int array_size = storage_type::array_size; + static_assert(array_size == 4, "invalid quaternion size"); + + /* Order and cross taken from the sub-expression: */ + using order_type = typename sub_traits::order_type; + using cross_type = typename sub_traits::cross_type; +}; + +/** Represents a unary quaternion operation. */ +template +class quaternion_unary_node +: public readable_quaternion> +{ + public: + using node_type = quaternion_unary_node; + using readable_type = readable_quaternion; + using traits_type = quaternion_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using order_type = typename traits_type::order_type; + using cross_type = typename traits_type::cross_type; + + + public: + /** The array size constant is the same as the subexpression. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expression. @c sub must be an + * lvalue reference or rvalue reference. + */ + quaternion_unary_node(Sub sub); + + /** Move constructor. */ + quaternion_unary_node(node_type&& other); + + /** Copy constructor. */ + quaternion_unary_node(const node_type& other); + + + protected: + /** @name readable_quaternion Interface */ + /*@{*/ + + friend readable_type; + + /** Apply the unary operator to element @c i of the subexpression and + * return the result. + */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using sub_wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + + protected: + /** The subexpression. */ + sub_wrap_type m_sub; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_QUATERNION_UNARY_NODE_TPP +#include +#undef __CML_QUATERNION_UNARY_NODE_TPP diff --git a/cml/quaternion/unary_node.tpp b/cml/quaternion/unary_node.tpp index 4872cf8..fefe1cc 100644 --- a/cml/quaternion/unary_node.tpp +++ b/cml/quaternion/unary_node.tpp @@ -1,40 +1,40 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_UNARY_NODE_TPP -# error "quaternion/unary_node.tpp not included correctly" -#endif - -namespace cml { - -/* quaternion_unary_node 'structors: */ - -template -quaternion_unary_node::quaternion_unary_node(Sub sub) -: m_sub(std::move(sub)) -{} - -template -quaternion_unary_node::quaternion_unary_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -{} - -template -quaternion_unary_node::quaternion_unary_node(const node_type& other) -: m_sub(other.m_sub) -{} - - -/* Internal methods: */ - -/* readable_quaternion interface: */ - -template -auto -quaternion_unary_node::i_get(int i) const -> immutable_value -{ - return Op().apply(this->m_sub.get(i)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_UNARY_NODE_TPP +# error "quaternion/unary_node.tpp not included correctly" +#endif + +namespace cml { + +/* quaternion_unary_node 'structors: */ + +template +quaternion_unary_node::quaternion_unary_node(Sub sub) +: m_sub(std::move(sub)) +{} + +template +quaternion_unary_node::quaternion_unary_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +{} + +template +quaternion_unary_node::quaternion_unary_node(const node_type& other) +: m_sub(other.m_sub) +{} + + +/* Internal methods: */ + +/* readable_quaternion interface: */ + +template +auto +quaternion_unary_node::i_get(int i) const -> immutable_value +{ + return Op().apply(this->m_sub.get(i)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/quaternion/unary_ops.h b/cml/quaternion/unary_ops.h index 44d086f..3ffea09 100644 --- a/cml/quaternion/unary_ops.h +++ b/cml/quaternion/unary_ops.h @@ -1,46 +1,46 @@ - -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Helper function to generate a quaternion_unary_node from a quaternion - * type (i.e. derived from readable_quaternion<>). - */ -template* = nullptr> -inline auto -make_quaternion_unary_node(Sub&& sub) - -> quaternion_unary_node, Op> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type"); - - /* Deduce the operand type of the subexpression (&, const&, &&): */ - using sub_type = actual_operand_type_of_t; - return quaternion_unary_node((sub_type) sub); -} - -template* = nullptr> -inline auto -operator-(Sub&& sub) -> decltype(make_quaternion_unary_node>( - std::forward(sub))) -{ - return make_quaternion_unary_node>(std::forward(sub)); -} - -template* = nullptr> -inline auto -operator+(Sub&& sub) -> decltype(make_quaternion_unary_node>( - std::forward(sub))) -{ - return make_quaternion_unary_node>(std::forward(sub)); -} - -} // namespace cml + +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Helper function to generate a quaternion_unary_node from a quaternion + * type (i.e. derived from readable_quaternion<>). + */ +template* = nullptr> +inline auto +make_quaternion_unary_node(Sub&& sub) + -> quaternion_unary_node, Op> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type"); + + /* Deduce the operand type of the subexpression (&, const&, &&): */ + using sub_type = actual_operand_type_of_t; + return quaternion_unary_node((sub_type) sub); +} + +template* = nullptr> +inline auto +operator-(Sub&& sub) -> decltype(make_quaternion_unary_node>( + std::forward(sub))) +{ + return make_quaternion_unary_node>(std::forward(sub)); +} + +template* = nullptr> +inline auto +operator+(Sub&& sub) -> decltype(make_quaternion_unary_node>( + std::forward(sub))) +{ + return make_quaternion_unary_node>(std::forward(sub)); +} + +} // namespace cml diff --git a/cml/quaternion/writable_quaternion.h b/cml/quaternion/writable_quaternion.h index 1330ba5..82409be 100644 --- a/cml/quaternion/writable_quaternion.h +++ b/cml/quaternion/writable_quaternion.h @@ -1,374 +1,374 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace cml { - -/** Base class for writable quaternion types. Writable quaternions support - * non-const read-write access to its elements, in addition to read-only - * access via readable_quaternion. - * - * In addition to the requirements of readable_quaternion, DerivedT must - * implement: - * - * - i_get(int i), where is the mutable_value type defined by - * quaternion_traits - * - * - template DerivedT& i_put(int i, const T&) - * - * for compilers without support for rvalue reference from *this; and - * - * template DerivedT& i_put(int i, const T&) & - * template DerivedT&& i_put(int i, const T&) && - * - * for compilers with support for rvalue reference from this. - * - * Note that mutable_value need not be a reference type. - */ -template -class writable_quaternion : public readable_quaternion -{ - public: - using quaternion_type = DerivedT; - using readable_type = readable_quaternion; - using traits_type = quaternion_traits; - using value_type = typename traits_type::value_type; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using order_type = typename traits_type::order_type; - - - public: - /* Disambiguate readable_quaternion<> methods: */ - using readable_type::W; - using readable_type::X; - using readable_type::Y; - using readable_type::Z; - using readable_type::actual; - using readable_type::get; - using readable_type::normalize; - using readable_type::conjugate; - using readable_type::inverse; - using readable_type::operator[]; - using readable_type::x; - using readable_type::y; - using readable_type::z; - using readable_type::w; - - - public: - /** Return a mutable reference to the quaternion cast as DerivedT. */ - DerivedT& actual(); - - /** Set element @c i. */ - template DerivedT& put(int i, const Other& v) &; - - /** Set element @c i on a temporary. */ - template DerivedT&& put(int i, const Other& v) &&; - - /** Return mutable element @c i. */ - mutable_value get(int i); - - /** Return a mutable reference to element @c i. */ - mutable_value operator[](int i); - - /** Return a mutable reference to the real part of the quaternion. */ - mutable_value w(); - - /** Return a mutable reference to the imaginary i coordinate. */ - mutable_value x(); - - /** Return a mutable reference to the imaginary j coordinate. */ - mutable_value y(); - - /** Return a mutable reference to the imaginary k coordinate. */ - mutable_value z(); - - - public: - /** Set the scalar of the quaternion to @c s, and the imaginary - * vector to @c v. - * - * @note This functin is enabled only if the value_type of @c v and @c - * E are convertible to value_type. - */ - template* = nullptr> - auto set(const readable_vector& v, const E& s) & -> enable_if_t< - are_convertible, E>::value, - DerivedT&>; - - /** Set the scalar of the quaternion to @c s, and the imaginary - * vector to @c v. - * - * @note This functin is enabled only if the value_type of @c v and @c - * E are convertible to value_type. - */ - template* = nullptr> - auto set(const E& s, const readable_vector& v) & -> enable_if_t< - are_convertible, E>::value, - DerivedT&>; - - /** Set the scalar of the temporary quaternion to @c s, and the - * imaginary vector to @c v. - * - * @note This functin is enabled only if the value_type of @c v and @c - * E are convertible to value_type. - */ - template* = nullptr> - auto set(const readable_vector& v, const E& s) && -> enable_if_t< - are_convertible, E>::value, - DerivedT&&>; - - /** Set the scalar of the temporary quaternion to @c s, and the - * imaginary vector to @c v. - * - * @note This functin is enabled only if the value_type of @c v and @c - * E are convertible to value_type. - */ - template* = nullptr> - auto set(const E& s, const readable_vector& v) && -> enable_if_t< - are_convertible, E>::value, - DerivedT&&>; - - - public: - /** Divide the quaternion elements by the length of the quaternion. */ - DerivedT& normalize() &; - - /** Divide the quaternion elements of a temporary by the length of the - * quaternion. - */ - DerivedT&& normalize() &&; - - /** Zero the quaternion elements. */ - DerivedT& zero() &; - - /** Zero the quaternion elements of a temporary. */ - DerivedT&& zero() &&; - - /** Set the quaternion to the identity. */ - DerivedT& identity() &; - - /** Set a temporary to the identity. */ - DerivedT&& identity() &&; - - /** Set the quaternion to its conjugate. */ - DerivedT& conjugate() &; - - /** Set a temporary to its conjugate. */ - DerivedT&& conjugate() &&; - - /** Set the quaternion to its inverse. */ - DerivedT& inverse() &; - - /** Set a temporary to its inverse. */ - DerivedT&& inverse() &&; - - /** Set the quaternion to its natural logarithm. - * - * @note It is up to the caller to ensure the quaternion has a usable - * non-zero length. - * - * @breaking In CML1, this function returns a temporary. Use cml::log() as a - * replacement. - */ - DerivedT& log() &; - - /** Set a temporary to its natural logarithm. - * - * @note It is up to the caller to ensure the quaternion has a usable - * non-zero length. - * - * @breaking In CML1, this function returns a temporary. Use cml::log() - * as a replacement. - */ - DerivedT&& log() &&; - - /** Set the quaternion to its exponential. - * - * @breaking In CML1, this function returns a temporary. Use cml::exp() - * as a replacement. - */ - DerivedT& exp() &; - - /** Set a temporary to its exponential. - * - * @breaking In CML1, this function returns a temporary. Use cml::exp() - * as a replacement. - */ - DerivedT&& exp() &&; - - - public: - /** Assign from a readable_quaternion. */ - template - DerivedT& operator=(const readable_quaternion& other) &; - - /** Assign a temporary from a readable_quaternion. */ - template - DerivedT&& operator=(const readable_quaternion& other) &&; - - /** Assign from a fixed-length array type. - * - * @throws incompatible_quaternion_size_error if @c - * array_size_of_c::value != 4. - */ - template* = nullptr> - DerivedT& operator=(const Array& array) &; - - /** Assign a temporary from a fixed-length array type. - * - * @throws incompatible_quaternion_size_error if @c - * array_size_of_c::value != 4. - */ - template* = nullptr> - DerivedT&& operator=(const Array& array) &&; - - /** Assign from initializer list. - * - * @throws incompatible_quaternion_size_error if if @c l.size() != 4. - */ - template DerivedT& operator=(std::initializer_list l) &; - - /** Assign a temporary from initializer list. - * - * @throws incompatible_quaternion_size_error if if @c l.size() != 4. - */ - template DerivedT&& operator=(std::initializer_list l) &&; - - /** Modify the quaternion by addition of another quaternion. */ - template - DerivedT& operator+=(const readable_quaternion& other) &; - - /** Modify a temporary quaternion by addition of another quaternion. */ - template - DerivedT&& operator+=(const readable_quaternion& other) &&; - - /** Modify the quaternion by subtraction of another quaternion. */ - template - DerivedT& operator-=(const readable_quaternion& other) &; - - /** Modify a temporary quaternion by subtraction of another quaternion. */ - template - DerivedT&& operator-=(const readable_quaternion& other) &&; - - /** Modify the quaternion by multiplication of another quaternion. */ - template - DerivedT& operator*=(const readable_quaternion& other) &; - - /** Modify a temporary quaternion by multiplication of another - * quaternion. - */ - template - DerivedT&& operator*=(const readable_quaternion& other) &&; - - /** Multiply the quaternion by a scalar convertible to its value_type. */ - template::type* = nullptr> - DerivedT& operator*=(const ScalarT& v) &; - - /** Multiply the temporary quaternion by a scalar convertible to its - * value_type. - */ - template::type* = nullptr> - DerivedT&& operator*=(const ScalarT& v) &&; - - /** Divide the quaternion by a scalar convertible to its value_type. */ - template::type* = nullptr> - DerivedT& operator/=(const ScalarT& v) &; - - /** Divide the quaternion temporary by a scalar convertible to its - * value_type. - */ - template::type* = nullptr> - DerivedT&& operator/=(const ScalarT& v) &&; - - - protected: - /** Assign from a readable_quaternion. - * - * @note This depends upon implicit conversion of the source quaternion - * elements to the quaternion value_type. - */ - template - DerivedT& assign(const readable_quaternion& other); - - /** Assign from a readable_vector and a scalar. */ - template - DerivedT& assign(const readable_vector& other, const E0& e0); - - /** Construct from a fixed-length array of values. The assignment - * order is determined by the quaternion order. - * - * @note This depends upon implicit conversions of the elements to the - * quaternion value_type. - */ - template* = nullptr> - DerivedT& assign(const Array& array); - - /** Assign from a pointer to an array. - * - * @note This depends upon implicit conversion of the array elements to - * the quaternion value_type. - */ - template* = nullptr> - DerivedT& assign(const Pointer& array); - - /** Construct from an array of 3 values and one additional element. - * The assignment order is determined by the quaternion order. - * - * @note This depends upon implicit conversions of the elements to the - * quaternion value_type. - */ - template* = nullptr> - DerivedT& assign(const Array& array, const E0& e0); - - /** Construct from an initializer_list. - * - * @note This depends upon implicit conversions of the elements to the - * quaternion value_type. - */ - template DerivedT& assign(const std::initializer_list& l); - - /** Construct from a list of 4 values. - * - * @note This depends upon implicit conversions of the elements to the - * quaternion value_type. - */ - template - DerivedT& assign_elements(const E0& e0, const E1& e1, const E2& e2, - const E3& e3); - - - protected: - // Use the compiler-generated default constructor: - writable_quaternion() = default; - - // Use the compiler-generated copy constructor: - writable_quaternion(const writable_quaternion&) = default; - - // Use the compiler-generated move constructor: - writable_quaternion(writable_quaternion&&) = default; - - // Force assignment through operator=(readable_quaternion<>): - writable_quaternion& operator=(const writable_quaternion&) = delete; -}; - -} // namespace cml - -#define __CML_QUATERNION_WRITABLE_QUATERNION_TPP -#include -#undef __CML_QUATERNION_WRITABLE_QUATERNION_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Base class for writable quaternion types. Writable quaternions support + * non-const read-write access to its elements, in addition to read-only + * access via readable_quaternion. + * + * In addition to the requirements of readable_quaternion, DerivedT must + * implement: + * + * - i_get(int i), where is the mutable_value type defined by + * quaternion_traits + * + * - template DerivedT& i_put(int i, const T&) + * + * for compilers without support for rvalue reference from *this; and + * + * template DerivedT& i_put(int i, const T&) & + * template DerivedT&& i_put(int i, const T&) && + * + * for compilers with support for rvalue reference from this. + * + * Note that mutable_value need not be a reference type. + */ +template +class writable_quaternion : public readable_quaternion +{ + public: + using quaternion_type = DerivedT; + using readable_type = readable_quaternion; + using traits_type = quaternion_traits; + using value_type = typename traits_type::value_type; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using order_type = typename traits_type::order_type; + + + public: + /* Disambiguate readable_quaternion<> methods: */ + using readable_type::W; + using readable_type::X; + using readable_type::Y; + using readable_type::Z; + using readable_type::actual; + using readable_type::get; + using readable_type::normalize; + using readable_type::conjugate; + using readable_type::inverse; + using readable_type::operator[]; + using readable_type::x; + using readable_type::y; + using readable_type::z; + using readable_type::w; + + + public: + /** Return a mutable reference to the quaternion cast as DerivedT. */ + DerivedT& actual(); + + /** Set element @c i. */ + template DerivedT& put(int i, const Other& v) &; + + /** Set element @c i on a temporary. */ + template DerivedT&& put(int i, const Other& v) &&; + + /** Return mutable element @c i. */ + mutable_value get(int i); + + /** Return a mutable reference to element @c i. */ + mutable_value operator[](int i); + + /** Return a mutable reference to the real part of the quaternion. */ + mutable_value w(); + + /** Return a mutable reference to the imaginary i coordinate. */ + mutable_value x(); + + /** Return a mutable reference to the imaginary j coordinate. */ + mutable_value y(); + + /** Return a mutable reference to the imaginary k coordinate. */ + mutable_value z(); + + + public: + /** Set the scalar of the quaternion to @c s, and the imaginary + * vector to @c v. + * + * @note This functin is enabled only if the value_type of @c v and @c + * E are convertible to value_type. + */ + template* = nullptr> + auto set(const readable_vector& v, const E& s) & -> enable_if_t< + are_convertible, E>::value, + DerivedT&>; + + /** Set the scalar of the quaternion to @c s, and the imaginary + * vector to @c v. + * + * @note This functin is enabled only if the value_type of @c v and @c + * E are convertible to value_type. + */ + template* = nullptr> + auto set(const E& s, const readable_vector& v) & -> enable_if_t< + are_convertible, E>::value, + DerivedT&>; + + /** Set the scalar of the temporary quaternion to @c s, and the + * imaginary vector to @c v. + * + * @note This functin is enabled only if the value_type of @c v and @c + * E are convertible to value_type. + */ + template* = nullptr> + auto set(const readable_vector& v, const E& s) && -> enable_if_t< + are_convertible, E>::value, + DerivedT&&>; + + /** Set the scalar of the temporary quaternion to @c s, and the + * imaginary vector to @c v. + * + * @note This functin is enabled only if the value_type of @c v and @c + * E are convertible to value_type. + */ + template* = nullptr> + auto set(const E& s, const readable_vector& v) && -> enable_if_t< + are_convertible, E>::value, + DerivedT&&>; + + + public: + /** Divide the quaternion elements by the length of the quaternion. */ + DerivedT& normalize() &; + + /** Divide the quaternion elements of a temporary by the length of the + * quaternion. + */ + DerivedT&& normalize() &&; + + /** Zero the quaternion elements. */ + DerivedT& zero() &; + + /** Zero the quaternion elements of a temporary. */ + DerivedT&& zero() &&; + + /** Set the quaternion to the identity. */ + DerivedT& identity() &; + + /** Set a temporary to the identity. */ + DerivedT&& identity() &&; + + /** Set the quaternion to its conjugate. */ + DerivedT& conjugate() &; + + /** Set a temporary to its conjugate. */ + DerivedT&& conjugate() &&; + + /** Set the quaternion to its inverse. */ + DerivedT& inverse() &; + + /** Set a temporary to its inverse. */ + DerivedT&& inverse() &&; + + /** Set the quaternion to its natural logarithm. + * + * @note It is up to the caller to ensure the quaternion has a usable + * non-zero length. + * + * @breaking In CML1, this function returns a temporary. Use cml::log() as a + * replacement. + */ + DerivedT& log() &; + + /** Set a temporary to its natural logarithm. + * + * @note It is up to the caller to ensure the quaternion has a usable + * non-zero length. + * + * @breaking In CML1, this function returns a temporary. Use cml::log() + * as a replacement. + */ + DerivedT&& log() &&; + + /** Set the quaternion to its exponential. + * + * @breaking In CML1, this function returns a temporary. Use cml::exp() + * as a replacement. + */ + DerivedT& exp() &; + + /** Set a temporary to its exponential. + * + * @breaking In CML1, this function returns a temporary. Use cml::exp() + * as a replacement. + */ + DerivedT&& exp() &&; + + + public: + /** Assign from a readable_quaternion. */ + template + DerivedT& operator=(const readable_quaternion& other) &; + + /** Assign a temporary from a readable_quaternion. */ + template + DerivedT&& operator=(const readable_quaternion& other) &&; + + /** Assign from a fixed-length array type. + * + * @throws incompatible_quaternion_size_error if @c + * array_size_of_c::value != 4. + */ + template* = nullptr> + DerivedT& operator=(const Array& array) &; + + /** Assign a temporary from a fixed-length array type. + * + * @throws incompatible_quaternion_size_error if @c + * array_size_of_c::value != 4. + */ + template* = nullptr> + DerivedT&& operator=(const Array& array) &&; + + /** Assign from initializer list. + * + * @throws incompatible_quaternion_size_error if if @c l.size() != 4. + */ + template DerivedT& operator=(std::initializer_list l) &; + + /** Assign a temporary from initializer list. + * + * @throws incompatible_quaternion_size_error if if @c l.size() != 4. + */ + template DerivedT&& operator=(std::initializer_list l) &&; + + /** Modify the quaternion by addition of another quaternion. */ + template + DerivedT& operator+=(const readable_quaternion& other) &; + + /** Modify a temporary quaternion by addition of another quaternion. */ + template + DerivedT&& operator+=(const readable_quaternion& other) &&; + + /** Modify the quaternion by subtraction of another quaternion. */ + template + DerivedT& operator-=(const readable_quaternion& other) &; + + /** Modify a temporary quaternion by subtraction of another quaternion. */ + template + DerivedT&& operator-=(const readable_quaternion& other) &&; + + /** Modify the quaternion by multiplication of another quaternion. */ + template + DerivedT& operator*=(const readable_quaternion& other) &; + + /** Modify a temporary quaternion by multiplication of another + * quaternion. + */ + template + DerivedT&& operator*=(const readable_quaternion& other) &&; + + /** Multiply the quaternion by a scalar convertible to its value_type. */ + template::type* = nullptr> + DerivedT& operator*=(const ScalarT& v) &; + + /** Multiply the temporary quaternion by a scalar convertible to its + * value_type. + */ + template::type* = nullptr> + DerivedT&& operator*=(const ScalarT& v) &&; + + /** Divide the quaternion by a scalar convertible to its value_type. */ + template::type* = nullptr> + DerivedT& operator/=(const ScalarT& v) &; + + /** Divide the quaternion temporary by a scalar convertible to its + * value_type. + */ + template::type* = nullptr> + DerivedT&& operator/=(const ScalarT& v) &&; + + + protected: + /** Assign from a readable_quaternion. + * + * @note This depends upon implicit conversion of the source quaternion + * elements to the quaternion value_type. + */ + template + DerivedT& assign(const readable_quaternion& other); + + /** Assign from a readable_vector and a scalar. */ + template + DerivedT& assign(const readable_vector& other, const E0& e0); + + /** Construct from a fixed-length array of values. The assignment + * order is determined by the quaternion order. + * + * @note This depends upon implicit conversions of the elements to the + * quaternion value_type. + */ + template* = nullptr> + DerivedT& assign(const Array& array); + + /** Assign from a pointer to an array. + * + * @note This depends upon implicit conversion of the array elements to + * the quaternion value_type. + */ + template* = nullptr> + DerivedT& assign(const Pointer& array); + + /** Construct from an array of 3 values and one additional element. + * The assignment order is determined by the quaternion order. + * + * @note This depends upon implicit conversions of the elements to the + * quaternion value_type. + */ + template* = nullptr> + DerivedT& assign(const Array& array, const E0& e0); + + /** Construct from an initializer_list. + * + * @note This depends upon implicit conversions of the elements to the + * quaternion value_type. + */ + template DerivedT& assign(const std::initializer_list& l); + + /** Construct from a list of 4 values. + * + * @note This depends upon implicit conversions of the elements to the + * quaternion value_type. + */ + template + DerivedT& assign_elements(const E0& e0, const E1& e1, const E2& e2, + const E3& e3); + + + protected: + // Use the compiler-generated default constructor: + writable_quaternion() = default; + + // Use the compiler-generated copy constructor: + writable_quaternion(const writable_quaternion&) = default; + + // Use the compiler-generated move constructor: + writable_quaternion(writable_quaternion&&) = default; + + // Force assignment through operator=(readable_quaternion<>): + writable_quaternion& operator=(const writable_quaternion&) = delete; +}; + +} // namespace cml + +#define __CML_QUATERNION_WRITABLE_QUATERNION_TPP +#include +#undef __CML_QUATERNION_WRITABLE_QUATERNION_TPP diff --git a/cml/quaternion/writable_quaternion.tpp b/cml/quaternion/writable_quaternion.tpp index 05cf0a5..d0b2f1d 100644 --- a/cml/quaternion/writable_quaternion.tpp +++ b/cml/quaternion/writable_quaternion.tpp @@ -1,526 +1,526 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_QUATERNION_WRITABLE_QUATERNION_TPP -# error "quaternion/writable_quaternion.tpp not included correctly" -#endif - -#include -#include -#include -#include - -namespace cml { - -/* Public methods: */ - -template -DT& -writable_quaternion
::actual() -{ - return (DT&) *this; -} - -template -auto -writable_quaternion
::get(int i) -> mutable_value -{ - return this->actual().i_get(i); -} - -template -template -DT& -writable_quaternion
::put(int i, const Other& v) & -{ - return this->actual().i_put(i, v); -} - -template -template -DT&& -writable_quaternion
::put(int i, const Other& v) && -{ - this->put(i, v); - return (DT&&) *this; -} - -template -auto -writable_quaternion
::operator[](int i) -> mutable_value -{ - return this->get(i); -} - -template -auto -writable_quaternion
::w() -> mutable_value -{ - return this->get(order_type::W); -} - -template -auto -writable_quaternion
::x() -> mutable_value -{ - return this->get(order_type::X); -} - -template -auto -writable_quaternion
::y() -> mutable_value -{ - return this->get(order_type::Y); -} - -template -auto -writable_quaternion
::z() -> mutable_value -{ - return this->get(order_type::Z); -} - -template -DT& -writable_quaternion
::normalize() & -{ - return this->operator/=(this->length()); -} - -template -DT&& -writable_quaternion
::normalize() && -{ - this->normalize(); // Forward to normalize & - return (DT&&) *this; -} - -template -DT& -writable_quaternion
::zero() & -{ - for(int i = 0; i < 4; ++i) this->put(i, value_type(0)); - return this->actual(); -} - -template -DT&& -writable_quaternion
::zero() && -{ - this->zero(); // Forward to zero & - return (DT&&) *this; -} - -template -DT& -writable_quaternion
::identity() & -{ - this->put(W, value_type(1)); - this->put(X, value_type(0)); - this->put(Y, value_type(0)); - this->put(Z, value_type(0)); - return this->actual(); -} - -template -DT&& -writable_quaternion
::identity() && -{ - this->identity(); // Forward to identity & - return (DT&&) *this; -} - -template -DT& -writable_quaternion
::conjugate() & -{ - this->put(W, this->get(W)); - this->put(X, -this->get(X)); - this->put(Y, -this->get(Y)); - this->put(Z, -this->get(Z)); - return this->actual(); -} - -template -DT&& -writable_quaternion
::conjugate() && -{ - this->conjugate(); // Forward to conjugate & - return (DT&&) *this; -} - -template -DT& -writable_quaternion
::inverse() & -{ - /* Cayley norm (squared length). */ - auto n = this->norm(); - - /* The inverse is conjugate() / norm(): */ - this->put(W, this->get(W) / n); - this->put(X, -this->get(X) / n); - this->put(Y, -this->get(Y) / n); - this->put(Z, -this->get(Z) / n); - return this->actual(); -} - -template -DT&& -writable_quaternion
::inverse() && -{ - this->inverse(); // Forward to inverse & - return (DT&&) *this; -} - -template -DT& -writable_quaternion
::log() & -{ - /* Shorthand: */ - using element_traits = typename traits_type::element_traits; - - /* The natural log of q is: - * - * ln(|q|) + v/|v| * arccos(w / |q|) - * - * where v is the imaginary part of q and w is the real part: - */ - auto lq = this->length(); - auto v = this->imaginary(); - auto lv = v.length(); - auto c = element_traits::acos(this->real() / lq) / lv; - this->assign(c * v, element_traits::log(lq)); - return this->actual(); -} - -template -DT&& -writable_quaternion
::log() && -{ - this->log(); // Forward to log & - return (DT&&) *this; -} - -template -DT& -writable_quaternion
::exp() & -{ - /* Shorthand: */ - using element_traits = typename traits_type::element_traits; - - /* The exponential of q is: - * - * exp(w) * (cos(|v|) + v/|v|*sin(|v|)) - * - * where v is the imaginary part of q and w is the real part: - */ - auto v = this->imaginary(); - auto lv = v.length(); - auto x = element_traits::exp(this->real()); - auto c = element_traits::sin(lv) / lv; - this->assign(x * c * v, x * element_traits::cos(lv)); - return this->actual(); -} - -template -DT&& -writable_quaternion
::exp() && -{ - this->exp(); // Forward to exp & - return (DT&&) *this; -} - -template -template*> -auto -writable_quaternion
:: - set(const readable_vector& v, const E& s) & -> enable_if_t< - are_convertible, E>::value, DT&> -{ - return this->assign(v, s); -} - -template -template*> -auto -writable_quaternion
:: - set(const E& s, const readable_vector& v) & -> enable_if_t< - are_convertible, E>::value, DT&> -{ - return this->assign(v, s); -} - -template -template*> -auto -writable_quaternion
:: - set(const readable_vector& v, const E& s) && -> enable_if_t< - are_convertible, E>::value, DT&&> -{ - this->assign(v, s); - return (DT&&) *this; -} - -template -template*> -auto -writable_quaternion
:: - set(const E& s, const readable_vector& v) && -> enable_if_t< - are_convertible, E>::value, DT&&> -{ - this->assign(v, s); - return (DT&&) *this; -} - -template -template -DT& -writable_quaternion
::operator=(const readable_quaternion& other) & -{ - return this->assign(other); -} - -template -template -DT&& -writable_quaternion
::operator=(const readable_quaternion& other) && -{ - this->operator=(other); - return (DT&&) *this; -} - -template -template*> -DT& -writable_quaternion
::operator=(const Array& array) & -{ - return this->assign(array); -} - -template -template*> -DT&& -writable_quaternion
::operator=(const Array& array) && -{ - this->operator=(array); - return (DT&&) *this; -} - -template -template -DT& -writable_quaternion
::operator=(std::initializer_list l) & -{ - return this->assign(l); -} - -template -template -DT&& -writable_quaternion
::operator=(std::initializer_list l) && -{ - return this->assign(l); -} - -template -template -DT& -writable_quaternion
::operator+=(const readable_quaternion& other) & -{ - using op_type = binary_plus_t; - for(int i = 0; i < 4; ++i) - this->put(i, op_type().apply(this->get(i), other.get(i))); - return this->actual(); -} - -template -template -DT&& -writable_quaternion
::operator+=(const readable_quaternion& other) && -{ - this->operator+=(other); - return (DT&&) *this; -} - -template -template -DT& -writable_quaternion
::operator-=(const readable_quaternion& other) & -{ - using op_type = binary_minus_t; - for(int i = 0; i < 4; ++i) - this->put(i, op_type().apply(this->get(i), other.get(i))); - return this->actual(); -} - -template -template -DT&& -writable_quaternion
::operator-=(const readable_quaternion& other) && -{ - this->operator-=(other); - return (DT&&) *this; -} - -template -template -DT& -writable_quaternion
::operator*=(const readable_quaternion& other) & -{ - return this->assign((*this) * other); - /* Note: operator*() returns a temporary here. */ -} - -template -template -DT&& -writable_quaternion
::operator*=(const readable_quaternion& other) && -{ - this->operator*=(other); - return (DT&&) *this; -} - -template -template::value_type, - ScalarT>::type*> -DT& -writable_quaternion
::operator*=(const ScalarT& v) & -{ - using op_type = binary_multiply_t; - for(int i = 0; i < 4; ++i) this->put(i, op_type().apply(this->get(i), v)); - return this->actual(); -} - -template -template::value_type, - ScalarT>::type*> -DT&& -writable_quaternion
::operator*=(const ScalarT& v) && -{ - this->operator*=(v); - return (DT&&) *this; -} - -template -template::value_type, - ScalarT>::type*> -DT& -writable_quaternion
::operator/=(const ScalarT& v) & -{ - using op_type = binary_divide_t; - for(int i = 0; i < 4; ++i) this->put(i, op_type().apply(this->get(i), v)); - return this->actual(); -} - -template -template::value_type, - ScalarT>::type*> -DT&& -writable_quaternion
::operator/=(const ScalarT& v) && -{ - this->operator/=(v); - return (DT&&) *this; -} - -/* Internal methods: */ - -template -template -DT& -writable_quaternion
::assign(const readable_quaternion& other) -{ - this->put(W, other.get(W)); - this->put(X, other.get(X)); - this->put(Y, other.get(Y)); - this->put(Z, other.get(Z)); - return this->actual(); -} - -template -template -DT& -writable_quaternion
::assign(const readable_vector& other, const E0& e0) -{ - cml::check_size(other, cml::int_c<3>()); - this->put(W, e0); - this->put(X, other.get(0)); - this->put(Y, other.get(1)); - this->put(Z, other.get(2)); - return this->actual(); -} - -template -template*> -DT& -writable_quaternion
::assign(const Array& array) -{ - static const int N = array_size_of_c::value; - static_assert(N == 4, "incorrect quaternion expression size"); - this->put(W, array[W]); - this->put(X, array[X]); - this->put(Y, array[Y]); - this->put(Z, array[Z]); - return this->actual(); -} - -template -template*> -DT& -writable_quaternion
::assign(const Pointer& array) -{ - this->put(W, array[W]); - this->put(X, array[X]); - this->put(Y, array[Y]); - this->put(Z, array[Z]); - return this->actual(); -} - -template -template*> -DT& -writable_quaternion
::assign(const Array& array, const E0& e0) -{ - static const int N = array_size_of_c::value; - static_assert(N == 3, "incorrect quaternion expression size"); - this->put(W, e0); - this->put(X, array[0]); - this->put(Y, array[1]); - this->put(Z, array[2]); - return this->actual(); -} - -template -template -DT& -writable_quaternion
::assign(const std::initializer_list& l) -{ -#ifndef CML_NO_RUNTIME_QUATERNION_SIZE_CHECKS - cml_require(l.size() == 4, quaternion_size_error, /**/); -#endif - auto array = l.begin(); - this->put(W, array[W]); - this->put(X, array[X]); - this->put(Y, array[Y]); - this->put(Z, array[Z]); - return this->actual(); -} - -template -template -DT& -writable_quaternion
::assign_elements(const E0& e0, const E1& e1, - const E2& e2, const E3& e3) -{ - this->put(W, item_at(e0, e1, e2, e3)); - this->put(X, item_at(e0, e1, e2, e3)); - this->put(Y, item_at(e0, e1, e2, e3)); - this->put(Z, item_at(e0, e1, e2, e3)); - return this->actual(); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_QUATERNION_WRITABLE_QUATERNION_TPP +# error "quaternion/writable_quaternion.tpp not included correctly" +#endif + +#include +#include +#include +#include + +namespace cml { + +/* Public methods: */ + +template +DT& +writable_quaternion
::actual() +{ + return (DT&) *this; +} + +template +auto +writable_quaternion
::get(int i) -> mutable_value +{ + return this->actual().i_get(i); +} + +template +template +DT& +writable_quaternion
::put(int i, const Other& v) & +{ + return this->actual().i_put(i, v); +} + +template +template +DT&& +writable_quaternion
::put(int i, const Other& v) && +{ + this->put(i, v); + return (DT&&) *this; +} + +template +auto +writable_quaternion
::operator[](int i) -> mutable_value +{ + return this->get(i); +} + +template +auto +writable_quaternion
::w() -> mutable_value +{ + return this->get(order_type::W); +} + +template +auto +writable_quaternion
::x() -> mutable_value +{ + return this->get(order_type::X); +} + +template +auto +writable_quaternion
::y() -> mutable_value +{ + return this->get(order_type::Y); +} + +template +auto +writable_quaternion
::z() -> mutable_value +{ + return this->get(order_type::Z); +} + +template +DT& +writable_quaternion
::normalize() & +{ + return this->operator/=(this->length()); +} + +template +DT&& +writable_quaternion
::normalize() && +{ + this->normalize(); // Forward to normalize & + return (DT&&) *this; +} + +template +DT& +writable_quaternion
::zero() & +{ + for(int i = 0; i < 4; ++i) this->put(i, value_type(0)); + return this->actual(); +} + +template +DT&& +writable_quaternion
::zero() && +{ + this->zero(); // Forward to zero & + return (DT&&) *this; +} + +template +DT& +writable_quaternion
::identity() & +{ + this->put(W, value_type(1)); + this->put(X, value_type(0)); + this->put(Y, value_type(0)); + this->put(Z, value_type(0)); + return this->actual(); +} + +template +DT&& +writable_quaternion
::identity() && +{ + this->identity(); // Forward to identity & + return (DT&&) *this; +} + +template +DT& +writable_quaternion
::conjugate() & +{ + this->put(W, this->get(W)); + this->put(X, -this->get(X)); + this->put(Y, -this->get(Y)); + this->put(Z, -this->get(Z)); + return this->actual(); +} + +template +DT&& +writable_quaternion
::conjugate() && +{ + this->conjugate(); // Forward to conjugate & + return (DT&&) *this; +} + +template +DT& +writable_quaternion
::inverse() & +{ + /* Cayley norm (squared length). */ + auto n = this->norm(); + + /* The inverse is conjugate() / norm(): */ + this->put(W, this->get(W) / n); + this->put(X, -this->get(X) / n); + this->put(Y, -this->get(Y) / n); + this->put(Z, -this->get(Z) / n); + return this->actual(); +} + +template +DT&& +writable_quaternion
::inverse() && +{ + this->inverse(); // Forward to inverse & + return (DT&&) *this; +} + +template +DT& +writable_quaternion
::log() & +{ + /* Shorthand: */ + using element_traits = typename traits_type::element_traits; + + /* The natural log of q is: + * + * ln(|q|) + v/|v| * arccos(w / |q|) + * + * where v is the imaginary part of q and w is the real part: + */ + auto lq = this->length(); + auto v = this->imaginary(); + auto lv = v.length(); + auto c = element_traits::acos(this->real() / lq) / lv; + this->assign(c * v, element_traits::log(lq)); + return this->actual(); +} + +template +DT&& +writable_quaternion
::log() && +{ + this->log(); // Forward to log & + return (DT&&) *this; +} + +template +DT& +writable_quaternion
::exp() & +{ + /* Shorthand: */ + using element_traits = typename traits_type::element_traits; + + /* The exponential of q is: + * + * exp(w) * (cos(|v|) + v/|v|*sin(|v|)) + * + * where v is the imaginary part of q and w is the real part: + */ + auto v = this->imaginary(); + auto lv = v.length(); + auto x = element_traits::exp(this->real()); + auto c = element_traits::sin(lv) / lv; + this->assign(x * c * v, x * element_traits::cos(lv)); + return this->actual(); +} + +template +DT&& +writable_quaternion
::exp() && +{ + this->exp(); // Forward to exp & + return (DT&&) *this; +} + +template +template*> +auto +writable_quaternion
:: + set(const readable_vector& v, const E& s) & -> enable_if_t< + are_convertible, E>::value, DT&> +{ + return this->assign(v, s); +} + +template +template*> +auto +writable_quaternion
:: + set(const E& s, const readable_vector& v) & -> enable_if_t< + are_convertible, E>::value, DT&> +{ + return this->assign(v, s); +} + +template +template*> +auto +writable_quaternion
:: + set(const readable_vector& v, const E& s) && -> enable_if_t< + are_convertible, E>::value, DT&&> +{ + this->assign(v, s); + return (DT&&) *this; +} + +template +template*> +auto +writable_quaternion
:: + set(const E& s, const readable_vector& v) && -> enable_if_t< + are_convertible, E>::value, DT&&> +{ + this->assign(v, s); + return (DT&&) *this; +} + +template +template +DT& +writable_quaternion
::operator=(const readable_quaternion& other) & +{ + return this->assign(other); +} + +template +template +DT&& +writable_quaternion
::operator=(const readable_quaternion& other) && +{ + this->operator=(other); + return (DT&&) *this; +} + +template +template*> +DT& +writable_quaternion
::operator=(const Array& array) & +{ + return this->assign(array); +} + +template +template*> +DT&& +writable_quaternion
::operator=(const Array& array) && +{ + this->operator=(array); + return (DT&&) *this; +} + +template +template +DT& +writable_quaternion
::operator=(std::initializer_list l) & +{ + return this->assign(l); +} + +template +template +DT&& +writable_quaternion
::operator=(std::initializer_list l) && +{ + return this->assign(l); +} + +template +template +DT& +writable_quaternion
::operator+=(const readable_quaternion& other) & +{ + using op_type = binary_plus_t; + for(int i = 0; i < 4; ++i) + this->put(i, op_type().apply(this->get(i), other.get(i))); + return this->actual(); +} + +template +template +DT&& +writable_quaternion
::operator+=(const readable_quaternion& other) && +{ + this->operator+=(other); + return (DT&&) *this; +} + +template +template +DT& +writable_quaternion
::operator-=(const readable_quaternion& other) & +{ + using op_type = binary_minus_t; + for(int i = 0; i < 4; ++i) + this->put(i, op_type().apply(this->get(i), other.get(i))); + return this->actual(); +} + +template +template +DT&& +writable_quaternion
::operator-=(const readable_quaternion& other) && +{ + this->operator-=(other); + return (DT&&) *this; +} + +template +template +DT& +writable_quaternion
::operator*=(const readable_quaternion& other) & +{ + return this->assign((*this) * other); + /* Note: operator*() returns a temporary here. */ +} + +template +template +DT&& +writable_quaternion
::operator*=(const readable_quaternion& other) && +{ + this->operator*=(other); + return (DT&&) *this; +} + +template +template::value_type, + ScalarT>::type*> +DT& +writable_quaternion
::operator*=(const ScalarT& v) & +{ + using op_type = binary_multiply_t; + for(int i = 0; i < 4; ++i) this->put(i, op_type().apply(this->get(i), v)); + return this->actual(); +} + +template +template::value_type, + ScalarT>::type*> +DT&& +writable_quaternion
::operator*=(const ScalarT& v) && +{ + this->operator*=(v); + return (DT&&) *this; +} + +template +template::value_type, + ScalarT>::type*> +DT& +writable_quaternion
::operator/=(const ScalarT& v) & +{ + using op_type = binary_divide_t; + for(int i = 0; i < 4; ++i) this->put(i, op_type().apply(this->get(i), v)); + return this->actual(); +} + +template +template::value_type, + ScalarT>::type*> +DT&& +writable_quaternion
::operator/=(const ScalarT& v) && +{ + this->operator/=(v); + return (DT&&) *this; +} + +/* Internal methods: */ + +template +template +DT& +writable_quaternion
::assign(const readable_quaternion& other) +{ + this->put(W, other.get(W)); + this->put(X, other.get(X)); + this->put(Y, other.get(Y)); + this->put(Z, other.get(Z)); + return this->actual(); +} + +template +template +DT& +writable_quaternion
::assign(const readable_vector& other, const E0& e0) +{ + cml::check_size(other, cml::int_c<3>()); + this->put(W, e0); + this->put(X, other.get(0)); + this->put(Y, other.get(1)); + this->put(Z, other.get(2)); + return this->actual(); +} + +template +template*> +DT& +writable_quaternion
::assign(const Array& array) +{ + static const int N = array_size_of_c::value; + static_assert(N == 4, "incorrect quaternion expression size"); + this->put(W, array[W]); + this->put(X, array[X]); + this->put(Y, array[Y]); + this->put(Z, array[Z]); + return this->actual(); +} + +template +template*> +DT& +writable_quaternion
::assign(const Pointer& array) +{ + this->put(W, array[W]); + this->put(X, array[X]); + this->put(Y, array[Y]); + this->put(Z, array[Z]); + return this->actual(); +} + +template +template*> +DT& +writable_quaternion
::assign(const Array& array, const E0& e0) +{ + static const int N = array_size_of_c::value; + static_assert(N == 3, "incorrect quaternion expression size"); + this->put(W, e0); + this->put(X, array[0]); + this->put(Y, array[1]); + this->put(Z, array[2]); + return this->actual(); +} + +template +template +DT& +writable_quaternion
::assign(const std::initializer_list& l) +{ +#ifndef CML_NO_RUNTIME_QUATERNION_SIZE_CHECKS + cml_require(l.size() == 4, quaternion_size_error, /**/); +#endif + auto array = l.begin(); + this->put(W, array[W]); + this->put(X, array[X]); + this->put(Y, array[Y]); + this->put(Z, array[Z]); + return this->actual(); +} + +template +template +DT& +writable_quaternion
::assign_elements(const E0& e0, const E1& e1, + const E2& e2, const E3& e3) +{ + this->put(W, item_at(e0, e1, e2, e3)); + this->put(X, item_at(e0, e1, e2, e3)); + this->put(Y, item_at(e0, e1, e2, e3)); + this->put(Z, item_at(e0, e1, e2, e3)); + return this->actual(); +} + +} // namespace cml diff --git a/cml/scalar/binary_ops.h b/cml/scalar/binary_ops.h index d2a0c32..32e7387 100644 --- a/cml/scalar/binary_ops.h +++ b/cml/scalar/binary_ops.h @@ -1,65 +1,65 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { -namespace op { - -#define __cml_binary_op(_name_, _op_) \ - template struct _name_ \ - { \ - typedef value_type_trait_promote_t result_type; \ - result_type apply(const Scalar1& a, const Scalar2& b) const \ - { \ - return result_type(a _op_ b); \ - } \ - } - -/** Binary minus (subtraction). */ -__cml_binary_op(binary_minus, -); - -/** Binary plus (addition). */ -__cml_binary_op(binary_plus, +); - -/** Binary multiply. */ -__cml_binary_op(binary_multiply, *); - -/** Binary divide. */ -__cml_binary_op(binary_divide, /); - -#undef __cml_binary_op - -} // namespace op - -#define __cml_binary_op_alias(_name_) \ - template \ - using _name_##_t = op::_name_>, \ - value_type_trait_of_t>> - -/** Convenience alias to create binary_minus from the value_type traits of - * @c Sub1 and @c Sub2 as unqualified types. - */ -__cml_binary_op_alias(binary_minus); - -/** Convenience alias to create binary_plus from the value_type traits of - * @c Sub1 and @c Sub2 as unqualified types. - */ -__cml_binary_op_alias(binary_plus); - -/** Convenience alias to create binary_multiply from the value_type traits - * of @c Sub1 and @c Sub2 as unqualified types. - */ -__cml_binary_op_alias(binary_multiply); - -/** Convenience alias to create binary_divide from the value_type traits - * of @c Sub1 and @c Sub2 as unqualified types. - */ -__cml_binary_op_alias(binary_divide); - -#undef __cml_binary_op_alias -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { +namespace op { + +#define __cml_binary_op(_name_, _op_) \ + template struct _name_ \ + { \ + typedef value_type_trait_promote_t result_type; \ + result_type apply(const Scalar1& a, const Scalar2& b) const \ + { \ + return result_type(a _op_ b); \ + } \ + } + +/** Binary minus (subtraction). */ +__cml_binary_op(binary_minus, -); + +/** Binary plus (addition). */ +__cml_binary_op(binary_plus, +); + +/** Binary multiply. */ +__cml_binary_op(binary_multiply, *); + +/** Binary divide. */ +__cml_binary_op(binary_divide, /); + +#undef __cml_binary_op + +} // namespace op + +#define __cml_binary_op_alias(_name_) \ + template \ + using _name_##_t = op::_name_>, \ + value_type_trait_of_t>> + +/** Convenience alias to create binary_minus from the value_type traits of + * @c Sub1 and @c Sub2 as unqualified types. + */ +__cml_binary_op_alias(binary_minus); + +/** Convenience alias to create binary_plus from the value_type traits of + * @c Sub1 and @c Sub2 as unqualified types. + */ +__cml_binary_op_alias(binary_plus); + +/** Convenience alias to create binary_multiply from the value_type traits + * of @c Sub1 and @c Sub2 as unqualified types. + */ +__cml_binary_op_alias(binary_multiply); + +/** Convenience alias to create binary_divide from the value_type traits + * of @c Sub1 and @c Sub2 as unqualified types. + */ +__cml_binary_op_alias(binary_divide); + +#undef __cml_binary_op_alias +} // namespace cml diff --git a/cml/scalar/constants.h b/cml/scalar/constants.h index 8df1470..13b306e 100644 --- a/cml/scalar/constants.h +++ b/cml/scalar/constants.h @@ -1,56 +1,56 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -#if !defined(M_PI) -# define M_PI 3.14159265358979323846 -#endif - -#if !defined(M_SQRT2) -# define M_SQRT2 1.41421356237309504880 -#endif - -#if !defined(M_E) -# define M_E 2.71828182845904523536 -#endif - -namespace cml { - -/** Templated constants struct. - * - * Either float or double can be used. - */ -template struct constants -{ - static inline Float pi() { return Float(M_PI); } - - static inline Float two_pi() { return Float(2. * M_PI); } - - static inline Float inv_pi() { return Float(1. / M_PI); } - - static inline Float inv_two_pi() { return Float(1. / (2. * M_PI)); } - - static inline Float pi_over_2() { return Float(M_PI / 2.); } - - static inline Float pi_over_4() { return Float(M_PI / 4.); } - - static inline Float e() { return Float(M_E); } - - static inline Float deg_per_rad() { return Float(180. / M_PI); } - - static inline Float rad_per_deg() { return Float(M_PI / 180.); } - - static inline Float sqrt_2() { return Float(M_SQRT2); } - - static inline Float sqrt_3() { return Float(1.73205080756887729353); } - - static inline Float sqrt_5() { return Float(2.23606797749978969641); } - - static inline Float sqrt_6() { return Float(2.44948974278317809820); } -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +#if !defined(M_PI) +# define M_PI 3.14159265358979323846 +#endif + +#if !defined(M_SQRT2) +# define M_SQRT2 1.41421356237309504880 +#endif + +#if !defined(M_E) +# define M_E 2.71828182845904523536 +#endif + +namespace cml { + +/** Templated constants struct. + * + * Either float or double can be used. + */ +template struct constants +{ + static inline Float pi() { return Float(M_PI); } + + static inline Float two_pi() { return Float(2. * M_PI); } + + static inline Float inv_pi() { return Float(1. / M_PI); } + + static inline Float inv_two_pi() { return Float(1. / (2. * M_PI)); } + + static inline Float pi_over_2() { return Float(M_PI / 2.); } + + static inline Float pi_over_4() { return Float(M_PI / 4.); } + + static inline Float e() { return Float(M_E); } + + static inline Float deg_per_rad() { return Float(180. / M_PI); } + + static inline Float rad_per_deg() { return Float(M_PI / 180.); } + + static inline Float sqrt_2() { return Float(M_SQRT2); } + + static inline Float sqrt_3() { return Float(1.73205080756887729353); } + + static inline Float sqrt_5() { return Float(2.23606797749978969641); } + + static inline Float sqrt_6() { return Float(2.44948974278317809820); } +}; + +} // namespace cml diff --git a/cml/scalar/functions.h b/cml/scalar/functions.h index f701b73..63350ab 100644 --- a/cml/scalar/functions.h +++ b/cml/scalar/functions.h @@ -1,361 +1,361 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml { - -/** Sign (-1, 0, 1) of @c value as type @c T. */ -template -inline T -sign(T value) -{ - return value < T(0) ? (-T(1)) : (value > T(0) ? T(1) : T(0)); -} - -/** Clamp input value to the range [min, max]. */ -template -inline T -clamp(T value, T min, T max) -{ - return std::max((std::min)(value, max), min); -} - -/** Wrap input value to the range [min,max]. */ -template -inline T -wrap(T value, T min, T max) -{ - max -= min; - value = scalar_traits::fmod(value - min, max); - if(value < T(0)) { - value += max; - } - return min + value; -} - -/** Test input value for inclusion in [min, max]. */ -template -inline bool -in_range(T value, T min, T max) -{ - return !(value < min) && !(value > max); -} - -/** Map input value from [min1, max1] to [min2, max2]. */ -template -inline T -map_range(T value, T min1, T max1, T min2, T max2) -{ - return min2 + ((value - min1) / (max1 - min1)) * (max2 - min2); -} - -/** Wrap scalar_traits::acos() and clamp argument to [-1, 1]. */ -template -inline T -acos_safe(T theta) -{ - return T(scalar_traits::acos(clamp(theta, T(-1), T(1)))); -} - -/** Wrap scalar_traits::asin() and clamp argument to [-1, 1]. */ -template -inline T -asin_safe(T theta) -{ - return T(scalar_traits::asin(clamp(theta, T(-1), T(1)))); -} - -/** Wrap scalar_traits::sqrt() and clamp argument to [0, inf). */ -template -inline T -sqrt_safe(T value) -{ - return T(scalar_traits::sqrt(std::max(value, T(0)))); -} - -/** Square a value. */ -template -inline T -sqr(T value) -{ - return value * value; -} - -/** Cube a value. */ -template -inline T -cub(T value) -{ - return value * value * value; -} - -/** Inverse square root. */ -template -inline T -inv_sqrt(T value) -{ - return T(1) / scalar_traits::sqrt(value); -} - -/** Convert radians to degrees. */ -template -inline T -deg(T theta) -{ - return theta * constants::deg_per_rad(); -} - -/** Convert degrees to radians. */ -template -inline T -rad(T theta) -{ - return theta * constants::rad_per_deg(); -} - -/** Uniformly random integer in the range [min, max]. */ -template -inline T -random_integer(T min, T max) -{ - std::default_random_engine gen(std::rand()); - std::uniform_int_distribution dis(min, max); - return dis(gen); -} - -/** Uniformly random binary (0,1) value. */ -inline int -random_binary() -{ - return random_integer(0, 1); -} - -/** Uniformly random polar (-1,1) value. */ -inline int -random_polar() -{ - return random_binary() ? 1 : -1; -} - -/* Uniformly distributed random real number in the range [min, max] */ -template -inline T -random_real(T min, T max) -{ - std::default_random_engine gen(std::rand()); - std::uniform_real_distribution dis(min, max); - return dis(gen); -} - -/** Uniformly distributed random real in [0,1]. */ -inline double -random_unit() -{ - return random_real(0., 1.); -} - -/** Squared length in R2. */ -template -inline T -length_squared(T x, T y) -{ - return x * x + y * y; -} - -/** Squared length in R3. */ -template -inline T -length_squared(T x, T y, T z) -{ - return x * x + y * y + z * z; -} - -/** Length in R2. */ -template -inline T -length(T x, T y) -{ - return scalar_traits::sqrt(length_squared(x, y)); -} - -/** Length in R3. */ -template -inline T -length(T x, T y, T z) -{ - return scalar_traits::sqrt(length_squared(x, y, z)); -} - -/** @defgroup cml_scalar_indexing Indexing Functions - * - * The next few functions deal with indexing. next() and prev() are useful - * for operations involving the vertices of a polygon or other cyclic set, - * and cyclic_permutation() is used by various functions that deal with - * axes or basis vectors in a generic way. As these functions are only - * relevant for unsigned integer types, I've just used int, but there - * may be reasons I haven't thought of that they should be templated. - */ -/*@{*/ - -/** Return next, with cycling, in a series of N non-negative integers. */ -inline int -next(int i, int N) -{ - return (i + 1) % N; -} - -/** Return previous, with cycling, in a series of N non-negative integers. */ -inline int -prev(int i, int N) -{ - return i ? (i - 1) : (N - 1); -} - -/** Cyclic permutation of the set { 0, 1 }, starting with 'first'. */ -inline void -cyclic_permutation(int first, int& i, int& j) -{ - i = first; - j = next(i, 2); -} - -/** Cyclic permutation of the set { 0, 1, 2 }, starting with 'first'. */ -inline void -cyclic_permutation(int first, int& i, int& j, int& k) -{ - i = first; - j = next(i, 3); - k = next(j, 3); -} - -/** Cyclic permutation of the set { 0, 1, 2, 3 }, starting with 'first'. */ -inline void -cyclic_permutation(int first, int& i, int& j, int& k, int& l) -{ - i = first; - j = next(i, 4); - k = next(j, 4); - l = next(k, 4); -} - -/*@}*/ - - -/** Index of maximum of 2 values. */ -template -inline int -index_of_max(T a, T b) -{ - return a > b ? 0 : 1; -} - -/** Index of maximum of 2 values by magnitude. */ -template -inline int -index_of_max_abs(T a, T b) -{ - auto fabs = &scalar_traits::fabs; - return index_of_max(fabs(a), fabs(b)); -} - -/** Index of minimum of 2 values. */ -template -inline int -index_of_min(T a, T b) -{ - return a < b ? 0 : 1; -} - -/** Index of minimum of 2 values by magnitude. */ -template -inline int -index_of_min_abs(T a, T b) -{ - auto fabs = &scalar_traits::fabs; - return index_of_min(fabs(a), fabs(b)); -} - -/** Index of maximum of 3 values. */ -template -inline int -index_of_max(T a, T b, T c) -{ - return a > b ? (c > a ? 2 : 0) : (b > c ? 1 : 2); -} - -/** Index of maximum of 3 values by magnitude. */ -template -inline int -index_of_max_abs(T a, T b, T c) -{ - auto fabs = &scalar_traits::fabs; - return index_of_max(fabs(a), fabs(b), fabs(c)); -} - -/** Index of minimum of 3 values. */ -template -inline int -index_of_min(T a, T b, T c) -{ - return a < b ? (c < a ? 2 : 0) : (b < c ? 1 : 2); -} - -/** Index of minimum of 3 values by magnitude. */ -template -inline int -index_of_min_abs(T a, T b, T c) -{ - auto fabs = &scalar_traits::fabs; - return index_of_min(fabs(a), fabs(b), fabs(c)); -} - -/** Index of maximum of 4 values. */ -template -inline int -index_of_max(T a, T b, T c, T d) -{ - if(a > b) { - return (c > d) ? ((a > c) ? 0 : 2) : ((a > d) ? 0 : 3); - } else { - return (c > d) ? ((b > c) ? 1 : 2) : ((b > d) ? 1 : 3); - } -} - -/** Index of maximum of 4 values by magnitude. */ -template -inline int -index_of_max_abs(T a, T b, T c, T d) -{ - auto fabs = &scalar_traits::fabs; - return index_of_max(fabs(a), fabs(b), fabs(c), fabs(d)); -} - -/** Index of minimum of 3 values. */ -template -inline int -index_of_min(T a, T b, T c, T d) -{ - if(a < b) { - return (c < d) ? ((a < c) ? 0 : 2) : ((a < d) ? 0 : 3); - } else { - return (c < d) ? ((b < c) ? 1 : 2) : ((b < d) ? 1 : 3); - } -} - -/** Index of minimum of 4 values by magnitude. */ -template -inline int -index_of_min_abs(T a, T b, T c, T d) -{ - auto fabs = &scalar_traits::fabs; - return index_of_min(fabs(a), fabs(b), fabs(c), fabs(d)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml { + +/** Sign (-1, 0, 1) of @c value as type @c T. */ +template +inline T +sign(T value) +{ + return value < T(0) ? (-T(1)) : (value > T(0) ? T(1) : T(0)); +} + +/** Clamp input value to the range [min, max]. */ +template +inline T +clamp(T value, T min, T max) +{ + return std::max((std::min)(value, max), min); +} + +/** Wrap input value to the range [min,max]. */ +template +inline T +wrap(T value, T min, T max) +{ + max -= min; + value = scalar_traits::fmod(value - min, max); + if(value < T(0)) { + value += max; + } + return min + value; +} + +/** Test input value for inclusion in [min, max]. */ +template +inline bool +in_range(T value, T min, T max) +{ + return !(value < min) && !(value > max); +} + +/** Map input value from [min1, max1] to [min2, max2]. */ +template +inline T +map_range(T value, T min1, T max1, T min2, T max2) +{ + return min2 + ((value - min1) / (max1 - min1)) * (max2 - min2); +} + +/** Wrap scalar_traits::acos() and clamp argument to [-1, 1]. */ +template +inline T +acos_safe(T theta) +{ + return T(scalar_traits::acos(clamp(theta, T(-1), T(1)))); +} + +/** Wrap scalar_traits::asin() and clamp argument to [-1, 1]. */ +template +inline T +asin_safe(T theta) +{ + return T(scalar_traits::asin(clamp(theta, T(-1), T(1)))); +} + +/** Wrap scalar_traits::sqrt() and clamp argument to [0, inf). */ +template +inline T +sqrt_safe(T value) +{ + return T(scalar_traits::sqrt(std::max(value, T(0)))); +} + +/** Square a value. */ +template +inline T +sqr(T value) +{ + return value * value; +} + +/** Cube a value. */ +template +inline T +cub(T value) +{ + return value * value * value; +} + +/** Inverse square root. */ +template +inline T +inv_sqrt(T value) +{ + return T(1) / scalar_traits::sqrt(value); +} + +/** Convert radians to degrees. */ +template +inline T +deg(T theta) +{ + return theta * constants::deg_per_rad(); +} + +/** Convert degrees to radians. */ +template +inline T +rad(T theta) +{ + return theta * constants::rad_per_deg(); +} + +/** Uniformly random integer in the range [min, max]. */ +template +inline T +random_integer(T min, T max) +{ + std::default_random_engine gen(std::rand()); + std::uniform_int_distribution dis(min, max); + return dis(gen); +} + +/** Uniformly random binary (0,1) value. */ +inline int +random_binary() +{ + return random_integer(0, 1); +} + +/** Uniformly random polar (-1,1) value. */ +inline int +random_polar() +{ + return random_binary() ? 1 : -1; +} + +/* Uniformly distributed random real number in the range [min, max] */ +template +inline T +random_real(T min, T max) +{ + std::default_random_engine gen(std::rand()); + std::uniform_real_distribution dis(min, max); + return dis(gen); +} + +/** Uniformly distributed random real in [0,1]. */ +inline double +random_unit() +{ + return random_real(0., 1.); +} + +/** Squared length in R2. */ +template +inline T +length_squared(T x, T y) +{ + return x * x + y * y; +} + +/** Squared length in R3. */ +template +inline T +length_squared(T x, T y, T z) +{ + return x * x + y * y + z * z; +} + +/** Length in R2. */ +template +inline T +length(T x, T y) +{ + return scalar_traits::sqrt(length_squared(x, y)); +} + +/** Length in R3. */ +template +inline T +length(T x, T y, T z) +{ + return scalar_traits::sqrt(length_squared(x, y, z)); +} + +/** @defgroup cml_scalar_indexing Indexing Functions + * + * The next few functions deal with indexing. next() and prev() are useful + * for operations involving the vertices of a polygon or other cyclic set, + * and cyclic_permutation() is used by various functions that deal with + * axes or basis vectors in a generic way. As these functions are only + * relevant for unsigned integer types, I've just used int, but there + * may be reasons I haven't thought of that they should be templated. + */ +/*@{*/ + +/** Return next, with cycling, in a series of N non-negative integers. */ +inline int +next(int i, int N) +{ + return (i + 1) % N; +} + +/** Return previous, with cycling, in a series of N non-negative integers. */ +inline int +prev(int i, int N) +{ + return i ? (i - 1) : (N - 1); +} + +/** Cyclic permutation of the set { 0, 1 }, starting with 'first'. */ +inline void +cyclic_permutation(int first, int& i, int& j) +{ + i = first; + j = next(i, 2); +} + +/** Cyclic permutation of the set { 0, 1, 2 }, starting with 'first'. */ +inline void +cyclic_permutation(int first, int& i, int& j, int& k) +{ + i = first; + j = next(i, 3); + k = next(j, 3); +} + +/** Cyclic permutation of the set { 0, 1, 2, 3 }, starting with 'first'. */ +inline void +cyclic_permutation(int first, int& i, int& j, int& k, int& l) +{ + i = first; + j = next(i, 4); + k = next(j, 4); + l = next(k, 4); +} + +/*@}*/ + + +/** Index of maximum of 2 values. */ +template +inline int +index_of_max(T a, T b) +{ + return a > b ? 0 : 1; +} + +/** Index of maximum of 2 values by magnitude. */ +template +inline int +index_of_max_abs(T a, T b) +{ + auto fabs = &scalar_traits::fabs; + return index_of_max(fabs(a), fabs(b)); +} + +/** Index of minimum of 2 values. */ +template +inline int +index_of_min(T a, T b) +{ + return a < b ? 0 : 1; +} + +/** Index of minimum of 2 values by magnitude. */ +template +inline int +index_of_min_abs(T a, T b) +{ + auto fabs = &scalar_traits::fabs; + return index_of_min(fabs(a), fabs(b)); +} + +/** Index of maximum of 3 values. */ +template +inline int +index_of_max(T a, T b, T c) +{ + return a > b ? (c > a ? 2 : 0) : (b > c ? 1 : 2); +} + +/** Index of maximum of 3 values by magnitude. */ +template +inline int +index_of_max_abs(T a, T b, T c) +{ + auto fabs = &scalar_traits::fabs; + return index_of_max(fabs(a), fabs(b), fabs(c)); +} + +/** Index of minimum of 3 values. */ +template +inline int +index_of_min(T a, T b, T c) +{ + return a < b ? (c < a ? 2 : 0) : (b < c ? 1 : 2); +} + +/** Index of minimum of 3 values by magnitude. */ +template +inline int +index_of_min_abs(T a, T b, T c) +{ + auto fabs = &scalar_traits::fabs; + return index_of_min(fabs(a), fabs(b), fabs(c)); +} + +/** Index of maximum of 4 values. */ +template +inline int +index_of_max(T a, T b, T c, T d) +{ + if(a > b) { + return (c > d) ? ((a > c) ? 0 : 2) : ((a > d) ? 0 : 3); + } else { + return (c > d) ? ((b > c) ? 1 : 2) : ((b > d) ? 1 : 3); + } +} + +/** Index of maximum of 4 values by magnitude. */ +template +inline int +index_of_max_abs(T a, T b, T c, T d) +{ + auto fabs = &scalar_traits::fabs; + return index_of_max(fabs(a), fabs(b), fabs(c), fabs(d)); +} + +/** Index of minimum of 3 values. */ +template +inline int +index_of_min(T a, T b, T c, T d) +{ + if(a < b) { + return (c < d) ? ((a < c) ? 0 : 2) : ((a < d) ? 0 : 3); + } else { + return (c < d) ? ((b < c) ? 1 : 2) : ((b < d) ? 1 : 3); + } +} + +/** Index of minimum of 4 values by magnitude. */ +template +inline int +index_of_min_abs(T a, T b, T c, T d) +{ + auto fabs = &scalar_traits::fabs; + return index_of_min(fabs(a), fabs(b), fabs(c), fabs(d)); +} + +} // namespace cml diff --git a/cml/scalar/promotion.h b/cml/scalar/promotion.h index c73a05b..80dbd48 100644 --- a/cml/scalar/promotion.h +++ b/cml/scalar/promotion.h @@ -1,53 +1,53 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Use C++ type deduction via std::common_type to determine the result of - * combining N scalars. - */ -template using scalar_promote = std::common_type; - -/** Use C++ type deduction via std::common_type to determine the result of - * combining N scalars. - */ -template -using scalar_promote_t = typename scalar_promote::type; - -/** Helper to simplify scalar promotion from objects with a value_type - * typedef. - */ -template struct value_type_promote -{ - using type = typename scalar_promote...>::type; -}; -// XXX This could be a template alias, except VC++12 can't grok it. -// Moreover, without value_type_of_t, even this fails to compile... - -/** Convenience alias for value_type_trait_promote<>::type. */ -template -using value_type_promote_t = typename value_type_promote::type; - -/** Helper to simplify scalar promotion from objects that implement a - * traits class with a value_type typedef. - */ -template struct value_type_trait_promote -{ - using type = typename scalar_promote...>::type; -}; -// XXX This could be a template alias, except VC++12 can't grok it. -// Moreover, without value_type_trait_of_t, even this fails to -// compile... - -/** Convenience alias for value_type_trait_promote<>::type. */ -template -using value_type_trait_promote_t = - typename value_type_trait_promote::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Use C++ type deduction via std::common_type to determine the result of + * combining N scalars. + */ +template using scalar_promote = std::common_type; + +/** Use C++ type deduction via std::common_type to determine the result of + * combining N scalars. + */ +template +using scalar_promote_t = typename scalar_promote::type; + +/** Helper to simplify scalar promotion from objects with a value_type + * typedef. + */ +template struct value_type_promote +{ + using type = typename scalar_promote...>::type; +}; +// XXX This could be a template alias, except VC++12 can't grok it. +// Moreover, without value_type_of_t, even this fails to compile... + +/** Convenience alias for value_type_trait_promote<>::type. */ +template +using value_type_promote_t = typename value_type_promote::type; + +/** Helper to simplify scalar promotion from objects that implement a + * traits class with a value_type typedef. + */ +template struct value_type_trait_promote +{ + using type = typename scalar_promote...>::type; +}; +// XXX This could be a template alias, except VC++12 can't grok it. +// Moreover, without value_type_trait_of_t, even this fails to +// compile... + +/** Convenience alias for value_type_trait_promote<>::type. */ +template +using value_type_trait_promote_t = + typename value_type_trait_promote::type; + +} // namespace cml diff --git a/cml/scalar/traits.h b/cml/scalar/traits.h index 6cf6ad3..f7da715 100644 --- a/cml/scalar/traits.h +++ b/cml/scalar/traits.h @@ -1,236 +1,236 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace cml { -namespace detail { - -/** Inheritable default scalar traits for integral types. If - * scalar_traits<> is specialized for a particular type T, T must be - * default constructible and assignable. - * - * @note For the std:: numeric functions, @c Scalar is promoted to double - * by default. - * - * @note default_integral_traits inherits from std::numeric_limits by default. - */ -template -struct default_integral_traits : std::numeric_limits -{ - using value_type = Scalar; - using pointer = value_type*; - using reference = value_type&; - using const_pointer = value_type const*; - using const_reference = value_type const&; - using mutable_value = reference&; - using immutable_value = const_reference; - - /** @name Basic Functions */ - /*@{*/ - - static inline value_type fabs(const value_type& v) - { - return (value_type) std::fabs(double(v)); - } - - static inline value_type fmod(const value_type& v, const value_type& w) - { - return (value_type) std::fmod(double(v), double(w)); - } - - static constexpr value_type sqrt(const value_type& v) - { - return (value_type) std::sqrt(double(v)); - } - - static inline value_type cos(const value_type& v) - { - return (value_type) std::cos(double(v)); - } - - static inline value_type sin(const value_type& v) - { - return (value_type) std::sin(double(v)); - } - - static inline value_type tan(const value_type& v) - { - return (value_type) std::tan(double(v)); - } - - static inline value_type acos(const value_type& v) - { - return (value_type) std::acos(double(v)); - } - - static inline value_type asin(const value_type& v) - { - return (value_type) std::asin(double(v)); - } - - static inline value_type atan(const value_type& v) - { - return (value_type) std::atan(double(v)); - } - - static inline value_type atan2(const value_type& x, const value_type& y) - { - return (value_type) std::atan2(double(x), double(y)); - } - - static inline value_type log(const value_type& v) - { - return (value_type) std::log(double(v)); - } - - static inline value_type exp(const value_type& v) - { - return (value_type) std::exp(double(v)); - } - - /*@}*/ -}; - -/** Inheritable default scalar traits for floating point types. If - * scalar_traits<> is specialized for a particular type T, T must be - * default constructible and assignable. - * - * @note default_scalar_traits inherits from std::numeric_limits by default. - */ -template -struct default_floating_point_traits : std::numeric_limits -{ - using value_type = Scalar; - using pointer = value_type*; - using reference = value_type&; - using const_pointer = value_type const*; - using const_reference = value_type const&; - using mutable_value = reference&; - using immutable_value = const_reference; - - /** @name Basic Functions */ - /*@{*/ - - static inline value_type fabs(const value_type& v) { return std::fabs(v); } - - static inline value_type fmod(const value_type& v, const value_type& w) - { - return std::fmod(v, w); - } - - static constexpr value_type sqrt(const value_type& v) { return std::sqrt(v); } - - static inline value_type cos(const value_type& v) { return std::cos(v); } - - static inline value_type sin(const value_type& v) { return std::sin(v); } - - static inline value_type tan(const value_type& v) { return std::tan(v); } - - static inline value_type acos(const value_type& v) { return std::acos(v); } - - static inline value_type asin(const value_type& v) { return std::asin(v); } - - static inline value_type atan(const value_type& v) { return std::atan(v); } - - static inline value_type atan2(const value_type& x, const value_type& y) - { - return std::atan2(x, y); - } - - static inline value_type log(const value_type& v) { return std::log(v); } - - static inline value_type exp(const value_type& v) { return std::exp(v); } - - /*@}*/ -}; - -} // namespace detail - - -/** Specializable class aggregating scalar properties. */ -template struct scalar_traits; - -/** Specialization of scalar traits for integral types. */ -template -struct scalar_traits::value>::type> -: detail::default_integral_traits -{ - /** Returns 0. */ - static constexpr Scalar sqrt_epsilon() { return 0; } -}; - -/** Specialization of scalar_traits for floating-point types. */ -template -struct scalar_traits::value>::type> -: detail::default_floating_point_traits -{ - /** Returns sqrt(numeric_limits::epsilon()). */ - static constexpr double sqrt_epsilon() - { - return detail::default_floating_point_traits::sqrt( - std::numeric_limits::epsilon()); - } -}; - -/** Specialization of scalar_traits for float. */ -template<> -struct scalar_traits : detail::default_floating_point_traits -{ - /** Returns a constant for sqrt(numeric_limits::epsilon()). */ - static constexpr float sqrt_epsilon() - { - return 3.452669831e-4f; // 10 digits - } -}; - -/** Specialization of scalar_traits for double. */ -template<> -struct scalar_traits : detail::default_floating_point_traits -{ - /** Returns a constant for sqrt(numeric_limits::epsilon()). */ - static constexpr double sqrt_epsilon() - { - return 1.49011611938476563e-8; // 18 digits - } -}; - -/** Returns eps for type S. */ -template -constexpr S -epsilon() -{ - return scalar_traits::epsilon(); -} - -/** Returns sqrt(eps) for type S. */ -template -constexpr S -sqrt_epsilon() -{ - return scalar_traits::sqrt_epsilon(); -} - -/** traits_of for arithmetic scalars. */ -template struct traits_of> -{ - using type = scalar_traits; -}; - -/** temporary_of for arithmetic scalars. */ -template -struct temporary_of> -{ - using type = cml::value_type_trait_of_t; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace cml { +namespace detail { + +/** Inheritable default scalar traits for integral types. If + * scalar_traits<> is specialized for a particular type T, T must be + * default constructible and assignable. + * + * @note For the std:: numeric functions, @c Scalar is promoted to double + * by default. + * + * @note default_integral_traits inherits from std::numeric_limits by default. + */ +template +struct default_integral_traits : std::numeric_limits +{ + using value_type = Scalar; + using pointer = value_type*; + using reference = value_type&; + using const_pointer = value_type const*; + using const_reference = value_type const&; + using mutable_value = reference&; + using immutable_value = const_reference; + + /** @name Basic Functions */ + /*@{*/ + + static inline value_type fabs(const value_type& v) + { + return (value_type) std::fabs(double(v)); + } + + static inline value_type fmod(const value_type& v, const value_type& w) + { + return (value_type) std::fmod(double(v), double(w)); + } + + static constexpr value_type sqrt(const value_type& v) + { + return (value_type) std::sqrt(double(v)); + } + + static inline value_type cos(const value_type& v) + { + return (value_type) std::cos(double(v)); + } + + static inline value_type sin(const value_type& v) + { + return (value_type) std::sin(double(v)); + } + + static inline value_type tan(const value_type& v) + { + return (value_type) std::tan(double(v)); + } + + static inline value_type acos(const value_type& v) + { + return (value_type) std::acos(double(v)); + } + + static inline value_type asin(const value_type& v) + { + return (value_type) std::asin(double(v)); + } + + static inline value_type atan(const value_type& v) + { + return (value_type) std::atan(double(v)); + } + + static inline value_type atan2(const value_type& x, const value_type& y) + { + return (value_type) std::atan2(double(x), double(y)); + } + + static inline value_type log(const value_type& v) + { + return (value_type) std::log(double(v)); + } + + static inline value_type exp(const value_type& v) + { + return (value_type) std::exp(double(v)); + } + + /*@}*/ +}; + +/** Inheritable default scalar traits for floating point types. If + * scalar_traits<> is specialized for a particular type T, T must be + * default constructible and assignable. + * + * @note default_scalar_traits inherits from std::numeric_limits by default. + */ +template +struct default_floating_point_traits : std::numeric_limits +{ + using value_type = Scalar; + using pointer = value_type*; + using reference = value_type&; + using const_pointer = value_type const*; + using const_reference = value_type const&; + using mutable_value = reference&; + using immutable_value = const_reference; + + /** @name Basic Functions */ + /*@{*/ + + static inline value_type fabs(const value_type& v) { return std::fabs(v); } + + static inline value_type fmod(const value_type& v, const value_type& w) + { + return std::fmod(v, w); + } + + static constexpr value_type sqrt(const value_type& v) { return std::sqrt(v); } + + static inline value_type cos(const value_type& v) { return std::cos(v); } + + static inline value_type sin(const value_type& v) { return std::sin(v); } + + static inline value_type tan(const value_type& v) { return std::tan(v); } + + static inline value_type acos(const value_type& v) { return std::acos(v); } + + static inline value_type asin(const value_type& v) { return std::asin(v); } + + static inline value_type atan(const value_type& v) { return std::atan(v); } + + static inline value_type atan2(const value_type& x, const value_type& y) + { + return std::atan2(x, y); + } + + static inline value_type log(const value_type& v) { return std::log(v); } + + static inline value_type exp(const value_type& v) { return std::exp(v); } + + /*@}*/ +}; + +} // namespace detail + + +/** Specializable class aggregating scalar properties. */ +template struct scalar_traits; + +/** Specialization of scalar traits for integral types. */ +template +struct scalar_traits::value>::type> +: detail::default_integral_traits +{ + /** Returns 0. */ + static constexpr Scalar sqrt_epsilon() { return 0; } +}; + +/** Specialization of scalar_traits for floating-point types. */ +template +struct scalar_traits::value>::type> +: detail::default_floating_point_traits +{ + /** Returns sqrt(numeric_limits::epsilon()). */ + static constexpr double sqrt_epsilon() + { + return detail::default_floating_point_traits::sqrt( + std::numeric_limits::epsilon()); + } +}; + +/** Specialization of scalar_traits for float. */ +template<> +struct scalar_traits : detail::default_floating_point_traits +{ + /** Returns a constant for sqrt(numeric_limits::epsilon()). */ + static constexpr float sqrt_epsilon() + { + return 3.452669831e-4f; // 10 digits + } +}; + +/** Specialization of scalar_traits for double. */ +template<> +struct scalar_traits : detail::default_floating_point_traits +{ + /** Returns a constant for sqrt(numeric_limits::epsilon()). */ + static constexpr double sqrt_epsilon() + { + return 1.49011611938476563e-8; // 18 digits + } +}; + +/** Returns eps for type S. */ +template +constexpr S +epsilon() +{ + return scalar_traits::epsilon(); +} + +/** Returns sqrt(eps) for type S. */ +template +constexpr S +sqrt_epsilon() +{ + return scalar_traits::sqrt_epsilon(); +} + +/** traits_of for arithmetic scalars. */ +template struct traits_of> +{ + using type = scalar_traits; +}; + +/** temporary_of for arithmetic scalars. */ +template +struct temporary_of> +{ + using type = cml::value_type_trait_of_t; +}; + +} // namespace cml diff --git a/cml/scalar/unary_ops.h b/cml/scalar/unary_ops.h index fbdbc0d..a8e5447 100644 --- a/cml/scalar/unary_ops.h +++ b/cml/scalar/unary_ops.h @@ -1,47 +1,47 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { -namespace op { - -/** Unary minus (negation). */ -template struct unary_minus -{ - using value_type = value_type_trait_of_t; - using result_type = decltype(-value_type()); - - result_type apply(const value_type& v) const { return -v; } -}; - -/** Unary plus. */ -template struct unary_plus -{ - using value_type = value_type_trait_of_t; - using result_type = decltype(+value_type()); - - result_type apply(const value_type& v) const { return +v; } -}; - -} // namespace op - -/** Convenience alias to create unary_minus from the value_type trait of - * @c Sub as an unqualified type. - */ -template -using unary_minus_t = - op::unary_minus>>; - -/** Convenience alias to create unary_plus from the value_type trait of - * @c Sub as an unqualified type. - */ -template -using unary_plus_t = - op::unary_plus>>; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { +namespace op { + +/** Unary minus (negation). */ +template struct unary_minus +{ + using value_type = value_type_trait_of_t; + using result_type = decltype(-value_type()); + + result_type apply(const value_type& v) const { return -v; } +}; + +/** Unary plus. */ +template struct unary_plus +{ + using value_type = value_type_trait_of_t; + using result_type = decltype(+value_type()); + + result_type apply(const value_type& v) const { return +v; } +}; + +} // namespace op + +/** Convenience alias to create unary_minus from the value_type trait of + * @c Sub as an unqualified type. + */ +template +using unary_minus_t = + op::unary_minus>>; + +/** Convenience alias to create unary_plus from the value_type trait of + * @c Sub as an unqualified type. + */ +template +using unary_plus_t = + op::unary_plus>>; + +} // namespace cml diff --git a/cml/storage/allocated_selector.h b/cml/storage/allocated_selector.h index 97f028e..84e2ec5 100644 --- a/cml/storage/allocated_selector.h +++ b/cml/storage/allocated_selector.h @@ -1,247 +1,247 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -// XXX Temporary, for fixed-size allocated proxies: -#include - -namespace cml { - -/* Forward declarations: */ -template, int Size1 = -1, - int Size2 = -1, class Tag = void> -struct allocated; - -/** Base selector to choose dynamically-allocated types (types with runtime - * storage and either fixed or dynamic size). - * - * @tparam Size1 First dimension size. - * - * @tparam Size2 Second dimension size. - * - * @tparam Allocator Optional allocator type that must be compatible with - * std::allocator. The default is std::allocator. - * - * @tparam Tag Tag specifying the type of storage (e.g. - * vector_storage_tag). This is set by instantiating @c rebind with the - * required tag. - */ -template -struct allocated -{ - /** Rebind the base selector to the required type. */ - template struct rebind - { - using other = allocated; - }; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - using type = allocated; - }; - - /** Make a partially bound selector with size @c R x @c C. */ - template struct reshape - { - using type = allocated; - }; -}; - -/** Specialized selector for dynamically-allocated vectors. */ -template -struct allocated -{ - using selector_type = allocated<>; - using unbound_type = allocated; - using proxy_type = allocated; - using storage_tag = vector_storage_tag; - using size_tag = dynamic_size_tag; - using memory_tag = allocated_memory_tag; - - /** Unspecified array size. */ - static const int array_size = -1; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - using type = allocated; - }; -}; - -/** Specialized selector for dynamically-allocated, fixed-size vectors. - * - * @todo Fixed-size allocated types are not actually implemented by CML, so - * the proxy_type is set to compiled. - */ -template -struct allocated -{ - using selector_type = allocated<>; - using unbound_type = allocated; - //XXX typedef allocated proxy_type; - using proxy_type = compiled; - using storage_tag = vector_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = allocated_memory_tag; - - /** Constant for the array size. */ - static const int array_size = Size; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - using type = allocated; - }; -}; - -/** Specialized selector for dynamically-allocated matrices. */ -template -struct allocated -{ - using selector_type = allocated<>; - using unbound_type = allocated; - using proxy_type = allocated; - using storage_tag = matrix_storage_tag; - using size_tag = dynamic_size_tag; - using memory_tag = allocated_memory_tag; - - /** Unspecified array rows. */ - static const int array_rows = -1; - - /** Unspecified array columns. */ - static const int array_cols = -1; - - /** Make a partially bound selector with size @c R x @c C. */ - template struct reshape - { - using type = allocated; - }; -}; - -/** Specialized selector for dynamically-allocated, fixed-size matrices. - * - * @todo Fixed-size allocated types are not actually implemented by CML, so - * the proxy_type is set to compiled. - */ -template -struct allocated -{ - using selector_type = allocated<>; - using unbound_type = allocated; - //XXX typedef allocated proxy_type; - using proxy_type = compiled; - using storage_tag = matrix_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = allocated_memory_tag; - - /** Constant for the number of array rows. */ - static const int array_rows = Size1; - - /** Constant for the number of array columns. */ - static const int array_cols = Size2; - - /** Make a partially bound selector with size @c R x @c C. */ - template struct resize - { - using type = allocated; - }; -}; - -/** Specialized selector for dynamically-allocated quaternions. - * - * @todo Fixed-size allocated types are not actually implemented by CML, so - * the proxy_type is set to compiled. - */ -template -struct allocated -{ - using selector_type = allocated<>; - using unbound_type = allocated; - //XXX typedef allocated proxy_type; - using proxy_type = compiled<4>; - using storage_tag = quaternion_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = allocated_memory_tag; - - /** Constant for the array size. */ - static const int array_size = 4; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - static_assert(N == 4, "invalid quaternion storage size"); - using type = allocated; - }; -}; - -/** is_storage_selector for allocated<>. */ -template -struct is_storage_selector> -{ - static const bool value = true; -}; - -/** Determine an unbound allocated<> storage type using an allocator that - * best represents the combination of the passed-in allocators. If the - * best allocator cannot be determined, std::allocator<> is used. - * - * @note This can be specialized for user-defined allocators if the default - * disambiguation strategy fails to yield the proper type. - */ -template -struct storage_disambiguate, - allocated> -{ - /* Rebind the allocators to void* to compare them: */ - using left_traits = std::allocator_traits; - using right_traits = std::allocator_traits; - using left_type = typename left_traits::template rebind_alloc; - using right_type = typename right_traits::template rebind_alloc; - - /* True if the unbound allocators are the same: */ - static const bool is_same = std::is_same::value; - - /* True if the left and/or right allocators are the default: */ - static const bool left_is_default = - std::is_same>::value; - static const bool right_is_default = - std::is_same>::value; - - /* Prefer the left allocator if it is not the default allocator: */ - static const bool prefer_left = !left_is_default && right_is_default; - - /* Prefer the right allocator if it is not the default allocator: */ - static const bool prefer_right = !right_is_default && left_is_default; - - /* Use std::allocator<> if the best cannot be determined: */ - static const bool prefer_default = !(is_same || prefer_left || prefer_right); - static_assert(is_same || prefer_left || prefer_right || prefer_default, - "unexpected storage_disambiguate result"); - - /* Determine the preferred allocator type: */ - using allocator_type = cml::if_t>>>; - - /* Build the disambiguated unbound storage type: */ - using type = allocated; -}; - - -/** For compatibility with CML1. */ -template> -using dynamic = allocated; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +// XXX Temporary, for fixed-size allocated proxies: +#include + +namespace cml { + +/* Forward declarations: */ +template, int Size1 = -1, + int Size2 = -1, class Tag = void> +struct allocated; + +/** Base selector to choose dynamically-allocated types (types with runtime + * storage and either fixed or dynamic size). + * + * @tparam Size1 First dimension size. + * + * @tparam Size2 Second dimension size. + * + * @tparam Allocator Optional allocator type that must be compatible with + * std::allocator. The default is std::allocator. + * + * @tparam Tag Tag specifying the type of storage (e.g. + * vector_storage_tag). This is set by instantiating @c rebind with the + * required tag. + */ +template +struct allocated +{ + /** Rebind the base selector to the required type. */ + template struct rebind + { + using other = allocated; + }; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + using type = allocated; + }; + + /** Make a partially bound selector with size @c R x @c C. */ + template struct reshape + { + using type = allocated; + }; +}; + +/** Specialized selector for dynamically-allocated vectors. */ +template +struct allocated +{ + using selector_type = allocated<>; + using unbound_type = allocated; + using proxy_type = allocated; + using storage_tag = vector_storage_tag; + using size_tag = dynamic_size_tag; + using memory_tag = allocated_memory_tag; + + /** Unspecified array size. */ + static const int array_size = -1; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + using type = allocated; + }; +}; + +/** Specialized selector for dynamically-allocated, fixed-size vectors. + * + * @todo Fixed-size allocated types are not actually implemented by CML, so + * the proxy_type is set to compiled. + */ +template +struct allocated +{ + using selector_type = allocated<>; + using unbound_type = allocated; + //XXX typedef allocated proxy_type; + using proxy_type = compiled; + using storage_tag = vector_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = allocated_memory_tag; + + /** Constant for the array size. */ + static const int array_size = Size; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + using type = allocated; + }; +}; + +/** Specialized selector for dynamically-allocated matrices. */ +template +struct allocated +{ + using selector_type = allocated<>; + using unbound_type = allocated; + using proxy_type = allocated; + using storage_tag = matrix_storage_tag; + using size_tag = dynamic_size_tag; + using memory_tag = allocated_memory_tag; + + /** Unspecified array rows. */ + static const int array_rows = -1; + + /** Unspecified array columns. */ + static const int array_cols = -1; + + /** Make a partially bound selector with size @c R x @c C. */ + template struct reshape + { + using type = allocated; + }; +}; + +/** Specialized selector for dynamically-allocated, fixed-size matrices. + * + * @todo Fixed-size allocated types are not actually implemented by CML, so + * the proxy_type is set to compiled. + */ +template +struct allocated +{ + using selector_type = allocated<>; + using unbound_type = allocated; + //XXX typedef allocated proxy_type; + using proxy_type = compiled; + using storage_tag = matrix_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = allocated_memory_tag; + + /** Constant for the number of array rows. */ + static const int array_rows = Size1; + + /** Constant for the number of array columns. */ + static const int array_cols = Size2; + + /** Make a partially bound selector with size @c R x @c C. */ + template struct resize + { + using type = allocated; + }; +}; + +/** Specialized selector for dynamically-allocated quaternions. + * + * @todo Fixed-size allocated types are not actually implemented by CML, so + * the proxy_type is set to compiled. + */ +template +struct allocated +{ + using selector_type = allocated<>; + using unbound_type = allocated; + //XXX typedef allocated proxy_type; + using proxy_type = compiled<4>; + using storage_tag = quaternion_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = allocated_memory_tag; + + /** Constant for the array size. */ + static const int array_size = 4; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + static_assert(N == 4, "invalid quaternion storage size"); + using type = allocated; + }; +}; + +/** is_storage_selector for allocated<>. */ +template +struct is_storage_selector> +{ + static const bool value = true; +}; + +/** Determine an unbound allocated<> storage type using an allocator that + * best represents the combination of the passed-in allocators. If the + * best allocator cannot be determined, std::allocator<> is used. + * + * @note This can be specialized for user-defined allocators if the default + * disambiguation strategy fails to yield the proper type. + */ +template +struct storage_disambiguate, + allocated> +{ + /* Rebind the allocators to void* to compare them: */ + using left_traits = std::allocator_traits; + using right_traits = std::allocator_traits; + using left_type = typename left_traits::template rebind_alloc; + using right_type = typename right_traits::template rebind_alloc; + + /* True if the unbound allocators are the same: */ + static const bool is_same = std::is_same::value; + + /* True if the left and/or right allocators are the default: */ + static const bool left_is_default = + std::is_same>::value; + static const bool right_is_default = + std::is_same>::value; + + /* Prefer the left allocator if it is not the default allocator: */ + static const bool prefer_left = !left_is_default && right_is_default; + + /* Prefer the right allocator if it is not the default allocator: */ + static const bool prefer_right = !right_is_default && left_is_default; + + /* Use std::allocator<> if the best cannot be determined: */ + static const bool prefer_default = !(is_same || prefer_left || prefer_right); + static_assert(is_same || prefer_left || prefer_right || prefer_default, + "unexpected storage_disambiguate result"); + + /* Determine the preferred allocator type: */ + using allocator_type = cml::if_t>>>; + + /* Build the disambiguated unbound storage type: */ + using type = allocated; +}; + + +/** For compatibility with CML1. */ +template> +using dynamic = allocated; + +} // namespace cml diff --git a/cml/storage/any_selector.h b/cml/storage/any_selector.h index 0afb727..20f8e47 100644 --- a/cml/storage/any_selector.h +++ b/cml/storage/any_selector.h @@ -1,134 +1,134 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml { - -/** Base selector to specify an arbitrary or unknown storage type. - * - * @tparam Tag Tag specifying the type of storage (e.g. - * vector_storage_tag). This is set by instantiating @c rebind with the - * required tag. - */ -template struct any_storage -{ - /** Rebind the base selector to the required type. */ - template struct rebind - { - using other = any_storage; - }; - - /** Make a partially bound selector by resizing. The new size is ignored - * for any_storage<>. - */ - template struct resize - { - using type = any_storage<>; - }; - - /** Make a partially bound selector by reshaping. The new shape is ignored - * for any_storage<>. - */ - template struct reshape - { - using type = any_storage<>; - }; -}; - -/** Specialized selector for any vector storage. */ -template<> struct any_storage -{ - using selector_type = any_storage<>; - using unbound_type = any_storage<>; - using proxy_type = any_storage<>; - using storage_tag = vector_storage_tag; - using size_tag = any_size_tag; - using memory_tag = any_memory_tag; - - /** Unspecified array size. */ - static const int array_size = -1; - - /** Rebind to a new vector any_storage<> selector (the template parameter - * is ignored). - */ - template struct resize - { - using type = any_storage<>; - }; -}; - -/** Specialized selector for any matrix storage. */ -template<> struct any_storage -{ - using selector_type = any_storage<>; - using unbound_type = any_storage<>; - using proxy_type = any_storage<>; - using storage_tag = matrix_storage_tag; - using size_tag = any_size_tag; - using memory_tag = any_memory_tag; - - /** Unspecified number of array rows. */ - static const int array_rows = -1; - - /** Unspecified number of array columns. */ - static const int array_cols = -1; - - /** Rebind to a new matrix any_storage<> selector (the template - * parameters are ignored). - */ - template struct reshape - { - using type = any_storage<>; - }; -}; - -/** Specialized selector for any quaternion storage. */ -template<> struct any_storage -{ - using selector_type = any_storage<>; - using unbound_type = any_storage<>; - using proxy_type = any_storage<>; - using storage_tag = quaternion_storage_tag; - using size_tag = any_size_tag; - using memory_tag = any_memory_tag; - - /** Unspecified array size. */ - static const int array_size = -1; - - /** Rebind to a new vector any_storage<> selector (the template parameter - * is ignored). - */ - template struct resize - { - using type = any_storage<>; - }; -}; - -/** is_storage_selector for any_storage<>. */ -template struct is_storage_selector> -{ - static const bool value = true; -}; - -/** Helper to detect any_storage<> types. */ -template struct is_any_storage -{ - static const bool value = - std::is_same>::value; -}; - -/** Helper to disambiguate any_storage<> types. */ -template -struct storage_disambiguate, any_storage> -{ - using type = any_storage<>; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml { + +/** Base selector to specify an arbitrary or unknown storage type. + * + * @tparam Tag Tag specifying the type of storage (e.g. + * vector_storage_tag). This is set by instantiating @c rebind with the + * required tag. + */ +template struct any_storage +{ + /** Rebind the base selector to the required type. */ + template struct rebind + { + using other = any_storage; + }; + + /** Make a partially bound selector by resizing. The new size is ignored + * for any_storage<>. + */ + template struct resize + { + using type = any_storage<>; + }; + + /** Make a partially bound selector by reshaping. The new shape is ignored + * for any_storage<>. + */ + template struct reshape + { + using type = any_storage<>; + }; +}; + +/** Specialized selector for any vector storage. */ +template<> struct any_storage +{ + using selector_type = any_storage<>; + using unbound_type = any_storage<>; + using proxy_type = any_storage<>; + using storage_tag = vector_storage_tag; + using size_tag = any_size_tag; + using memory_tag = any_memory_tag; + + /** Unspecified array size. */ + static const int array_size = -1; + + /** Rebind to a new vector any_storage<> selector (the template parameter + * is ignored). + */ + template struct resize + { + using type = any_storage<>; + }; +}; + +/** Specialized selector for any matrix storage. */ +template<> struct any_storage +{ + using selector_type = any_storage<>; + using unbound_type = any_storage<>; + using proxy_type = any_storage<>; + using storage_tag = matrix_storage_tag; + using size_tag = any_size_tag; + using memory_tag = any_memory_tag; + + /** Unspecified number of array rows. */ + static const int array_rows = -1; + + /** Unspecified number of array columns. */ + static const int array_cols = -1; + + /** Rebind to a new matrix any_storage<> selector (the template + * parameters are ignored). + */ + template struct reshape + { + using type = any_storage<>; + }; +}; + +/** Specialized selector for any quaternion storage. */ +template<> struct any_storage +{ + using selector_type = any_storage<>; + using unbound_type = any_storage<>; + using proxy_type = any_storage<>; + using storage_tag = quaternion_storage_tag; + using size_tag = any_size_tag; + using memory_tag = any_memory_tag; + + /** Unspecified array size. */ + static const int array_size = -1; + + /** Rebind to a new vector any_storage<> selector (the template parameter + * is ignored). + */ + template struct resize + { + using type = any_storage<>; + }; +}; + +/** is_storage_selector for any_storage<>. */ +template struct is_storage_selector> +{ + static const bool value = true; +}; + +/** Helper to detect any_storage<> types. */ +template struct is_any_storage +{ + static const bool value = + std::is_same>::value; +}; + +/** Helper to disambiguate any_storage<> types. */ +template +struct storage_disambiguate, any_storage> +{ + using type = any_storage<>; +}; + +} // namespace cml diff --git a/cml/storage/compiled_selector.h b/cml/storage/compiled_selector.h index ee67bfc..0949a44 100644 --- a/cml/storage/compiled_selector.h +++ b/cml/storage/compiled_selector.h @@ -1,129 +1,129 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml { - -/* Forward declarations: */ -template struct compiled; - -/** Base selector to choose compiled storage types. - * - * @tparam Size1 First dimension size. - * - * @tparam Size2 Second dimension size. - * - * @tparam Tag Tag specifying the type of storage (e.g. - * vector_storage_tag). This is set by instantiating @c rebind with the - * required tag. - */ -template struct compiled -{ - /** Rebind the base selector to the required type. */ - template struct rebind - { - using other = compiled; - }; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - using type = compiled; - }; - - /** Make a partially bound selector with size @c R x @c C. */ - template struct reshape - { - using type = compiled; - }; -}; - -/** Specialized selector for fixed-size compiled vectors. */ -template struct compiled -{ - using selector_type = compiled<>; - using unbound_type = compiled<>; - using proxy_type = compiled; - using storage_tag = vector_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = compiled_memory_tag; - - /** Constant for the array size. */ - static const int array_size = Size; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - using type = compiled; - }; -}; - -/** Specialized selector for fixed-size compiled matrices. */ -template struct compiled -{ - using selector_type = compiled<>; - using unbound_type = compiled<>; - using proxy_type = compiled; - using storage_tag = matrix_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = compiled_memory_tag; - - /** Constant for the number of array rows. */ - static const int array_rows = Size1; - - /** Constant for the number of array columns. */ - static const int array_cols = Size2; - - /** Make a partially bound selector with size @c R x @c C. */ - template struct reshape - { - using type = compiled; - }; -}; - -/** Specialized selector for quaternions. */ -template<> struct compiled<4, -1, quaternion_storage_tag> -{ - using selector_type = compiled<>; - using unbound_type = compiled<>; - using proxy_type = compiled<>; - using storage_tag = quaternion_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = compiled_memory_tag; - - /** Constant for the array size. */ - static const int array_size = 4; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - static_assert(N == 4, "invalid quaternion storage size"); - using type = compiled<4>; - }; -}; - -/** is_storage_selector for compiled<>. */ -template -struct is_storage_selector> -{ - static const bool value = true; -}; - -/** Helper to disambiguate compiled<> types. */ -template -struct storage_disambiguate, compiled> -{ - using type = compiled<>; -}; - -/** For compatibility with CML1. */ -template using fixed = compiled; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml { + +/* Forward declarations: */ +template struct compiled; + +/** Base selector to choose compiled storage types. + * + * @tparam Size1 First dimension size. + * + * @tparam Size2 Second dimension size. + * + * @tparam Tag Tag specifying the type of storage (e.g. + * vector_storage_tag). This is set by instantiating @c rebind with the + * required tag. + */ +template struct compiled +{ + /** Rebind the base selector to the required type. */ + template struct rebind + { + using other = compiled; + }; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + using type = compiled; + }; + + /** Make a partially bound selector with size @c R x @c C. */ + template struct reshape + { + using type = compiled; + }; +}; + +/** Specialized selector for fixed-size compiled vectors. */ +template struct compiled +{ + using selector_type = compiled<>; + using unbound_type = compiled<>; + using proxy_type = compiled; + using storage_tag = vector_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = compiled_memory_tag; + + /** Constant for the array size. */ + static const int array_size = Size; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + using type = compiled; + }; +}; + +/** Specialized selector for fixed-size compiled matrices. */ +template struct compiled +{ + using selector_type = compiled<>; + using unbound_type = compiled<>; + using proxy_type = compiled; + using storage_tag = matrix_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = compiled_memory_tag; + + /** Constant for the number of array rows. */ + static const int array_rows = Size1; + + /** Constant for the number of array columns. */ + static const int array_cols = Size2; + + /** Make a partially bound selector with size @c R x @c C. */ + template struct reshape + { + using type = compiled; + }; +}; + +/** Specialized selector for quaternions. */ +template<> struct compiled<4, -1, quaternion_storage_tag> +{ + using selector_type = compiled<>; + using unbound_type = compiled<>; + using proxy_type = compiled<>; + using storage_tag = quaternion_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = compiled_memory_tag; + + /** Constant for the array size. */ + static const int array_size = 4; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + static_assert(N == 4, "invalid quaternion storage size"); + using type = compiled<4>; + }; +}; + +/** is_storage_selector for compiled<>. */ +template +struct is_storage_selector> +{ + static const bool value = true; +}; + +/** Helper to disambiguate compiled<> types. */ +template +struct storage_disambiguate, compiled> +{ + using type = compiled<>; +}; + +/** For compatibility with CML1. */ +template using fixed = compiled; + +} // namespace cml diff --git a/cml/storage/external_selector.h b/cml/storage/external_selector.h index 7f6a51a..c2d2918 100644 --- a/cml/storage/external_selector.h +++ b/cml/storage/external_selector.h @@ -1,168 +1,168 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/* Forward declarations: */ -template struct external; - -/** Base selector to choose storage types that wrap a pointer or reference - * to array data. - * - * @tparam Size1 First dimension size. - * - * @tparam Size2 Second dimension size. - * - * @tparam Tag Tag specifying the type of storage (e.g. - * vector_storage_tag). This is set by instantiating @c rebind with the - * required tag. - */ -template struct external -{ - /** Rebind the base selector to the required type. */ - template struct rebind - { - using other = external; - }; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - using type = external; - }; - - /** Make a partially bound selector with size @c R x @c C. */ - template struct reshape - { - using type = external; - }; -}; - -/** Specialized selector for dynamic-size external vectors. */ -template<> struct external<-1, -1, vector_storage_tag> -{ - using selector_type = external<>; - using unbound_type = external<>; - using proxy_type = allocated<>; - using storage_tag = vector_storage_tag; - using size_tag = dynamic_size_tag; - using memory_tag = external_memory_tag; - - /** Unspecified array size. */ - static const int array_size = -1; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - using type = external; - }; -}; - -/** Specialized selector for fixed-size external vectors. */ -template struct external -{ - using selector_type = external<>; - using unbound_type = external<>; - using proxy_type = compiled; - using storage_tag = vector_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = external_memory_tag; - - /** Constant for the array size. */ - static const int array_size = Size; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - using type = external; - }; -}; - -/** Specialized selector for dynamic-size external matrices. */ -template<> struct external<-1, -1, matrix_storage_tag> -{ - using selector_type = external<>; - using unbound_type = external<>; - using proxy_type = allocated<>; - using storage_tag = matrix_storage_tag; - using size_tag = dynamic_size_tag; - using memory_tag = external_memory_tag; - - /** Unspecified array rows. */ - static const int array_rows = -1; - - /** Unspecified array columns. */ - static const int array_cols = -1; - - /** Make a partially bound selector with size @c R x @c C. */ - template struct reshape - { - using type = external; - }; -}; - -/** Specialized selector for fixed-size external matrices. */ -template struct external -{ - using selector_type = external<>; - using unbound_type = external<>; - using proxy_type = compiled; - using storage_tag = matrix_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = external_memory_tag; - - /** Constant for the number of array rows. */ - static const int array_rows = Size1; - - /** Constant for the number of array columns. */ - static const int array_cols = Size2; - - /** Make a partially bound selector with size @c R x @c C. */ - template struct reshape - { - using type = external; - }; -}; - -/** Specialized selector for external quaternions. */ -template<> struct external<4, -1, quaternion_storage_tag> -{ - using selector_type = external<>; - using unbound_type = external<>; - using proxy_type = compiled<4>; - using storage_tag = quaternion_storage_tag; - using size_tag = fixed_size_tag; - using memory_tag = external_memory_tag; - - /** Constant for the array size. */ - static const int array_size = 4; - - /** Make a partially bound selector with size @c N. */ - template struct resize - { - static_assert(N == 4, "invalid quaternion storage size"); - using type = external<4>; - }; -}; - -/** is_storage_selector for external<>. */ -template -struct is_storage_selector> -{ - static const bool value = true; -}; - -/** Helper to disambiguate external<> types. */ -template -struct storage_disambiguate, external> -{ - using type = external<>; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/* Forward declarations: */ +template struct external; + +/** Base selector to choose storage types that wrap a pointer or reference + * to array data. + * + * @tparam Size1 First dimension size. + * + * @tparam Size2 Second dimension size. + * + * @tparam Tag Tag specifying the type of storage (e.g. + * vector_storage_tag). This is set by instantiating @c rebind with the + * required tag. + */ +template struct external +{ + /** Rebind the base selector to the required type. */ + template struct rebind + { + using other = external; + }; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + using type = external; + }; + + /** Make a partially bound selector with size @c R x @c C. */ + template struct reshape + { + using type = external; + }; +}; + +/** Specialized selector for dynamic-size external vectors. */ +template<> struct external<-1, -1, vector_storage_tag> +{ + using selector_type = external<>; + using unbound_type = external<>; + using proxy_type = allocated<>; + using storage_tag = vector_storage_tag; + using size_tag = dynamic_size_tag; + using memory_tag = external_memory_tag; + + /** Unspecified array size. */ + static const int array_size = -1; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + using type = external; + }; +}; + +/** Specialized selector for fixed-size external vectors. */ +template struct external +{ + using selector_type = external<>; + using unbound_type = external<>; + using proxy_type = compiled; + using storage_tag = vector_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = external_memory_tag; + + /** Constant for the array size. */ + static const int array_size = Size; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + using type = external; + }; +}; + +/** Specialized selector for dynamic-size external matrices. */ +template<> struct external<-1, -1, matrix_storage_tag> +{ + using selector_type = external<>; + using unbound_type = external<>; + using proxy_type = allocated<>; + using storage_tag = matrix_storage_tag; + using size_tag = dynamic_size_tag; + using memory_tag = external_memory_tag; + + /** Unspecified array rows. */ + static const int array_rows = -1; + + /** Unspecified array columns. */ + static const int array_cols = -1; + + /** Make a partially bound selector with size @c R x @c C. */ + template struct reshape + { + using type = external; + }; +}; + +/** Specialized selector for fixed-size external matrices. */ +template struct external +{ + using selector_type = external<>; + using unbound_type = external<>; + using proxy_type = compiled; + using storage_tag = matrix_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = external_memory_tag; + + /** Constant for the number of array rows. */ + static const int array_rows = Size1; + + /** Constant for the number of array columns. */ + static const int array_cols = Size2; + + /** Make a partially bound selector with size @c R x @c C. */ + template struct reshape + { + using type = external; + }; +}; + +/** Specialized selector for external quaternions. */ +template<> struct external<4, -1, quaternion_storage_tag> +{ + using selector_type = external<>; + using unbound_type = external<>; + using proxy_type = compiled<4>; + using storage_tag = quaternion_storage_tag; + using size_tag = fixed_size_tag; + using memory_tag = external_memory_tag; + + /** Constant for the array size. */ + static const int array_size = 4; + + /** Make a partially bound selector with size @c N. */ + template struct resize + { + static_assert(N == 4, "invalid quaternion storage size"); + using type = external<4>; + }; +}; + +/** is_storage_selector for external<>. */ +template +struct is_storage_selector> +{ + static const bool value = true; +}; + +/** Helper to disambiguate external<> types. */ +template +struct storage_disambiguate, external> +{ + using type = external<>; +}; + +} // namespace cml diff --git a/cml/storage/promotion.h b/cml/storage/promotion.h index e595209..c7aaf2d 100644 --- a/cml/storage/promotion.h +++ b/cml/storage/promotion.h @@ -1,102 +1,102 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Build a storage type that best represents the combination of @c - * Storage1 and @c Storage2 into a single type. - * - * @note This only supports built-in CML storage types, but can be - * specialized for user-defined storage types. - */ -template -struct storage_promote -{ - /* Map selector types to the preferred selector: */ - template - using selector_map = type_table_item; - - /* True if PreferDynamic is false, or if both Storage1 and Storage2 are - * fixed-size types: - */ - static const bool is_fixed = !PreferDynamic - || (is_fixed_size::value && is_fixed_size::value); - - /* Build the symmetric type table for the built-in types, giving - * preference to dynamic-size types if PreferDynamic is true: - */ - using selector_table = cml::type_table< - /**/ selector_map, compiled<>, compiled<>> - - /* Override and select allocated<> if PreferDynamic is true and the - * original storage types are not both fixed-size: - */ - , - selector_map, allocated<>, - cml::if_t, allocated<>>> - - /* Override and select external<> if PreferDynamic is true and the - * original storage types are not both fixed-size: - */ - , - selector_map, external<>, - cml::if_t, external<>>> - - , - selector_map, any_storage<>, compiled<>> - - , - selector_map, allocated<>, allocated<>> - - , - selector_map, external<>, allocated<>> - - , - selector_map, any_storage<>, allocated<>> - - , - selector_map, external<>, external<>> - - , - selector_map, any_storage<>, external<>> - - , - selector_map, any_storage<>, any_storage<>>>; - - /* Lookup the storage selector for the passed-in types: */ - using left_selector = typename Storage1::selector_type; - using right_selector = typename Storage2::selector_type; - using result = typename selector_table::template find::type; - using selector_type = typename result::type; - static_assert(result::value, "no common storage selector found"); - - /* True if the resulting selector matches the left and/or right - * selectors: - */ - static const bool is_left = std::is_same::value; - static const bool is_right = - std::is_same::value; - static const bool is_same = is_left && is_right; - static_assert(is_left || is_right, "unexpected storage_promote result"); - - /* Determine the final selector type: */ - using left_unbound = typename Storage1::unbound_type; - using right_unbound = typename Storage2::unbound_type; - using type = cml::if_t, - cml::if_t>; -}; - -/** Convenience alias for storage_selector_promote. */ -template -using storage_promote_t = - typename storage_promote::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Build a storage type that best represents the combination of @c + * Storage1 and @c Storage2 into a single type. + * + * @note This only supports built-in CML storage types, but can be + * specialized for user-defined storage types. + */ +template +struct storage_promote +{ + /* Map selector types to the preferred selector: */ + template + using selector_map = type_table_item; + + /* True if PreferDynamic is false, or if both Storage1 and Storage2 are + * fixed-size types: + */ + static const bool is_fixed = !PreferDynamic + || (is_fixed_size::value && is_fixed_size::value); + + /* Build the symmetric type table for the built-in types, giving + * preference to dynamic-size types if PreferDynamic is true: + */ + using selector_table = cml::type_table< + /**/ selector_map, compiled<>, compiled<>> + + /* Override and select allocated<> if PreferDynamic is true and the + * original storage types are not both fixed-size: + */ + , + selector_map, allocated<>, + cml::if_t, allocated<>>> + + /* Override and select external<> if PreferDynamic is true and the + * original storage types are not both fixed-size: + */ + , + selector_map, external<>, + cml::if_t, external<>>> + + , + selector_map, any_storage<>, compiled<>> + + , + selector_map, allocated<>, allocated<>> + + , + selector_map, external<>, allocated<>> + + , + selector_map, any_storage<>, allocated<>> + + , + selector_map, external<>, external<>> + + , + selector_map, any_storage<>, external<>> + + , + selector_map, any_storage<>, any_storage<>>>; + + /* Lookup the storage selector for the passed-in types: */ + using left_selector = typename Storage1::selector_type; + using right_selector = typename Storage2::selector_type; + using result = typename selector_table::template find::type; + using selector_type = typename result::type; + static_assert(result::value, "no common storage selector found"); + + /* True if the resulting selector matches the left and/or right + * selectors: + */ + static const bool is_left = std::is_same::value; + static const bool is_right = + std::is_same::value; + static const bool is_same = is_left && is_right; + static_assert(is_left || is_right, "unexpected storage_promote result"); + + /* Determine the final selector type: */ + using left_unbound = typename Storage1::unbound_type; + using right_unbound = typename Storage2::unbound_type; + using type = cml::if_t, + cml::if_t>; +}; + +/** Convenience alias for storage_selector_promote. */ +template +using storage_promote_t = + typename storage_promote::type; + +} // namespace cml diff --git a/cml/storage/resize.h b/cml/storage/resize.h index 85bb813..6df6a3b 100644 --- a/cml/storage/resize.h +++ b/cml/storage/resize.h @@ -1,35 +1,35 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Compute a new storage type by changing the size of @c Storage to @c N. */ -template struct resize_storage -{ - /* Determine the new storage type: */ - using type = typename Storage::template resize::type; -}; - -/** Convenience alias for resize_storage. */ -template -using resize_storage_t = typename resize_storage::type; - -/** Compute a new storage type by changing the shape of @c Storage to @c R x - * @c C. - */ -template struct reshape_storage -{ - /* Determine the new storage type: */ - using type = typename Storage::template reshape::type; -}; - -/** Convenience alias for reshape_storage. */ -template -using reshape_storage_t = typename reshape_storage::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Compute a new storage type by changing the size of @c Storage to @c N. */ +template struct resize_storage +{ + /* Determine the new storage type: */ + using type = typename Storage::template resize::type; +}; + +/** Convenience alias for resize_storage. */ +template +using resize_storage_t = typename resize_storage::type; + +/** Compute a new storage type by changing the shape of @c Storage to @c R x + * @c C. + */ +template struct reshape_storage +{ + /* Determine the new storage type: */ + using type = typename Storage::template reshape::type; +}; + +/** Convenience alias for reshape_storage. */ +template +using reshape_storage_t = typename reshape_storage::type; + +} // namespace cml diff --git a/cml/storage/selectors.h b/cml/storage/selectors.h index d807a23..966c0d4 100644 --- a/cml/storage/selectors.h +++ b/cml/storage/selectors.h @@ -1,10 +1,10 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include diff --git a/cml/storage/type_util.h b/cml/storage/type_util.h index 097ee8a..0909538 100644 --- a/cml/storage/type_util.h +++ b/cml/storage/type_util.h @@ -1,104 +1,104 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Specializable class to detect storage selectors. */ -template struct is_storage_selector -{ - static const bool value = false; -}; - -/** Templated helper to determine the storage selector of @c T. @c T must - * implement a selector_type typedef. - */ -template struct storage_selector_of -{ - using type = typename T::selector_type; - static_assert(is_storage_selector::value, "invalid storage selector"); -}; - -/** Convenience alias for storage_selector_of. */ -template -using storage_selector_of_t = typename storage_selector_of::type; - -/** Templated helper to determine the storage type of @c T. @c T must - * implement a storage_type typedef. - */ -template struct storage_type_of -{ - using type = typename T::storage_type; -}; - -/** Convenience alias for storage_type_of. */ -template using storage_type_of_t = typename storage_type_of::type; - -/** Templated helper to determine the proxy type of @c T. @c T must - * implement a proxy_type typedef. - */ -template struct proxy_type_of -{ - using type = typename T::proxy_type; -}; - -/** Convenience alias for proxy_type_of. */ -template using proxy_type_of_t = typename proxy_type_of::type; - -/** Templated helper to rebind a storage type as vector storage. */ -template::value>::type* = nullptr> -struct rebind_vector_storage -{ - using type = rebind_t; -}; - -/** Convenience alias for rebind_vector_storage. */ -template -using rebind_vector_storage_t = typename rebind_vector_storage::type; - -/** Templated helper to rebind a storage type as matrix storage. */ -template::value>::type* = nullptr> -struct rebind_matrix_storage -{ - using type = rebind_t; -}; - -/** Convenience alias for rebind_matrix_storage. */ -template -using rebind_matrix_storage_t = typename rebind_matrix_storage::type; - -/** Templated helper to rebind a storage type as vector storage. */ -template::value>::type* = nullptr> -struct rebind_quaternion_storage -{ - using type = rebind_t; -}; - -/** Convenience alias for rebind_quaternion_storage. */ -template -using rebind_quaternion_storage_t = typename rebind_quaternion_storage::type; - -/** Specializable class used to disambiguate configurable storage types @c - * Storage1 and @c Storage2 that have matching storage selectors. - * - * @note This should be specialized for user-defined storage types. - */ -template struct storage_disambiguate -{ - using type = void; -}; - -/** Convenience alias for storage_disambiguate. */ -template -using storage_disambiguate_t = - typename storage_disambiguate::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Specializable class to detect storage selectors. */ +template struct is_storage_selector +{ + static const bool value = false; +}; + +/** Templated helper to determine the storage selector of @c T. @c T must + * implement a selector_type typedef. + */ +template struct storage_selector_of +{ + using type = typename T::selector_type; + static_assert(is_storage_selector::value, "invalid storage selector"); +}; + +/** Convenience alias for storage_selector_of. */ +template +using storage_selector_of_t = typename storage_selector_of::type; + +/** Templated helper to determine the storage type of @c T. @c T must + * implement a storage_type typedef. + */ +template struct storage_type_of +{ + using type = typename T::storage_type; +}; + +/** Convenience alias for storage_type_of. */ +template using storage_type_of_t = typename storage_type_of::type; + +/** Templated helper to determine the proxy type of @c T. @c T must + * implement a proxy_type typedef. + */ +template struct proxy_type_of +{ + using type = typename T::proxy_type; +}; + +/** Convenience alias for proxy_type_of. */ +template using proxy_type_of_t = typename proxy_type_of::type; + +/** Templated helper to rebind a storage type as vector storage. */ +template::value>::type* = nullptr> +struct rebind_vector_storage +{ + using type = rebind_t; +}; + +/** Convenience alias for rebind_vector_storage. */ +template +using rebind_vector_storage_t = typename rebind_vector_storage::type; + +/** Templated helper to rebind a storage type as matrix storage. */ +template::value>::type* = nullptr> +struct rebind_matrix_storage +{ + using type = rebind_t; +}; + +/** Convenience alias for rebind_matrix_storage. */ +template +using rebind_matrix_storage_t = typename rebind_matrix_storage::type; + +/** Templated helper to rebind a storage type as vector storage. */ +template::value>::type* = nullptr> +struct rebind_quaternion_storage +{ + using type = rebind_t; +}; + +/** Convenience alias for rebind_quaternion_storage. */ +template +using rebind_quaternion_storage_t = typename rebind_quaternion_storage::type; + +/** Specializable class used to disambiguate configurable storage types @c + * Storage1 and @c Storage2 that have matching storage selectors. + * + * @note This should be specialized for user-defined storage types. + */ +template struct storage_disambiguate +{ + using type = void; +}; + +/** Convenience alias for storage_disambiguate. */ +template +using storage_disambiguate_t = + typename storage_disambiguate::type; + +} // namespace cml diff --git a/cml/types.h b/cml/types.h index 575ad2d..3437768 100644 --- a/cml/types.h +++ b/cml/types.h @@ -1,9 +1,9 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include diff --git a/cml/util.h b/cml/util.h index ae6f410..7490370 100644 --- a/cml/util.h +++ b/cml/util.h @@ -1,61 +1,61 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Convert horizontal field of view to vertical field of view. */ -template -inline T -xfov_to_yfov(T xfov, T aspect) -{ - return T(2 - * scalar_traits::atan(scalar_traits::tan(xfov / 2) / aspect)); -} - -/** Convert vertical field of view to horizontal field of view. */ -template -inline T -yfov_to_xfov(T yfov, T aspect) -{ - return T(2 - * scalar_traits::atan(scalar_traits::tan(yfov / 2) * aspect)); -} - -/** Convert horizontal zoom to vertical zoom. */ -template -inline T -xzoom_to_yzoom(T xzoom, T aspect) -{ - return xzoom * aspect; -} - -/** Convert vertical zoom to horizontal zoom. */ -template -inline T -yzoom_to_xzoom(T yzoom, T aspect) -{ - return yzoom / aspect; -} - -/** Convert zoom factor to field of view. */ -template -inline T -zoom_to_fov(T zoom) -{ - return T(2 * scalar_traits::atan(T(1) / zoom)); -} - -/** Convert field of view to zoom factor. */ -template -inline T -fov_to_zoom(T fov) -{ - return T(1) / scalar_traits::tan(fov / 2); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Convert horizontal field of view to vertical field of view. */ +template +inline T +xfov_to_yfov(T xfov, T aspect) +{ + return T(2 + * scalar_traits::atan(scalar_traits::tan(xfov / 2) / aspect)); +} + +/** Convert vertical field of view to horizontal field of view. */ +template +inline T +yfov_to_xfov(T yfov, T aspect) +{ + return T(2 + * scalar_traits::atan(scalar_traits::tan(yfov / 2) * aspect)); +} + +/** Convert horizontal zoom to vertical zoom. */ +template +inline T +xzoom_to_yzoom(T xzoom, T aspect) +{ + return xzoom * aspect; +} + +/** Convert vertical zoom to horizontal zoom. */ +template +inline T +yzoom_to_xzoom(T yzoom, T aspect) +{ + return yzoom / aspect; +} + +/** Convert zoom factor to field of view. */ +template +inline T +zoom_to_fov(T zoom) +{ + return T(2 * scalar_traits::atan(T(1) / zoom)); +} + +/** Convert field of view to zoom factor. */ +template +inline T +fov_to_zoom(T fov) +{ + return T(1) / scalar_traits::tan(fov / 2); +} + +} // namespace cml diff --git a/cml/util/matrix_print.h b/cml/util/matrix_print.h index 75f48e7..75882a7 100644 --- a/cml/util/matrix_print.h +++ b/cml/util/matrix_print.h @@ -1,22 +1,22 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/* Forward declarations: */ -template class readable_matrix; - -/** Output a matrix to a std::ostream. */ -template -std::ostream& operator<<(std::ostream& os, const readable_matrix& v); - -} // namespace cml - -#define __CML_UTIL_MATRIX_PRINT_TPP -#include -#undef __CML_UTIL_MATRIX_PRINT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/* Forward declarations: */ +template class readable_matrix; + +/** Output a matrix to a std::ostream. */ +template +std::ostream& operator<<(std::ostream& os, const readable_matrix& v); + +} // namespace cml + +#define __CML_UTIL_MATRIX_PRINT_TPP +#include +#undef __CML_UTIL_MATRIX_PRINT_TPP diff --git a/cml/util/matrix_print.tpp b/cml/util/matrix_print.tpp index b1f04cd..afa83e0 100644 --- a/cml/util/matrix_print.tpp +++ b/cml/util/matrix_print.tpp @@ -1,27 +1,27 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_UTIL_MATRIX_PRINT_TPP -# error "util/matrix_print.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -template -inline std::ostream& -operator<<(std::ostream& os, const readable_matrix
& M) -{ - for(int i = 0; i < M.rows(); ++i) { - os << "["; - for(int j = 0; j < M.cols(); ++j) os << " " << M(i, j); - os << " ]"; - if(i != M.rows() - 1) os << std::endl; - } - return os; -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_UTIL_MATRIX_PRINT_TPP +# error "util/matrix_print.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +template +inline std::ostream& +operator<<(std::ostream& os, const readable_matrix
& M) +{ + for(int i = 0; i < M.rows(); ++i) { + os << "["; + for(int j = 0; j < M.cols(); ++j) os << " " << M(i, j); + os << " ]"; + if(i != M.rows() - 1) os << std::endl; + } + return os; +} + +} // namespace cml diff --git a/cml/util/quaternion_print.h b/cml/util/quaternion_print.h index 716f5ce..978f657 100644 --- a/cml/util/quaternion_print.h +++ b/cml/util/quaternion_print.h @@ -1,23 +1,23 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/* Forward declarations: */ -template class readable_quaternion; - -/** Output a quaternion to a std::ostream. */ -template -std::ostream& operator<<(std::ostream& os, - const readable_quaternion& v); - -} // namespace cml - -#define __CML_UTIL_QUATERNION_PRINT_TPP -#include -#undef __CML_UTIL_QUATERNION_PRINT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/* Forward declarations: */ +template class readable_quaternion; + +/** Output a quaternion to a std::ostream. */ +template +std::ostream& operator<<(std::ostream& os, + const readable_quaternion& v); + +} // namespace cml + +#define __CML_UTIL_QUATERNION_PRINT_TPP +#include +#undef __CML_UTIL_QUATERNION_PRINT_TPP diff --git a/cml/util/quaternion_print.tpp b/cml/util/quaternion_print.tpp index c152bea..62991b3 100644 --- a/cml/util/quaternion_print.tpp +++ b/cml/util/quaternion_print.tpp @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_UTIL_QUATERNION_PRINT_TPP -# error "util/quaternion_print.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { - -template -inline std::ostream& -operator<<(std::ostream& os, const readable_quaternion
& q) -{ - using order_type = order_type_trait_of_t
; - os << "[ " - << " " << q[order_type::W] << " " << q[order_type::X] << " " - << q[order_type::Y] << " " << q[order_type::Z] << " ]"; - return os; -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_UTIL_QUATERNION_PRINT_TPP +# error "util/quaternion_print.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { + +template +inline std::ostream& +operator<<(std::ostream& os, const readable_quaternion
& q) +{ + using order_type = order_type_trait_of_t
; + os << "[ " + << " " << q[order_type::W] << " " << q[order_type::X] << " " + << q[order_type::Y] << " " << q[order_type::Z] << " ]"; + return os; +} + +} // namespace cml diff --git a/cml/util/vector_hash.h b/cml/util/vector_hash.h index 1e348dc..2f9d69e 100644 --- a/cml/util/vector_hash.h +++ b/cml/util/vector_hash.h @@ -1,27 +1,27 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -/* Need specialization in std: */ -namespace std { -template -struct hash> -{ - using vector_type = cml::vector; - - inline std::size_t operator()(const vector_type& v) const - { - std::size_t seed = 0; - std::hash> hasher; - for(int i = 0; i < v.size(); ++i) - cml::detail::hash_combine(seed, hasher(v.get(i))); - return seed; - } -}; -} // namespace std +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +/* Need specialization in std: */ +namespace std { +template +struct hash> +{ + using vector_type = cml::vector; + + inline std::size_t operator()(const vector_type& v) const + { + std::size_t seed = 0; + std::hash> hasher; + for(int i = 0; i < v.size(); ++i) + cml::detail::hash_combine(seed, hasher(v.get(i))); + return seed; + } +}; +} // namespace std diff --git a/cml/util/vector_print.h b/cml/util/vector_print.h index 65bd159..ba13bc6 100644 --- a/cml/util/vector_print.h +++ b/cml/util/vector_print.h @@ -1,22 +1,22 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/* Forward declarations: */ -template class readable_vector; - -/** Output a vector to a std::ostream. */ -template -std::ostream& operator<<(std::ostream& os, const readable_vector& v); - -} // namespace cml - -#define __CML_UTIL_VECTOR_PRINT_TPP -#include -#undef __CML_UTIL_VECTOR_PRINT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/* Forward declarations: */ +template class readable_vector; + +/** Output a vector to a std::ostream. */ +template +std::ostream& operator<<(std::ostream& os, const readable_vector& v); + +} // namespace cml + +#define __CML_UTIL_VECTOR_PRINT_TPP +#include +#undef __CML_UTIL_VECTOR_PRINT_TPP diff --git a/cml/util/vector_print.tpp b/cml/util/vector_print.tpp index 90cea17..bb3a031 100644 --- a/cml/util/vector_print.tpp +++ b/cml/util/vector_print.tpp @@ -1,23 +1,23 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_UTIL_VECTOR_PRINT_TPP -# error "util/vector_print.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -template -inline std::ostream& -operator<<(std::ostream& os, const readable_vector
& v) -{ - os << v[0]; - for(int i = 1; i < v.size(); ++i) os << " " << v[i]; - return os; -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_UTIL_VECTOR_PRINT_TPP +# error "util/vector_print.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +template +inline std::ostream& +operator<<(std::ostream& os, const readable_vector
& v) +{ + os << v[0]; + for(int i = 1; i < v.size(); ++i) os << " " << v[i]; + return os; +} + +} // namespace cml diff --git a/cml/vector.h b/cml/vector.h index b7bb320..140eb0b 100644 --- a/cml/vector.h +++ b/cml/vector.h @@ -1,16 +1,16 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/cml/vector/binary_node.h b/cml/vector/binary_node.h index 03c4767..56a5752 100644 --- a/cml/vector/binary_node.h +++ b/cml/vector/binary_node.h @@ -1,135 +1,135 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class vector_binary_node; - -/** vector_binary_node<> traits. */ -template -struct vector_traits> -{ - using vector_type = vector_binary_node; - using left_arg_type = Sub1; - using right_arg_type = Sub2; - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = vector_traits; - using right_traits = vector_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - - /* Determine the common storage type for the node, based on the storage - * types of its subexpressions: - */ - using storage_type = vector_binary_storage_promote_t, - storage_type_of_t>; - - /* Traits and types for the storage: */ - using size_tag = typename storage_type::size_tag; - - /* Array size: */ - static const int array_size = storage_type::array_size; -}; - -/** Represents a binary vector operation in an expression tree. */ -template -class vector_binary_node -: public readable_vector> -{ - public: - using node_type = vector_binary_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using left_arg_type = typename traits_type::left_arg_type; - using right_arg_type = typename traits_type::right_arg_type; - using left_type = typename traits_type::left_type; - using right_type = typename traits_type::right_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** Constant containing the array size. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be - * lvalue reference or rvalue reference types. - * - * @throws incompatible_vector_size_error at run-time if either Sub1 or - * Sub2 is a dynamically-sized vector, and sub1.size() != sub2.size(). - * If both Sub1 and Sub2 are fixed-size expressions, then the sizes are - * checked at compile time. - */ - vector_binary_node(Sub1 left, Sub2 right); - - /** Move constructor. */ - vector_binary_node(node_type&& other); - - /** Copy constructor. */ - vector_binary_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Apply the operator to element @c i of the subexpressions and return - * the result. - */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the left subexpression. The expression is - * stored as a copy if Sub1 is an rvalue reference (temporary), or by - * const reference if Sub1 is an lvalue reference. - */ - using left_wrap_type = cml::if_t::value, const left_type&, - left_type>; - - /** The type used to store the right subexpression. The expression is - * stored as a copy if Sub2 is an rvalue reference (temporary), or by - * const reference if Sub2 is an lvalue reference. - */ - using right_wrap_type = cml::if_t::value, const right_type&, - right_type>; - - - protected: - /** The wrapped left subexpression. */ - left_wrap_type m_left; - - /** The wrapped right subexpression. */ - right_wrap_type m_right; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_VECTOR_BINARY_NODE_TPP -#include -#undef __CML_VECTOR_BINARY_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class vector_binary_node; + +/** vector_binary_node<> traits. */ +template +struct vector_traits> +{ + using vector_type = vector_binary_node; + using left_arg_type = Sub1; + using right_arg_type = Sub2; + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = vector_traits; + using right_traits = vector_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + + /* Determine the common storage type for the node, based on the storage + * types of its subexpressions: + */ + using storage_type = vector_binary_storage_promote_t, + storage_type_of_t>; + + /* Traits and types for the storage: */ + using size_tag = typename storage_type::size_tag; + + /* Array size: */ + static const int array_size = storage_type::array_size; +}; + +/** Represents a binary vector operation in an expression tree. */ +template +class vector_binary_node +: public readable_vector> +{ + public: + using node_type = vector_binary_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using left_arg_type = typename traits_type::left_arg_type; + using right_arg_type = typename traits_type::right_arg_type; + using left_type = typename traits_type::left_type; + using right_type = typename traits_type::right_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** Constant containing the array size. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be + * lvalue reference or rvalue reference types. + * + * @throws incompatible_vector_size_error at run-time if either Sub1 or + * Sub2 is a dynamically-sized vector, and sub1.size() != sub2.size(). + * If both Sub1 and Sub2 are fixed-size expressions, then the sizes are + * checked at compile time. + */ + vector_binary_node(Sub1 left, Sub2 right); + + /** Move constructor. */ + vector_binary_node(node_type&& other); + + /** Copy constructor. */ + vector_binary_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Apply the operator to element @c i of the subexpressions and return + * the result. + */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the left subexpression. The expression is + * stored as a copy if Sub1 is an rvalue reference (temporary), or by + * const reference if Sub1 is an lvalue reference. + */ + using left_wrap_type = cml::if_t::value, const left_type&, + left_type>; + + /** The type used to store the right subexpression. The expression is + * stored as a copy if Sub2 is an rvalue reference (temporary), or by + * const reference if Sub2 is an lvalue reference. + */ + using right_wrap_type = cml::if_t::value, const right_type&, + right_type>; + + + protected: + /** The wrapped left subexpression. */ + left_wrap_type m_left; + + /** The wrapped right subexpression. */ + right_wrap_type m_right; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_VECTOR_BINARY_NODE_TPP +#include +#undef __CML_VECTOR_BINARY_NODE_TPP diff --git a/cml/vector/binary_node.tpp b/cml/vector/binary_node.tpp index 8667290..b4c4b3e 100644 --- a/cml/vector/binary_node.tpp +++ b/cml/vector/binary_node.tpp @@ -1,57 +1,57 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_BINARY_NODE_TPP -# error "vector/binary_node.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* vector_binary_node 'structors: */ - -template -vector_binary_node::vector_binary_node(Sub1 left, Sub2 right) -: m_left(std::move(left)) -, m_right(std::move(right)) -{ - cml::check_same_size(this->m_left, this->m_right); - /* Note: this seems to be exception-safe since temporaries are stored by - * value and references by reference. - */ -} - -template -vector_binary_node::vector_binary_node(node_type&& other) -: m_left(std::move(other.m_left)) -, m_right(std::move(other.m_right)) -{} - -template -vector_binary_node::vector_binary_node(const node_type& other) -: m_left(other.m_left) -, m_right(other.m_right) -{} - - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector_binary_node::i_size() const -{ - return this->m_left.size(); -} - -template -auto -vector_binary_node::i_get(int i) const -> immutable_value -{ - return Op().apply(this->m_left.get(i), this->m_right.get(i)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_BINARY_NODE_TPP +# error "vector/binary_node.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* vector_binary_node 'structors: */ + +template +vector_binary_node::vector_binary_node(Sub1 left, Sub2 right) +: m_left(std::move(left)) +, m_right(std::move(right)) +{ + cml::check_same_size(this->m_left, this->m_right); + /* Note: this seems to be exception-safe since temporaries are stored by + * value and references by reference. + */ +} + +template +vector_binary_node::vector_binary_node(node_type&& other) +: m_left(std::move(other.m_left)) +, m_right(std::move(other.m_right)) +{} + +template +vector_binary_node::vector_binary_node(const node_type& other) +: m_left(other.m_left) +, m_right(other.m_right) +{} + + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector_binary_node::i_size() const +{ + return this->m_left.size(); +} + +template +auto +vector_binary_node::i_get(int i) const -> immutable_value +{ + return Op().apply(this->m_left.get(i), this->m_right.get(i)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/binary_ops.h b/cml/vector/binary_ops.h index b20d033..022cfb2 100644 --- a/cml/vector/binary_ops.h +++ b/cml/vector/binary_ops.h @@ -1,58 +1,58 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Helper function to generate a vector_binary_node from two vector types - * (i.e. derived from readable_vector<>). - */ -template* = nullptr, - enable_if_vector_t* = nullptr> -inline auto -make_vector_binary_node(Sub1&& sub1, - Sub2&& sub2) -> vector_binary_node, - actual_operand_type_of_t, Op> -{ - static_assert( - std::is_same(sub1))>::value, - "internal error: unexpected expression type (sub1)"); - static_assert( - std::is_same(sub2))>::value, - "internal error: unexpected expression type (sub2)"); - - /* Deduce the operand types of the subexpressions (&, const&, &&): */ - using sub1_type = actual_operand_type_of_t; - using sub2_type = actual_operand_type_of_t; - return vector_binary_node((sub1_type) sub1, - (sub2_type) sub2); -} - -template* = nullptr, - enable_if_vector_t* = nullptr> -inline auto -operator-(Sub1&& sub1, Sub2&& sub2) - -> decltype(make_vector_binary_node>( - std::forward(sub1), std::forward(sub2))) -{ - return make_vector_binary_node>( - std::forward(sub1), std::forward(sub2)); -} - -template* = nullptr, - enable_if_vector_t* = nullptr> -inline auto -operator+(Sub1&& sub1, Sub2&& sub2) - -> decltype(make_vector_binary_node>( - std::forward(sub1), std::forward(sub2))) -{ - return make_vector_binary_node>( - std::forward(sub1), std::forward(sub2)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Helper function to generate a vector_binary_node from two vector types + * (i.e. derived from readable_vector<>). + */ +template* = nullptr, + enable_if_vector_t* = nullptr> +inline auto +make_vector_binary_node(Sub1&& sub1, + Sub2&& sub2) -> vector_binary_node, + actual_operand_type_of_t, Op> +{ + static_assert( + std::is_same(sub1))>::value, + "internal error: unexpected expression type (sub1)"); + static_assert( + std::is_same(sub2))>::value, + "internal error: unexpected expression type (sub2)"); + + /* Deduce the operand types of the subexpressions (&, const&, &&): */ + using sub1_type = actual_operand_type_of_t; + using sub2_type = actual_operand_type_of_t; + return vector_binary_node((sub1_type) sub1, + (sub2_type) sub2); +} + +template* = nullptr, + enable_if_vector_t* = nullptr> +inline auto +operator-(Sub1&& sub1, Sub2&& sub2) + -> decltype(make_vector_binary_node>( + std::forward(sub1), std::forward(sub2))) +{ + return make_vector_binary_node>( + std::forward(sub1), std::forward(sub2)); +} + +template* = nullptr, + enable_if_vector_t* = nullptr> +inline auto +operator+(Sub1&& sub1, Sub2&& sub2) + -> decltype(make_vector_binary_node>( + std::forward(sub1), std::forward(sub2))) +{ + return make_vector_binary_node>( + std::forward(sub1), std::forward(sub2)); +} + +} // namespace cml diff --git a/cml/vector/comparison.h b/cml/vector/comparison.h index 13be45b..985f5ef 100644 --- a/cml/vector/comparison.h +++ b/cml/vector/comparison.h @@ -1,53 +1,53 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Returns true if @c left is lexicographically less than @c right. */ -template -bool operator<(const readable_vector& left, - const readable_vector& right); - -/** Returns true if @c left is lexicographically less than or equal to @c - * right. - */ -template -bool operator<=(const readable_vector& left, - const readable_vector& right); - -/** Returns true if @c left is lexicographically greater than @c right. */ -template -bool operator>(const readable_vector& left, - const readable_vector& right); - -/** Returns true if @c left is lexicographically greater than or equal to - * @c right. - */ -template -bool operator>=(const readable_vector& left, - const readable_vector& right); - -/** Returns true if the elements of @c left are all equal to the elements - * of @c right. - */ -template -bool operator==(const readable_vector& left, - const readable_vector& right); - -/** Returns true if some element of @c left is not equal to the - * corresponding element of @c right. - */ -template -bool operator!=(const readable_vector& left, - const readable_vector& right); - -} // namespace cml - -#define __CML_VECTOR_COMPARISON_TPP -#include -#undef __CML_VECTOR_COMPARISON_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Returns true if @c left is lexicographically less than @c right. */ +template +bool operator<(const readable_vector& left, + const readable_vector& right); + +/** Returns true if @c left is lexicographically less than or equal to @c + * right. + */ +template +bool operator<=(const readable_vector& left, + const readable_vector& right); + +/** Returns true if @c left is lexicographically greater than @c right. */ +template +bool operator>(const readable_vector& left, + const readable_vector& right); + +/** Returns true if @c left is lexicographically greater than or equal to + * @c right. + */ +template +bool operator>=(const readable_vector& left, + const readable_vector& right); + +/** Returns true if the elements of @c left are all equal to the elements + * of @c right. + */ +template +bool operator==(const readable_vector& left, + const readable_vector& right); + +/** Returns true if some element of @c left is not equal to the + * corresponding element of @c right. + */ +template +bool operator!=(const readable_vector& left, + const readable_vector& right); + +} // namespace cml + +#define __CML_VECTOR_COMPARISON_TPP +#include +#undef __CML_VECTOR_COMPARISON_TPP diff --git a/cml/vector/comparison.tpp b/cml/vector/comparison.tpp index 1a0e16e..ba17059 100644 --- a/cml/vector/comparison.tpp +++ b/cml/vector/comparison.tpp @@ -1,85 +1,85 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_COMPARISON_TPP -# error "vector/comparison.tpp not included correctly" -#endif - -#include - -namespace cml { - -template -inline bool -operator<(const readable_vector& left, const readable_vector& right) -{ - int n = std::min(left.size(), right.size()); - for(int i = 0; i < n; i++) { - /**/ if(left[i] < right[i]) - return true; // Strictly less. - else if(right[i] < left[i]) return false; // Strictly greater. - else continue; // Possibly equal. - } - - /* Equal only if the same length: */ - return left.size() < right.size(); -} - -template -inline bool -operator>(const readable_vector& left, const readable_vector& right) -{ - int n = std::min(left.size(), right.size()); - for(int i = 0; i < n; i++) { - /**/ if(left[i] < right[i]) - return false; // Strictly less. - else if(right[i] < left[i]) return true; // Strictly greater. - else continue; // Possibly equal. - } - - /* Equal only if the same length: */ - return left.size() > right.size(); -} - -template -inline bool -operator==(const readable_vector& left, - const readable_vector& right) -{ - /* Possibly equal only if the same length: */ - if(left.size() != right.size()) return false; - for(int i = 0; i < left.size(); i++) { - /**/ if(left[i] < right[i]) - return false; // Strictly less. - else if(right[i] < left[i]) return false; // Strictly greater. - else continue; // Possibly equal. - } - return true; -} - -template -inline bool -operator<=(const readable_vector& left, - const readable_vector& right) -{ - return !(left > right); -} - -template -inline bool -operator>=(const readable_vector& left, - const readable_vector& right) -{ - return !(left < right); -} - -template -inline bool -operator!=(const readable_vector& left, - const readable_vector& right) -{ - return !(left == right); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_COMPARISON_TPP +# error "vector/comparison.tpp not included correctly" +#endif + +#include + +namespace cml { + +template +inline bool +operator<(const readable_vector& left, const readable_vector& right) +{ + int n = std::min(left.size(), right.size()); + for(int i = 0; i < n; i++) { + /**/ if(left[i] < right[i]) + return true; // Strictly less. + else if(right[i] < left[i]) return false; // Strictly greater. + else continue; // Possibly equal. + } + + /* Equal only if the same length: */ + return left.size() < right.size(); +} + +template +inline bool +operator>(const readable_vector& left, const readable_vector& right) +{ + int n = std::min(left.size(), right.size()); + for(int i = 0; i < n; i++) { + /**/ if(left[i] < right[i]) + return false; // Strictly less. + else if(right[i] < left[i]) return true; // Strictly greater. + else continue; // Possibly equal. + } + + /* Equal only if the same length: */ + return left.size() > right.size(); +} + +template +inline bool +operator==(const readable_vector& left, + const readable_vector& right) +{ + /* Possibly equal only if the same length: */ + if(left.size() != right.size()) return false; + for(int i = 0; i < left.size(); i++) { + /**/ if(left[i] < right[i]) + return false; // Strictly less. + else if(right[i] < left[i]) return false; // Strictly greater. + else continue; // Possibly equal. + } + return true; +} + +template +inline bool +operator<=(const readable_vector& left, + const readable_vector& right) +{ + return !(left > right); +} + +template +inline bool +operator>=(const readable_vector& left, + const readable_vector& right) +{ + return !(left < right); +} + +template +inline bool +operator!=(const readable_vector& left, + const readable_vector& right) +{ + return !(left == right); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/cross.h b/cml/vector/cross.h index 8e81ea9..c4e7a0b 100644 --- a/cml/vector/cross.h +++ b/cml/vector/cross.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/vector/cross_node.h b/cml/vector/cross_node.h index 3baeecf..59b30ad 100644 --- a/cml/vector/cross_node.h +++ b/cml/vector/cross_node.h @@ -1,136 +1,136 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class vector_cross_node; - -/** vector_cross_node<> traits. */ -template -struct vector_traits> -{ - using vector_type = vector_cross_node; - using left_arg_type = Sub1; - using right_arg_type = Sub2; - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = vector_traits; - using right_traits = vector_traits; - - using element_type = value_type_promote_t; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - - /* Determine the common storage type for the node, based on the storage - * types of its subexpressions: - */ - using storage_type = vector_binary_storage_promote_t, - storage_type_of_t>; - - /* Traits and types for the storage: */ - using size_tag = typename storage_type::size_tag; - - /* Array size: */ - static const int array_size = storage_type::array_size; -}; - -/** Represents a cross product in an expression tree. */ -template -class vector_cross_node : public readable_vector> -{ - public: - using node_type = vector_cross_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using left_arg_type = typename traits_type::left_arg_type; - using right_arg_type = typename traits_type::right_arg_type; - using left_type = typename traits_type::left_type; - using right_type = typename traits_type::right_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** Constant containing the array size. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be - * lvalue reference or rvalue reference types. - * - * @throws vector_size_error at run-time if either Sub1 or Sub2 is a - * dynamically-sized vector, and sub1.size() != sub2.size() != 3. If - * both Sub1 and Sub2 are fixed-size expressions, then the sizes are - * checked at compile time. - */ - vector_cross_node(Sub1 left, Sub2 right); - - /** Move constructor. */ - vector_cross_node(node_type&& other); - - /** Copy constructor. */ - vector_cross_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Apply the operator to element @c i of the subexpressions and return - * the result. - */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the left subexpression. The expression is - * stored as a copy if Sub1 is an rvalue reference (temporary), or by - * const reference if Sub1 is an lvalue reference. - */ - using left_wrap_type = cml::if_t::value, const left_type&, - left_type>; - - /** The type used to store the right subexpression. The expression is - * stored as a copy if Sub2 is an rvalue reference (temporary), or by - * const reference if Sub2 is an lvalue reference. - */ - using right_wrap_type = cml::if_t::value, const right_type&, - right_type>; - - - protected: - /** The wrapped left subexpression. */ - left_wrap_type m_left; - - /** The wrapped right subexpression. */ - right_wrap_type m_right; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_VECTOR_CROSS_NODE_TPP -#include -#undef __CML_VECTOR_CROSS_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class vector_cross_node; + +/** vector_cross_node<> traits. */ +template +struct vector_traits> +{ + using vector_type = vector_cross_node; + using left_arg_type = Sub1; + using right_arg_type = Sub2; + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = vector_traits; + using right_traits = vector_traits; + + using element_type = value_type_promote_t; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + + /* Determine the common storage type for the node, based on the storage + * types of its subexpressions: + */ + using storage_type = vector_binary_storage_promote_t, + storage_type_of_t>; + + /* Traits and types for the storage: */ + using size_tag = typename storage_type::size_tag; + + /* Array size: */ + static const int array_size = storage_type::array_size; +}; + +/** Represents a cross product in an expression tree. */ +template +class vector_cross_node : public readable_vector> +{ + public: + using node_type = vector_cross_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using left_arg_type = typename traits_type::left_arg_type; + using right_arg_type = typename traits_type::right_arg_type; + using left_type = typename traits_type::left_type; + using right_type = typename traits_type::right_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** Constant containing the array size. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be + * lvalue reference or rvalue reference types. + * + * @throws vector_size_error at run-time if either Sub1 or Sub2 is a + * dynamically-sized vector, and sub1.size() != sub2.size() != 3. If + * both Sub1 and Sub2 are fixed-size expressions, then the sizes are + * checked at compile time. + */ + vector_cross_node(Sub1 left, Sub2 right); + + /** Move constructor. */ + vector_cross_node(node_type&& other); + + /** Copy constructor. */ + vector_cross_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Apply the operator to element @c i of the subexpressions and return + * the result. + */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the left subexpression. The expression is + * stored as a copy if Sub1 is an rvalue reference (temporary), or by + * const reference if Sub1 is an lvalue reference. + */ + using left_wrap_type = cml::if_t::value, const left_type&, + left_type>; + + /** The type used to store the right subexpression. The expression is + * stored as a copy if Sub2 is an rvalue reference (temporary), or by + * const reference if Sub2 is an lvalue reference. + */ + using right_wrap_type = cml::if_t::value, const right_type&, + right_type>; + + + protected: + /** The wrapped left subexpression. */ + left_wrap_type m_left; + + /** The wrapped right subexpression. */ + right_wrap_type m_right; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_VECTOR_CROSS_NODE_TPP +#include +#undef __CML_VECTOR_CROSS_NODE_TPP diff --git a/cml/vector/cross_node.tpp b/cml/vector/cross_node.tpp index c5494a8..8afa41d 100644 --- a/cml/vector/cross_node.tpp +++ b/cml/vector/cross_node.tpp @@ -1,61 +1,61 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_CROSS_NODE_TPP -# error "vector/cross_node.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* vector_cross_node 'structors: */ - -template -vector_cross_node::vector_cross_node(Sub1 left, Sub2 right) -: m_left(std::move(left)) -, m_right(std::move(right)) -{ - cml::check_size(left, cml::int_c<3>()); - cml::check_size(right, cml::int_c<3>()); - /* Note: this seems to be exception-safe since temporaries are stored by - * value and references by reference. - */ -} - -template -vector_cross_node::vector_cross_node(node_type&& other) -: m_left(std::move(other.m_left)) -, m_right(std::move(other.m_right)) -{} - -template -vector_cross_node::vector_cross_node(const node_type& other) -: m_left(other.m_left) -, m_right(other.m_right) -{} - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector_cross_node::i_size() const -{ - return 3; -} - -template -auto -vector_cross_node::i_get(int i) const -> immutable_value -{ - int i0 = (i + 1) % 3, i1 = (i + 2) % 3; - return immutable_value( - this->m_left.get(i0) * this->m_right.get(i1) // 1,2; 2,0; 0,1 - - this->m_left.get(i1) * this->m_right.get(i0)) // 2,1; 0,2; 1,0 - ; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_CROSS_NODE_TPP +# error "vector/cross_node.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* vector_cross_node 'structors: */ + +template +vector_cross_node::vector_cross_node(Sub1 left, Sub2 right) +: m_left(std::move(left)) +, m_right(std::move(right)) +{ + cml::check_size(left, cml::int_c<3>()); + cml::check_size(right, cml::int_c<3>()); + /* Note: this seems to be exception-safe since temporaries are stored by + * value and references by reference. + */ +} + +template +vector_cross_node::vector_cross_node(node_type&& other) +: m_left(std::move(other.m_left)) +, m_right(std::move(other.m_right)) +{} + +template +vector_cross_node::vector_cross_node(const node_type& other) +: m_left(other.m_left) +, m_right(other.m_right) +{} + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector_cross_node::i_size() const +{ + return 3; +} + +template +auto +vector_cross_node::i_get(int i) const -> immutable_value +{ + int i0 = (i + 1) % 3, i1 = (i + 2) % 3; + return immutable_value( + this->m_left.get(i0) * this->m_right.get(i1) // 1,2; 2,0; 0,1 + - this->m_left.get(i1) * this->m_right.get(i0)) // 2,1; 0,2; 1,0 + ; +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/cross_ops.h b/cml/vector/cross_ops.h index 64725f2..790ca39 100644 --- a/cml/vector/cross_ops.h +++ b/cml/vector/cross_ops.h @@ -1,32 +1,32 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Compute the cross-product of two 3D vectors, and return the result as an - * expression node (vector_cross_node). - * - * @throws vector_size_error at run-time if left or right is - * dynamically-sized and is not a 3D vector. The size is checked at - * compile time for fixed-sized expressions. - */ -template* = nullptr, - enable_if_vector_t* = nullptr> -inline auto -cross(Sub1&& sub1, - Sub2&& sub2) -> vector_cross_node, - actual_operand_type_of_t> -{ - /* Deduce the operand types of the subexpressions (&, const&, &&): */ - using sub1_type = actual_operand_type_of_t; - using sub2_type = actual_operand_type_of_t; - return vector_cross_node((sub1_type) sub1, - (sub2_type) sub2); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Compute the cross-product of two 3D vectors, and return the result as an + * expression node (vector_cross_node). + * + * @throws vector_size_error at run-time if left or right is + * dynamically-sized and is not a 3D vector. The size is checked at + * compile time for fixed-sized expressions. + */ +template* = nullptr, + enable_if_vector_t* = nullptr> +inline auto +cross(Sub1&& sub1, + Sub2&& sub2) -> vector_cross_node, + actual_operand_type_of_t> +{ + /* Deduce the operand types of the subexpressions (&, const&, &&): */ + using sub1_type = actual_operand_type_of_t; + using sub2_type = actual_operand_type_of_t; + return vector_cross_node((sub1_type) sub1, + (sub2_type) sub2); +} + +} // namespace cml diff --git a/cml/vector/detail/check_or_resize.h b/cml/vector/detail/check_or_resize.h index 216b711..d6b375a 100644 --- a/cml/vector/detail/check_or_resize.h +++ b/cml/vector/detail/check_or_resize.h @@ -1,120 +1,120 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml::detail { - -/* check_or_resize for a read-only vector, left, that just forwards to - * check_same_size. - */ -template -inline void -check_or_resize(const readable_vector& left, const Other& right) -{ - cml::check_same_size(left, right); -} - -/* check_or_resize for a resizable vector, left, that resizes the vector to - * ensure it has the same size as right. - */ -template -inline auto -check_or_resize(writable_vector& left, const Other& right) - -> decltype(left.actual().resize(0), void()) -{ - left.actual().resize(cml::array_size_of(right)); -} - -/* check_or_resize for a read-only vector left and constant size N that - * just forwards to check_size. - */ -template -inline void -check_or_resize(const readable_vector& sub, int_c) -{ - cml::check_size(sub, int_c()); -} - -/* check_or_resize for a read-only vector left and run-time size N that - * just forwards to check_size. - */ -template -inline void -check_or_resize(const readable_vector& sub, int N) -{ - cml::check_size(sub, N); -} - -/* check_or_resize for a resizable vector left and compile-time size N that - * resizes the vector to N. - */ -template -inline auto -check_or_resize(writable_vector& sub, int_c) - -> decltype(sub.actual().resize(0), void()) -{ - sub.actual().resize(N); -} - -/* check_or_resize for a resizable vector left and run-time size N that - * resizes the vector to N. - */ -template -inline auto -check_or_resize(writable_vector& sub, int N) - -> decltype(sub.actual().resize(0), void()) -{ - sub.actual().resize(N); -} - -/* check_or_resize for a read-only vector, left, that just forwards to - * check_same_size. - */ -template -inline void -check_or_resize(const readable_vector& left, - const readable_vector& right) -{ - cml::check_same_size(left, right); -} - -/* check_or_resize for a resizable vector, left, that resizes the vector to - * ensure it has the same size as right. - */ -template -inline auto -check_or_resize(writable_vector& left, const readable_vector& right) - -> decltype(left.actual().resize(0), void()) -{ - left.actual().resize(cml::array_size_of(right)); -} - -/* check_or_resize for a read-only vector that verifies the size is - * other.size() + sizeof(eN): - */ -template -inline void -check_or_resize(const readable_vector& sub, - const readable_vector& other, const Elements&... eN) -{ - cml::check_size(sub, combined_size_of(other, eN...)); -} - -/* check_or_resize for a resizable vector that resizes the vector to - * other.size() + sizeof(eN): - */ -template -inline auto -check_or_resize(writable_vector& sub, const readable_vector& other, - const Elements&... eN) -> decltype(sub.actual().resize(0), void()) -{ - sub.actual().resize(combined_size_of(other, eN...)); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml::detail { + +/* check_or_resize for a read-only vector, left, that just forwards to + * check_same_size. + */ +template +inline void +check_or_resize(const readable_vector& left, const Other& right) +{ + cml::check_same_size(left, right); +} + +/* check_or_resize for a resizable vector, left, that resizes the vector to + * ensure it has the same size as right. + */ +template +inline auto +check_or_resize(writable_vector& left, const Other& right) + -> decltype(left.actual().resize(0), void()) +{ + left.actual().resize(cml::array_size_of(right)); +} + +/* check_or_resize for a read-only vector left and constant size N that + * just forwards to check_size. + */ +template +inline void +check_or_resize(const readable_vector& sub, int_c) +{ + cml::check_size(sub, int_c()); +} + +/* check_or_resize for a read-only vector left and run-time size N that + * just forwards to check_size. + */ +template +inline void +check_or_resize(const readable_vector& sub, int N) +{ + cml::check_size(sub, N); +} + +/* check_or_resize for a resizable vector left and compile-time size N that + * resizes the vector to N. + */ +template +inline auto +check_or_resize(writable_vector& sub, int_c) + -> decltype(sub.actual().resize(0), void()) +{ + sub.actual().resize(N); +} + +/* check_or_resize for a resizable vector left and run-time size N that + * resizes the vector to N. + */ +template +inline auto +check_or_resize(writable_vector& sub, int N) + -> decltype(sub.actual().resize(0), void()) +{ + sub.actual().resize(N); +} + +/* check_or_resize for a read-only vector, left, that just forwards to + * check_same_size. + */ +template +inline void +check_or_resize(const readable_vector& left, + const readable_vector& right) +{ + cml::check_same_size(left, right); +} + +/* check_or_resize for a resizable vector, left, that resizes the vector to + * ensure it has the same size as right. + */ +template +inline auto +check_or_resize(writable_vector& left, const readable_vector& right) + -> decltype(left.actual().resize(0), void()) +{ + left.actual().resize(cml::array_size_of(right)); +} + +/* check_or_resize for a read-only vector that verifies the size is + * other.size() + sizeof(eN): + */ +template +inline void +check_or_resize(const readable_vector& sub, + const readable_vector& other, const Elements&... eN) +{ + cml::check_size(sub, combined_size_of(other, eN...)); +} + +/* check_or_resize for a resizable vector that resizes the vector to + * other.size() + sizeof(eN): + */ +template +inline auto +check_or_resize(writable_vector& sub, const readable_vector& other, + const Elements&... eN) -> decltype(sub.actual().resize(0), void()) +{ + sub.actual().resize(combined_size_of(other, eN...)); +} + +} diff --git a/cml/vector/detail/combined_size_of.h b/cml/vector/detail/combined_size_of.h index e79bdf0..b044ae4 100644 --- a/cml/vector/detail/combined_size_of.h +++ b/cml/vector/detail/combined_size_of.h @@ -1,41 +1,41 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml::detail { - -template -inline enable_if_fixed_size_t::value>> -combined_size_of(const readable_vector&) -{ - return array_size_of_c::value; -} - -template -inline enable_if_fixed_size_t::value, int(sizeof...(Elements))>::value>> -combined_size_of(const readable_vector&, const Elements&...) -{ - return cml::int_c::value + int(sizeof...(Elements))>(); -} - -template -inline enable_if_dynamic_size_t -combined_size_of(const readable_vector& sub) -{ - return sub.size(); -} - -template -inline enable_if_dynamic_size_t -combined_size_of(const readable_vector& sub, const Elements&...) -{ - return sub.size() + int(sizeof...(Elements)); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml::detail { + +template +inline enable_if_fixed_size_t::value>> +combined_size_of(const readable_vector&) +{ + return array_size_of_c::value; +} + +template +inline enable_if_fixed_size_t::value, int(sizeof...(Elements))>::value>> +combined_size_of(const readable_vector&, const Elements&...) +{ + return cml::int_c::value + int(sizeof...(Elements))>(); +} + +template +inline enable_if_dynamic_size_t +combined_size_of(const readable_vector& sub) +{ + return sub.size(); +} + +template +inline enable_if_dynamic_size_t +combined_size_of(const readable_vector& sub, const Elements&...) +{ + return sub.size() + int(sizeof...(Elements)); +} + +} diff --git a/cml/vector/detail/resize.h b/cml/vector/detail/resize.h index 93eb3de..5f9e67d 100644 --- a/cml/vector/detail/resize.h +++ b/cml/vector/detail/resize.h @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml::detail { - -/** No-op for non-resizable vector. */ -template -inline void -resize(readable_vector&, int) -{} - -/** Resize vectors that implement resize(). */ -template -inline auto -resize(writable_vector& sub, int size) - -> decltype(sub.actual().resize(0), void()) -{ - sub.actual().resize(size); -} - -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml::detail { + +/** No-op for non-resizable vector. */ +template +inline void +resize(readable_vector&, int) +{} + +/** Resize vectors that implement resize(). */ +template +inline auto +resize(writable_vector& sub, int size) + -> decltype(sub.actual().resize(0), void()) +{ + sub.actual().resize(size); +} + +} diff --git a/cml/vector/dot.h b/cml/vector/dot.h index 4f901ad..8beb794 100644 --- a/cml/vector/dot.h +++ b/cml/vector/dot.h @@ -1,30 +1,30 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Compute the dot-product of two vectors. - * - * @note Currently, the result is computed immediately, even if it appears - * as a term in an expression. - * - * @throws incompatible_vector_size_error at run-time if either left or - * right is a dynamically-sized vector, and left.size() != right.size(). If - * both are fixed-size expressions, then the sizes are checked at compile - * time. - */ -template -auto dot(const readable_vector& left, const readable_vector& right) - -> value_type_trait_promote_t; - -} // namespace cml - -#define __CML_VECTOR_DOT_TPP -#include -#undef __CML_VECTOR_DOT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Compute the dot-product of two vectors. + * + * @note Currently, the result is computed immediately, even if it appears + * as a term in an expression. + * + * @throws incompatible_vector_size_error at run-time if either left or + * right is a dynamically-sized vector, and left.size() != right.size(). If + * both are fixed-size expressions, then the sizes are checked at compile + * time. + */ +template +auto dot(const readable_vector& left, const readable_vector& right) + -> value_type_trait_promote_t; + +} // namespace cml + +#define __CML_VECTOR_DOT_TPP +#include +#undef __CML_VECTOR_DOT_TPP diff --git a/cml/vector/dot.tpp b/cml/vector/dot.tpp index 2d57ff1..84397d4 100644 --- a/cml/vector/dot.tpp +++ b/cml/vector/dot.tpp @@ -1,29 +1,29 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_DOT_TPP -# error "vector/dot.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -template -inline auto -dot(const readable_vector& left, const readable_vector& right) - -> value_type_trait_promote_t -{ - using result_type = value_type_trait_promote_t; - cml::check_minimum_size(left, cml::int_c<1>()); - cml::check_minimum_size(right, cml::int_c<1>()); - cml::check_same_size(left, right); - result_type accum = result_type(left.get(0) * right.get(0)); - for(int i = 1; i < left.size(); ++i) - accum += result_type(left.get(i) * right.get(i)); - return accum; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_DOT_TPP +# error "vector/dot.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +template +inline auto +dot(const readable_vector& left, const readable_vector& right) + -> value_type_trait_promote_t +{ + using result_type = value_type_trait_promote_t; + cml::check_minimum_size(left, cml::int_c<1>()); + cml::check_minimum_size(right, cml::int_c<1>()); + cml::check_same_size(left, right); + result_type accum = result_type(left.get(0) * right.get(0)); + for(int i = 1; i < left.size(); ++i) + accum += result_type(left.get(i) * right.get(i)); + return accum; +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/dynamic.h b/cml/vector/dynamic.h index fa2a633..bcb36bc 100644 --- a/cml/vector/dynamic.h +++ b/cml/vector/dynamic.h @@ -1,7 +1,7 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include diff --git a/cml/vector/dynamic_allocated.h b/cml/vector/dynamic_allocated.h index efc9775..bc9aa21 100644 --- a/cml/vector/dynamic_allocated.h +++ b/cml/vector/dynamic_allocated.h @@ -1,257 +1,257 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace cml { - -template -struct vector_traits>> -{ - /* Traits and types for the vector element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The vector storage type: */ - using storage_type = rebind_t, vector_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array size (should be -1): */ - static const int array_size = storage_type::array_size; - static_assert(array_size == -1, "invalid vector size"); -}; - -/** Resizable vector. */ -template -class vector> -: public writable_vector>> -{ - protected: - /** The real allocator type. */ - using allocator_type = cml::rebind_alloc_t; - - /** Allocator traits. */ - using allocator_traits = std::allocator_traits; - - /** Require a stateless allocator. */ - static_assert(std::is_empty::value, - "cannot use a stateful allocator for dynamic<> vectors"); - - - public: - using vector_type = vector>; - using readable_type = readable_vector; - using writable_type = writable_vector; - using traits_type = vector_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /* Include methods from writable_type: */ - using writable_type::operator[]; - using writable_type::operator=; - - - public: - /** Constant containing the array size. */ - static const int array_size = traits_type::array_size; - - - public: - /** Default constructor. - * - * @note The vector has no elements. - */ - vector(); - - /** Construct given a size. - * - * @throws std::invalid_argument if @c size < 0. - */ - template::value>* = nullptr> - explicit vector(Int size); - - /** Copy constructor. */ - vector(const vector_type& other); - - /** Move constructor. */ - vector(vector_type&& other); - - /** Construct from a readable_vector. */ - template vector(const readable_vector& sub); - - /** Construct from at least 1 value. The vector is resized to - * accomodate the number of elements passed. - * - * @note This overload is enabled only if all of the arguments are - * convertible to value_type. - */ - template* = nullptr> - vector(const E0& e0, const Elements&... eN) - // XXX Should be in vector/dynamic_allocated.tpp, but VC++12 has - // brain-dead out-of-line template argument matching... - : m_data(0) - , m_size(0) - { - this->assign_elements(e0, eN...); - } - - /** Construct from a readable_vector and at least one - * additional element. The vector is resized to accomodate the total - * number of elements passed. - * - * @note This overload is enabled only if the value_type of @c sub and - * all of the scalar arguments are convertible to value_type. - */ - template, E0, - Elements...>* = nullptr> - vector(const readable_vector& sub, const E0& e0, const Elements&... eN) - // XXX Should be in vector/fixed_compiled.tpp, but VC++12 has - // brain-dead out-of-line template argument matching... - : m_data(0) - , m_size(0) - { - this->assign(sub, e0, eN...); - } - - /** Construct from an array type. */ - template* = nullptr> - vector(const Array& array); - - /** Construct from a pointer to an array. */ - template* = nullptr> - vector(const Pointer& array, int size); - - /** Construct from a pointer to an array. */ - template* = nullptr> - vector(int size, const Pointer& array); - - /** Construct from std::initializer_list. */ - template vector(std::initializer_list l); - - /** Destructor. */ - ~vector(); - - - public: - /** Return access to the vector data as a raw pointer. */ - pointer data(); - - /** Return const access to the vector data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator. */ - const_pointer begin() const; - - /** Read-only iterator. */ - const_pointer end() const; - - /** Resize the vector to the specified size. - * - * @note This will reallocate the array and copy existing elements, if - * any. - * - * @throws std::invalid_argument if @c n is negative. - */ - void resize(int n); - - /** Resize the vector to the specified size without copying the old - * elements. - * - * @throws std::invalid_argument if @c n is negative. - */ - void resize_fast(int n); - - - public: - /** Copy assignment. */ - vector_type& operator=(const vector_type& other); - - /** Move assignment. */ - vector_type& operator=(vector_type&& other); - - - protected: - /** No-op for trivially destructible elements - * (is_trivially_destructible). - */ - void destruct(pointer, int, std::true_type); - - /** Invoke non-trivial destructors for @c n elements starting at @c - * data. - */ - void destruct(pointer data, int n, std::false_type); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the length of the vector. */ - int i_size() const; - - /** Return vector const element @c i. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** @name writable_vector Interface */ - /*@{*/ - - friend writable_type; - - /** Return vector element @c i. */ - mutable_value i_get(int i); - - /** Set element @c i. */ - template vector_type& i_put(int i, const Other& v) &; - - /** Set element @c i on a temporary. */ - template vector_type&& i_put(int i, const Other& v) &&; - - /*@}*/ - - - protected: - /** Dynamic storage. */ - pointer m_data; - - /** Size of the vector. */ - int m_size; -}; - -} // namespace cml - -#define __CML_VECTOR_DYNAMIC_ALLOCATED_TPP -#include -#undef __CML_VECTOR_DYNAMIC_ALLOCATED_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace cml { + +template +struct vector_traits>> +{ + /* Traits and types for the vector element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The vector storage type: */ + using storage_type = rebind_t, vector_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array size (should be -1): */ + static const int array_size = storage_type::array_size; + static_assert(array_size == -1, "invalid vector size"); +}; + +/** Resizable vector. */ +template +class vector> +: public writable_vector>> +{ + protected: + /** The real allocator type. */ + using allocator_type = cml::rebind_alloc_t; + + /** Allocator traits. */ + using allocator_traits = std::allocator_traits; + + /** Require a stateless allocator. */ + static_assert(std::is_empty::value, + "cannot use a stateful allocator for dynamic<> vectors"); + + + public: + using vector_type = vector>; + using readable_type = readable_vector; + using writable_type = writable_vector; + using traits_type = vector_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /* Include methods from writable_type: */ + using writable_type::operator[]; + using writable_type::operator=; + + + public: + /** Constant containing the array size. */ + static const int array_size = traits_type::array_size; + + + public: + /** Default constructor. + * + * @note The vector has no elements. + */ + vector(); + + /** Construct given a size. + * + * @throws std::invalid_argument if @c size < 0. + */ + template::value>* = nullptr> + explicit vector(Int size); + + /** Copy constructor. */ + vector(const vector_type& other); + + /** Move constructor. */ + vector(vector_type&& other); + + /** Construct from a readable_vector. */ + template vector(const readable_vector& sub); + + /** Construct from at least 1 value. The vector is resized to + * accomodate the number of elements passed. + * + * @note This overload is enabled only if all of the arguments are + * convertible to value_type. + */ + template* = nullptr> + vector(const E0& e0, const Elements&... eN) + // XXX Should be in vector/dynamic_allocated.tpp, but VC++12 has + // brain-dead out-of-line template argument matching... + : m_data(0) + , m_size(0) + { + this->assign_elements(e0, eN...); + } + + /** Construct from a readable_vector and at least one + * additional element. The vector is resized to accomodate the total + * number of elements passed. + * + * @note This overload is enabled only if the value_type of @c sub and + * all of the scalar arguments are convertible to value_type. + */ + template, E0, + Elements...>* = nullptr> + vector(const readable_vector& sub, const E0& e0, const Elements&... eN) + // XXX Should be in vector/fixed_compiled.tpp, but VC++12 has + // brain-dead out-of-line template argument matching... + : m_data(0) + , m_size(0) + { + this->assign(sub, e0, eN...); + } + + /** Construct from an array type. */ + template* = nullptr> + vector(const Array& array); + + /** Construct from a pointer to an array. */ + template* = nullptr> + vector(const Pointer& array, int size); + + /** Construct from a pointer to an array. */ + template* = nullptr> + vector(int size, const Pointer& array); + + /** Construct from std::initializer_list. */ + template vector(std::initializer_list l); + + /** Destructor. */ + ~vector(); + + + public: + /** Return access to the vector data as a raw pointer. */ + pointer data(); + + /** Return const access to the vector data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator. */ + const_pointer begin() const; + + /** Read-only iterator. */ + const_pointer end() const; + + /** Resize the vector to the specified size. + * + * @note This will reallocate the array and copy existing elements, if + * any. + * + * @throws std::invalid_argument if @c n is negative. + */ + void resize(int n); + + /** Resize the vector to the specified size without copying the old + * elements. + * + * @throws std::invalid_argument if @c n is negative. + */ + void resize_fast(int n); + + + public: + /** Copy assignment. */ + vector_type& operator=(const vector_type& other); + + /** Move assignment. */ + vector_type& operator=(vector_type&& other); + + + protected: + /** No-op for trivially destructible elements + * (is_trivially_destructible). + */ + void destruct(pointer, int, std::true_type); + + /** Invoke non-trivial destructors for @c n elements starting at @c + * data. + */ + void destruct(pointer data, int n, std::false_type); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the length of the vector. */ + int i_size() const; + + /** Return vector const element @c i. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** @name writable_vector Interface */ + /*@{*/ + + friend writable_type; + + /** Return vector element @c i. */ + mutable_value i_get(int i); + + /** Set element @c i. */ + template vector_type& i_put(int i, const Other& v) &; + + /** Set element @c i on a temporary. */ + template vector_type&& i_put(int i, const Other& v) &&; + + /*@}*/ + + + protected: + /** Dynamic storage. */ + pointer m_data; + + /** Size of the vector. */ + int m_size; +}; + +} // namespace cml + +#define __CML_VECTOR_DYNAMIC_ALLOCATED_TPP +#include +#undef __CML_VECTOR_DYNAMIC_ALLOCATED_TPP diff --git a/cml/vector/dynamic_allocated.tpp b/cml/vector/dynamic_allocated.tpp index 3bd5c6f..17324a7 100644 --- a/cml/vector/dynamic_allocated.tpp +++ b/cml/vector/dynamic_allocated.tpp @@ -1,294 +1,294 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_DYNAMIC_ALLOCATED_TPP -# error "vector/dynamic_allocated.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* dynamic 'structors: */ - -template -vector>::vector() -: m_data(0) -, m_size(0) -{} - -template -template::value>*> -vector>::vector(Int size) -: m_data(0) -, m_size(0) -{ - this->resize_fast(int(size)); -} - -template -vector>::vector(const vector_type& other) -: m_data(0) -, m_size(0) -{ - this->assign(other); -} - -template -vector>::vector(vector_type&& other) -: m_data(0) -, m_size(0) -{ - this->operator=(std::move(other)); -} - -template -template -vector>::vector(const readable_vector& sub) -: m_data(0) -, m_size(0) -{ - this->assign(sub); -} - -template -template*> -vector>::vector(const Array& array) -: m_data(0) -, m_size(0) -{ - this->assign(array); -} - -template -template*> -vector>::vector(const Pointer& array, int size) -: m_data(0) -, m_size(0) -{ - this->resize_fast(size); - this->assign(array); -} - -template -template*> -vector>::vector(int size, const Pointer& array) -: m_data(0) -, m_size(0) -{ - this->resize_fast(size); - this->assign(array); -} - -template -template -vector>::vector(std::initializer_list l) -: m_data(0) -, m_size(0) -{ - this->assign(l); -} - -template vector>::~vector() -{ - using size_type = typename allocator_traits::size_type; - int n = this->m_size; - this->destruct(this->m_data, n, - typename std::is_trivially_destructible::type()); - - auto allocator = allocator_type(); - allocator_traits::deallocate(allocator, this->m_data, size_type(n)); -} - -/* Public methods: */ - -template -auto -vector>::data() -> pointer -{ - return this->m_data; -} - -template -auto -vector>::data() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::begin() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::end() const -> const_pointer -{ - return this->m_data + this->m_size; -} - -template -void -vector>::resize(int n) -{ - cml_require(n >= 0, std::invalid_argument, "size < 0"); - - /* Short-circuit same size: */ - if(n == this->m_size) return; - - /* Allocator to use: */ - auto allocator = allocator_type(); - - /* Allocate the new array: */ - pointer data = this->m_data; - int size = this->m_size; - pointer copy = allocator_traits::allocate(allocator, n); - try { - /* Destruct elements if necessary: */ - this->destruct(data, size, - typename std::is_trivially_destructible::type()); - - /* Copy elements to the new array if necessary: */ - if(data) { - int to = std::min(size, n); - for(pointer src = data, dst = copy; src < data + to; ++src, ++dst) { - allocator_traits::construct(allocator, dst, *src); - } - - /* Deallocate the old array: */ - allocator_traits::deallocate(allocator, data, size); - } - } catch(...) { - allocator_traits::deallocate(allocator, copy, n); - throw; - } - - /* Save the new array: */ - this->m_data = copy; - this->m_size = n; -} - -template -void -vector>::resize_fast(int n) -{ - cml_require(n >= 0, std::invalid_argument, "size < 0"); - - /* Short-circuit same size: */ - if(n == this->m_size) return; - - /* Allocator to use: */ - auto allocator = allocator_type(); - - /* Allocate the new array: */ - pointer data = this->m_data; - int size = this->m_size; - pointer copy = allocator_traits::allocate(allocator, n); - try { - /* Destruct elements if necessary: */ - this->destruct(data, size, - typename std::is_trivially_destructible::type()); - - /* Deallocate the old array: */ - allocator_traits::deallocate(allocator, data, size); - } catch(...) { - allocator_traits::deallocate(allocator, copy, n); - throw; - } - - /* Save the new array: */ - this->m_data = copy; - this->m_size = n; -} - -template -auto -vector>::operator=(const vector_type& other) -> vector_type& -{ - return this->assign(other); -} - -template -auto -vector>::operator=(vector_type&& other) -> vector_type& -{ - /* Ensure deletion of the current array, if any: */ - std::swap(this->m_data, other.m_data); - std::swap(this->m_size, other.m_size); - /* Note: swap() can't throw here, so this is exception-safe. */ - - return *this; -} - -/* Internal methods: */ - -template -void -vector>::destruct(pointer, int, std::true_type) -{ - /* Nothing to do. */ -} - -template -void -vector>::destruct(pointer data, int n, std::false_type) -{ - /* Short-circuit null: */ - if(data == nullptr) return; - - /* Destruct each element: */ - else { - auto allocator = allocator_type(); - for(pointer e = data; e < data + n; ++e) - allocator_traits::destroy(allocator, e); - } -} - -/* readable_vector interface: */ - -template -int -vector>::i_size() const -{ - return this->m_size; -} - -template -auto -vector>::i_get(int i) const -> immutable_value -{ - return this->m_data[i]; -} - -/* writable_vector interface: */ - -template -auto -vector>::i_get(int i) -> mutable_value -{ - return this->m_data[i]; -} - -template -template -auto -vector>::i_put(int i, const Other& v) &->vector_type& -{ - this->m_data[i] = value_type(v); - return *this; -} - -template -template -auto -vector>::i_put(int i, const Other& v) && -> vector_type&& -{ - this->m_data[i] = value_type(v); - return (vector_type&&) *this; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_DYNAMIC_ALLOCATED_TPP +# error "vector/dynamic_allocated.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* dynamic 'structors: */ + +template +vector>::vector() +: m_data(0) +, m_size(0) +{} + +template +template::value>*> +vector>::vector(Int size) +: m_data(0) +, m_size(0) +{ + this->resize_fast(int(size)); +} + +template +vector>::vector(const vector_type& other) +: m_data(0) +, m_size(0) +{ + this->assign(other); +} + +template +vector>::vector(vector_type&& other) +: m_data(0) +, m_size(0) +{ + this->operator=(std::move(other)); +} + +template +template +vector>::vector(const readable_vector& sub) +: m_data(0) +, m_size(0) +{ + this->assign(sub); +} + +template +template*> +vector>::vector(const Array& array) +: m_data(0) +, m_size(0) +{ + this->assign(array); +} + +template +template*> +vector>::vector(const Pointer& array, int size) +: m_data(0) +, m_size(0) +{ + this->resize_fast(size); + this->assign(array); +} + +template +template*> +vector>::vector(int size, const Pointer& array) +: m_data(0) +, m_size(0) +{ + this->resize_fast(size); + this->assign(array); +} + +template +template +vector>::vector(std::initializer_list l) +: m_data(0) +, m_size(0) +{ + this->assign(l); +} + +template vector>::~vector() +{ + using size_type = typename allocator_traits::size_type; + int n = this->m_size; + this->destruct(this->m_data, n, + typename std::is_trivially_destructible::type()); + + auto allocator = allocator_type(); + allocator_traits::deallocate(allocator, this->m_data, size_type(n)); +} + +/* Public methods: */ + +template +auto +vector>::data() -> pointer +{ + return this->m_data; +} + +template +auto +vector>::data() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::begin() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::end() const -> const_pointer +{ + return this->m_data + this->m_size; +} + +template +void +vector>::resize(int n) +{ + cml_require(n >= 0, std::invalid_argument, "size < 0"); + + /* Short-circuit same size: */ + if(n == this->m_size) return; + + /* Allocator to use: */ + auto allocator = allocator_type(); + + /* Allocate the new array: */ + pointer data = this->m_data; + int size = this->m_size; + pointer copy = allocator_traits::allocate(allocator, n); + try { + /* Destruct elements if necessary: */ + this->destruct(data, size, + typename std::is_trivially_destructible::type()); + + /* Copy elements to the new array if necessary: */ + if(data) { + int to = std::min(size, n); + for(pointer src = data, dst = copy; src < data + to; ++src, ++dst) { + allocator_traits::construct(allocator, dst, *src); + } + + /* Deallocate the old array: */ + allocator_traits::deallocate(allocator, data, size); + } + } catch(...) { + allocator_traits::deallocate(allocator, copy, n); + throw; + } + + /* Save the new array: */ + this->m_data = copy; + this->m_size = n; +} + +template +void +vector>::resize_fast(int n) +{ + cml_require(n >= 0, std::invalid_argument, "size < 0"); + + /* Short-circuit same size: */ + if(n == this->m_size) return; + + /* Allocator to use: */ + auto allocator = allocator_type(); + + /* Allocate the new array: */ + pointer data = this->m_data; + int size = this->m_size; + pointer copy = allocator_traits::allocate(allocator, n); + try { + /* Destruct elements if necessary: */ + this->destruct(data, size, + typename std::is_trivially_destructible::type()); + + /* Deallocate the old array: */ + allocator_traits::deallocate(allocator, data, size); + } catch(...) { + allocator_traits::deallocate(allocator, copy, n); + throw; + } + + /* Save the new array: */ + this->m_data = copy; + this->m_size = n; +} + +template +auto +vector>::operator=(const vector_type& other) -> vector_type& +{ + return this->assign(other); +} + +template +auto +vector>::operator=(vector_type&& other) -> vector_type& +{ + /* Ensure deletion of the current array, if any: */ + std::swap(this->m_data, other.m_data); + std::swap(this->m_size, other.m_size); + /* Note: swap() can't throw here, so this is exception-safe. */ + + return *this; +} + +/* Internal methods: */ + +template +void +vector>::destruct(pointer, int, std::true_type) +{ + /* Nothing to do. */ +} + +template +void +vector>::destruct(pointer data, int n, std::false_type) +{ + /* Short-circuit null: */ + if(data == nullptr) return; + + /* Destruct each element: */ + else { + auto allocator = allocator_type(); + for(pointer e = data; e < data + n; ++e) + allocator_traits::destroy(allocator, e); + } +} + +/* readable_vector interface: */ + +template +int +vector>::i_size() const +{ + return this->m_size; +} + +template +auto +vector>::i_get(int i) const -> immutable_value +{ + return this->m_data[i]; +} + +/* writable_vector interface: */ + +template +auto +vector>::i_get(int i) -> mutable_value +{ + return this->m_data[i]; +} + +template +template +auto +vector>::i_put(int i, const Other& v) &->vector_type& +{ + this->m_data[i] = value_type(v); + return *this; +} + +template +template +auto +vector>::i_put(int i, const Other& v) && -> vector_type&& +{ + this->m_data[i] = value_type(v); + return (vector_type&&) *this; +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/dynamic_const_external.h b/cml/vector/dynamic_const_external.h index c4a4833..6c42c8c 100644 --- a/cml/vector/dynamic_const_external.h +++ b/cml/vector/dynamic_const_external.h @@ -1,115 +1,115 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template struct vector_traits>> -{ - /* Traits and types for the vector element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using immutable_value = typename element_traits::immutable_value; - - /* The vector storage type: */ - using storage_type = rebind_t, vector_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array size (should be -1): */ - static const int array_size = storage_type::array_size; - static_assert(array_size == -1, "invalid vector size"); -}; - -/** Runtime-length wrapped array pointer as a vector. */ -template -class vector> -: public readable_vector>> -{ - public: - using vector_type = vector>; - using readable_type = readable_vector; - using traits_type = vector_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** Constant containing the array size. */ - static const int array_size = -1; - - - public: - /** Default construct with a null pointer and 0 size. - * - * @warning The default constructor is enabled only if the compiler - * supports rvalue references from *this. - */ - vector(); - - /** Construct from the wrapped pointer and size. */ - vector(const_pointer data, int size); - - /** Construct from the wrapped pointer and size. */ - vector(int size, const_pointer data); - - /** Move constructor. */ - vector(vector_type&& other); - - - public: - /** Return const access to the vector data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator. */ - const_pointer begin() const; - - /** Read-only iterator. */ - const_pointer end() const; - - /** Reset the vector to have no elements and no external pointer. */ - void reset(); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the length of the vector. */ - int i_size() const; - - /** Return vector const element @c i. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** Wrapped pointer. */ - const_pointer m_data; - - /** Number of elements. */ - int m_size; -}; - -} // namespace cml - -#define __CML_VECTOR_DYNAMIC_CONST_EXTERNAL_TPP -#include -#undef __CML_VECTOR_DYNAMIC_CONST_EXTERNAL_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template struct vector_traits>> +{ + /* Traits and types for the vector element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using immutable_value = typename element_traits::immutable_value; + + /* The vector storage type: */ + using storage_type = rebind_t, vector_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array size (should be -1): */ + static const int array_size = storage_type::array_size; + static_assert(array_size == -1, "invalid vector size"); +}; + +/** Runtime-length wrapped array pointer as a vector. */ +template +class vector> +: public readable_vector>> +{ + public: + using vector_type = vector>; + using readable_type = readable_vector; + using traits_type = vector_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** Constant containing the array size. */ + static const int array_size = -1; + + + public: + /** Default construct with a null pointer and 0 size. + * + * @warning The default constructor is enabled only if the compiler + * supports rvalue references from *this. + */ + vector(); + + /** Construct from the wrapped pointer and size. */ + vector(const_pointer data, int size); + + /** Construct from the wrapped pointer and size. */ + vector(int size, const_pointer data); + + /** Move constructor. */ + vector(vector_type&& other); + + + public: + /** Return const access to the vector data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator. */ + const_pointer begin() const; + + /** Read-only iterator. */ + const_pointer end() const; + + /** Reset the vector to have no elements and no external pointer. */ + void reset(); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the length of the vector. */ + int i_size() const; + + /** Return vector const element @c i. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** Wrapped pointer. */ + const_pointer m_data; + + /** Number of elements. */ + int m_size; +}; + +} // namespace cml + +#define __CML_VECTOR_DYNAMIC_CONST_EXTERNAL_TPP +#include +#undef __CML_VECTOR_DYNAMIC_CONST_EXTERNAL_TPP diff --git a/cml/vector/dynamic_const_external.tpp b/cml/vector/dynamic_const_external.tpp index 2691c17..74a49f9 100644 --- a/cml/vector/dynamic_const_external.tpp +++ b/cml/vector/dynamic_const_external.tpp @@ -1,94 +1,94 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_DYNAMIC_CONST_EXTERNAL_TPP -# error "vector/dynamic_const_external.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* dynamic_const_external 'structors: */ - -template -vector>::vector() -: m_data(0) -, m_size(0) -{} - -template -vector>::vector(const_pointer data, int size) -: m_data(data) -, m_size(size) -{ - cml_require(size >= 0, std::invalid_argument, "size < 0"); -} - -template -vector>::vector(int size, const_pointer data) -: m_data(data) -, m_size(size) -{ - cml_require(size >= 0, std::invalid_argument, "size < 0"); -} - -template vector>::vector(vector_type&& other) -{ - this->m_data = other.m_data; - this->m_size = other.m_size; - other.m_data = nullptr; - other.m_size = 0; -} - -/* Public methods: */ - -template -auto -vector>::data() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::begin() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::end() const -> const_pointer -{ - return this->m_data + this->m_size; -} - -template -void -vector>::reset() -{ - this->m_size = 0; - this->m_data = nullptr; -} - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector>::i_size() const -{ - return this->m_size; -} - -template -auto -vector>::i_get(int i) const -> immutable_value -{ - return this->m_data[i]; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_DYNAMIC_CONST_EXTERNAL_TPP +# error "vector/dynamic_const_external.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* dynamic_const_external 'structors: */ + +template +vector>::vector() +: m_data(0) +, m_size(0) +{} + +template +vector>::vector(const_pointer data, int size) +: m_data(data) +, m_size(size) +{ + cml_require(size >= 0, std::invalid_argument, "size < 0"); +} + +template +vector>::vector(int size, const_pointer data) +: m_data(data) +, m_size(size) +{ + cml_require(size >= 0, std::invalid_argument, "size < 0"); +} + +template vector>::vector(vector_type&& other) +{ + this->m_data = other.m_data; + this->m_size = other.m_size; + other.m_data = nullptr; + other.m_size = 0; +} + +/* Public methods: */ + +template +auto +vector>::data() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::begin() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::end() const -> const_pointer +{ + return this->m_data + this->m_size; +} + +template +void +vector>::reset() +{ + this->m_size = 0; + this->m_data = nullptr; +} + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector>::i_size() const +{ + return this->m_size; +} + +template +auto +vector>::i_get(int i) const -> immutable_value +{ + return this->m_data[i]; +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/dynamic_external.h b/cml/vector/dynamic_external.h index 66215ce..f399a44 100644 --- a/cml/vector/dynamic_external.h +++ b/cml/vector/dynamic_external.h @@ -1,175 +1,175 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -/* Need const specializations with non-const for proper type trait - * resolution: - */ -#include - -namespace cml { - -template struct vector_traits>> -{ - /* Traits and types for the vector element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The vector storage type: */ - using storage_type = rebind_t, vector_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array size (should be -1): */ - static const int array_size = storage_type::array_size; - static_assert(array_size == -1, "invalid vector size"); -}; - -/** Runtime-length wrapped array pointer as a vector. */ -template -class vector> -: public writable_vector>> -{ - public: - using vector_type = vector>; - using readable_type = readable_vector; - using writable_type = writable_vector; - using traits_type = vector_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /* Include methods from writable_type: */ - using writable_type::operator[]; - using writable_type::operator=; - - - public: - /** Constant containing the array size. */ - static const int array_size = -1; - - - public: - /** Default construct with a null pointer and 0 size. - * - * @warning The default constructor is enabled only if the compiler - * supports rvalue references from *this. - */ - vector(); - - /** Construct from the wrapped pointer and size. - * - * @note This is for CML1 compatibility. - */ - vector(pointer data, int size); - - /** Construct from the wrapped pointer and size. */ - vector(int size, pointer data); - - /** Copy constructor. - * - * @warning This copy has the semantics of a raw pointer, and can lead - * to memory leaks if not used correctly. - */ - vector(const vector_type& other); - - /** Move constructor. */ - vector(vector_type&& other); - - - public: - /** Return access to the vector data as a raw pointer. */ - pointer data(); - - /** Return const access to the vector data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator. */ - const_pointer begin() const; - - /** Read-only iterator. */ - const_pointer end() const; - - /** Reset the vector to have no elements and no external pointer. */ - void reset(); - - - public: - /** Copy assignment. - * - * @note This copies element-by-element from @c other. - */ - vector_type& operator=(const vector_type& other); - - /** Move assignment. */ - vector_type& operator=(vector_type&& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the length of the vector. */ - int i_size() const; - - /** Return vector const element @c i. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** @name writable_vector Interface */ - /*@{*/ - - friend writable_type; - - /** Return vector element @c i. */ - mutable_value i_get(int i); - - /** Set element @c i. */ - template vector_type& i_put(int i, const Other& v) &; - - /** Set element @c i on a temporary. */ - template vector_type&& i_put(int i, const Other& v) &&; - - /*@}*/ - - - protected: - /** Wrapped pointer. */ - pointer m_data; - - /** Number of elements. */ - int m_size; -}; - -} // namespace cml - -#define __CML_VECTOR_DYNAMIC_EXTERNAL_TPP -#include -#undef __CML_VECTOR_DYNAMIC_EXTERNAL_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +/* Need const specializations with non-const for proper type trait + * resolution: + */ +#include + +namespace cml { + +template struct vector_traits>> +{ + /* Traits and types for the vector element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The vector storage type: */ + using storage_type = rebind_t, vector_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array size (should be -1): */ + static const int array_size = storage_type::array_size; + static_assert(array_size == -1, "invalid vector size"); +}; + +/** Runtime-length wrapped array pointer as a vector. */ +template +class vector> +: public writable_vector>> +{ + public: + using vector_type = vector>; + using readable_type = readable_vector; + using writable_type = writable_vector; + using traits_type = vector_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /* Include methods from writable_type: */ + using writable_type::operator[]; + using writable_type::operator=; + + + public: + /** Constant containing the array size. */ + static const int array_size = -1; + + + public: + /** Default construct with a null pointer and 0 size. + * + * @warning The default constructor is enabled only if the compiler + * supports rvalue references from *this. + */ + vector(); + + /** Construct from the wrapped pointer and size. + * + * @note This is for CML1 compatibility. + */ + vector(pointer data, int size); + + /** Construct from the wrapped pointer and size. */ + vector(int size, pointer data); + + /** Copy constructor. + * + * @warning This copy has the semantics of a raw pointer, and can lead + * to memory leaks if not used correctly. + */ + vector(const vector_type& other); + + /** Move constructor. */ + vector(vector_type&& other); + + + public: + /** Return access to the vector data as a raw pointer. */ + pointer data(); + + /** Return const access to the vector data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator. */ + const_pointer begin() const; + + /** Read-only iterator. */ + const_pointer end() const; + + /** Reset the vector to have no elements and no external pointer. */ + void reset(); + + + public: + /** Copy assignment. + * + * @note This copies element-by-element from @c other. + */ + vector_type& operator=(const vector_type& other); + + /** Move assignment. */ + vector_type& operator=(vector_type&& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the length of the vector. */ + int i_size() const; + + /** Return vector const element @c i. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** @name writable_vector Interface */ + /*@{*/ + + friend writable_type; + + /** Return vector element @c i. */ + mutable_value i_get(int i); + + /** Set element @c i. */ + template vector_type& i_put(int i, const Other& v) &; + + /** Set element @c i on a temporary. */ + template vector_type&& i_put(int i, const Other& v) &&; + + /*@}*/ + + + protected: + /** Wrapped pointer. */ + pointer m_data; + + /** Number of elements. */ + int m_size; +}; + +} // namespace cml + +#define __CML_VECTOR_DYNAMIC_EXTERNAL_TPP +#include +#undef __CML_VECTOR_DYNAMIC_EXTERNAL_TPP diff --git a/cml/vector/dynamic_external.tpp b/cml/vector/dynamic_external.tpp index 1d75bd7..10a62c6 100644 --- a/cml/vector/dynamic_external.tpp +++ b/cml/vector/dynamic_external.tpp @@ -1,153 +1,153 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_DYNAMIC_EXTERNAL_TPP -# error "vector/dynamic_external.tpp not included correctly" -#endif - -#include - -namespace cml { - -/* dynamic_external 'structors: */ - -template -vector>::vector() -: m_data(0) -, m_size(0) -{ -} - -template -vector>::vector(pointer data, int size) -: m_data(data) -, m_size(size) -{ - cml_require(size >= 0, std::invalid_argument, "size < 0"); -} - -template -vector>::vector(int size, pointer data) -: m_data(data) -, m_size(size) -{ - cml_require(size >= 0, std::invalid_argument, "size < 0"); -} - -template vector>::vector(const vector_type& other) -{ - this->m_data = other.m_data; - this->m_size = other.m_size; -} - -template vector>::vector(vector_type&& other) -{ - this->m_data = other.m_data; - this->m_size = other.m_size; - other.m_data = nullptr; - other.m_size = 0; -} - -/* Public methods: */ - -template -auto -vector>::data() -> pointer -{ - return this->m_data; -} - -template -auto -vector>::data() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::begin() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::end() const -> const_pointer -{ - return this->m_data + this->m_size; -} - -template -void -vector>::reset() -{ - this->m_size = 0; - this->m_data = nullptr; -} - -template -auto -vector>::operator=(const vector_type& other) -> vector_type& -{ - return this->assign(other); -} - -template -auto -vector>::operator=(vector_type&& other) -> vector_type& -{ - this->m_data = other.m_data; - this->m_size = other.m_size; - other.m_data = nullptr; - other.m_size = 0; - return *this; -} - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector>::i_size() const -{ - return this->m_size; -} - -template -auto -vector>::i_get(int i) const -> immutable_value -{ - return this->m_data[i]; -} - -/* writable_vector interface: */ - -template -auto -vector>::i_get(int i) -> mutable_value -{ - return this->m_data[i]; -} - -template -template -auto -vector>::i_put(int i, const Other& v) &->vector_type& -{ - this->m_data[i] = value_type(v); - return *this; -} - -template -template -auto -vector>::i_put(int i, const Other& v) && -> vector_type&& -{ - this->m_data[i] = value_type(v); - return (vector_type&&) *this; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_DYNAMIC_EXTERNAL_TPP +# error "vector/dynamic_external.tpp not included correctly" +#endif + +#include + +namespace cml { + +/* dynamic_external 'structors: */ + +template +vector>::vector() +: m_data(0) +, m_size(0) +{ +} + +template +vector>::vector(pointer data, int size) +: m_data(data) +, m_size(size) +{ + cml_require(size >= 0, std::invalid_argument, "size < 0"); +} + +template +vector>::vector(int size, pointer data) +: m_data(data) +, m_size(size) +{ + cml_require(size >= 0, std::invalid_argument, "size < 0"); +} + +template vector>::vector(const vector_type& other) +{ + this->m_data = other.m_data; + this->m_size = other.m_size; +} + +template vector>::vector(vector_type&& other) +{ + this->m_data = other.m_data; + this->m_size = other.m_size; + other.m_data = nullptr; + other.m_size = 0; +} + +/* Public methods: */ + +template +auto +vector>::data() -> pointer +{ + return this->m_data; +} + +template +auto +vector>::data() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::begin() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::end() const -> const_pointer +{ + return this->m_data + this->m_size; +} + +template +void +vector>::reset() +{ + this->m_size = 0; + this->m_data = nullptr; +} + +template +auto +vector>::operator=(const vector_type& other) -> vector_type& +{ + return this->assign(other); +} + +template +auto +vector>::operator=(vector_type&& other) -> vector_type& +{ + this->m_data = other.m_data; + this->m_size = other.m_size; + other.m_data = nullptr; + other.m_size = 0; + return *this; +} + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector>::i_size() const +{ + return this->m_size; +} + +template +auto +vector>::i_get(int i) const -> immutable_value +{ + return this->m_data[i]; +} + +/* writable_vector interface: */ + +template +auto +vector>::i_get(int i) -> mutable_value +{ + return this->m_data[i]; +} + +template +template +auto +vector>::i_put(int i, const Other& v) &->vector_type& +{ + this->m_data[i] = value_type(v); + return *this; +} + +template +template +auto +vector>::i_put(int i, const Other& v) && -> vector_type&& +{ + this->m_data[i] = value_type(v); + return (vector_type&&) *this; +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/external.h b/cml/vector/external.h index 56b4020..d6defc2 100644 --- a/cml/vector/external.h +++ b/cml/vector/external.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/vector/fixed.h b/cml/vector/fixed.h index 192d9af..71cf452 100644 --- a/cml/vector/fixed.h +++ b/cml/vector/fixed.h @@ -1,7 +1,7 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include diff --git a/cml/vector/fixed_compiled.h b/cml/vector/fixed_compiled.h index 2e0acdd..32302ea 100644 --- a/cml/vector/fixed_compiled.h +++ b/cml/vector/fixed_compiled.h @@ -1,210 +1,210 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template -struct vector_traits>> -{ - /* Traits and types for the vector element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The vector storage type: */ - using storage_type = rebind_t, vector_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array size (should be positive): */ - static const int array_size = storage_type::array_size; - static_assert(array_size > 0, "invalid vector size"); -}; - -/** Fixed-length vector. */ -template -class vector> -: public writable_vector>> -{ - public: - using vector_type = vector>; - using readable_type = readable_vector; - using writable_type = writable_vector; - using traits_type = vector_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /* Include methods from writable_type: */ - using writable_type::operator[]; - using writable_type::operator=; - - - public: - /** Constant containing the array size. */ - static const int array_size = traits_type::array_size; - - /** The dimension (same as array_size). */ - static const int dimension = array_size; - - - public: - /** Compiler-default constructor. - * - * @note The vector elements are uninitialized. - */ - vector() = default; - - /** Compiler-default destructor. */ - ~vector() = default; - - /** Compiler-default copy constructor. */ - vector(const vector_type& other) = default; - - /** Compiler-default move constructor. */ - vector(vector_type&& other) = default; - - /** Construct from a readable_vector. */ - template vector(const readable_vector& sub); - - /** Construct from at least 1 value. - * - * @note This overload is enabled only if all of the arguments are - * convertible to value_type. - */ - template* = nullptr> - vector(const E0& e0, const Elements&... eN) - // XXX Should be in vector/fixed_compiled.tpp, but VC++12 has - // brain-dead out-of-line template argument matching... - { - this->assign_elements(e0, eN...); - } - - /** Construct from a readable_vector and at least one - * additional element. - * - * @note This overload is enabled only if the value_type of @c sub and - * all of the scalar arguments are convertible to value_type. - */ - template, E0, - Elements...>* = nullptr> - vector(const readable_vector& sub, const E0& e0, const Elements&... eN) - // XXX Should be in vector/fixed_compiled.tpp, but VC++12 has - // brain-dead out-of-line template argument matching... - { - this->assign(sub, e0, eN...); - } - - /** Construct from an array type. */ - template* = nullptr> - vector(const Array& array); - - /** Construct from a pointer to an array. */ - template* = nullptr> - vector(const Pointer& array); - - /** Construct from std::initializer_list. */ - template vector(std::initializer_list l); - - - public: - /** Return access to the vector data as a raw pointer. */ - pointer data(); - - /** Return const access to the vector data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator. */ - const_pointer begin() const; - - /** Read-only iterator. */ - const_pointer end() const; - - - public: - /** Copy assignment. */ - vector_type& operator=(const vector_type& other); - - /** Move assignment. */ - vector_type& operator=(vector_type&& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the length of the vector. */ - int i_size() const; - - /** Return vector const element @c i. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** @name writable_vector Interface */ - /*@{*/ - - friend writable_type; - - /** Return vector element @c i. */ - mutable_value i_get(int i); - - /** Set element @c i. */ - template vector_type& i_put(int i, const Other& v) &; - - /** Set element @c i on a temporary. */ - template vector_type&& i_put(int i, const Other& v) &&; - - /*@}*/ - - - protected: - /** Fixed-length array. */ - value_type m_data[Size]; -}; - -} // namespace cml - -template -struct std::tuple_size>> -{ - static const int value = Size; -}; - -template -struct std::tuple_element>> -{ - using type = cml::value_type_of_t>>; -}; - -#define __CML_VECTOR_FIXED_COMPILED_TPP -#include -#undef __CML_VECTOR_FIXED_COMPILED_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template +struct vector_traits>> +{ + /* Traits and types for the vector element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The vector storage type: */ + using storage_type = rebind_t, vector_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array size (should be positive): */ + static const int array_size = storage_type::array_size; + static_assert(array_size > 0, "invalid vector size"); +}; + +/** Fixed-length vector. */ +template +class vector> +: public writable_vector>> +{ + public: + using vector_type = vector>; + using readable_type = readable_vector; + using writable_type = writable_vector; + using traits_type = vector_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /* Include methods from writable_type: */ + using writable_type::operator[]; + using writable_type::operator=; + + + public: + /** Constant containing the array size. */ + static const int array_size = traits_type::array_size; + + /** The dimension (same as array_size). */ + static const int dimension = array_size; + + + public: + /** Compiler-default constructor. + * + * @note The vector elements are uninitialized. + */ + vector() = default; + + /** Compiler-default destructor. */ + ~vector() = default; + + /** Compiler-default copy constructor. */ + vector(const vector_type& other) = default; + + /** Compiler-default move constructor. */ + vector(vector_type&& other) = default; + + /** Construct from a readable_vector. */ + template vector(const readable_vector& sub); + + /** Construct from at least 1 value. + * + * @note This overload is enabled only if all of the arguments are + * convertible to value_type. + */ + template* = nullptr> + vector(const E0& e0, const Elements&... eN) + // XXX Should be in vector/fixed_compiled.tpp, but VC++12 has + // brain-dead out-of-line template argument matching... + { + this->assign_elements(e0, eN...); + } + + /** Construct from a readable_vector and at least one + * additional element. + * + * @note This overload is enabled only if the value_type of @c sub and + * all of the scalar arguments are convertible to value_type. + */ + template, E0, + Elements...>* = nullptr> + vector(const readable_vector& sub, const E0& e0, const Elements&... eN) + // XXX Should be in vector/fixed_compiled.tpp, but VC++12 has + // brain-dead out-of-line template argument matching... + { + this->assign(sub, e0, eN...); + } + + /** Construct from an array type. */ + template* = nullptr> + vector(const Array& array); + + /** Construct from a pointer to an array. */ + template* = nullptr> + vector(const Pointer& array); + + /** Construct from std::initializer_list. */ + template vector(std::initializer_list l); + + + public: + /** Return access to the vector data as a raw pointer. */ + pointer data(); + + /** Return const access to the vector data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator. */ + const_pointer begin() const; + + /** Read-only iterator. */ + const_pointer end() const; + + + public: + /** Copy assignment. */ + vector_type& operator=(const vector_type& other); + + /** Move assignment. */ + vector_type& operator=(vector_type&& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the length of the vector. */ + int i_size() const; + + /** Return vector const element @c i. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** @name writable_vector Interface */ + /*@{*/ + + friend writable_type; + + /** Return vector element @c i. */ + mutable_value i_get(int i); + + /** Set element @c i. */ + template vector_type& i_put(int i, const Other& v) &; + + /** Set element @c i on a temporary. */ + template vector_type&& i_put(int i, const Other& v) &&; + + /*@}*/ + + + protected: + /** Fixed-length array. */ + value_type m_data[Size]; +}; + +} // namespace cml + +template +struct std::tuple_size>> +{ + static const int value = Size; +}; + +template +struct std::tuple_element>> +{ + using type = cml::value_type_of_t>>; +}; + +#define __CML_VECTOR_FIXED_COMPILED_TPP +#include +#undef __CML_VECTOR_FIXED_COMPILED_TPP diff --git a/cml/vector/fixed_compiled.tpp b/cml/vector/fixed_compiled.tpp index ea42f23..c56b373 100644 --- a/cml/vector/fixed_compiled.tpp +++ b/cml/vector/fixed_compiled.tpp @@ -1,131 +1,131 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_FIXED_COMPILED_TPP -# error "vector/fixed_compiled.tpp not included correctly" -#endif - -namespace cml { - -/* fixed 'structors: */ - -template -template -vector>::vector(const readable_vector& sub) -{ - this->assign(sub); -} - -template -template*> -vector>::vector(const Array& array) -{ - this->assign(array); -} - -template -template*> -vector>::vector(const Pointer& array) -{ - this->assign(array); -} - -template -template -vector>::vector(std::initializer_list l) -{ - this->assign(l); -} - -/* Public methods: */ - -template -auto -vector>::data() -> pointer -{ - return &this->m_data[0]; -} - -template -auto -vector>::data() const -> const_pointer -{ - return &this->m_data[0]; -} - -template -auto -vector>::begin() const -> const_pointer -{ - return &this->m_data[0]; -} - -template -auto -vector>::end() const -> const_pointer -{ - return (&this->m_data[0]) + S; -} - -template -auto -vector>::operator=(const vector_type& other) -> vector_type& -{ - return this->assign(other); -} - -template -auto -vector>::operator=(vector_type&& other) -> vector_type& -{ - for(int i = 0; i < S; ++i) this->m_data[i] = std::move(other.m_data[i]); - return *this; -} - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector>::i_size() const -{ - return S; -} - -template -auto -vector>::i_get(int i) const -> immutable_value -{ - return this->m_data[i]; -} - -/* writable_vector interface: */ - -template -auto -vector>::i_get(int i) -> mutable_value -{ - return this->m_data[i]; -} - -template -template -auto -vector>::i_put(int i, const Other& v) &->vector_type& -{ - this->m_data[i] = value_type(v); - return *this; -} - -template -template -auto -vector>::i_put(int i, const Other& v) && -> vector_type&& -{ - this->m_data[i] = value_type(v); - return (vector_type&&) *this; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_FIXED_COMPILED_TPP +# error "vector/fixed_compiled.tpp not included correctly" +#endif + +namespace cml { + +/* fixed 'structors: */ + +template +template +vector>::vector(const readable_vector& sub) +{ + this->assign(sub); +} + +template +template*> +vector>::vector(const Array& array) +{ + this->assign(array); +} + +template +template*> +vector>::vector(const Pointer& array) +{ + this->assign(array); +} + +template +template +vector>::vector(std::initializer_list l) +{ + this->assign(l); +} + +/* Public methods: */ + +template +auto +vector>::data() -> pointer +{ + return &this->m_data[0]; +} + +template +auto +vector>::data() const -> const_pointer +{ + return &this->m_data[0]; +} + +template +auto +vector>::begin() const -> const_pointer +{ + return &this->m_data[0]; +} + +template +auto +vector>::end() const -> const_pointer +{ + return (&this->m_data[0]) + S; +} + +template +auto +vector>::operator=(const vector_type& other) -> vector_type& +{ + return this->assign(other); +} + +template +auto +vector>::operator=(vector_type&& other) -> vector_type& +{ + for(int i = 0; i < S; ++i) this->m_data[i] = std::move(other.m_data[i]); + return *this; +} + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector>::i_size() const +{ + return S; +} + +template +auto +vector>::i_get(int i) const -> immutable_value +{ + return this->m_data[i]; +} + +/* writable_vector interface: */ + +template +auto +vector>::i_get(int i) -> mutable_value +{ + return this->m_data[i]; +} + +template +template +auto +vector>::i_put(int i, const Other& v) &->vector_type& +{ + this->m_data[i] = value_type(v); + return *this; +} + +template +template +auto +vector>::i_put(int i, const Other& v) && -> vector_type&& +{ + this->m_data[i] = value_type(v); + return (vector_type&&) *this; +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/fixed_const_external.h b/cml/vector/fixed_const_external.h index d0f6e52..e78e35e 100644 --- a/cml/vector/fixed_const_external.h +++ b/cml/vector/fixed_const_external.h @@ -1,110 +1,110 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template -struct vector_traits>> -{ - /* Traits and types for the vector element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using immutable_value = typename element_traits::immutable_value; - - /* The vector storage type: */ - using storage_type = rebind_t, vector_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array size (should be positive): */ - static const int array_size = storage_type::array_size; - static_assert(array_size > 0, "invalid vector size"); -}; - -/** Fixed-length wrapped array pointer as a vector. */ -template -class vector> -: public readable_vector>> -{ - public: - using vector_type = vector>; - using readable_type = readable_vector; - using traits_type = vector_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** Constant containing the array size. */ - static const int array_size = traits_type::array_size; - - /** The dimension (same as array_size). */ - static const int dimension = array_size; - - - public: - /** Default construct with a null pointer. - * - * @warning The default constructor is enabled only if the compiler - * supports rvalue references from *this. - */ - vector(); - - /** Construct from the wrapped pointer. */ - explicit vector(const_pointer data); - - /** Move constructor. */ - vector(vector_type&& other); - - - public: - /** Return const access to the vector data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator. */ - const_pointer begin() const; - - /** Read-only iterator. */ - const_pointer end() const; - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the length of the vector. */ - int i_size() const; - - /** Return vector const element @c i. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** Wrapped pointer. */ - const_pointer m_data; -}; - -} // namespace cml - -#define __CML_VECTOR_FIXED_CONST_EXTERNAL_TPP -#include -#undef __CML_VECTOR_FIXED_CONST_EXTERNAL_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template +struct vector_traits>> +{ + /* Traits and types for the vector element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using immutable_value = typename element_traits::immutable_value; + + /* The vector storage type: */ + using storage_type = rebind_t, vector_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array size (should be positive): */ + static const int array_size = storage_type::array_size; + static_assert(array_size > 0, "invalid vector size"); +}; + +/** Fixed-length wrapped array pointer as a vector. */ +template +class vector> +: public readable_vector>> +{ + public: + using vector_type = vector>; + using readable_type = readable_vector; + using traits_type = vector_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** Constant containing the array size. */ + static const int array_size = traits_type::array_size; + + /** The dimension (same as array_size). */ + static const int dimension = array_size; + + + public: + /** Default construct with a null pointer. + * + * @warning The default constructor is enabled only if the compiler + * supports rvalue references from *this. + */ + vector(); + + /** Construct from the wrapped pointer. */ + explicit vector(const_pointer data); + + /** Move constructor. */ + vector(vector_type&& other); + + + public: + /** Return const access to the vector data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator. */ + const_pointer begin() const; + + /** Read-only iterator. */ + const_pointer end() const; + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the length of the vector. */ + int i_size() const; + + /** Return vector const element @c i. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** Wrapped pointer. */ + const_pointer m_data; +}; + +} // namespace cml + +#define __CML_VECTOR_FIXED_CONST_EXTERNAL_TPP +#include +#undef __CML_VECTOR_FIXED_CONST_EXTERNAL_TPP diff --git a/cml/vector/fixed_const_external.tpp b/cml/vector/fixed_const_external.tpp index 7fe787b..8555e5e 100644 --- a/cml/vector/fixed_const_external.tpp +++ b/cml/vector/fixed_const_external.tpp @@ -1,71 +1,71 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_FIXED_CONST_EXTERNAL_TPP -# error "vector/fixed_const_external.tpp not included correctly" -#endif - -namespace cml { - -/* fixed_external 'structors: */ - -template -vector>::vector() -: m_data(0) -{} - -template -vector>::vector(const_pointer data) -: m_data(data) -{} - -template -vector>::vector(vector_type&& other) -{ - this->m_data = other.m_data; - other.m_data = nullptr; -} - -/* Public methods: */ - -template -auto -vector>::data() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::begin() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::end() const -> const_pointer -{ - return this->m_data + S; -} - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector>::i_size() const -{ - return S; -} - -template -auto -vector>::i_get(int i) const -> immutable_value -{ - return this->m_data[i]; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_FIXED_CONST_EXTERNAL_TPP +# error "vector/fixed_const_external.tpp not included correctly" +#endif + +namespace cml { + +/* fixed_external 'structors: */ + +template +vector>::vector() +: m_data(0) +{} + +template +vector>::vector(const_pointer data) +: m_data(data) +{} + +template +vector>::vector(vector_type&& other) +{ + this->m_data = other.m_data; + other.m_data = nullptr; +} + +/* Public methods: */ + +template +auto +vector>::data() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::begin() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::end() const -> const_pointer +{ + return this->m_data + S; +} + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector>::i_size() const +{ + return S; +} + +template +auto +vector>::i_get(int i) const -> immutable_value +{ + return this->m_data[i]; +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/fixed_external.h b/cml/vector/fixed_external.h index b26cf01..0a70937 100644 --- a/cml/vector/fixed_external.h +++ b/cml/vector/fixed_external.h @@ -1,176 +1,176 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -/* Need const specializations with non-const for proper type trait - * resolution: - */ -#include - -namespace cml { - -template -struct vector_traits>> -{ - /* Traits and types for the vector element: */ - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using pointer = typename element_traits::pointer; - using reference = typename element_traits::reference; - using const_pointer = typename element_traits::const_pointer; - using const_reference = typename element_traits::const_reference; - using mutable_value = typename element_traits::mutable_value; - using immutable_value = typename element_traits::immutable_value; - - /* The vector storage type: */ - using storage_type = rebind_t, vector_storage_tag>; - using size_tag = typename storage_type::size_tag; - static_assert(std::is_same::value, - "invalid size tag"); - - /* Array size (should be positive): */ - static const int array_size = storage_type::array_size; - static_assert(array_size > 0, "invalid vector size"); -}; - -/** Fixed-length wrapped array pointer as a vector. */ -template -class vector> -: public writable_vector>> -{ - public: - using vector_type = vector>; - using readable_type = readable_vector; - using writable_type = writable_vector; - using traits_type = vector_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using pointer = typename traits_type::pointer; - using reference = typename traits_type::reference; - using const_pointer = typename traits_type::const_pointer; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /* Include methods from writable_type: */ - using writable_type::operator[]; - using writable_type::operator=; - - - public: - /** Constant containing the array size. */ - static const int array_size = traits_type::array_size; - - /** The dimension (same as array_size). */ - static const int dimension = array_size; - - - public: - /** Default construct with a null pointer. */ - vector(); - - /** Construct from the wrapped pointer. */ - explicit vector(pointer data); - - /** Copy constructor. - * - * @warning This copy has the semantics of a raw pointer, and can lead - * to memory leaks if not used correctly. - */ - vector(const vector_type& other); - - /** Move constructor. */ - vector(vector_type&& other); - - - public: - /** Return access to the vector data as a raw pointer. */ - pointer data(); - - /** Return const access to the vector data as a raw pointer. */ - const_pointer data() const; - - /** Read-only iterator. */ - const_pointer begin() const; - - /** Read-only iterator. */ - const_pointer end() const; - - - public: - /** Copy assignment. - * - * @warning This assignment has the semantics of a raw pointer, and can - * lead to memory leaks if not used correctly. - */ - vector_type& operator=(const vector_type& other); - - /** Move assignment. */ - vector_type& operator=(vector_type&& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the length of the vector. */ - int i_size() const; - - /** Return vector const element @c i. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** @name writable_vector Interface */ - /*@{*/ - - friend writable_type; - - /** Return vector element @c i. */ - mutable_value i_get(int i); - - /** Set element @c i. */ - template vector_type& i_put(int i, const Other& v) &; - - /** Set element @c i on a temporary. */ - template vector_type&& i_put(int i, const Other& v) &&; - - /*@}*/ - - - protected: - /** Wrapped pointer. */ - pointer m_data; -}; - -} // namespace cml - -template -struct std::tuple_size>> -{ - static const int value = Size; -}; - -template -struct std::tuple_element>> -{ - using type = cml::value_type_of_t>>; -}; - -#define __CML_VECTOR_FIXED_EXTERNAL_TPP -#include -#undef __CML_VECTOR_FIXED_EXTERNAL_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +/* Need const specializations with non-const for proper type trait + * resolution: + */ +#include + +namespace cml { + +template +struct vector_traits>> +{ + /* Traits and types for the vector element: */ + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using pointer = typename element_traits::pointer; + using reference = typename element_traits::reference; + using const_pointer = typename element_traits::const_pointer; + using const_reference = typename element_traits::const_reference; + using mutable_value = typename element_traits::mutable_value; + using immutable_value = typename element_traits::immutable_value; + + /* The vector storage type: */ + using storage_type = rebind_t, vector_storage_tag>; + using size_tag = typename storage_type::size_tag; + static_assert(std::is_same::value, + "invalid size tag"); + + /* Array size (should be positive): */ + static const int array_size = storage_type::array_size; + static_assert(array_size > 0, "invalid vector size"); +}; + +/** Fixed-length wrapped array pointer as a vector. */ +template +class vector> +: public writable_vector>> +{ + public: + using vector_type = vector>; + using readable_type = readable_vector; + using writable_type = writable_vector; + using traits_type = vector_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using pointer = typename traits_type::pointer; + using reference = typename traits_type::reference; + using const_pointer = typename traits_type::const_pointer; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /* Include methods from writable_type: */ + using writable_type::operator[]; + using writable_type::operator=; + + + public: + /** Constant containing the array size. */ + static const int array_size = traits_type::array_size; + + /** The dimension (same as array_size). */ + static const int dimension = array_size; + + + public: + /** Default construct with a null pointer. */ + vector(); + + /** Construct from the wrapped pointer. */ + explicit vector(pointer data); + + /** Copy constructor. + * + * @warning This copy has the semantics of a raw pointer, and can lead + * to memory leaks if not used correctly. + */ + vector(const vector_type& other); + + /** Move constructor. */ + vector(vector_type&& other); + + + public: + /** Return access to the vector data as a raw pointer. */ + pointer data(); + + /** Return const access to the vector data as a raw pointer. */ + const_pointer data() const; + + /** Read-only iterator. */ + const_pointer begin() const; + + /** Read-only iterator. */ + const_pointer end() const; + + + public: + /** Copy assignment. + * + * @warning This assignment has the semantics of a raw pointer, and can + * lead to memory leaks if not used correctly. + */ + vector_type& operator=(const vector_type& other); + + /** Move assignment. */ + vector_type& operator=(vector_type&& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the length of the vector. */ + int i_size() const; + + /** Return vector const element @c i. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** @name writable_vector Interface */ + /*@{*/ + + friend writable_type; + + /** Return vector element @c i. */ + mutable_value i_get(int i); + + /** Set element @c i. */ + template vector_type& i_put(int i, const Other& v) &; + + /** Set element @c i on a temporary. */ + template vector_type&& i_put(int i, const Other& v) &&; + + /*@}*/ + + + protected: + /** Wrapped pointer. */ + pointer m_data; +}; + +} // namespace cml + +template +struct std::tuple_size>> +{ + static const int value = Size; +}; + +template +struct std::tuple_element>> +{ + using type = cml::value_type_of_t>>; +}; + +#define __CML_VECTOR_FIXED_EXTERNAL_TPP +#include +#undef __CML_VECTOR_FIXED_EXTERNAL_TPP diff --git a/cml/vector/fixed_external.tpp b/cml/vector/fixed_external.tpp index eaba87f..953e0a0 100644 --- a/cml/vector/fixed_external.tpp +++ b/cml/vector/fixed_external.tpp @@ -1,126 +1,126 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_FIXED_EXTERNAL_TPP -# error "vector/fixed_external.tpp not included correctly" -#endif - -namespace cml { - -/* fixed_external 'structors: */ - -template -vector>::vector() -: m_data(0) -{} - -template -vector>::vector(pointer data) -: m_data(data) -{} - -template -vector>::vector(const vector_type& other) -{ - this->m_data = other.m_data; -} - -template vector>::vector(vector_type&& other) -{ - this->m_data = other.m_data; - other.m_data = nullptr; -} - -/* Public methods: */ - -template -auto -vector>::data() -> pointer -{ - return this->m_data; -} - -template -auto -vector>::data() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::begin() const -> const_pointer -{ - return this->m_data; -} - -template -auto -vector>::end() const -> const_pointer -{ - return this->m_data + S; -} - -template -auto -vector>::operator=(const vector_type& other) -> vector_type& -{ - return this->assign(other); -} - -template -auto -vector>::operator=(vector_type&& other) -> vector_type& -{ - this->m_data = other.m_data; - other.m_data = nullptr; - return *this; -} - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector>::i_size() const -{ - return S; -} - -template -auto -vector>::i_get(int i) const -> immutable_value -{ - return this->m_data[i]; -} - -/* writable_vector interface: */ - -template -auto -vector>::i_get(int i) -> mutable_value -{ - return this->m_data[i]; -} - -template -template -auto -vector>::i_put(int i, const Other& v) &->vector_type& -{ - this->m_data[i] = value_type(v); - return *this; -} - -template -template -auto -vector>::i_put(int i, const Other& v) && -> vector_type&& -{ - this->m_data[i] = value_type(v); - return (vector_type&&) *this; -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_FIXED_EXTERNAL_TPP +# error "vector/fixed_external.tpp not included correctly" +#endif + +namespace cml { + +/* fixed_external 'structors: */ + +template +vector>::vector() +: m_data(0) +{} + +template +vector>::vector(pointer data) +: m_data(data) +{} + +template +vector>::vector(const vector_type& other) +{ + this->m_data = other.m_data; +} + +template vector>::vector(vector_type&& other) +{ + this->m_data = other.m_data; + other.m_data = nullptr; +} + +/* Public methods: */ + +template +auto +vector>::data() -> pointer +{ + return this->m_data; +} + +template +auto +vector>::data() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::begin() const -> const_pointer +{ + return this->m_data; +} + +template +auto +vector>::end() const -> const_pointer +{ + return this->m_data + S; +} + +template +auto +vector>::operator=(const vector_type& other) -> vector_type& +{ + return this->assign(other); +} + +template +auto +vector>::operator=(vector_type&& other) -> vector_type& +{ + this->m_data = other.m_data; + other.m_data = nullptr; + return *this; +} + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector>::i_size() const +{ + return S; +} + +template +auto +vector>::i_get(int i) const -> immutable_value +{ + return this->m_data[i]; +} + +/* writable_vector interface: */ + +template +auto +vector>::i_get(int i) -> mutable_value +{ + return this->m_data[i]; +} + +template +template +auto +vector>::i_put(int i, const Other& v) &->vector_type& +{ + this->m_data[i] = value_type(v); + return *this; +} + +template +template +auto +vector>::i_put(int i, const Other& v) && -> vector_type&& +{ + this->m_data[i] = value_type(v); + return (vector_type&&) *this; +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/functions.h b/cml/vector/functions.h index bf58958..a768bcb 100644 --- a/cml/vector/functions.h +++ b/cml/vector/functions.h @@ -1,30 +1,30 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Return the squared length of @c v. */ -template -auto length_squared(const readable_vector& v) - -> value_type_trait_of_t; - -/** Return the length of @c v. */ -template -auto length(const readable_vector& v) - -> value_type_trait_of_t; - -/** Return a normalized copy of @c v. */ -template -auto normalize(const readable_vector& v) -> temporary_of_t; - -} // namespace cml - -#define __CML_VECTOR_FUNCTIONS_TPP -#include -#undef __CML_VECTOR_FUNCTIONS_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Return the squared length of @c v. */ +template +auto length_squared(const readable_vector& v) + -> value_type_trait_of_t; + +/** Return the length of @c v. */ +template +auto length(const readable_vector& v) + -> value_type_trait_of_t; + +/** Return a normalized copy of @c v. */ +template +auto normalize(const readable_vector& v) -> temporary_of_t; + +} // namespace cml + +#define __CML_VECTOR_FUNCTIONS_TPP +#include +#undef __CML_VECTOR_FUNCTIONS_TPP diff --git a/cml/vector/functions.tpp b/cml/vector/functions.tpp index ec7d7d2..375e283 100644 --- a/cml/vector/functions.tpp +++ b/cml/vector/functions.tpp @@ -1,34 +1,34 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_FUNCTIONS_TPP -# error "vector/functions.tpp not included correctly" -#endif - -#include - -namespace cml { - -template -inline auto -length_squared(const readable_vector
& v) -> value_type_trait_of_t
-{ - return v.length_squared(); -} - -template -inline auto -length(const readable_vector
& v) -> value_type_trait_of_t
-{ - return v.length(); -} - -template -inline auto -normalize(const readable_vector
& v) -> temporary_of_t
-{ - return v.normalize(); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_FUNCTIONS_TPP +# error "vector/functions.tpp not included correctly" +#endif + +#include + +namespace cml { + +template +inline auto +length_squared(const readable_vector
& v) -> value_type_trait_of_t
+{ + return v.length_squared(); +} + +template +inline auto +length(const readable_vector
& v) -> value_type_trait_of_t
+{ + return v.length(); +} + +template +inline auto +normalize(const readable_vector
& v) -> temporary_of_t
+{ + return v.normalize(); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/fwd.h b/cml/vector/fwd.h index 89aa33e..3b479ee 100644 --- a/cml/vector/fwd.h +++ b/cml/vector/fwd.h @@ -1,12 +1,12 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -template class readable_vector; -template class writable_vector; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +template class readable_vector; +template class writable_vector; + +} // namespace cml diff --git a/cml/vector/hadamard_product.h b/cml/vector/hadamard_product.h index c5e744c..8ad6d1c 100644 --- a/cml/vector/hadamard_product.h +++ b/cml/vector/hadamard_product.h @@ -1,23 +1,23 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Elementwise (Hadamard) product of two vectors. */ -template* = nullptr, - enable_if_vector_t* = nullptr> -inline auto -hadamard(Sub1&& sub1, Sub2&& sub2) - -> decltype(make_vector_binary_node>( - std::forward(sub1), std::forward(sub2))) -{ - return make_vector_binary_node>( - std::forward(sub1), std::forward(sub2)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Elementwise (Hadamard) product of two vectors. */ +template* = nullptr, + enable_if_vector_t* = nullptr> +inline auto +hadamard(Sub1&& sub1, Sub2&& sub2) + -> decltype(make_vector_binary_node>( + std::forward(sub1), std::forward(sub2))) +{ + return make_vector_binary_node>( + std::forward(sub1), std::forward(sub2)); +} + +} // namespace cml diff --git a/cml/vector/ops.h b/cml/vector/ops.h index 3e78efd..20f56da 100644 --- a/cml/vector/ops.h +++ b/cml/vector/ops.h @@ -1,9 +1,9 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include diff --git a/cml/vector/outer_product.h b/cml/vector/outer_product.h index 04ed2f1..c81ec6c 100644 --- a/cml/vector/outer_product.h +++ b/cml/vector/outer_product.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/vector/outer_product_node.h b/cml/vector/outer_product_node.h index 15abd77..382693b 100644 --- a/cml/vector/outer_product_node.h +++ b/cml/vector/outer_product_node.h @@ -1,168 +1,168 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -template class outer_product_node; - -/** outer_product_node<> traits. */ -template -struct matrix_traits> -{ - using matrix_type = outer_product_node; - using left_arg_type = Sub1; - using right_arg_type = Sub2; - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = vector_traits; - using right_traits = vector_traits; - - /* Deduce the element type: */ - using element_traits = scalar_traits>; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - - /* Determine the common storage type for the node, based on the storage - * types of its subexpressions: - */ - using left_storage_type = storage_type_of_t; - using right_storage_type = storage_type_of_t; - using storage_type = matrix_outer_product_storage_promote_t; - - /* Traits and types for the storage: */ - using size_tag = typename storage_type::size_tag; - - /* Array rows: */ - static const int array_rows = storage_type::array_rows; - - /* Array cols: */ - static const int array_cols = storage_type::array_cols; - - /* Unspecified basis: */ - using basis_tag = any_basis; - - /* Unspecified layout: */ - using layout_tag = any_major; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = basis_tag::value; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = layout_tag::value; -}; - -/** Represents a vector outer product in an expression tree. */ -template -class outer_product_node -: public readable_matrix> -{ - public: - using node_type = outer_product_node; - using readable_type = readable_matrix; - using traits_type = matrix_traits; - using left_arg_type = typename traits_type::left_arg_type; - using right_arg_type = typename traits_type::right_arg_type; - using left_type = typename traits_type::left_type; - using right_type = typename traits_type::right_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - using basis_tag = typename traits_type::basis_tag; - using layout_tag = typename traits_type::layout_tag; - - - public: - /** Constant containing the number of rows. */ - static const int array_rows = traits_type::array_rows; - - /** Constant containing the number of columns. */ - static const int array_cols = traits_type::array_cols; - - /** Constant containing the array layout enumeration value. */ - static const layout_kind array_layout = traits_type::array_layout; - - /** Constant containing the matrix basis enumeration value. */ - static const basis_kind matrix_basis = traits_type::matrix_basis; - - - public: - /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be - * lvalue reference or rvalue reference types. - * - * @throws incompatible_matrix_sizes at run-time if either Sub1 or Sub2 - * is a dynamically-sized matrix, and sub1.size() != sub2.size(). If - * both Sub1 and Sub2 are fixed-size expressions, then the sizes are - * checked at compile time. - */ - outer_product_node(Sub1 left, Sub2 right); - - /** Move constructor. */ - outer_product_node(node_type&& other); - - /** Copy constructor. */ - outer_product_node(const node_type& other); - - protected: - /** @name readable_matrix Interface */ - /*@{*/ - - friend readable_type; - - /** Return the row size of the matrix expression. */ - int i_rows() const; - - /** Return the column size of the matrix expression. */ - int i_cols() const; - - /** Apply the operator to element @c (i,j) of the subexpressions and - * return the result. - */ - immutable_value i_get(int i, int j) const; - - /*@}*/ - - - protected: - /** The type used to store the left subexpression. The expression is - * stored as a copy if Sub1 is an rvalue reference (temporary), or by - * const reference if Sub1 is an lvalue reference. - */ - using left_wrap_type = cml::if_t::value, const left_type&, - left_type>; - - /** The type used to store the right subexpression. The expression is - * stored as a copy if Sub2 is an rvalue reference (temporary), or by - * const reference if Sub2 is an lvalue reference. - */ - using right_wrap_type = cml::if_t::value, const right_type&, - right_type>; - - - protected: - /** The wrapped left subexpression. */ - left_wrap_type m_left; - - /** The wrapped right subexpression. */ - right_wrap_type m_right; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_VECTOR_OUTER_PRODUCT_NODE_TPP -#include -#undef __CML_VECTOR_OUTER_PRODUCT_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +template class outer_product_node; + +/** outer_product_node<> traits. */ +template +struct matrix_traits> +{ + using matrix_type = outer_product_node; + using left_arg_type = Sub1; + using right_arg_type = Sub2; + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = vector_traits; + using right_traits = vector_traits; + + /* Deduce the element type: */ + using element_traits = scalar_traits>; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + + /* Determine the common storage type for the node, based on the storage + * types of its subexpressions: + */ + using left_storage_type = storage_type_of_t; + using right_storage_type = storage_type_of_t; + using storage_type = matrix_outer_product_storage_promote_t; + + /* Traits and types for the storage: */ + using size_tag = typename storage_type::size_tag; + + /* Array rows: */ + static const int array_rows = storage_type::array_rows; + + /* Array cols: */ + static const int array_cols = storage_type::array_cols; + + /* Unspecified basis: */ + using basis_tag = any_basis; + + /* Unspecified layout: */ + using layout_tag = any_major; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = basis_tag::value; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = layout_tag::value; +}; + +/** Represents a vector outer product in an expression tree. */ +template +class outer_product_node +: public readable_matrix> +{ + public: + using node_type = outer_product_node; + using readable_type = readable_matrix; + using traits_type = matrix_traits; + using left_arg_type = typename traits_type::left_arg_type; + using right_arg_type = typename traits_type::right_arg_type; + using left_type = typename traits_type::left_type; + using right_type = typename traits_type::right_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + using basis_tag = typename traits_type::basis_tag; + using layout_tag = typename traits_type::layout_tag; + + + public: + /** Constant containing the number of rows. */ + static const int array_rows = traits_type::array_rows; + + /** Constant containing the number of columns. */ + static const int array_cols = traits_type::array_cols; + + /** Constant containing the array layout enumeration value. */ + static const layout_kind array_layout = traits_type::array_layout; + + /** Constant containing the matrix basis enumeration value. */ + static const basis_kind matrix_basis = traits_type::matrix_basis; + + + public: + /** Construct from the wrapped sub-expressions. Sub1 and Sub2 must be + * lvalue reference or rvalue reference types. + * + * @throws incompatible_matrix_sizes at run-time if either Sub1 or Sub2 + * is a dynamically-sized matrix, and sub1.size() != sub2.size(). If + * both Sub1 and Sub2 are fixed-size expressions, then the sizes are + * checked at compile time. + */ + outer_product_node(Sub1 left, Sub2 right); + + /** Move constructor. */ + outer_product_node(node_type&& other); + + /** Copy constructor. */ + outer_product_node(const node_type& other); + + protected: + /** @name readable_matrix Interface */ + /*@{*/ + + friend readable_type; + + /** Return the row size of the matrix expression. */ + int i_rows() const; + + /** Return the column size of the matrix expression. */ + int i_cols() const; + + /** Apply the operator to element @c (i,j) of the subexpressions and + * return the result. + */ + immutable_value i_get(int i, int j) const; + + /*@}*/ + + + protected: + /** The type used to store the left subexpression. The expression is + * stored as a copy if Sub1 is an rvalue reference (temporary), or by + * const reference if Sub1 is an lvalue reference. + */ + using left_wrap_type = cml::if_t::value, const left_type&, + left_type>; + + /** The type used to store the right subexpression. The expression is + * stored as a copy if Sub2 is an rvalue reference (temporary), or by + * const reference if Sub2 is an lvalue reference. + */ + using right_wrap_type = cml::if_t::value, const right_type&, + right_type>; + + + protected: + /** The wrapped left subexpression. */ + left_wrap_type m_left; + + /** The wrapped right subexpression. */ + right_wrap_type m_right; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_VECTOR_OUTER_PRODUCT_NODE_TPP +#include +#undef __CML_VECTOR_OUTER_PRODUCT_NODE_TPP diff --git a/cml/vector/outer_product_node.tpp b/cml/vector/outer_product_node.tpp index 04c2aac..8d53e7b 100644 --- a/cml/vector/outer_product_node.tpp +++ b/cml/vector/outer_product_node.tpp @@ -1,57 +1,57 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_OUTER_PRODUCT_NODE_TPP -# error "vector/outer_product_node.tpp not included correctly" -#endif - -namespace cml { - -/* outer_product_node 'structors: */ - -template -outer_product_node::outer_product_node(Sub1 left, Sub2 right) -: m_left(std::move(left)) -, m_right(std::move(right)) -{} - -template -outer_product_node::outer_product_node(node_type&& other) -: m_left(std::move(other.m_left)) -, m_right(std::move(other.m_right)) -{} - -template -outer_product_node::outer_product_node(const node_type& other) -: m_left(other.m_left) -, m_right(other.m_right) -{} - - -/* Internal methods: */ - -/* readable_matrix interface: */ - -template -int -outer_product_node::i_rows() const -{ - return this->m_left.size(); -} - -template -int -outer_product_node::i_cols() const -{ - return this->m_right.size(); -} - -template -auto -outer_product_node::i_get(int i, int j) const -> immutable_value -{ - return immutable_value(this->m_left.get(i) * this->m_right.get(j)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_OUTER_PRODUCT_NODE_TPP +# error "vector/outer_product_node.tpp not included correctly" +#endif + +namespace cml { + +/* outer_product_node 'structors: */ + +template +outer_product_node::outer_product_node(Sub1 left, Sub2 right) +: m_left(std::move(left)) +, m_right(std::move(right)) +{} + +template +outer_product_node::outer_product_node(node_type&& other) +: m_left(std::move(other.m_left)) +, m_right(std::move(other.m_right)) +{} + +template +outer_product_node::outer_product_node(const node_type& other) +: m_left(other.m_left) +, m_right(other.m_right) +{} + + +/* Internal methods: */ + +/* readable_matrix interface: */ + +template +int +outer_product_node::i_rows() const +{ + return this->m_left.size(); +} + +template +int +outer_product_node::i_cols() const +{ + return this->m_right.size(); +} + +template +auto +outer_product_node::i_get(int i, int j) const -> immutable_value +{ + return immutable_value(this->m_left.get(i) * this->m_right.get(j)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/outer_product_ops.h b/cml/vector/outer_product_ops.h index 1a61fc0..e9da3d2 100644 --- a/cml/vector/outer_product_ops.h +++ b/cml/vector/outer_product_ops.h @@ -1,35 +1,35 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Compute the outer product of vectors @c sub1 and @c sub2 as a matrix - * expression node. - */ -template* = nullptr, - enable_if_vector_t* = nullptr> -inline auto -outer(Sub1&& sub1, - Sub2&& sub2) -> outer_product_node, - actual_operand_type_of_t> -{ - static_assert( - std::is_same(sub1))>::value, - "internal error: unexpected expression type (sub1)"); - static_assert( - std::is_same(sub2))>::value, - "internal error: unexpected expression type (sub2)"); - - /* Deduce the operand types of the subexpressions (&, const&, &&): */ - using sub1_type = actual_operand_type_of_t; - using sub2_type = actual_operand_type_of_t; - return outer_product_node((sub1_type) sub1, - (sub2_type) sub2); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Compute the outer product of vectors @c sub1 and @c sub2 as a matrix + * expression node. + */ +template* = nullptr, + enable_if_vector_t* = nullptr> +inline auto +outer(Sub1&& sub1, + Sub2&& sub2) -> outer_product_node, + actual_operand_type_of_t> +{ + static_assert( + std::is_same(sub1))>::value, + "internal error: unexpected expression type (sub1)"); + static_assert( + std::is_same(sub2))>::value, + "internal error: unexpected expression type (sub2)"); + + /* Deduce the operand types of the subexpressions (&, const&, &&): */ + using sub1_type = actual_operand_type_of_t; + using sub2_type = actual_operand_type_of_t; + return outer_product_node((sub1_type) sub1, + (sub2_type) sub2); +} + +} // namespace cml diff --git a/cml/vector/perp_dot.h b/cml/vector/perp_dot.h index 18ed97c..ce08a0c 100644 --- a/cml/vector/perp_dot.h +++ b/cml/vector/perp_dot.h @@ -1,36 +1,36 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Convenience alias to determine the scalar type to return from - * cml::perp_dot. - */ -template -using perp_dot_promote_t = value_type_trait_promote_t; - -/** Compute the "cross-product" of two 2D vectors, and return the scalar - * result. - * - * @note Currently, the result is computed immediately, even if it appears - * in an expression. - * - * @throws vector_size_error at run-time if left or right is - * dynamically-sized and is not a 2D vector. The size is checked at - * compile time for fixed-sized expressions. - */ -template -auto perp_dot(const readable_vector& left, - const readable_vector& right) -> perp_dot_promote_t; - -} // namespace cml - -#define __CML_VECTOR_PERP_DOT_TPP -#include -#undef __CML_VECTOR_PERP_DOT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Convenience alias to determine the scalar type to return from + * cml::perp_dot. + */ +template +using perp_dot_promote_t = value_type_trait_promote_t; + +/** Compute the "cross-product" of two 2D vectors, and return the scalar + * result. + * + * @note Currently, the result is computed immediately, even if it appears + * in an expression. + * + * @throws vector_size_error at run-time if left or right is + * dynamically-sized and is not a 2D vector. The size is checked at + * compile time for fixed-sized expressions. + */ +template +auto perp_dot(const readable_vector& left, + const readable_vector& right) -> perp_dot_promote_t; + +} // namespace cml + +#define __CML_VECTOR_PERP_DOT_TPP +#include +#undef __CML_VECTOR_PERP_DOT_TPP diff --git a/cml/vector/perp_dot.tpp b/cml/vector/perp_dot.tpp index 84a95a6..6bca2fb 100644 --- a/cml/vector/perp_dot.tpp +++ b/cml/vector/perp_dot.tpp @@ -1,25 +1,25 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_PERP_DOT_TPP -# error "vector/perp_dot.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -template -inline auto -perp_dot(const readable_vector& left, const readable_vector& right) - -> perp_dot_promote_t -{ - using result_type = perp_dot_promote_t; - cml::check_size(left, cml::int_c<2>()); - cml::check_size(right, cml::int_c<2>()); - return result_type(left[0] * right[1] - left[1] * right[0]); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_PERP_DOT_TPP +# error "vector/perp_dot.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +template +inline auto +perp_dot(const readable_vector& left, const readable_vector& right) + -> perp_dot_promote_t +{ + using result_type = perp_dot_promote_t; + cml::check_size(left, cml::int_c<2>()); + cml::check_size(right, cml::int_c<2>()); + return result_type(left[0] * right[1] - left[1] * right[0]); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/products.h b/cml/vector/products.h index 7abdae0..e609473 100644 --- a/cml/vector/products.h +++ b/cml/vector/products.h @@ -1,11 +1,11 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include diff --git a/cml/vector/promotion.h b/cml/vector/promotion.h index 09aefdf..b939996 100644 --- a/cml/vector/promotion.h +++ b/cml/vector/promotion.h @@ -1,82 +1,82 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace cml { - -/** Determine an appropriate storage type to use when combining vector - * expressions via a pairwise binary operator. - * - * @note This can be specialized to accomodate user-defined storage types. - */ -template struct vector_binary_storage_promote -{ - static_assert( - is_vector_storage::value && is_vector_storage::value, - "expected vector storage types for binary promotion"); - - /* Determine the common unbound storage type: */ - using unbound_type = storage_promote_t; - - /* Determine the new vector size: */ - static const int array_size = Storage1::array_size > Storage2::array_size - ? Storage1::array_size - : Storage2::array_size; - - /* Resize: */ - using resized_type = resize_storage_t; - - /* Rebind to a vector storage type: */ - using type = rebind_vector_storage_t; -}; - -/** Convenience alias for vector_binary_storage_promote. */ -template -using vector_binary_storage_promote_t = - typename vector_binary_storage_promote::type; - - -/** Helper to deduce a reasonable vector type from two vector subexpression - * types. This can be specialized for non-default behavior. - */ -template struct vector_promote; - -template -struct vector_promote::value - && is_vector::value>::type> -{ - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = vector_traits; - using right_traits = vector_traits; - - /* Deduce the new vector element type: */ - using value_type = value_type_promote_t; - - /* Determine the new storage type: */ - using storage_type = vector_binary_storage_promote_t, - storage_type_of_t>; - - /* Use the proxy type for the temporary: */ - using proxy_type = proxy_type_of_t; - - /* Build the vector type: */ - using type = vector; -}; - -/** Convenience alias for vector_promote<>. */ -template -using vector_promote_t = typename vector_promote::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Determine an appropriate storage type to use when combining vector + * expressions via a pairwise binary operator. + * + * @note This can be specialized to accomodate user-defined storage types. + */ +template struct vector_binary_storage_promote +{ + static_assert( + is_vector_storage::value && is_vector_storage::value, + "expected vector storage types for binary promotion"); + + /* Determine the common unbound storage type: */ + using unbound_type = storage_promote_t; + + /* Determine the new vector size: */ + static const int array_size = Storage1::array_size > Storage2::array_size + ? Storage1::array_size + : Storage2::array_size; + + /* Resize: */ + using resized_type = resize_storage_t; + + /* Rebind to a vector storage type: */ + using type = rebind_vector_storage_t; +}; + +/** Convenience alias for vector_binary_storage_promote. */ +template +using vector_binary_storage_promote_t = + typename vector_binary_storage_promote::type; + + +/** Helper to deduce a reasonable vector type from two vector subexpression + * types. This can be specialized for non-default behavior. + */ +template struct vector_promote; + +template +struct vector_promote::value + && is_vector::value>::type> +{ + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = vector_traits; + using right_traits = vector_traits; + + /* Deduce the new vector element type: */ + using value_type = value_type_promote_t; + + /* Determine the new storage type: */ + using storage_type = vector_binary_storage_promote_t, + storage_type_of_t>; + + /* Use the proxy type for the temporary: */ + using proxy_type = proxy_type_of_t; + + /* Build the vector type: */ + using type = vector; +}; + +/** Convenience alias for vector_promote<>. */ +template +using vector_promote_t = typename vector_promote::type; + +} // namespace cml diff --git a/cml/vector/readable_vector.h b/cml/vector/readable_vector.h index 5148f22..d9a9667 100644 --- a/cml/vector/readable_vector.h +++ b/cml/vector/readable_vector.h @@ -1,111 +1,111 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/* Forward declarations: */ -template class vector_scalar_node; -template class subvector_node; - -/** Base class for readable vector types. Readable vectors support const - * access to its elements. - * - * DerivedT must implement: - * - * - int i_size() const, returning the number of vector elements (even if - * static); and - * - * - i_get(int i) const, where is the immutable_value type defined - * by vector_traits. Note that immutable_value is not - * necessarily a reference or const type. - */ -template class readable_vector -{ - public: - using vector_type = DerivedT; - using traits_type = vector_traits; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using size_tag = typename traits_type::size_tag; - - - public: - /** @name CML1 Types */ - /*@{*/ - - using subvector_type = subvector_of_t; - using supervector_type = supervector_of_t; - - /*@}*/ - - - public: - /** Return a const reference to the vector cast as DerivedT. */ - const DerivedT& actual() const; - - /** Return the number of vector elements. */ - int size() const; - - /** Return const element @c i. */ - immutable_value get(int i) const; - - /** Return const element @c i. */ - template>* = nullptr> - immutable_value get() const; - - /** Return const element @c i. */ - immutable_value operator[](int i) const; - - - public: - /** Return the squared length of the vector. */ - value_type length_squared() const; - - /** Return the length of the vector. */ - value_type length() const; - - /** Return the normalized vector as an expression node. */ - vector_scalar_node> - normalize() const&; - - /** Return the normalized vector as an expression node, moving the - * source into the node. - */ - vector_scalar_node> - normalize() const&&; - - /** Return subvector @c i as an expression node. */ - subvector_node subvector(int i) const&; - - /** Return subvector @c i as an expression node, moving the source - * into the node. - */ - subvector_node subvector(int i) const&&; - - - protected: - // Use the compiler-generated default constructor: - readable_vector() = default; - - // Use the compiler-generated copy constructor: - readable_vector(const readable_vector&) = default; - - // Use the compiler-generated move constructor: - readable_vector(readable_vector&&) = default; -}; - -} // namespace cml - -#define __CML_VECTOR_READABLE_VECTOR_TPP -#include -#undef __CML_VECTOR_READABLE_VECTOR_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/* Forward declarations: */ +template class vector_scalar_node; +template class subvector_node; + +/** Base class for readable vector types. Readable vectors support const + * access to its elements. + * + * DerivedT must implement: + * + * - int i_size() const, returning the number of vector elements (even if + * static); and + * + * - i_get(int i) const, where is the immutable_value type defined + * by vector_traits. Note that immutable_value is not + * necessarily a reference or const type. + */ +template class readable_vector +{ + public: + using vector_type = DerivedT; + using traits_type = vector_traits; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using size_tag = typename traits_type::size_tag; + + + public: + /** @name CML1 Types */ + /*@{*/ + + using subvector_type = subvector_of_t; + using supervector_type = supervector_of_t; + + /*@}*/ + + + public: + /** Return a const reference to the vector cast as DerivedT. */ + const DerivedT& actual() const; + + /** Return the number of vector elements. */ + int size() const; + + /** Return const element @c i. */ + immutable_value get(int i) const; + + /** Return const element @c i. */ + template>* = nullptr> + immutable_value get() const; + + /** Return const element @c i. */ + immutable_value operator[](int i) const; + + + public: + /** Return the squared length of the vector. */ + value_type length_squared() const; + + /** Return the length of the vector. */ + value_type length() const; + + /** Return the normalized vector as an expression node. */ + vector_scalar_node> + normalize() const&; + + /** Return the normalized vector as an expression node, moving the + * source into the node. + */ + vector_scalar_node> + normalize() const&&; + + /** Return subvector @c i as an expression node. */ + subvector_node subvector(int i) const&; + + /** Return subvector @c i as an expression node, moving the source + * into the node. + */ + subvector_node subvector(int i) const&&; + + + protected: + // Use the compiler-generated default constructor: + readable_vector() = default; + + // Use the compiler-generated copy constructor: + readable_vector(const readable_vector&) = default; + + // Use the compiler-generated move constructor: + readable_vector(readable_vector&&) = default; +}; + +} // namespace cml + +#define __CML_VECTOR_READABLE_VECTOR_TPP +#include +#undef __CML_VECTOR_READABLE_VECTOR_TPP diff --git a/cml/vector/readable_vector.tpp b/cml/vector/readable_vector.tpp index 38edcd9..f441421 100644 --- a/cml/vector/readable_vector.tpp +++ b/cml/vector/readable_vector.tpp @@ -1,105 +1,105 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_READABLE_VECTOR_TPP -# error "vector/readable_vector.tpp not included correctly" -#endif - -#include -#include -#include -#include -#include - -namespace cml { - -/* Public methods: */ - -template -const DT& -readable_vector
::actual() const -{ - return (const DT&) *this; -} - -template -int -readable_vector
::size() const -{ - return this->actual().i_size(); -} - -template -auto -readable_vector
::get(int i) const -> immutable_value -{ - return this->actual().i_get(i); -} - -template -template>*> -auto -readable_vector
::get() const -> immutable_value -{ - return this->actual().i_get(I); -} - -template -auto -readable_vector
::operator[](int i) const -> immutable_value -{ - return this->get(i); -} - -template -auto -readable_vector
::length_squared() const -> value_type -{ - cml::check_minimum_size(*this, cml::int_c<1>()); - auto accum = cml::sqr(this->get(0)); - for(int i = 1; i < this->size(); ++i) accum += cml::sqr(this->get(i)); - return accum; -} - -template -auto -readable_vector
::length() const -> value_type -{ - return element_traits::sqrt(this->length_squared()); -} - -template -auto -readable_vector
::normalize() const& -> vector_scalar_node> -{ - return vector_scalar_node>((const DT&) *this, - this->length()); -} - -template -auto -readable_vector
::normalize() const&& -> vector_scalar_node> -{ - return vector_scalar_node>((DT&&) *this, this->length()); -} - -template -auto -readable_vector
::subvector(int i) const& -> subvector_node -{ - return subvector_node((const DT&) *this, i); -} - -template -auto -readable_vector
::subvector(int i) const&& -> subvector_node -{ - return subvector_node((DT&&) *this, i); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_READABLE_VECTOR_TPP +# error "vector/readable_vector.tpp not included correctly" +#endif + +#include +#include +#include +#include +#include + +namespace cml { + +/* Public methods: */ + +template +const DT& +readable_vector
::actual() const +{ + return (const DT&) *this; +} + +template +int +readable_vector
::size() const +{ + return this->actual().i_size(); +} + +template +auto +readable_vector
::get(int i) const -> immutable_value +{ + return this->actual().i_get(i); +} + +template +template>*> +auto +readable_vector
::get() const -> immutable_value +{ + return this->actual().i_get(I); +} + +template +auto +readable_vector
::operator[](int i) const -> immutable_value +{ + return this->get(i); +} + +template +auto +readable_vector
::length_squared() const -> value_type +{ + cml::check_minimum_size(*this, cml::int_c<1>()); + auto accum = cml::sqr(this->get(0)); + for(int i = 1; i < this->size(); ++i) accum += cml::sqr(this->get(i)); + return accum; +} + +template +auto +readable_vector
::length() const -> value_type +{ + return element_traits::sqrt(this->length_squared()); +} + +template +auto +readable_vector
::normalize() const& -> vector_scalar_node> +{ + return vector_scalar_node>((const DT&) *this, + this->length()); +} + +template +auto +readable_vector
::normalize() const&& -> vector_scalar_node> +{ + return vector_scalar_node>((DT&&) *this, this->length()); +} + +template +auto +readable_vector
::subvector(int i) const& -> subvector_node +{ + return subvector_node((const DT&) *this, i); +} + +template +auto +readable_vector
::subvector(int i) const&& -> subvector_node +{ + return subvector_node((DT&&) *this, i); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/scalar_node.h b/cml/vector/scalar_node.h index 9d8854d..208a998 100644 --- a/cml/vector/scalar_node.h +++ b/cml/vector/scalar_node.h @@ -1,117 +1,117 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -template class vector_scalar_node; - -/** vector_scalar_node<> traits. */ -template -struct vector_traits> -{ - /* Figure out the basic types of Sub and Scalar: */ - using vector_type = vector_scalar_node; - using left_arg_type = Sub; - using right_arg_type = Scalar; - using left_type = cml::unqualified_type_t; - using right_type = cml::unqualified_type_t; - using left_traits = vector_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - using storage_type = typename left_traits::storage_type; - using size_tag = typename left_traits::size_tag; - - /* Propagate the array size from the subexpression: */ - static const int array_size = left_traits::array_size; -}; - -/** Represents a binary vector operation, where one operand is a scalar - * value, and the other is a vector. - */ -template -class vector_scalar_node -: public readable_vector> -{ - public: - using node_type = vector_scalar_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using left_arg_type = typename traits_type::left_arg_type; - using right_arg_type = typename traits_type::right_arg_type; - using left_type = typename traits_type::left_type; - using right_type = typename traits_type::right_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** The array size constant is the same as the subexpression. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expression and the scalar to apply. - * @c left must be an lvalue reference or rvalue reference. - */ - vector_scalar_node(Sub left, const right_type& right); - - /** Move constructor. */ - vector_scalar_node(node_type&& other); - - /** Copy constructor. */ - vector_scalar_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Apply the scalar operator to element @c i of the subexpression and - * return the result. - */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the left subexpression. The expression is - * stored as a copy if Sub is an rvalue reference (temporary), or by - * const reference if Sub is an lvalue reference. - */ - using left_wrap_type = cml::if_t::value, const left_type&, - left_type>; - - - protected: - /** The vector operand. */ - left_wrap_type m_left; - - /** The scalar operand. */ - right_type m_right; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_VECTOR_SCALAR_NODE_TPP -#include -#undef __CML_VECTOR_SCALAR_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +template class vector_scalar_node; + +/** vector_scalar_node<> traits. */ +template +struct vector_traits> +{ + /* Figure out the basic types of Sub and Scalar: */ + using vector_type = vector_scalar_node; + using left_arg_type = Sub; + using right_arg_type = Scalar; + using left_type = cml::unqualified_type_t; + using right_type = cml::unqualified_type_t; + using left_traits = vector_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + using storage_type = typename left_traits::storage_type; + using size_tag = typename left_traits::size_tag; + + /* Propagate the array size from the subexpression: */ + static const int array_size = left_traits::array_size; +}; + +/** Represents a binary vector operation, where one operand is a scalar + * value, and the other is a vector. + */ +template +class vector_scalar_node +: public readable_vector> +{ + public: + using node_type = vector_scalar_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using left_arg_type = typename traits_type::left_arg_type; + using right_arg_type = typename traits_type::right_arg_type; + using left_type = typename traits_type::left_type; + using right_type = typename traits_type::right_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** The array size constant is the same as the subexpression. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expression and the scalar to apply. + * @c left must be an lvalue reference or rvalue reference. + */ + vector_scalar_node(Sub left, const right_type& right); + + /** Move constructor. */ + vector_scalar_node(node_type&& other); + + /** Copy constructor. */ + vector_scalar_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Apply the scalar operator to element @c i of the subexpression and + * return the result. + */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the left subexpression. The expression is + * stored as a copy if Sub is an rvalue reference (temporary), or by + * const reference if Sub is an lvalue reference. + */ + using left_wrap_type = cml::if_t::value, const left_type&, + left_type>; + + + protected: + /** The vector operand. */ + left_wrap_type m_left; + + /** The scalar operand. */ + right_type m_right; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_VECTOR_SCALAR_NODE_TPP +#include +#undef __CML_VECTOR_SCALAR_NODE_TPP diff --git a/cml/vector/scalar_node.tpp b/cml/vector/scalar_node.tpp index 3259c3d..df55d01 100644 --- a/cml/vector/scalar_node.tpp +++ b/cml/vector/scalar_node.tpp @@ -1,51 +1,51 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_SCALAR_NODE_TPP -# error "vector/scalar_node.tpp not included correctly" -#endif - -namespace cml { - -/* vector_scalar_node 'structors: */ - -template -vector_scalar_node::vector_scalar_node(Sub left, - const right_type& right) -: m_left(std::move(left)) -, m_right(right) -{} - -template -vector_scalar_node::vector_scalar_node(node_type&& other) -: m_left(std::move(other.m_left)) -, m_right(std::move(other.m_right)) -{} - -template -vector_scalar_node::vector_scalar_node(const node_type& other) -: m_left(other.m_left) -, m_right(other.m_right) -{} - - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector_scalar_node::i_size() const -{ - return this->m_left.size(); -} - -template -auto -vector_scalar_node::i_get(int i) const -> immutable_value -{ - return Op().apply(this->m_left.get(i), this->m_right); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_SCALAR_NODE_TPP +# error "vector/scalar_node.tpp not included correctly" +#endif + +namespace cml { + +/* vector_scalar_node 'structors: */ + +template +vector_scalar_node::vector_scalar_node(Sub left, + const right_type& right) +: m_left(std::move(left)) +, m_right(right) +{} + +template +vector_scalar_node::vector_scalar_node(node_type&& other) +: m_left(std::move(other.m_left)) +, m_right(std::move(other.m_right)) +{} + +template +vector_scalar_node::vector_scalar_node(const node_type& other) +: m_left(other.m_left) +, m_right(other.m_right) +{} + + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector_scalar_node::i_size() const +{ + return this->m_left.size(); +} + +template +auto +vector_scalar_node::i_get(int i) const -> immutable_value +{ + return Op().apply(this->m_left.get(i), this->m_right); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/scalar_ops.h b/cml/vector/scalar_ops.h index 9e565ef..ebb9af1 100644 --- a/cml/vector/scalar_ops.h +++ b/cml/vector/scalar_ops.h @@ -1,73 +1,73 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include - -namespace cml { - -/** Helper function to generate a vector_scalar_node from a vector type - * (i.e. derived from readable_vector<>) and a scalar type. - */ -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -make_vector_scalar_node(Sub&& sub, - Scalar&& v) -> vector_scalar_node, - actual_operand_type_of_t, Op> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type (sub)"); - static_assert( - std::is_same(v))>::value, - "internal error: unexpected expression type (v)"); - - /* Deduce the operand types of the scalar and the subexpression (&, - * const&, &&): - */ - using sub_type = actual_operand_type_of_t; - using scalar_type = actual_operand_type_of_t; - return vector_scalar_node((sub_type) sub, - (scalar_type) v); -} - -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -operator*(Sub&& sub, Scalar&& v) - -> decltype(make_vector_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_vector_scalar_node>( - std::forward(sub), std::forward(v)); -} - -template>* = nullptr, - enable_if_vector_t* = nullptr> -inline auto -operator*(Scalar&& v, Sub&& sub) - -> decltype(make_vector_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_vector_scalar_node>( - std::forward(sub), std::forward(v)); -} - -template* = nullptr, - enable_if_arithmetic_t>* = nullptr> -inline auto -operator/(Sub&& sub, Scalar&& v) - -> decltype(make_vector_scalar_node>( - std::forward(sub), std::forward(v))) -{ - return make_vector_scalar_node>( - std::forward(sub), std::forward(v)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +namespace cml { + +/** Helper function to generate a vector_scalar_node from a vector type + * (i.e. derived from readable_vector<>) and a scalar type. + */ +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +make_vector_scalar_node(Sub&& sub, + Scalar&& v) -> vector_scalar_node, + actual_operand_type_of_t, Op> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type (sub)"); + static_assert( + std::is_same(v))>::value, + "internal error: unexpected expression type (v)"); + + /* Deduce the operand types of the scalar and the subexpression (&, + * const&, &&): + */ + using sub_type = actual_operand_type_of_t; + using scalar_type = actual_operand_type_of_t; + return vector_scalar_node((sub_type) sub, + (scalar_type) v); +} + +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +operator*(Sub&& sub, Scalar&& v) + -> decltype(make_vector_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_vector_scalar_node>( + std::forward(sub), std::forward(v)); +} + +template>* = nullptr, + enable_if_vector_t* = nullptr> +inline auto +operator*(Scalar&& v, Sub&& sub) + -> decltype(make_vector_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_vector_scalar_node>( + std::forward(sub), std::forward(v)); +} + +template* = nullptr, + enable_if_arithmetic_t>* = nullptr> +inline auto +operator/(Sub&& sub, Scalar&& v) + -> decltype(make_vector_scalar_node>( + std::forward(sub), std::forward(v))) +{ + return make_vector_scalar_node>( + std::forward(sub), std::forward(v)); +} + +} // namespace cml diff --git a/cml/vector/size_checking.h b/cml/vector/size_checking.h index 2917897..f431cd3 100644 --- a/cml/vector/size_checking.h +++ b/cml/vector/size_checking.h @@ -1,218 +1,218 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -namespace cml { - -/** Exception thrown when run-time size checking is enabled, and the - * operands of a vector expression have incompatible sizes. - */ -struct incompatible_vector_size_error : std::runtime_error -{ - incompatible_vector_size_error() - : std::runtime_error("incompatible vector expression sizes") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and the - * operand of a vector expression does not meet a minimum size. - */ -struct minimum_vector_size_error : std::runtime_error -{ - minimum_vector_size_error() - : std::runtime_error("vector expression too short") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and the - * operand of a vector expression does not have the required size. - */ -struct vector_size_error : std::runtime_error -{ - vector_size_error() - : std::runtime_error("incorrect vector expression size") - {} -}; - -/** Exception thrown when run-time size checking is enabled, and the - * size of a vector expression operand is outside the required range. - */ -struct vector_size_range_error : std::runtime_error -{ - vector_size_range_error() - : std::runtime_error("vector expression size out of range") - {} -}; - - -/** Front-end for both compile-time and run-time vector binary expression - * length checking. Both expressions must derive from readable_vector. - * - * @tparam Sub1 the actual type of the first expression. - * @tparam Sub2 the actual type of the second expression. - * - * @param left First vector expression. - * @param right Second vector expression. - * - * @throws incompatible_vector_size_error at run-time if either @c left or - * @c right is a dynamically-sized expression, and @c left.size() != - * @c right.size(). If both are fixed-size expressions, then the sizes are - * checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template -void check_same_size(const readable_vector& left, - const readable_vector& right); - -/** Front-end for both compile-time and run-time vector binary expression - * length checking against a fixed-length array. The first expression must - * derive from readable_vector, and std::is_array<>::value must be true for - * the second expression (e.g. double v[3]). - * - * @tparam Sub1 the actual type of the first expression. - * @tparam Sub2 the actual type of the second expression. - * - * @param left Vector expression. - * @param right Fixed-length array. - * - * @throws incompatible_vector_size_error at run-time if @c left is a - * dynamically-sized expression, and @c left.size() != array_size_of(@c right). - * If @c left is a fixed-size expression, then the sizes are checked at - * compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template -void check_same_size(const readable_vector& left, const Sub2& right, - enable_if_array_t* = 0); - -/** Front-end for run-time vector binary expression length checking. The - * first expression must derive from readable_vector, and the second must - * implement a size() method for this overload to be enabled. - * - * @tparam Sub1 the actual type of the first expression. - * @tparam Sub2 the actual type of the second expression. - * - * @param left First vector expression. - * @param right Second expression. - * - * @throws incompatible_vector_size_error if @c left.size() != @c right.size(). - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template -auto check_same_size(const readable_vector& left, const Sub2& right) - -> decltype(right.size(), void()); - - -/** Front-end for minimum vector expression length checking against a - * run-time size. The expression must derive from readable_vector. - * - * @param left Vector expression. - * @param N Size to check. - * - * @throws minimum_vector_size_error if @c left.size() < @c N. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template -void check_minimum_size(const readable_vector& left, int N); - -/** Front-end for compile-time and run-time minimum vector expression - * length checking against an integer constant via cml::int_c. The - * expression must derive from readable_vector. - * - * @param left Vector expression. - * - * @throws minimum_vector_size_error at run-time if @c left is a - * dynamically-sized expression and @c left.size() < @c N. If @c left is a - * fixed-size expression, then the size is checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template -void check_minimum_size(const readable_vector& left, cml::int_c); - - -/** Front-end for vector expression length checking against a run-time - * size. The expression must derive from readable_vector. - * - * @param left Vector expression. - * @param N Size to check. - * - * @throws vector_size_error if @c left.size() != @c N. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template void check_size(const readable_vector& left, int N); - -/** Front-end for compile-time and run-time vector expression length - * checking against an integer constant via int_c. The expression must - * derive from readable_vector. - * - * @param left Vector expression. - * - * @throws vector_size_error at run-time if @c left is a dynamically-sized - * expression and @c left.size() != N. If @c left is a fixed-size expression, - * then the size is checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template -void check_size(const readable_vector& left, cml::int_c); - - -/** Front-end for vector expression length checking against a run-time - * inclusive size range. The expression must derive from readable_vector. - * - * @param left Vector expression. - * @param Low Minimum size to check. - * @param High Maximum size to check. - * - * @throws vector_size_range_error if @c left.size() < @c Low or @c - * left.size() > @c High. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template -void check_size_range(const readable_vector& left, int Low, int High); - -/** Front-end for compile-time and run-time vector expression length - * checking against an integer constant inclusive range via int_c. The - * expression must derive from readable_vector. - * - * @param left Vector expression. - * - * @throws vector_size_range_error at run-time if @c left is a - * dynamically-sized expression and @c left.size() < @c Low or @c - * left.size() > @c High. If @c left is a fixed-size expression, then the - * size is checked at compile time. - * - * @note Run-time checking can be disabled by defining - * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. - */ -template -void check_size_range(const readable_vector& left, cml::int_c, - cml::int_c); - -} // namespace cml - -#define __CML_VECTOR_SIZE_CHECKING_TPP -#include -#undef __CML_VECTOR_SIZE_CHECKING_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +namespace cml { + +/** Exception thrown when run-time size checking is enabled, and the + * operands of a vector expression have incompatible sizes. + */ +struct incompatible_vector_size_error : std::runtime_error +{ + incompatible_vector_size_error() + : std::runtime_error("incompatible vector expression sizes") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and the + * operand of a vector expression does not meet a minimum size. + */ +struct minimum_vector_size_error : std::runtime_error +{ + minimum_vector_size_error() + : std::runtime_error("vector expression too short") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and the + * operand of a vector expression does not have the required size. + */ +struct vector_size_error : std::runtime_error +{ + vector_size_error() + : std::runtime_error("incorrect vector expression size") + {} +}; + +/** Exception thrown when run-time size checking is enabled, and the + * size of a vector expression operand is outside the required range. + */ +struct vector_size_range_error : std::runtime_error +{ + vector_size_range_error() + : std::runtime_error("vector expression size out of range") + {} +}; + + +/** Front-end for both compile-time and run-time vector binary expression + * length checking. Both expressions must derive from readable_vector. + * + * @tparam Sub1 the actual type of the first expression. + * @tparam Sub2 the actual type of the second expression. + * + * @param left First vector expression. + * @param right Second vector expression. + * + * @throws incompatible_vector_size_error at run-time if either @c left or + * @c right is a dynamically-sized expression, and @c left.size() != + * @c right.size(). If both are fixed-size expressions, then the sizes are + * checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template +void check_same_size(const readable_vector& left, + const readable_vector& right); + +/** Front-end for both compile-time and run-time vector binary expression + * length checking against a fixed-length array. The first expression must + * derive from readable_vector, and std::is_array<>::value must be true for + * the second expression (e.g. double v[3]). + * + * @tparam Sub1 the actual type of the first expression. + * @tparam Sub2 the actual type of the second expression. + * + * @param left Vector expression. + * @param right Fixed-length array. + * + * @throws incompatible_vector_size_error at run-time if @c left is a + * dynamically-sized expression, and @c left.size() != array_size_of(@c right). + * If @c left is a fixed-size expression, then the sizes are checked at + * compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template +void check_same_size(const readable_vector& left, const Sub2& right, + enable_if_array_t* = 0); + +/** Front-end for run-time vector binary expression length checking. The + * first expression must derive from readable_vector, and the second must + * implement a size() method for this overload to be enabled. + * + * @tparam Sub1 the actual type of the first expression. + * @tparam Sub2 the actual type of the second expression. + * + * @param left First vector expression. + * @param right Second expression. + * + * @throws incompatible_vector_size_error if @c left.size() != @c right.size(). + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template +auto check_same_size(const readable_vector& left, const Sub2& right) + -> decltype(right.size(), void()); + + +/** Front-end for minimum vector expression length checking against a + * run-time size. The expression must derive from readable_vector. + * + * @param left Vector expression. + * @param N Size to check. + * + * @throws minimum_vector_size_error if @c left.size() < @c N. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template +void check_minimum_size(const readable_vector& left, int N); + +/** Front-end for compile-time and run-time minimum vector expression + * length checking against an integer constant via cml::int_c. The + * expression must derive from readable_vector. + * + * @param left Vector expression. + * + * @throws minimum_vector_size_error at run-time if @c left is a + * dynamically-sized expression and @c left.size() < @c N. If @c left is a + * fixed-size expression, then the size is checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template +void check_minimum_size(const readable_vector& left, cml::int_c); + + +/** Front-end for vector expression length checking against a run-time + * size. The expression must derive from readable_vector. + * + * @param left Vector expression. + * @param N Size to check. + * + * @throws vector_size_error if @c left.size() != @c N. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template void check_size(const readable_vector& left, int N); + +/** Front-end for compile-time and run-time vector expression length + * checking against an integer constant via int_c. The expression must + * derive from readable_vector. + * + * @param left Vector expression. + * + * @throws vector_size_error at run-time if @c left is a dynamically-sized + * expression and @c left.size() != N. If @c left is a fixed-size expression, + * then the size is checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template +void check_size(const readable_vector& left, cml::int_c); + + +/** Front-end for vector expression length checking against a run-time + * inclusive size range. The expression must derive from readable_vector. + * + * @param left Vector expression. + * @param Low Minimum size to check. + * @param High Maximum size to check. + * + * @throws vector_size_range_error if @c left.size() < @c Low or @c + * left.size() > @c High. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template +void check_size_range(const readable_vector& left, int Low, int High); + +/** Front-end for compile-time and run-time vector expression length + * checking against an integer constant inclusive range via int_c. The + * expression must derive from readable_vector. + * + * @param left Vector expression. + * + * @throws vector_size_range_error at run-time if @c left is a + * dynamically-sized expression and @c left.size() < @c Low or @c + * left.size() > @c High. If @c left is a fixed-size expression, then the + * size is checked at compile time. + * + * @note Run-time checking can be disabled by defining + * CML_NO_RUNTIME_VECTOR_SIZE_CHECKS at compile time. + */ +template +void check_size_range(const readable_vector& left, cml::int_c, + cml::int_c); + +} // namespace cml + +#define __CML_VECTOR_SIZE_CHECKING_TPP +#include +#undef __CML_VECTOR_SIZE_CHECKING_TPP diff --git a/cml/vector/size_checking.tpp b/cml/vector/size_checking.tpp index 4f5f256..fbb3c7e 100644 --- a/cml/vector/size_checking.tpp +++ b/cml/vector/size_checking.tpp @@ -1,212 +1,212 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_SIZE_CHECKING_TPP -# error "vector/size_checking.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { -namespace detail { - -/* No-op binary vector expression size checking: */ -template -inline void -check_same_size(const readable_vector&, const Sub2&, any_size_tag) -{} - -/* Compile-time binary vector expression size checking: */ -template -inline void -check_same_size(const readable_vector&, const Sub2&, fixed_size_tag) -{ - static_assert(array_size_of_c::value == array_size_of_c::value, - "incompatible vector expression sizes"); -} - -/* Run-time binary vector expression size checking: */ -template -inline void -check_same_size(const readable_vector& left, const Sub2& right, - dynamic_size_tag) -{ -#ifndef CML_NO_RUNTIME_VECTOR_SIZE_CHECKS - cml_require(array_size_of(left) == array_size_of(right), - incompatible_vector_size_error, - /**/); -#endif -} - -/* No-op minimum vector size checking. */ -template -inline void -check_minimum_size(const readable_vector&, int, - enable_if_any_size_t* = nullptr) -{} - -/* Compile-time minimum size checking against a constant. */ -template -inline void -check_minimum_size(const readable_vector&, cml::int_c, - enable_if_fixed_size_t* = nullptr) -{ - static_assert(array_size_of_c::value >= N, - "vector expression too short"); -} - -/* Run-time minimum vector size checking. */ -template -inline void -check_minimum_size(const readable_vector& sub, int N) -{ -#ifndef CML_NO_RUNTIME_VECTOR_SIZE_CHECKS - cml_require(array_size_of(sub) >= N, minimum_vector_size_error, /**/); -#endif -} - -/* No-op vector size checking. */ -template -inline void -check_size(const readable_vector&, int, - enable_if_any_size_t* = nullptr) -{} - -/* Compile-time size checking against a constant. */ -template -inline void -check_size(const readable_vector&, cml::int_c, - enable_if_fixed_size_t* = nullptr) -{ - static_assert(array_size_of_c::value == N, - "incorrect vector expression size"); -} - -/* Run-time vector size checking. */ -template -inline void -check_size(const readable_vector& sub, int N) -{ -#ifndef CML_NO_RUNTIME_VECTOR_SIZE_CHECKS - cml_require(array_size_of(sub) == N, vector_size_error, /**/); -#endif -} - -/* No-op vector size range checking. */ -template -inline void -check_size_range(const readable_vector&, int, int, - enable_if_any_size_t* = nullptr) -{} - -/* Compile-time size range checking against constants. */ -template -inline void -check_size_range(const readable_vector&, cml::int_c, cml::int_c, - enable_if_fixed_size_t* = nullptr) -{ - static_assert( - array_size_of_c::value >= Low && array_size_of_c::value <= High, - "vector expression size out of range"); -} - -/* Run-time vector size checking. */ -template -inline void -check_size_range(const readable_vector& sub, int Low, int High) -{ -#ifndef CML_NO_RUNTIME_VECTOR_SIZE_CHECKS - cml_require(array_size_of(sub) >= Low && array_size_of(sub) <= High, - vector_size_range_error, - /**/); -#endif -} - -} // namespace detail - -/* check_same_size: */ - -template -inline void -check_same_size(const readable_vector& left, - const readable_vector& right) -{ - using tag1 = size_tag_of_t; - using tag2 = size_tag_of_t; - detail::check_same_size(left, right.actual(), - size_check_promote_t()); -} - -template -inline void -check_same_size(const readable_vector& left, const Sub2& right, - enable_if_array_t*) -{ - using tag1 = size_tag_of_t; - using tag2 = tag1; // dynamic/dynamic or fixed/fixed. - detail::check_same_size(left, right, size_check_promote_t()); -} - -template -auto -check_same_size(const readable_vector& left, const Sub2& right) - -> decltype(right.size(), void()) -{ - using tag1 = size_tag_of_t; - using tag2 = dynamic_size_tag; // dynamic/dynamic or fixed/dynamic. - detail::check_same_size(left, right, size_check_promote_t()); -} - -/* check_minimum_size: */ - -template -inline void -check_minimum_size(const readable_vector& left, int N) -{ - detail::check_minimum_size(left, N); -} - -template -inline void -check_minimum_size(const readable_vector& left, cml::int_c) -{ - detail::check_minimum_size(left, cml::int_c()); -} - -/* check_size: */ - -template -inline void -check_size(const readable_vector& left, int N) -{ - detail::check_size(left, N); -} - -template -inline void -check_size(const readable_vector& left, cml::int_c) -{ - detail::check_size(left, cml::int_c()); -} - -/* check_size_range: */ - -template -inline void -check_size_range(const readable_vector& left, int Low, int High) -{ - detail::check_size_range(left, Low, High); -} - -template -inline void -check_size_range(const readable_vector& left, cml::int_c, - cml::int_c) -{ - detail::check_size_range(left, cml::int_c(), cml::int_c()); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_SIZE_CHECKING_TPP +# error "vector/size_checking.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { +namespace detail { + +/* No-op binary vector expression size checking: */ +template +inline void +check_same_size(const readable_vector&, const Sub2&, any_size_tag) +{} + +/* Compile-time binary vector expression size checking: */ +template +inline void +check_same_size(const readable_vector&, const Sub2&, fixed_size_tag) +{ + static_assert(array_size_of_c::value == array_size_of_c::value, + "incompatible vector expression sizes"); +} + +/* Run-time binary vector expression size checking: */ +template +inline void +check_same_size(const readable_vector& left, const Sub2& right, + dynamic_size_tag) +{ +#ifndef CML_NO_RUNTIME_VECTOR_SIZE_CHECKS + cml_require(array_size_of(left) == array_size_of(right), + incompatible_vector_size_error, + /**/); +#endif +} + +/* No-op minimum vector size checking. */ +template +inline void +check_minimum_size(const readable_vector&, int, + enable_if_any_size_t* = nullptr) +{} + +/* Compile-time minimum size checking against a constant. */ +template +inline void +check_minimum_size(const readable_vector&, cml::int_c, + enable_if_fixed_size_t* = nullptr) +{ + static_assert(array_size_of_c::value >= N, + "vector expression too short"); +} + +/* Run-time minimum vector size checking. */ +template +inline void +check_minimum_size(const readable_vector& sub, int N) +{ +#ifndef CML_NO_RUNTIME_VECTOR_SIZE_CHECKS + cml_require(array_size_of(sub) >= N, minimum_vector_size_error, /**/); +#endif +} + +/* No-op vector size checking. */ +template +inline void +check_size(const readable_vector&, int, + enable_if_any_size_t* = nullptr) +{} + +/* Compile-time size checking against a constant. */ +template +inline void +check_size(const readable_vector&, cml::int_c, + enable_if_fixed_size_t* = nullptr) +{ + static_assert(array_size_of_c::value == N, + "incorrect vector expression size"); +} + +/* Run-time vector size checking. */ +template +inline void +check_size(const readable_vector& sub, int N) +{ +#ifndef CML_NO_RUNTIME_VECTOR_SIZE_CHECKS + cml_require(array_size_of(sub) == N, vector_size_error, /**/); +#endif +} + +/* No-op vector size range checking. */ +template +inline void +check_size_range(const readable_vector&, int, int, + enable_if_any_size_t* = nullptr) +{} + +/* Compile-time size range checking against constants. */ +template +inline void +check_size_range(const readable_vector&, cml::int_c, cml::int_c, + enable_if_fixed_size_t* = nullptr) +{ + static_assert( + array_size_of_c::value >= Low && array_size_of_c::value <= High, + "vector expression size out of range"); +} + +/* Run-time vector size checking. */ +template +inline void +check_size_range(const readable_vector& sub, int Low, int High) +{ +#ifndef CML_NO_RUNTIME_VECTOR_SIZE_CHECKS + cml_require(array_size_of(sub) >= Low && array_size_of(sub) <= High, + vector_size_range_error, + /**/); +#endif +} + +} // namespace detail + +/* check_same_size: */ + +template +inline void +check_same_size(const readable_vector& left, + const readable_vector& right) +{ + using tag1 = size_tag_of_t; + using tag2 = size_tag_of_t; + detail::check_same_size(left, right.actual(), + size_check_promote_t()); +} + +template +inline void +check_same_size(const readable_vector& left, const Sub2& right, + enable_if_array_t*) +{ + using tag1 = size_tag_of_t; + using tag2 = tag1; // dynamic/dynamic or fixed/fixed. + detail::check_same_size(left, right, size_check_promote_t()); +} + +template +auto +check_same_size(const readable_vector& left, const Sub2& right) + -> decltype(right.size(), void()) +{ + using tag1 = size_tag_of_t; + using tag2 = dynamic_size_tag; // dynamic/dynamic or fixed/dynamic. + detail::check_same_size(left, right, size_check_promote_t()); +} + +/* check_minimum_size: */ + +template +inline void +check_minimum_size(const readable_vector& left, int N) +{ + detail::check_minimum_size(left, N); +} + +template +inline void +check_minimum_size(const readable_vector& left, cml::int_c) +{ + detail::check_minimum_size(left, cml::int_c()); +} + +/* check_size: */ + +template +inline void +check_size(const readable_vector& left, int N) +{ + detail::check_size(left, N); +} + +template +inline void +check_size(const readable_vector& left, cml::int_c) +{ + detail::check_size(left, cml::int_c()); +} + +/* check_size_range: */ + +template +inline void +check_size_range(const readable_vector& left, int Low, int High) +{ + detail::check_size_range(left, Low, High); +} + +template +inline void +check_size_range(const readable_vector& left, cml::int_c, + cml::int_c) +{ + detail::check_size_range(left, cml::int_c(), cml::int_c()); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/subvector.h b/cml/vector/subvector.h index a2f2ba3..87f8094 100644 --- a/cml/vector/subvector.h +++ b/cml/vector/subvector.h @@ -1,8 +1,8 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include diff --git a/cml/vector/subvector_node.h b/cml/vector/subvector_node.h index 6c7d297..a82e753 100644 --- a/cml/vector/subvector_node.h +++ b/cml/vector/subvector_node.h @@ -1,122 +1,122 @@ -/*------------------------------------------------------------------------- @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -template class subvector_node; - -/** subvector_node<> traits. */ -template struct vector_traits> -{ - /* Figure out the basic type of Sub: */ - using vector_type = subvector_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = vector_traits; - using element_traits = typename sub_traits::element_traits; - using value_type = typename sub_traits::value_type; - using immutable_value = typename sub_traits::immutable_value; - - /* Compute the new storage size: */ - - private: - static const int old_array_size = sub_traits::array_size; - static const int new_array_size = old_array_size - 1; - static const int N = new_array_size > 0 ? new_array_size : -1; - - public: - /* Resize the storage type of the subexpression: */ - using resized_type = resize_storage_t, N>; - - /* Rebind to vector storage: */ - using storage_type = rebind_t; - - /* Traits and types for the new storage: */ - using size_tag = typename storage_type::size_tag; - - /* Array size: */ - static const int array_size = storage_type::array_size; -}; - -/** Represents an N-1 subvector operation in an expression tree, where N is - * the length of the wrapped subexpression. - */ -template -class subvector_node : public readable_vector> -{ - public: - using node_type = subvector_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** The array size constant depends upon the subexpression size. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expression and the element to drop. - * @c sub must be an lvalue reference or rvalue reference. - */ - subvector_node(Sub sub, int skip); - - /** Move constructor. */ - subvector_node(node_type&& other); - - /** Copy constructor. */ - subvector_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Apply the operator to element @c i and return the result. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - /** The wrapped subexpression. */ - wrap_type m_sub; - - /** The element to skip. */ - int m_skip; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_VECTOR_SUBVECTOR_NODE_TPP -#include -#undef __CML_VECTOR_SUBVECTOR_NODE_TPP +/*------------------------------------------------------------------------- @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +template class subvector_node; + +/** subvector_node<> traits. */ +template struct vector_traits> +{ + /* Figure out the basic type of Sub: */ + using vector_type = subvector_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = vector_traits; + using element_traits = typename sub_traits::element_traits; + using value_type = typename sub_traits::value_type; + using immutable_value = typename sub_traits::immutable_value; + + /* Compute the new storage size: */ + + private: + static const int old_array_size = sub_traits::array_size; + static const int new_array_size = old_array_size - 1; + static const int N = new_array_size > 0 ? new_array_size : -1; + + public: + /* Resize the storage type of the subexpression: */ + using resized_type = resize_storage_t, N>; + + /* Rebind to vector storage: */ + using storage_type = rebind_t; + + /* Traits and types for the new storage: */ + using size_tag = typename storage_type::size_tag; + + /* Array size: */ + static const int array_size = storage_type::array_size; +}; + +/** Represents an N-1 subvector operation in an expression tree, where N is + * the length of the wrapped subexpression. + */ +template +class subvector_node : public readable_vector> +{ + public: + using node_type = subvector_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** The array size constant depends upon the subexpression size. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expression and the element to drop. + * @c sub must be an lvalue reference or rvalue reference. + */ + subvector_node(Sub sub, int skip); + + /** Move constructor. */ + subvector_node(node_type&& other); + + /** Copy constructor. */ + subvector_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Apply the operator to element @c i and return the result. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + /** The wrapped subexpression. */ + wrap_type m_sub; + + /** The element to skip. */ + int m_skip; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_VECTOR_SUBVECTOR_NODE_TPP +#include +#undef __CML_VECTOR_SUBVECTOR_NODE_TPP diff --git a/cml/vector/subvector_node.tpp b/cml/vector/subvector_node.tpp index c4e7cb1..28eafe8 100644 --- a/cml/vector/subvector_node.tpp +++ b/cml/vector/subvector_node.tpp @@ -1,50 +1,50 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_SUBVECTOR_NODE_TPP -# error "vector/subvector_node.tpp not included correctly" -#endif - -namespace cml { - -/* subvector_node 'structors: */ - -template -subvector_node::subvector_node(Sub sub, int skip) -: m_sub(std::move(sub)) -, m_skip(skip) -{} - -template -subvector_node::subvector_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -, m_skip(other.m_skip) -{} - -template -subvector_node::subvector_node(const node_type& other) -: m_sub(other.m_sub) -, m_skip(other.m_skip) -{} - - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -subvector_node::i_size() const -{ - return this->m_sub.size() - 1; -} - -template -auto -subvector_node::i_get(int i) const -> immutable_value -{ - return this->m_sub.get((i < this->m_skip) ? i : (i + 1)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_SUBVECTOR_NODE_TPP +# error "vector/subvector_node.tpp not included correctly" +#endif + +namespace cml { + +/* subvector_node 'structors: */ + +template +subvector_node::subvector_node(Sub sub, int skip) +: m_sub(std::move(sub)) +, m_skip(skip) +{} + +template +subvector_node::subvector_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +, m_skip(other.m_skip) +{} + +template +subvector_node::subvector_node(const node_type& other) +: m_sub(other.m_sub) +, m_skip(other.m_skip) +{} + + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +subvector_node::i_size() const +{ + return this->m_sub.size() - 1; +} + +template +auto +subvector_node::i_get(int i) const -> immutable_value +{ + return this->m_sub.get((i < this->m_skip) ? i : (i + 1)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/subvector_ops.h b/cml/vector/subvector_ops.h index 3e92637..28ce81d 100644 --- a/cml/vector/subvector_ops.h +++ b/cml/vector/subvector_ops.h @@ -1,29 +1,29 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -/** Return an expression node for the subvector @c i of @c sub. @c sub is - * stored by const reference in the node. - */ -template -auto subvector(const readable_vector& sub, int i) - -> subvector_node; - -/** Return an expression node for subvector @c i of the temporary - * subexpression @c sub. @c sub is stored by value in the node (via - * std::move). - */ -template -auto subvector(readable_vector&& sub) -> subvector_node; - -} // namespace cml - -#define __CML_VECTOR_SUBVECTOR_OPS_TPP -#include -#undef __CML_VECTOR_SUBVECTOR_OPS_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +/** Return an expression node for the subvector @c i of @c sub. @c sub is + * stored by const reference in the node. + */ +template +auto subvector(const readable_vector& sub, int i) + -> subvector_node; + +/** Return an expression node for subvector @c i of the temporary + * subexpression @c sub. @c sub is stored by value in the node (via + * std::move). + */ +template +auto subvector(readable_vector&& sub) -> subvector_node; + +} // namespace cml + +#define __CML_VECTOR_SUBVECTOR_OPS_TPP +#include +#undef __CML_VECTOR_SUBVECTOR_OPS_TPP diff --git a/cml/vector/subvector_ops.tpp b/cml/vector/subvector_ops.tpp index 65aee65..80fd3aa 100644 --- a/cml/vector/subvector_ops.tpp +++ b/cml/vector/subvector_ops.tpp @@ -1,25 +1,25 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_SUBVECTOR_OPS_TPP -# error "vector/subvector_ops.tpp not included correctly" -#endif - -namespace cml { - -template -inline auto -subvector(const readable_vector& sub, int i) -> subvector_node -{ - return subvector_node(sub.actual(), i); -} - -template -inline auto -subvector(readable_vector&& sub, int i) -> subvector_node -{ - return subvector_node((Sub&&) sub, i); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_SUBVECTOR_OPS_TPP +# error "vector/subvector_ops.tpp not included correctly" +#endif + +namespace cml { + +template +inline auto +subvector(const readable_vector& sub, int i) -> subvector_node +{ + return subvector_node(sub.actual(), i); +} + +template +inline auto +subvector(readable_vector&& sub, int i) -> subvector_node +{ + return subvector_node((Sub&&) sub, i); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/temporary.h b/cml/vector/temporary.h index fd9a05a..e6055e7 100644 --- a/cml/vector/temporary.h +++ b/cml/vector/temporary.h @@ -1,101 +1,101 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace cml { - -/** Deduce a temporary for a vector expression. */ -template -struct temporary_of> -{ - using vector_type = cml::unqualified_type_t; - - /* Propagate the element type of the original vector: */ - using traits_type = vector_traits; - using value_type = typename traits_type::value_type; - using storage_type = typename traits_type::storage_type; - - /* Need the proxy for the storage type: */ - using proxy_type = proxy_type_of_t; - - /* Build the temporary: */ - using type = vector; -}; - -/** Deduce a subvector temporary type for a vector expression. */ -template::array_size - == vector_traits::array_size>::type* = nullptr> -struct subvector_of -{ - using vector_type = cml::unqualified_type_t; - - /* Propagate the element type of the original vector: */ - using traits_type = vector_traits; - using storage_type = typename traits_type::storage_type; - using value_type = typename traits_type::value_type; - using size_tag = typename traits_type::size_tag; - - /* Compute the new storage size: */ - - private: - static const int old_array_size = traits_type::array_size; - static const int new_array_size = old_array_size - 1; - static const int N = new_array_size > 0 ? new_array_size : -1; - - public: - /* Determine the new storage type: */ - using resized_type = resize_storage_t; - using rebound_type = rebind_t; - using proxy_type = proxy_type_of_t; - - /* Build the subvector from the new storage type: */ - using type = vector; -}; - -/** Convenience alias for subvector_of. */ -template using subvector_of_t = typename subvector_of::type; - -/** Deduce a supervector temporary type for a vector expression. */ -template::array_size - == vector_traits::array_size>::type* = nullptr> -struct supervector_of -{ - using vector_type = cml::unqualified_type_t; - - /* Propagate the element type of the original vector: */ - using traits_type = vector_traits; - using storage_type = typename traits_type::storage_type; - using value_type = typename traits_type::value_type; - using size_tag = typename traits_type::size_tag; - - /* Compute the new storage size: */ - - private: - static const int old_array_size = traits_type::array_size; - static const int new_array_size = old_array_size + 1; - static const int N = new_array_size > 0 ? new_array_size : -1; - - public: - /* Determine the new storage type: */ - using resized_type = resize_storage_t; - using rebound_type = rebind_t; - using proxy_type = proxy_type_of_t; - - /* Build the supervector from the new storage type: */ - using type = vector; -}; - -/** Convenience alias for supervector_of. */ -template using supervector_of_t = typename supervector_of::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace cml { + +/** Deduce a temporary for a vector expression. */ +template +struct temporary_of> +{ + using vector_type = cml::unqualified_type_t; + + /* Propagate the element type of the original vector: */ + using traits_type = vector_traits; + using value_type = typename traits_type::value_type; + using storage_type = typename traits_type::storage_type; + + /* Need the proxy for the storage type: */ + using proxy_type = proxy_type_of_t; + + /* Build the temporary: */ + using type = vector; +}; + +/** Deduce a subvector temporary type for a vector expression. */ +template::array_size + == vector_traits::array_size>::type* = nullptr> +struct subvector_of +{ + using vector_type = cml::unqualified_type_t; + + /* Propagate the element type of the original vector: */ + using traits_type = vector_traits; + using storage_type = typename traits_type::storage_type; + using value_type = typename traits_type::value_type; + using size_tag = typename traits_type::size_tag; + + /* Compute the new storage size: */ + + private: + static const int old_array_size = traits_type::array_size; + static const int new_array_size = old_array_size - 1; + static const int N = new_array_size > 0 ? new_array_size : -1; + + public: + /* Determine the new storage type: */ + using resized_type = resize_storage_t; + using rebound_type = rebind_t; + using proxy_type = proxy_type_of_t; + + /* Build the subvector from the new storage type: */ + using type = vector; +}; + +/** Convenience alias for subvector_of. */ +template using subvector_of_t = typename subvector_of::type; + +/** Deduce a supervector temporary type for a vector expression. */ +template::array_size + == vector_traits::array_size>::type* = nullptr> +struct supervector_of +{ + using vector_type = cml::unqualified_type_t; + + /* Propagate the element type of the original vector: */ + using traits_type = vector_traits; + using storage_type = typename traits_type::storage_type; + using value_type = typename traits_type::value_type; + using size_tag = typename traits_type::size_tag; + + /* Compute the new storage size: */ + + private: + static const int old_array_size = traits_type::array_size; + static const int new_array_size = old_array_size + 1; + static const int N = new_array_size > 0 ? new_array_size : -1; + + public: + /* Determine the new storage type: */ + using resized_type = resize_storage_t; + using rebound_type = rebind_t; + using proxy_type = proxy_type_of_t; + + /* Build the supervector from the new storage type: */ + using type = vector; +}; + +/** Convenience alias for supervector_of. */ +template using supervector_of_t = typename supervector_of::type; + +} // namespace cml diff --git a/cml/vector/traits.h b/cml/vector/traits.h index e2a859d..926910f 100644 --- a/cml/vector/traits.h +++ b/cml/vector/traits.h @@ -1,26 +1,26 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Specializable class wrapping traits for vector<> types. This class is - * used to simplify static polymorphism by providing a base class the types - * used by a particular derived class. - * - * @tparam Vector The vector<> type the traits correspond to. - */ -template struct vector_traits; - -/** traits_of for vector types. */ -template struct traits_of> -{ - using type = vector_traits; -}; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Specializable class wrapping traits for vector<> types. This class is + * used to simplify static polymorphism by providing a base class the types + * used by a particular derived class. + * + * @tparam Vector The vector<> type the traits correspond to. + */ +template struct vector_traits; + +/** traits_of for vector types. */ +template struct traits_of> +{ + using type = vector_traits; +}; + +} // namespace cml diff --git a/cml/vector/triple_product.h b/cml/vector/triple_product.h index 7e1f719..0d19878 100644 --- a/cml/vector/triple_product.h +++ b/cml/vector/triple_product.h @@ -1,37 +1,37 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Convenience alias to determine the scalar type to return from - * cml::triple_product. - */ -template -using triple_product_promote_t = value_type_trait_promote_t; - -/** Compute the scalar triple product ("box product") of 3 3D vectors, and - * return the scalar result. - * - * @note Currently, the result is computed immediately, even if it appears - * as a term in an expression. - * - * @throws vector_size_error at run-time if a, b, or c is dynamically-sized - * and is not a 3D vector. The size is checked at compile time for - * fixed-sized expressions. - */ -template -auto triple_product(const readable_vector& a, - const readable_vector& b, const readable_vector& c) - -> triple_product_promote_t; - -} // namespace cml - -#define __CML_VECTOR_TRIPLE_PRODUCT_TPP -#include -#undef __CML_VECTOR_TRIPLE_PRODUCT_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Convenience alias to determine the scalar type to return from + * cml::triple_product. + */ +template +using triple_product_promote_t = value_type_trait_promote_t; + +/** Compute the scalar triple product ("box product") of 3 3D vectors, and + * return the scalar result. + * + * @note Currently, the result is computed immediately, even if it appears + * as a term in an expression. + * + * @throws vector_size_error at run-time if a, b, or c is dynamically-sized + * and is not a 3D vector. The size is checked at compile time for + * fixed-sized expressions. + */ +template +auto triple_product(const readable_vector& a, + const readable_vector& b, const readable_vector& c) + -> triple_product_promote_t; + +} // namespace cml + +#define __CML_VECTOR_TRIPLE_PRODUCT_TPP +#include +#undef __CML_VECTOR_TRIPLE_PRODUCT_TPP diff --git a/cml/vector/triple_product.tpp b/cml/vector/triple_product.tpp index ae711d6..27ff393 100644 --- a/cml/vector/triple_product.tpp +++ b/cml/vector/triple_product.tpp @@ -1,25 +1,25 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_TRIPLE_PRODUCT_TPP -# error "vector/triple_product.tpp not included correctly" -#endif - -#include -#include - -namespace cml { - -template -inline auto -triple_product(const readable_vector& a, const readable_vector& b, - const readable_vector& c) -> triple_product_promote_t -{ - cml::check_size(a, cml::int_c<3>()); - cml::check_size(b, cml::int_c<3>()); - cml::check_size(c, cml::int_c<3>()); - return cml::dot(a, cross(b, c)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_TRIPLE_PRODUCT_TPP +# error "vector/triple_product.tpp not included correctly" +#endif + +#include +#include + +namespace cml { + +template +inline auto +triple_product(const readable_vector& a, const readable_vector& b, + const readable_vector& c) -> triple_product_promote_t +{ + cml::check_size(a, cml::int_c<3>()); + cml::check_size(b, cml::int_c<3>()); + cml::check_size(c, cml::int_c<3>()); + return cml::dot(a, cross(b, c)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/type_util.h b/cml/vector/type_util.h index 325fa62..f6e8e9f 100644 --- a/cml/vector/type_util.h +++ b/cml/vector/type_util.h @@ -1,48 +1,48 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Defines typedef @c type as std::true_type if @c T is statically - * polymorphic and derived from @c readable_vector, or std::false_type - * otherwise. The static bool @c value is set to true or false to match @c - * type. - */ -template struct is_vector -{ - private: - /* Strip const, volatile, and reference from T to get the type to test: */ - using naked_type = cml::unqualified_type_t; - - /* Deduce the derived type (fails if T is not statically polymorphic): */ - using derived_type = actual_type_of_t; - - - public: - /* std::true_type if T is derived from readable_vector<>, std::false_type - * otherwise: - */ - using type = std::is_base_of, naked_type>; - - /* True or false, depending upon 'type': */ - static const bool value = type::value; -}; - -/** Wrapper for enable_if to detect vector types (derived from - * readable_vector). - */ -template -struct enable_if_vector : std::enable_if::value> -{}; - -/** Convenience alias for enable_if_vector. */ -template -using enable_if_vector_t = typename enable_if_vector::type; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Defines typedef @c type as std::true_type if @c T is statically + * polymorphic and derived from @c readable_vector, or std::false_type + * otherwise. The static bool @c value is set to true or false to match @c + * type. + */ +template struct is_vector +{ + private: + /* Strip const, volatile, and reference from T to get the type to test: */ + using naked_type = cml::unqualified_type_t; + + /* Deduce the derived type (fails if T is not statically polymorphic): */ + using derived_type = actual_type_of_t; + + + public: + /* std::true_type if T is derived from readable_vector<>, std::false_type + * otherwise: + */ + using type = std::is_base_of, naked_type>; + + /* True or false, depending upon 'type': */ + static const bool value = type::value; +}; + +/** Wrapper for enable_if to detect vector types (derived from + * readable_vector). + */ +template +struct enable_if_vector : std::enable_if::value> +{}; + +/** Convenience alias for enable_if_vector. */ +template +using enable_if_vector_t = typename enable_if_vector::type; + +} // namespace cml diff --git a/cml/vector/types.h b/cml/vector/types.h index ac0b274..3a1d4b2 100644 --- a/cml/vector/types.h +++ b/cml/vector/types.h @@ -1,56 +1,56 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** @defgroup vector_types Predefined Vector Types */ -/*@{*/ - -using vector2i = vector>; -using vector3i = vector>; -using vector4i = vector>; -using vectori = vector>; -using external2i = vector>; -using external3i = vector>; -using external4i = vector>; -using externalni = vector>; -using external2ci = vector>; -using external3ci = vector>; -using external4ci = vector>; -using externalnci = vector>; - -using vector2f = vector>; -using vector3f = vector>; -using vector4f = vector>; -using vectorf = vector>; -using external2f = vector>; -using external3f = vector>; -using external4f = vector>; -using externalnf = vector>; -using external2cf = vector>; -using external3cf = vector>; -using external4cf = vector>; -using externalncf = vector>; - -using vector2d = vector>; -using vector3d = vector>; -using vector4d = vector>; -using vectord = vector>; -using external2d = vector>; -using external3d = vector>; -using external4d = vector>; -using externalnd = vector>; -using external2cd = vector>; -using external3cd = vector>; -using external4cd = vector>; -using externalncd = vector>; - -/*@}*/ - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** @defgroup vector_types Predefined Vector Types */ +/*@{*/ + +using vector2i = vector>; +using vector3i = vector>; +using vector4i = vector>; +using vectori = vector>; +using external2i = vector>; +using external3i = vector>; +using external4i = vector>; +using externalni = vector>; +using external2ci = vector>; +using external3ci = vector>; +using external4ci = vector>; +using externalnci = vector>; + +using vector2f = vector>; +using vector3f = vector>; +using vector4f = vector>; +using vectorf = vector>; +using external2f = vector>; +using external3f = vector>; +using external4f = vector>; +using externalnf = vector>; +using external2cf = vector>; +using external3cf = vector>; +using external4cf = vector>; +using externalncf = vector>; + +using vector2d = vector>; +using vector3d = vector>; +using vector4d = vector>; +using vectord = vector>; +using external2d = vector>; +using external3d = vector>; +using external4d = vector>; +using externalnd = vector>; +using external2cd = vector>; +using external3cd = vector>; +using external4cd = vector>; +using externalncd = vector>; + +/*@}*/ + +} // namespace cml diff --git a/cml/vector/unary_node.h b/cml/vector/unary_node.h index c8ea758..f100284 100644 --- a/cml/vector/unary_node.h +++ b/cml/vector/unary_node.h @@ -1,101 +1,101 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include - -namespace cml { - -template class vector_unary_node; - -/** vector_unary_node<> traits. */ -template struct vector_traits> -{ - using vector_type = vector_unary_node; - using sub_arg_type = Sub; - using sub_type = cml::unqualified_type_t; - using sub_traits = vector_traits; - using element_traits = scalar_traits; - using value_type = typename element_traits::value_type; - using immutable_value = value_type; - using storage_type = typename sub_traits::storage_type; - using size_tag = typename sub_traits::size_tag; - - /* Propagate the array size from the subexpression: */ - static const int array_size = sub_traits::array_size; -}; - -/** Represents a unary vector operation in an expression tree. */ -template -class vector_unary_node : public readable_vector> -{ - public: - using node_type = vector_unary_node; - using readable_type = readable_vector; - using traits_type = vector_traits; - using sub_arg_type = typename traits_type::sub_arg_type; - using sub_type = typename traits_type::sub_type; - using element_traits = typename traits_type::element_traits; - using value_type = typename traits_type::value_type; - using immutable_value = typename traits_type::immutable_value; - using storage_type = typename traits_type::storage_type; - using size_tag = typename traits_type::size_tag; - - - public: - /** The array size constant is the same as the subexpression. */ - static const int array_size = traits_type::array_size; - - - public: - /** Construct from the wrapped sub-expression. @c sub must be an - * lvalue reference or rvalue reference. - */ - explicit vector_unary_node(Sub sub); - - /** Move constructor. */ - vector_unary_node(node_type&& other); - - /** Copy constructor. */ - vector_unary_node(const node_type& other); - - - protected: - /** @name readable_vector Interface */ - /*@{*/ - - friend readable_type; - - /** Return the size of the vector expression. */ - int i_size() const; - - /** Apply the operator to element @c i and return the result. */ - immutable_value i_get(int i) const; - - /*@}*/ - - - protected: - /** The type used to store the subexpression. The expression is stored - * as a copy if Sub is an rvalue reference (temporary), or by const - * reference if Sub is an lvalue reference. - */ - using sub_wrap_type = cml::if_t::value, const sub_type&, - sub_type>; - - /** The wrapped subexpression. */ - sub_wrap_type m_sub; - - - private: - // Not assignable. - node_type& operator=(const node_type&); -}; - -} // namespace cml - -#define __CML_VECTOR_UNARY_NODE_TPP -#include -#undef __CML_VECTOR_UNARY_NODE_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include + +namespace cml { + +template class vector_unary_node; + +/** vector_unary_node<> traits. */ +template struct vector_traits> +{ + using vector_type = vector_unary_node; + using sub_arg_type = Sub; + using sub_type = cml::unqualified_type_t; + using sub_traits = vector_traits; + using element_traits = scalar_traits; + using value_type = typename element_traits::value_type; + using immutable_value = value_type; + using storage_type = typename sub_traits::storage_type; + using size_tag = typename sub_traits::size_tag; + + /* Propagate the array size from the subexpression: */ + static const int array_size = sub_traits::array_size; +}; + +/** Represents a unary vector operation in an expression tree. */ +template +class vector_unary_node : public readable_vector> +{ + public: + using node_type = vector_unary_node; + using readable_type = readable_vector; + using traits_type = vector_traits; + using sub_arg_type = typename traits_type::sub_arg_type; + using sub_type = typename traits_type::sub_type; + using element_traits = typename traits_type::element_traits; + using value_type = typename traits_type::value_type; + using immutable_value = typename traits_type::immutable_value; + using storage_type = typename traits_type::storage_type; + using size_tag = typename traits_type::size_tag; + + + public: + /** The array size constant is the same as the subexpression. */ + static const int array_size = traits_type::array_size; + + + public: + /** Construct from the wrapped sub-expression. @c sub must be an + * lvalue reference or rvalue reference. + */ + explicit vector_unary_node(Sub sub); + + /** Move constructor. */ + vector_unary_node(node_type&& other); + + /** Copy constructor. */ + vector_unary_node(const node_type& other); + + + protected: + /** @name readable_vector Interface */ + /*@{*/ + + friend readable_type; + + /** Return the size of the vector expression. */ + int i_size() const; + + /** Apply the operator to element @c i and return the result. */ + immutable_value i_get(int i) const; + + /*@}*/ + + + protected: + /** The type used to store the subexpression. The expression is stored + * as a copy if Sub is an rvalue reference (temporary), or by const + * reference if Sub is an lvalue reference. + */ + using sub_wrap_type = cml::if_t::value, const sub_type&, + sub_type>; + + /** The wrapped subexpression. */ + sub_wrap_type m_sub; + + + private: + // Not assignable. + node_type& operator=(const node_type&); +}; + +} // namespace cml + +#define __CML_VECTOR_UNARY_NODE_TPP +#include +#undef __CML_VECTOR_UNARY_NODE_TPP diff --git a/cml/vector/unary_node.tpp b/cml/vector/unary_node.tpp index 340bc20..d394940 100644 --- a/cml/vector/unary_node.tpp +++ b/cml/vector/unary_node.tpp @@ -1,47 +1,47 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_UNARY_NODE_TPP -# error "vector/unary_node.tpp not included correctly" -#endif - -namespace cml { - -/* vector_unary_node 'structors: */ - -template -vector_unary_node::vector_unary_node(Sub sub) -: m_sub(std::move(sub)) -{} - -template -vector_unary_node::vector_unary_node(node_type&& other) -: m_sub(std::move(other.m_sub)) -{} - -template -vector_unary_node::vector_unary_node(const node_type& other) -: m_sub(other.m_sub) -{} - - -/* Internal methods: */ - -/* readable_vector interface: */ - -template -int -vector_unary_node::i_size() const -{ - return this->m_sub.size(); -} - -template -auto -vector_unary_node::i_get(int i) const -> immutable_value -{ - return Op().apply(this->m_sub.get(i)); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_UNARY_NODE_TPP +# error "vector/unary_node.tpp not included correctly" +#endif + +namespace cml { + +/* vector_unary_node 'structors: */ + +template +vector_unary_node::vector_unary_node(Sub sub) +: m_sub(std::move(sub)) +{} + +template +vector_unary_node::vector_unary_node(node_type&& other) +: m_sub(std::move(other.m_sub)) +{} + +template +vector_unary_node::vector_unary_node(const node_type& other) +: m_sub(other.m_sub) +{} + + +/* Internal methods: */ + +/* readable_vector interface: */ + +template +int +vector_unary_node::i_size() const +{ + return this->m_sub.size(); +} + +template +auto +vector_unary_node::i_get(int i) const -> immutable_value +{ + return Op().apply(this->m_sub.get(i)); +} + } // namespace cml \ No newline at end of file diff --git a/cml/vector/unary_ops.h b/cml/vector/unary_ops.h index b6bc5ea..a9f8aa9 100644 --- a/cml/vector/unary_ops.h +++ b/cml/vector/unary_ops.h @@ -1,45 +1,45 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -namespace cml { - -/** Helper function to generate a vector_unary_node from a vector type - * (i.e. derived from readable_vector<>). - */ -template* = nullptr> -inline auto -make_vector_unary_node(Sub&& sub) - -> vector_unary_node, Op> -{ - static_assert( - std::is_same(sub))>::value, - "internal error: unexpected expression type"); - - /* Deduce the operand type of the subexpression (&, const&, &&): */ - using sub_type = actual_operand_type_of_t; - return vector_unary_node((sub_type) sub); -} - -template* = nullptr> -inline auto -operator-(Sub&& sub) -> decltype(make_vector_unary_node>( - std::forward(sub))) -{ - return make_vector_unary_node>(std::forward(sub)); -} - -template* = nullptr> -inline auto -operator+(Sub&& sub) - -> decltype(make_vector_unary_node>(std::forward(sub))) -{ - return make_vector_unary_node>(std::forward(sub)); -} - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +namespace cml { + +/** Helper function to generate a vector_unary_node from a vector type + * (i.e. derived from readable_vector<>). + */ +template* = nullptr> +inline auto +make_vector_unary_node(Sub&& sub) + -> vector_unary_node, Op> +{ + static_assert( + std::is_same(sub))>::value, + "internal error: unexpected expression type"); + + /* Deduce the operand type of the subexpression (&, const&, &&): */ + using sub_type = actual_operand_type_of_t; + return vector_unary_node((sub_type) sub); +} + +template* = nullptr> +inline auto +operator-(Sub&& sub) -> decltype(make_vector_unary_node>( + std::forward(sub))) +{ + return make_vector_unary_node>(std::forward(sub)); +} + +template* = nullptr> +inline auto +operator+(Sub&& sub) + -> decltype(make_vector_unary_node>(std::forward(sub))) +{ + return make_vector_unary_node>(std::forward(sub)); +} + +} // namespace cml diff --git a/cml/vector/vector.h b/cml/vector/vector.h index 4309a13..fbb4b9b 100644 --- a/cml/vector/vector.h +++ b/cml/vector/vector.h @@ -1,23 +1,23 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -namespace cml { - -/** Specializable class for building vector types. - * - * This class encapsulates the notion of a vector. - * - * @tparam Element The scalar type for vector elements, with the following - * operators defined: +, -, *, /, <, >, ==, = (assign). - * - * @tparam StorageType Storage type to use for holding the array of vector - * elements. - * - * @sa scalar_traits - */ -template class vector; - -} // namespace cml +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +namespace cml { + +/** Specializable class for building vector types. + * + * This class encapsulates the notion of a vector. + * + * @tparam Element The scalar type for vector elements, with the following + * operators defined: +, -, *, /, <, >, ==, = (assign). + * + * @tparam StorageType Storage type to use for holding the array of vector + * elements. + * + * @sa scalar_traits + */ +template class vector; + +} // namespace cml diff --git a/cml/vector/writable_vector.h b/cml/vector/writable_vector.h index 9f6a531..ace4c3c 100644 --- a/cml/vector/writable_vector.h +++ b/cml/vector/writable_vector.h @@ -1,379 +1,379 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace cml { - -/** Base class for writable vector types. Writable vectors support - * non-const read-write access to its elements, in addition to read-only - * access via readable_vector. - * - * In addition to the requirements of readable_vector, DerivedT must - * implement: - * - * - i_get(int i), where is the mutable_value type defined by - * vector_traits - * - * - template DerivedT& i_put(int i, const T&) - * - * for compilers without support for rvalue reference from *this; and - * - * template DerivedT& i_put(int i, const T&) & - * template DerivedT&& i_put(int i, const T&) && - * - * for compilers with support for rvalue reference from this. - * - * Note that mutable_value need not be a reference type. - */ -template -class writable_vector : public readable_vector -{ - public: - using vector_type = DerivedT; - using readable_type = readable_vector; - using traits_type = vector_traits; - using value_type = typename traits_type::value_type; - using const_reference = typename traits_type::const_reference; - using mutable_value = typename traits_type::mutable_value; - - - public: - /* Disambiguate readable_vector<> methods: */ - using readable_type::actual; - using readable_type::get; - using readable_type::normalize; - using readable_type::operator[]; - - - public: - /** Return a mutable reference to the vector cast as DerivedT. */ - DerivedT& actual(); - - /** Set element @c i. */ - template DerivedT& put(int i, const Other& v) &; - - /** Set element @c i on a temporary. */ - template DerivedT&& put(int i, const Other& v) &&; - - /** Return mutable element @c i. */ - mutable_value get(int i); - - /** Return const element @c i. */ - template>* = nullptr> - mutable_value get(); - - /** Return a mutable reference to element @c i. */ - mutable_value operator[](int i); - - - public: - /** Divide the vector elements by the length of the vector. */ - DerivedT& normalize() &; - - /** Divide the vector elements of a temporary by the length of the - * vector. - */ - DerivedT&& normalize() &&; - - /** Zero the vector elements. */ - DerivedT& zero() &; - - /** Zero the vector elements of a temporary. */ - DerivedT&& zero() &&; - - /** Set element @c i to value_type(1), and the other elements to 0. */ - DerivedT& cardinal(int i) &; - - /** Set element @c i of a temporary to value_type(1), and the other - * elements to 0. - */ - DerivedT&& cardinal(int i) &&; - - /** Set the vector to the pairwise minimum elements with @c other. - * - * @throws incompatible_vector_size_error at run-time if either vector is - * dynamically-sized, and @c other.size() != this->size(). If both are - * fixed-size expressions, then the size is checked at compile time. - */ - template - DerivedT& minimize(const readable_vector& other) &; - - /** Set the temporary vector to the pairwise minimum elements with @c - * other. - * - * @throws incompatible_vector_size_error at run-time if either vector is - * dynamically-sized, and @c other.size() != this->size(). If both are - * fixed-size expressions, then the size is checked at compile time. - */ - template - DerivedT&& minimize(const readable_vector& other) &&; - - /** Set the vector to the pairwise minimum elements with @c other. - * - * @throws incompatible_vector_size_error at run-time if either vector is - * dynamically-sized, and @c other.size() != this->size(). If both are - * fixed-size expressions, then the size is checked at compile time. - */ - template - DerivedT& maximize(const readable_vector& other) &; - - /** Set the vector to the pairwise minimum elements with @c other. - * - * @throws incompatible_vector_size_error at run-time if either vector is - * dynamically-sized, and @c other.size() != this->size(). If both are - * fixed-size expressions, then the size is checked at compile time. - */ - template - DerivedT&& maximize(const readable_vector& other) &&; - - /** Set elements to random values in the range @c[low,high]. - * - * @note Use std::srand() to seed the random number generator. - */ - DerivedT& random(const_reference low, const_reference high) &; - - /** Set elements of a temporary to random values in the range - * @c[low,high]. - */ - DerivedT&& random(const_reference low, const_reference high) &&; - - /** Set all elements to a specific value. */ - DerivedT& fill(const_reference v) &; - - /** Set all elements of a temporary to a specific value. */ - DerivedT&& fill(const_reference v) &&; - - - public: - /** Assign from a variable list of at least one value. If the vector is - * resizable, it is resized to exactly accomodate the elements of @c - * eN. If the vector is fixed-size, it must have the same length as @c - * eN. - * - * @note This overload is enabled only if all of the arguments are - * convertible to value_type. - */ - template - auto set(const E0& e0, const Elements&... eN) &->enable_if_t< - are_convertible::value, DerivedT&>; - - /** Assign a temporary from a variable list of at least one value. If - * the vector is resizable, it is resized to exactly accomodate the - * elements of @c eN. If the vector is fixed-size, it must have the - * same length as @c eN. - * - * @note This overload is enabled only if all of the arguments are - * convertible to value_type. - */ - template - auto set(const E0& e0, const Elements&... eN) && -> enable_if_t< - are_convertible::value, DerivedT&&>; - - /** Copy assignment. */ - DerivedT& operator=(const writable_vector& other) &; - - /** Assign from a readable_vector. - * - * @throws incompatible_vector_size_error at run-time if the vector is not - * resizable, and if @c other.size() != this->size(). If both are - * fixed-size, then the size is checked at compile time. - */ - template - DerivedT& operator=(const readable_vector& other) &; - - /** Assign a temporary from a readable_vector. - * - * @throws incompatible_vector_size_error at run-time if the vector is not - * resizable, and if @c other.size() != this->size(). If both are - * fixed-size, then the size is checked at compile time. - */ - template - DerivedT&& operator=(const readable_vector& other) &&; - - /** Assign from a fixed-length array type. - * - * @throws incompatible_vector_size_error at run-time if the vector is not - * resizable, and if @c array_size_of_c::value != - * this->size(). If both are fixed-size, then the size is checked at - * compile time. - */ - template* = nullptr> - DerivedT& operator=(const Array& array) &; - - /** Assign a temporary from a fixed-length array type. - * - * @throws incompatible_vector_size_error at run-time if the vector is not - * resizable, and if @c array_size_of_c::value != - * this->size(). If both are fixed-size, then the size is checked at - * compile time. - */ - template* = nullptr> - DerivedT&& operator=(const Array& array) &&; - - /** Assign from initializer list. - * - * @throws incompatible_vector_size_error if the vector is not resizable, - * and if @c l.size() != this->size(). - */ - template - DerivedT& operator=(std::initializer_list l) &; - - /** Assign a temporary from initializer list. - * - * @throws incompatible_vector_size_error if the vector is not resizable, - * and if @c l.size() != this->size(). - */ - template DerivedT&& operator=(std::initializer_list l) &&; - - /** Modify the vector by addition of another vector. - * - * @throws incompatible_vector_size_error at run-time if the vector is - * dynamically-sized, and if @c other.size() != this->size(). If both - * are fixed-size expressions, then the size is checked at compile - * time. - */ - template - DerivedT& operator+=(const readable_vector& other) &; - - /** Modify a temporary vector by addition of another vector. - * - * @throws incompatible_vector_size_error at run-time if the vector is - * dynamically-sized, and if @c other.size() != this->size(). If both - * are fixed-size expressions, then the size is checked at compile - * time. - */ - template - DerivedT&& operator+=(const readable_vector& other) &&; - - /** Modify the vector by subtraction of another vector. - * - * @throws incompatible_vector_size_error at run-time if the vector is - * dynamically-sized, and if @c other.size() != this->size(). If both - * are fixed-size expressions, then the size is checked at compile - * time. - */ - template - DerivedT& operator-=(const readable_vector& other) &; - - /** Modify a temporary vector by subtraction of another vector. - * - * @throws incompatible_vector_size_error at run-time if the vector is - * dynamically-sized, and if @c other.size() != this->size(). If both - * are fixed-size expressions, then the size is checked at compile - * time. - */ - template - DerivedT&& operator-=(const readable_vector& other) &&; - - /** Multiply the vector by a scalar convertible to its value_type. */ - template* = nullptr> - DerivedT& operator*=(const ScalarT& v) &; - - /** Multiply the temporary vector by a scalar convertible to its - * value_type. - */ - template* = nullptr> - DerivedT&& operator*=(const ScalarT& v) &&; - - /** Divide the vector by a scalar convertible to its value_type. */ - template* = nullptr> - DerivedT& operator/=(const ScalarT& v) &; - - /** Divide the vector temporary by a scalar convertible to its - * value_type. - */ - template* = nullptr> - DerivedT&& operator/=(const ScalarT& v) &&; - - - protected: - /** Assign from a readable_vector. - * - * @note This depends upon implicit conversion of the source vector - * elements to the vector value_type. - * - * @throws incompatible_vector_size_error at run-time if the vector is not - * resizable, and if @c other.size() != this->size(). If both are - * fixed-size expressions, then the size is checked at compile time. - */ - template - DerivedT& assign(const readable_vector& other); - - /** Construct from a fixed-length array of values. If the vector is - * resizable, it is resized to exactly accomodate the array. If the - * vector is fixed-size, it must have the same length as @c array. - * - * @note This depends upon implicit conversions of the elements to the - * vector value_type. - */ - template* = nullptr> - DerivedT& assign(const Array& array); - - /** Assign from a pointer to an array. - * - * @note This depends upon implicit conversion of the array elements to - * the vector value_type. - * - * @note The number of elements read from @c array depends upon the - * current size of the vector. - */ - template* = nullptr> - DerivedT& assign(const Pointer& array); - - /** Construct from an initializer_list. If the vector is resizable, it - * is resized to exactly accomodate the elements of @c l. If the vector - * is fixed-size, it must have the same length as @c array. - * - * @note This depends upon implicit conversions of the elements to the - * vector value_type. - */ - template DerivedT& assign(const std::initializer_list& l); - - /** Assign from a subvector and 1 or more additional elements to - * append. - */ - template - DerivedT& assign(const readable_vector& other, - const Elements&... eN); - - /** Construct from a variable list of values. If the vector is - * resizable, it is resized to exactly accomodate the elements of @c - * eN. If the vector is fixed-size, it must have the same length as @c - * eN. - * - * @note This depends upon implicit conversions of the elements to the - * vector value_type. - */ - template DerivedT& assign_elements(const Elements&... eN); - - - protected: - // Use the compiler-generated default constructor: - writable_vector() = default; - - // Use the compiler-generated copy constructor: - writable_vector(const writable_vector&) = default; - - // Use the compiler-generated move constructor: - writable_vector(writable_vector&&) = default; -}; - -} // namespace cml - -#define __CML_VECTOR_WRITABLE_VECTOR_TPP -#include -#undef __CML_VECTOR_WRITABLE_VECTOR_TPP +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Base class for writable vector types. Writable vectors support + * non-const read-write access to its elements, in addition to read-only + * access via readable_vector. + * + * In addition to the requirements of readable_vector, DerivedT must + * implement: + * + * - i_get(int i), where is the mutable_value type defined by + * vector_traits + * + * - template DerivedT& i_put(int i, const T&) + * + * for compilers without support for rvalue reference from *this; and + * + * template DerivedT& i_put(int i, const T&) & + * template DerivedT&& i_put(int i, const T&) && + * + * for compilers with support for rvalue reference from this. + * + * Note that mutable_value need not be a reference type. + */ +template +class writable_vector : public readable_vector +{ + public: + using vector_type = DerivedT; + using readable_type = readable_vector; + using traits_type = vector_traits; + using value_type = typename traits_type::value_type; + using const_reference = typename traits_type::const_reference; + using mutable_value = typename traits_type::mutable_value; + + + public: + /* Disambiguate readable_vector<> methods: */ + using readable_type::actual; + using readable_type::get; + using readable_type::normalize; + using readable_type::operator[]; + + + public: + /** Return a mutable reference to the vector cast as DerivedT. */ + DerivedT& actual(); + + /** Set element @c i. */ + template DerivedT& put(int i, const Other& v) &; + + /** Set element @c i on a temporary. */ + template DerivedT&& put(int i, const Other& v) &&; + + /** Return mutable element @c i. */ + mutable_value get(int i); + + /** Return const element @c i. */ + template>* = nullptr> + mutable_value get(); + + /** Return a mutable reference to element @c i. */ + mutable_value operator[](int i); + + + public: + /** Divide the vector elements by the length of the vector. */ + DerivedT& normalize() &; + + /** Divide the vector elements of a temporary by the length of the + * vector. + */ + DerivedT&& normalize() &&; + + /** Zero the vector elements. */ + DerivedT& zero() &; + + /** Zero the vector elements of a temporary. */ + DerivedT&& zero() &&; + + /** Set element @c i to value_type(1), and the other elements to 0. */ + DerivedT& cardinal(int i) &; + + /** Set element @c i of a temporary to value_type(1), and the other + * elements to 0. + */ + DerivedT&& cardinal(int i) &&; + + /** Set the vector to the pairwise minimum elements with @c other. + * + * @throws incompatible_vector_size_error at run-time if either vector is + * dynamically-sized, and @c other.size() != this->size(). If both are + * fixed-size expressions, then the size is checked at compile time. + */ + template + DerivedT& minimize(const readable_vector& other) &; + + /** Set the temporary vector to the pairwise minimum elements with @c + * other. + * + * @throws incompatible_vector_size_error at run-time if either vector is + * dynamically-sized, and @c other.size() != this->size(). If both are + * fixed-size expressions, then the size is checked at compile time. + */ + template + DerivedT&& minimize(const readable_vector& other) &&; + + /** Set the vector to the pairwise minimum elements with @c other. + * + * @throws incompatible_vector_size_error at run-time if either vector is + * dynamically-sized, and @c other.size() != this->size(). If both are + * fixed-size expressions, then the size is checked at compile time. + */ + template + DerivedT& maximize(const readable_vector& other) &; + + /** Set the vector to the pairwise minimum elements with @c other. + * + * @throws incompatible_vector_size_error at run-time if either vector is + * dynamically-sized, and @c other.size() != this->size(). If both are + * fixed-size expressions, then the size is checked at compile time. + */ + template + DerivedT&& maximize(const readable_vector& other) &&; + + /** Set elements to random values in the range @c[low,high]. + * + * @note Use std::srand() to seed the random number generator. + */ + DerivedT& random(const_reference low, const_reference high) &; + + /** Set elements of a temporary to random values in the range + * @c[low,high]. + */ + DerivedT&& random(const_reference low, const_reference high) &&; + + /** Set all elements to a specific value. */ + DerivedT& fill(const_reference v) &; + + /** Set all elements of a temporary to a specific value. */ + DerivedT&& fill(const_reference v) &&; + + + public: + /** Assign from a variable list of at least one value. If the vector is + * resizable, it is resized to exactly accomodate the elements of @c + * eN. If the vector is fixed-size, it must have the same length as @c + * eN. + * + * @note This overload is enabled only if all of the arguments are + * convertible to value_type. + */ + template + auto set(const E0& e0, const Elements&... eN) &->enable_if_t< + are_convertible::value, DerivedT&>; + + /** Assign a temporary from a variable list of at least one value. If + * the vector is resizable, it is resized to exactly accomodate the + * elements of @c eN. If the vector is fixed-size, it must have the + * same length as @c eN. + * + * @note This overload is enabled only if all of the arguments are + * convertible to value_type. + */ + template + auto set(const E0& e0, const Elements&... eN) && -> enable_if_t< + are_convertible::value, DerivedT&&>; + + /** Copy assignment. */ + DerivedT& operator=(const writable_vector& other) &; + + /** Assign from a readable_vector. + * + * @throws incompatible_vector_size_error at run-time if the vector is not + * resizable, and if @c other.size() != this->size(). If both are + * fixed-size, then the size is checked at compile time. + */ + template + DerivedT& operator=(const readable_vector& other) &; + + /** Assign a temporary from a readable_vector. + * + * @throws incompatible_vector_size_error at run-time if the vector is not + * resizable, and if @c other.size() != this->size(). If both are + * fixed-size, then the size is checked at compile time. + */ + template + DerivedT&& operator=(const readable_vector& other) &&; + + /** Assign from a fixed-length array type. + * + * @throws incompatible_vector_size_error at run-time if the vector is not + * resizable, and if @c array_size_of_c::value != + * this->size(). If both are fixed-size, then the size is checked at + * compile time. + */ + template* = nullptr> + DerivedT& operator=(const Array& array) &; + + /** Assign a temporary from a fixed-length array type. + * + * @throws incompatible_vector_size_error at run-time if the vector is not + * resizable, and if @c array_size_of_c::value != + * this->size(). If both are fixed-size, then the size is checked at + * compile time. + */ + template* = nullptr> + DerivedT&& operator=(const Array& array) &&; + + /** Assign from initializer list. + * + * @throws incompatible_vector_size_error if the vector is not resizable, + * and if @c l.size() != this->size(). + */ + template + DerivedT& operator=(std::initializer_list l) &; + + /** Assign a temporary from initializer list. + * + * @throws incompatible_vector_size_error if the vector is not resizable, + * and if @c l.size() != this->size(). + */ + template DerivedT&& operator=(std::initializer_list l) &&; + + /** Modify the vector by addition of another vector. + * + * @throws incompatible_vector_size_error at run-time if the vector is + * dynamically-sized, and if @c other.size() != this->size(). If both + * are fixed-size expressions, then the size is checked at compile + * time. + */ + template + DerivedT& operator+=(const readable_vector& other) &; + + /** Modify a temporary vector by addition of another vector. + * + * @throws incompatible_vector_size_error at run-time if the vector is + * dynamically-sized, and if @c other.size() != this->size(). If both + * are fixed-size expressions, then the size is checked at compile + * time. + */ + template + DerivedT&& operator+=(const readable_vector& other) &&; + + /** Modify the vector by subtraction of another vector. + * + * @throws incompatible_vector_size_error at run-time if the vector is + * dynamically-sized, and if @c other.size() != this->size(). If both + * are fixed-size expressions, then the size is checked at compile + * time. + */ + template + DerivedT& operator-=(const readable_vector& other) &; + + /** Modify a temporary vector by subtraction of another vector. + * + * @throws incompatible_vector_size_error at run-time if the vector is + * dynamically-sized, and if @c other.size() != this->size(). If both + * are fixed-size expressions, then the size is checked at compile + * time. + */ + template + DerivedT&& operator-=(const readable_vector& other) &&; + + /** Multiply the vector by a scalar convertible to its value_type. */ + template* = nullptr> + DerivedT& operator*=(const ScalarT& v) &; + + /** Multiply the temporary vector by a scalar convertible to its + * value_type. + */ + template* = nullptr> + DerivedT&& operator*=(const ScalarT& v) &&; + + /** Divide the vector by a scalar convertible to its value_type. */ + template* = nullptr> + DerivedT& operator/=(const ScalarT& v) &; + + /** Divide the vector temporary by a scalar convertible to its + * value_type. + */ + template* = nullptr> + DerivedT&& operator/=(const ScalarT& v) &&; + + + protected: + /** Assign from a readable_vector. + * + * @note This depends upon implicit conversion of the source vector + * elements to the vector value_type. + * + * @throws incompatible_vector_size_error at run-time if the vector is not + * resizable, and if @c other.size() != this->size(). If both are + * fixed-size expressions, then the size is checked at compile time. + */ + template + DerivedT& assign(const readable_vector& other); + + /** Construct from a fixed-length array of values. If the vector is + * resizable, it is resized to exactly accomodate the array. If the + * vector is fixed-size, it must have the same length as @c array. + * + * @note This depends upon implicit conversions of the elements to the + * vector value_type. + */ + template* = nullptr> + DerivedT& assign(const Array& array); + + /** Assign from a pointer to an array. + * + * @note This depends upon implicit conversion of the array elements to + * the vector value_type. + * + * @note The number of elements read from @c array depends upon the + * current size of the vector. + */ + template* = nullptr> + DerivedT& assign(const Pointer& array); + + /** Construct from an initializer_list. If the vector is resizable, it + * is resized to exactly accomodate the elements of @c l. If the vector + * is fixed-size, it must have the same length as @c array. + * + * @note This depends upon implicit conversions of the elements to the + * vector value_type. + */ + template DerivedT& assign(const std::initializer_list& l); + + /** Assign from a subvector and 1 or more additional elements to + * append. + */ + template + DerivedT& assign(const readable_vector& other, + const Elements&... eN); + + /** Construct from a variable list of values. If the vector is + * resizable, it is resized to exactly accomodate the elements of @c + * eN. If the vector is fixed-size, it must have the same length as @c + * eN. + * + * @note This depends upon implicit conversions of the elements to the + * vector value_type. + */ + template DerivedT& assign_elements(const Elements&... eN); + + + protected: + // Use the compiler-generated default constructor: + writable_vector() = default; + + // Use the compiler-generated copy constructor: + writable_vector(const writable_vector&) = default; + + // Use the compiler-generated move constructor: + writable_vector(writable_vector&&) = default; +}; + +} // namespace cml + +#define __CML_VECTOR_WRITABLE_VECTOR_TPP +#include +#undef __CML_VECTOR_WRITABLE_VECTOR_TPP diff --git a/cml/vector/writable_vector.tpp b/cml/vector/writable_vector.tpp index 7781a4f..e774d1f 100644 --- a/cml/vector/writable_vector.tpp +++ b/cml/vector/writable_vector.tpp @@ -1,459 +1,459 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#ifndef __CML_VECTOR_WRITABLE_VECTOR_TPP -# error "vector/writable_vector.tpp not included correctly" -#endif - -#include -#include -#include - -namespace cml { -namespace detail { - -/* Terminate the assignment recursion at the final element. */ -template -inline void -assign_elements(writable_vector& sub, cml::int_c, const E0& e0) -{ - sub.put(I, e0); -} - -/* Set element I of sub to e0, then assign the remainder of the elements - * starting from I+1. - */ -template -inline void -assign_elements(writable_vector& sub, cml::int_c, const E0& e0, - const Es&... eN) -{ - sub.put(I, e0); - assign_elements(sub, cml::int_c(), eN...); -} - -/* Set sub(i) to e0: */ -template -inline void -assign_elements(writable_vector& sub, int i, const E0& e0) -{ - sub.put(i, e0); -} - -/* Assign the elements of sub from eN starting from index i. */ -template -inline void -assign_elements(writable_vector& sub, int i, const E0& e0, const Es&... eN) -{ - sub.put(i, e0); - assign_elements(sub, i + 1, eN...); -} - -} // namespace detail - -/* Public methods: */ - -template -DT& -writable_vector
::actual() -{ - return (DT&) *this; -} - -template -auto -writable_vector
::get(int i) -> mutable_value -{ - return this->actual().i_get(i); -} - -template -template>*> -auto -writable_vector
::get() -> mutable_value -{ - return this->actual().i_get(I); -} - -template -auto -writable_vector
::operator[](int i) -> mutable_value -{ - return this->get(i); -} - -template -template -DT& -writable_vector
::put(int i, const Other& v) & -{ - return this->actual().i_put(i, v); -} - -template -template -DT&& -writable_vector
::put(int i, const Other& v) && -{ - this->put(i, v); // Forward to put(...) & - return (DT&&) *this; -} - - -template -DT& -writable_vector
::normalize() & -{ - return this->operator/=(this->length()); -} - -template -DT&& -writable_vector
::normalize() && -{ - this->normalize(); // Forward to normalize & - return (DT&&) *this; -} - -template -DT& -writable_vector
::zero() & -{ - for(int i = 0; i < this->size(); ++i) this->put(i, 0); - return this->actual(); -} - -template -DT&& -writable_vector
::zero() && -{ - this->zero(); // Forward to zero & - return (DT&&) *this; -} - -template -DT& -writable_vector
::cardinal(int i) & -{ - return this->zero().put(i, 1); -} - -template -DT&& -writable_vector
::cardinal(int i) && -{ - this->cardinal(i); // Forward to cardinal & - return (DT&&) *this; -} - -template -template -DT& -writable_vector
::minimize(const readable_vector& other) & -{ - cml::check_same_size(*this, other); - for(int i = 0; i < this->size(); ++i) { - this->put(i, std::min(this->get(i), value_type(other.get(i)))); - } - return this->actual(); -} - -template -template -DT&& -writable_vector
::minimize(const readable_vector& other) && -{ - this->minimize(other); // Forward to minimize & - return (DT&&) *this; -} - -template -template -DT& -writable_vector
::maximize(const readable_vector& other) & -{ - cml::check_same_size(*this, other); - for(int i = 0; i < this->size(); ++i) { - this->put(i, std::max(this->get(i), value_type(other.get(i)))); - } - return this->actual(); -} - -template -template -DT&& -writable_vector
::maximize(const readable_vector& other) && -{ - this->maximize(other); // Forward to maximize & - return (DT&&) *this; -} - -template -DT& -writable_vector
::random(const_reference low, const_reference high) & -{ - using distribution_type = if_t::value, - std::uniform_int_distribution, - std::uniform_real_distribution>; - - std::default_random_engine gen(std::rand()); - distribution_type d(low, high); - for(int i = 0; i < this->size(); ++i) this->put(i, d(gen)); - return this->actual(); -} - -template -DT&& -writable_vector
::random(const_reference low, const_reference high) && -{ - this->random(low, high); - return (DT&&) *this; -} - -template -DT& -writable_vector
::fill(const_reference v) & -{ - for(int i = 0; i < this->size(); ++i) this->put(i, v); - return this->actual(); -} - -template -DT&& -writable_vector
::fill(const_reference v) && -{ - this->fill(v); - return (DT&&) *this; -} - -template -template -auto -writable_vector
::set(const E0& e0, const Es&... eN) & - ->enable_if_t::value, DT&> -{ - return this->assign_elements(e0, eN...); -} - -template -template -auto -writable_vector
::set(const E0& e0, const Es&... eN) && -> enable_if_t< - are_convertible::value, DT&&> -{ - this->assign_elements(e0, eN...); - return (DT&&) *this; -} - -template -DT& -writable_vector
::operator=(const writable_vector& other) & -{ - return this->assign(other); -} - -template -template -DT& -writable_vector
::operator=(const readable_vector& other) & -{ - return this->assign(other); -} - -template -template -DT&& -writable_vector
::operator=(const readable_vector& other) && -{ - this->operator=(other); - return (DT&&) *this; -} - -template -template*> -DT& -writable_vector
::operator=(const Array& array) & -{ - return this->assign(array); -} - -template -template*> -DT&& -writable_vector
::operator=(const Array& array) && -{ - this->operator=(array); - return (DT&&) *this; -} - -template -template -DT& -writable_vector
::operator=(std::initializer_list l) & -{ - return this->assign(l); -} - -template -template -DT&& -writable_vector
::operator=(std::initializer_list l) && -{ - return this->assign(l); -} - -template -template -DT& -writable_vector
::operator+=(const readable_vector& other) & -{ - using op_type = binary_plus_t; - detail::check_or_resize(*this, other); - for(int i = 0; i < this->size(); ++i) - this->put(i, op_type().apply(this->get(i), other.get(i))); - return this->actual(); -} - -template -template -DT&& -writable_vector
::operator+=(const readable_vector& other) && -{ - this->operator+=(other); - return (DT&&) *this; -} - -template -template -DT& -writable_vector
::operator-=(const readable_vector& other) & -{ - using op_type = binary_minus_t; - detail::check_or_resize(*this, other); - for(int i = 0; i < this->size(); ++i) - this->put(i, op_type().apply(this->get(i), other.get(i))); - return this->actual(); -} - -template -template -DT&& -writable_vector
::operator-=(const readable_vector& other) && -{ - this->operator-=(other); - return (DT&&) *this; -} - -template -template::value_type, ScalarT>*> -DT& -writable_vector
::operator*=(const ScalarT& v) & -{ - using op_type = binary_multiply_t; - for(int i = 0; i < this->size(); ++i) - this->put(i, op_type().apply(this->get(i), v)); - return this->actual(); -} - -template -template::value_type, ScalarT>*> -DT&& -writable_vector
::operator*=(const ScalarT& v) && -{ - this->operator*=(v); - return (DT&&) *this; -} - -template -template::value_type, ScalarT>*> -DT& -writable_vector
::operator/=(const ScalarT& v) & -{ - using op_type = binary_divide_t; - for(int i = 0; i < this->size(); ++i) - this->put(i, op_type().apply(this->get(i), v)); - return this->actual(); -} - -template -template::value_type, ScalarT>*> -DT&& -writable_vector
::operator/=(const ScalarT& v) && -{ - this->operator/=(v); - return (DT&&) *this; -} - -/* Internal methods: */ - -template -template -DT& -writable_vector
::assign(const readable_vector& other) -{ - detail::check_or_resize(*this, other); - for(int i = 0; i < this->size(); ++i) this->put(i, other.get(i)); - return this->actual(); -} - -template -template*> -DT& -writable_vector
::assign(const Array& array) -{ - static const int N = array_size_of_c::value; - detail::check_or_resize(*this, N); - for(int i = 0; i < N; ++i) this->put(i, array[i]); - return this->actual(); -} - -template -template*> -DT& -writable_vector
::assign(const Pointer& array) -{ - for(int i = 0; i < this->size(); ++i) this->put(i, array[i]); - return this->actual(); -} - -template -template -DT& -writable_vector
::assign(const std::initializer_list& l) -{ - detail::check_or_resize(*this, l); - int i = 0; - for(Other v : l) { - this->put(i++, v); - } - return this->actual(); -} - -template -template -DT& -writable_vector
::assign(const readable_vector& other, const Es&... eN) -{ - detail::check_or_resize(*this, other, eN...); - for(int i = 0; i < other.size(); ++i) this->put(i, other.get(i)); - detail::assign_elements(*this, other.size(), eN...); - return this->actual(); -} - -template -template -DT& -writable_vector
::assign_elements(const Es&... eN) -{ - static const int N = int(sizeof...(eN)); - detail::check_or_resize(*this, int_c()); - detail::assign_elements(*this, int_c<0>(), eN...); - return this->actual(); -} - +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#ifndef __CML_VECTOR_WRITABLE_VECTOR_TPP +# error "vector/writable_vector.tpp not included correctly" +#endif + +#include +#include +#include + +namespace cml { +namespace detail { + +/* Terminate the assignment recursion at the final element. */ +template +inline void +assign_elements(writable_vector& sub, cml::int_c, const E0& e0) +{ + sub.put(I, e0); +} + +/* Set element I of sub to e0, then assign the remainder of the elements + * starting from I+1. + */ +template +inline void +assign_elements(writable_vector& sub, cml::int_c, const E0& e0, + const Es&... eN) +{ + sub.put(I, e0); + assign_elements(sub, cml::int_c(), eN...); +} + +/* Set sub(i) to e0: */ +template +inline void +assign_elements(writable_vector& sub, int i, const E0& e0) +{ + sub.put(i, e0); +} + +/* Assign the elements of sub from eN starting from index i. */ +template +inline void +assign_elements(writable_vector& sub, int i, const E0& e0, const Es&... eN) +{ + sub.put(i, e0); + assign_elements(sub, i + 1, eN...); +} + +} // namespace detail + +/* Public methods: */ + +template +DT& +writable_vector
::actual() +{ + return (DT&) *this; +} + +template +auto +writable_vector
::get(int i) -> mutable_value +{ + return this->actual().i_get(i); +} + +template +template>*> +auto +writable_vector
::get() -> mutable_value +{ + return this->actual().i_get(I); +} + +template +auto +writable_vector
::operator[](int i) -> mutable_value +{ + return this->get(i); +} + +template +template +DT& +writable_vector
::put(int i, const Other& v) & +{ + return this->actual().i_put(i, v); +} + +template +template +DT&& +writable_vector
::put(int i, const Other& v) && +{ + this->put(i, v); // Forward to put(...) & + return (DT&&) *this; +} + + +template +DT& +writable_vector
::normalize() & +{ + return this->operator/=(this->length()); +} + +template +DT&& +writable_vector
::normalize() && +{ + this->normalize(); // Forward to normalize & + return (DT&&) *this; +} + +template +DT& +writable_vector
::zero() & +{ + for(int i = 0; i < this->size(); ++i) this->put(i, 0); + return this->actual(); +} + +template +DT&& +writable_vector
::zero() && +{ + this->zero(); // Forward to zero & + return (DT&&) *this; +} + +template +DT& +writable_vector
::cardinal(int i) & +{ + return this->zero().put(i, 1); +} + +template +DT&& +writable_vector
::cardinal(int i) && +{ + this->cardinal(i); // Forward to cardinal & + return (DT&&) *this; +} + +template +template +DT& +writable_vector
::minimize(const readable_vector& other) & +{ + cml::check_same_size(*this, other); + for(int i = 0; i < this->size(); ++i) { + this->put(i, std::min(this->get(i), value_type(other.get(i)))); + } + return this->actual(); +} + +template +template +DT&& +writable_vector
::minimize(const readable_vector& other) && +{ + this->minimize(other); // Forward to minimize & + return (DT&&) *this; +} + +template +template +DT& +writable_vector
::maximize(const readable_vector& other) & +{ + cml::check_same_size(*this, other); + for(int i = 0; i < this->size(); ++i) { + this->put(i, std::max(this->get(i), value_type(other.get(i)))); + } + return this->actual(); +} + +template +template +DT&& +writable_vector
::maximize(const readable_vector& other) && +{ + this->maximize(other); // Forward to maximize & + return (DT&&) *this; +} + +template +DT& +writable_vector
::random(const_reference low, const_reference high) & +{ + using distribution_type = if_t::value, + std::uniform_int_distribution, + std::uniform_real_distribution>; + + std::default_random_engine gen(std::rand()); + distribution_type d(low, high); + for(int i = 0; i < this->size(); ++i) this->put(i, d(gen)); + return this->actual(); +} + +template +DT&& +writable_vector
::random(const_reference low, const_reference high) && +{ + this->random(low, high); + return (DT&&) *this; +} + +template +DT& +writable_vector
::fill(const_reference v) & +{ + for(int i = 0; i < this->size(); ++i) this->put(i, v); + return this->actual(); +} + +template +DT&& +writable_vector
::fill(const_reference v) && +{ + this->fill(v); + return (DT&&) *this; +} + +template +template +auto +writable_vector
::set(const E0& e0, const Es&... eN) & + ->enable_if_t::value, DT&> +{ + return this->assign_elements(e0, eN...); +} + +template +template +auto +writable_vector
::set(const E0& e0, const Es&... eN) && -> enable_if_t< + are_convertible::value, DT&&> +{ + this->assign_elements(e0, eN...); + return (DT&&) *this; +} + +template +DT& +writable_vector
::operator=(const writable_vector& other) & +{ + return this->assign(other); +} + +template +template +DT& +writable_vector
::operator=(const readable_vector& other) & +{ + return this->assign(other); +} + +template +template +DT&& +writable_vector
::operator=(const readable_vector& other) && +{ + this->operator=(other); + return (DT&&) *this; +} + +template +template*> +DT& +writable_vector
::operator=(const Array& array) & +{ + return this->assign(array); +} + +template +template*> +DT&& +writable_vector
::operator=(const Array& array) && +{ + this->operator=(array); + return (DT&&) *this; +} + +template +template +DT& +writable_vector
::operator=(std::initializer_list l) & +{ + return this->assign(l); +} + +template +template +DT&& +writable_vector
::operator=(std::initializer_list l) && +{ + return this->assign(l); +} + +template +template +DT& +writable_vector
::operator+=(const readable_vector& other) & +{ + using op_type = binary_plus_t; + detail::check_or_resize(*this, other); + for(int i = 0; i < this->size(); ++i) + this->put(i, op_type().apply(this->get(i), other.get(i))); + return this->actual(); +} + +template +template +DT&& +writable_vector
::operator+=(const readable_vector& other) && +{ + this->operator+=(other); + return (DT&&) *this; +} + +template +template +DT& +writable_vector
::operator-=(const readable_vector& other) & +{ + using op_type = binary_minus_t; + detail::check_or_resize(*this, other); + for(int i = 0; i < this->size(); ++i) + this->put(i, op_type().apply(this->get(i), other.get(i))); + return this->actual(); +} + +template +template +DT&& +writable_vector
::operator-=(const readable_vector& other) && +{ + this->operator-=(other); + return (DT&&) *this; +} + +template +template::value_type, ScalarT>*> +DT& +writable_vector
::operator*=(const ScalarT& v) & +{ + using op_type = binary_multiply_t; + for(int i = 0; i < this->size(); ++i) + this->put(i, op_type().apply(this->get(i), v)); + return this->actual(); +} + +template +template::value_type, ScalarT>*> +DT&& +writable_vector
::operator*=(const ScalarT& v) && +{ + this->operator*=(v); + return (DT&&) *this; +} + +template +template::value_type, ScalarT>*> +DT& +writable_vector
::operator/=(const ScalarT& v) & +{ + using op_type = binary_divide_t; + for(int i = 0; i < this->size(); ++i) + this->put(i, op_type().apply(this->get(i), v)); + return this->actual(); +} + +template +template::value_type, ScalarT>*> +DT&& +writable_vector
::operator/=(const ScalarT& v) && +{ + this->operator/=(v); + return (DT&&) *this; +} + +/* Internal methods: */ + +template +template +DT& +writable_vector
::assign(const readable_vector& other) +{ + detail::check_or_resize(*this, other); + for(int i = 0; i < this->size(); ++i) this->put(i, other.get(i)); + return this->actual(); +} + +template +template*> +DT& +writable_vector
::assign(const Array& array) +{ + static const int N = array_size_of_c::value; + detail::check_or_resize(*this, N); + for(int i = 0; i < N; ++i) this->put(i, array[i]); + return this->actual(); +} + +template +template*> +DT& +writable_vector
::assign(const Pointer& array) +{ + for(int i = 0; i < this->size(); ++i) this->put(i, array[i]); + return this->actual(); +} + +template +template +DT& +writable_vector
::assign(const std::initializer_list& l) +{ + detail::check_or_resize(*this, l); + int i = 0; + for(Other v : l) { + this->put(i++, v); + } + return this->actual(); +} + +template +template +DT& +writable_vector
::assign(const readable_vector& other, const Es&... eN) +{ + detail::check_or_resize(*this, other, eN...); + for(int i = 0; i < other.size(); ++i) this->put(i, other.get(i)); + detail::assign_elements(*this, other.size(), eN...); + return this->actual(); +} + +template +template +DT& +writable_vector
::assign_elements(const Es&... eN) +{ + static const int N = int(sizeof...(eN)); + detail::check_or_resize(*this, int_c()); + detail::assign_elements(*this, int_c<0>(), eN...); + return this->actual(); +} + } // namespace cml \ No newline at end of file diff --git a/cml/version.h b/cml/version.h index 5a4a47e..cd6cf51 100644 --- a/cml/version.h +++ b/cml/version.h @@ -1,11 +1,11 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#pragma once - -/* Current CML version: */ -#define CML_VERSION 200300U - -/* Current CML version as a string: */ -#define CML_VERSION_STRING "2.3.0" +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#pragma once + +/* Current CML version: */ +#define CML_VERSION 200300U + +/* Current CML version as a string: */ +#define CML_VERSION_STRING "2.3.0" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fa53c21..165a39b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,31 +2,17 @@ # @@COPYRIGHT@@ # -------------------------------------------------------------------------- -# Function to add a single-file test to the build, using ${_name}.cpp as the -# test source. -function(cml_add_test _name) - # Define the executable name: - set(ExecName "${_name}") - - # Define the test name: - if(DEFINED CML_TEST_GROUP) - set(TestName "CML:${CML_TEST_GROUP}:${_name}") - else() - message(FATAL_ERROR "CML_TEST_GROUP must be defined") - endif() - - # Setup the build target: - add_executable(${ExecName} ${_name}.cpp) - +function(cml_default_compile_options _name) # MSVC-only C++ compiler options: if(MSVC) + set(_cxx_is_msvc $) + set(_msvc_common_options /permissive- /EHsc /W4 # Enable strict warnings. ) - set(_cxx_is_msvc $) set(_msvc_compile_options /Zc:inline /Zc:strictStrings @@ -36,41 +22,62 @@ function(cml_add_test _name) /diagnostics:caret /WL /MP + /arch:AVX2 ) - set(_msvc_link_options - /NOIMPLIB - /NOEXP - ) - - target_compile_options(${ExecName} + target_compile_options(${_name} PRIVATE - ${_msvc_common_options} - $<${_cxx_is_msvc}:${_msvc_compile_options}> + ${_msvc_common_options} + $<${_cxx_is_msvc}:${_msvc_compile_options}> ) - target_compile_features(${ExecName} + target_compile_features(${_name} PRIVATE cxx_std_17 ) + endif() +endfunction() - target_link_options(${ExecName} - PRIVATE $<${_cxx_is_msvc}:${_msvc_link_options}> +# Function to add a single-file executable to the build, using ${_name}.cpp as +# the test source. +function(cml_add_executable _name) + add_executable(${_name} ${ARGN}) + cml_default_compile_options(${_name}) + + if(MSVC) + set(_cxx_is_msvc $) + + set(_msvc_link_options + /NOIMPLIB + /NOEXP ) - set_target_properties(${ExecName} PROPERTIES - FOLDER "cml-tests/${CML_TEST_GROUP}" + target_link_options(${_name} + PRIVATE $<${_cxx_is_msvc}:${_msvc_link_options}> ) + endif() - get_target_property(_path ${_name} SOURCE_DIR) - get_target_property(_sources ${_name} SOURCES) - source_group(TREE "${_path}" FILES ${_sources}) + get_target_property(_path ${_name} SOURCE_DIR) + get_target_property(_sources ${_name} SOURCES) + source_group(TREE "${_path}" FILES ${_sources}) +endfunction() + +# Function to add a single-file test to the build, using ${_name}.cpp as the +# test source. +function(cml_add_test _name) + if(DEFINED CML_TEST_GROUP) + set(TestName "CML:${CML_TEST_GROUP}:${_name}") + else() + message(FATAL_ERROR "CML_TEST_GROUP must be defined") endif() - target_link_libraries(${ExecName} cml cml_test_main) + cml_add_executable(${_name} ${_name}.cpp ${ARGN}) - # Setup the test: - add_test(NAME ${TestName} COMMAND ${ExecName}) + add_test(NAME ${TestName} COMMAND ${_name}) + set_target_properties(${_name} PROPERTIES + FOLDER "cml-tests/${CML_TEST_GROUP}" + ) + target_link_libraries(${_name} cml cml_test_main) endfunction() add_subdirectory(main) @@ -80,4 +87,8 @@ add_subdirectory(vector) add_subdirectory(matrix) add_subdirectory(quaternion) add_subdirectory(mathlib) -add_subdirectory(util) \ No newline at end of file +add_subdirectory(util) + +#if(BUILD_TIMING) +add_subdirectory(timing) +#endif() \ No newline at end of file diff --git a/tests/common/CMakeLists.txt b/tests/common/CMakeLists.txt index d820d15..699bfc7 100644 --- a/tests/common/CMakeLists.txt +++ b/tests/common/CMakeLists.txt @@ -1,11 +1,11 @@ -# *------------------------------------------------------------------------- -# @@COPYRIGHT@@ -# *------------------------------------------------------------------------- - -set(CML_TEST_GROUP "common") - -cml_add_test(rv_from_this1) -cml_add_test(type_util1) -cml_add_test(type_table1) -cml_add_test(type_map1) +# *------------------------------------------------------------------------- +# @@COPYRIGHT@@ +# *------------------------------------------------------------------------- + +set(CML_TEST_GROUP "common") + +cml_add_test(rv_from_this1) +cml_add_test(type_util1) +cml_add_test(type_table1) +cml_add_test(type_map1) cml_add_test(temporary_of1) \ No newline at end of file diff --git a/tests/common/rv_from_this1.cpp b/tests/common/rv_from_this1.cpp index a7a764a..0236a96 100644 --- a/tests/common/rv_from_this1.cpp +++ b/tests/common/rv_from_this1.cpp @@ -1,24 +1,24 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#include -#include - -/* Testing headers: */ -#include "catch_runner.h" - -struct rv_from_this -{ - rv_from_this&& mover() &&; - rv_from_this& refer() &; -}; - -CATCH_TEST_CASE("rv_from_this1") -{ - CATCH_CHECK(true - == (std::is_same::value)); - CATCH_REQUIRE(true - == (std::is_same().refer()), - rv_from_this&>::value)); -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#include +#include + +/* Testing headers: */ +#include "catch_runner.h" + +struct rv_from_this +{ + rv_from_this&& mover() &&; + rv_from_this& refer() &; +}; + +CATCH_TEST_CASE("rv_from_this1") +{ + CATCH_CHECK(true + == (std::is_same::value)); + CATCH_REQUIRE(true + == (std::is_same().refer()), + rv_from_this&>::value)); +} diff --git a/tests/common/temporary_of1.cpp b/tests/common/temporary_of1.cpp index b1298f4..59bb4c4 100644 --- a/tests/common/temporary_of1.cpp +++ b/tests/common/temporary_of1.cpp @@ -1,15 +1,15 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#include -#include - -/* Testing headers: */ -#include "catch_runner.h" - -CATCH_TEST_CASE("const_temporary1") -{ - using const_type = cml::temporary_of_t; - CATCH_CHECK(std::is_same_v); -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#include +#include + +/* Testing headers: */ +#include "catch_runner.h" + +CATCH_TEST_CASE("const_temporary1") +{ + using const_type = cml::temporary_of_t; + CATCH_CHECK(std::is_same_v); +} diff --git a/tests/common/type_map1.cpp b/tests/common/type_map1.cpp index 112f01f..87f292a 100644 --- a/tests/common/type_map1.cpp +++ b/tests/common/type_map1.cpp @@ -1,45 +1,45 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#include - -/* Testing headers: */ -#include "catch_runner.h" - -template struct table_item -{ - using first = T1; - using second = T2; -}; - -CATCH_TEST_CASE("map1") -{ - using cml::type_map; - using int_table = type_map< - /**/ table_item, table_item, table_item>; - - using Ti = int_table::find_second::type; - CATCH_CHECK(Ti::value); - CATCH_CHECK((std::is_same::value)); - - using Ti2 = int_table::find_first::type; - CATCH_CHECK(Ti2::value); - CATCH_CHECK((std::is_same::value)); - - using Tf1 = int_table::find_first::type; - CATCH_CHECK(Tf1::value); - CATCH_CHECK((std::is_same::value)); - - using Tf2 = int_table::find_second::type; - CATCH_CHECK(!Tf2::value); - CATCH_CHECK((std::is_same::value)); - - using Td1 = int_table::find_first::type; - CATCH_CHECK(Td1::value); - CATCH_CHECK((std::is_same::value)); - - using Td2 = int_table::find_second::type; - CATCH_CHECK(!Td2::value); - CATCH_CHECK((std::is_same::value)); -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#include + +/* Testing headers: */ +#include "catch_runner.h" + +template struct table_item +{ + using first = T1; + using second = T2; +}; + +CATCH_TEST_CASE("map1") +{ + using cml::type_map; + using int_table = type_map< + /**/ table_item, table_item, table_item>; + + using Ti = int_table::find_second::type; + CATCH_CHECK(Ti::value); + CATCH_CHECK((std::is_same::value)); + + using Ti2 = int_table::find_first::type; + CATCH_CHECK(Ti2::value); + CATCH_CHECK((std::is_same::value)); + + using Tf1 = int_table::find_first::type; + CATCH_CHECK(Tf1::value); + CATCH_CHECK((std::is_same::value)); + + using Tf2 = int_table::find_second::type; + CATCH_CHECK(!Tf2::value); + CATCH_CHECK((std::is_same::value)); + + using Td1 = int_table::find_first::type; + CATCH_CHECK(Td1::value); + CATCH_CHECK((std::is_same::value)); + + using Td2 = int_table::find_second::type; + CATCH_CHECK(!Td2::value); + CATCH_CHECK((std::is_same::value)); +} diff --git a/tests/common/type_table1.cpp b/tests/common/type_table1.cpp index 5b12da8..01bdb45 100644 --- a/tests/common/type_table1.cpp +++ b/tests/common/type_table1.cpp @@ -1,72 +1,72 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#include - -/* Testing headers: */ -#include "catch_runner.h" - -template struct table_item -{ - using first = T1; - using second = T2; - using type = T; -}; - -CATCH_TEST_CASE("map1") -{ - using cml::type_table; - using int_table = type_table< - /**/ table_item, table_item, - table_item>; - - using Tii = int_table::find::type; - CATCH_CHECK(Tii::value); - - using Tid = int_table::find::type; - CATCH_CHECK(Tid::value); - - using Tdi = int_table::find::type; - CATCH_CHECK(Tdi::value); - - using Tic = int_table::find::type; - CATCH_CHECK(!Tic::value); - - using Tic = int_table::find::type; - CATCH_CHECK(!Tic::value); -} - -struct map_struct -{ - template struct table_item - { - using first = T1; - using second = T2; - using type = T; - }; - - using int_table = cml::type_table< - /**/ table_item, table_item, - table_item>; -}; - -CATCH_TEST_CASE("map_struct1") -{ - using int_table = map_struct::int_table; - - using Tii = int_table::find::type; - CATCH_CHECK(Tii::value); - - using Tid = int_table::find::type; - CATCH_CHECK(Tid::value); - - using Tdi = int_table::find::type; - CATCH_CHECK(Tdi::value); - - using Tic = int_table::find::type; - CATCH_CHECK(!Tic::value); - - using Tic = int_table::find::type; - CATCH_CHECK(!Tic::value); -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#include + +/* Testing headers: */ +#include "catch_runner.h" + +template struct table_item +{ + using first = T1; + using second = T2; + using type = T; +}; + +CATCH_TEST_CASE("map1") +{ + using cml::type_table; + using int_table = type_table< + /**/ table_item, table_item, + table_item>; + + using Tii = int_table::find::type; + CATCH_CHECK(Tii::value); + + using Tid = int_table::find::type; + CATCH_CHECK(Tid::value); + + using Tdi = int_table::find::type; + CATCH_CHECK(Tdi::value); + + using Tic = int_table::find::type; + CATCH_CHECK(!Tic::value); + + using Tic = int_table::find::type; + CATCH_CHECK(!Tic::value); +} + +struct map_struct +{ + template struct table_item + { + using first = T1; + using second = T2; + using type = T; + }; + + using int_table = cml::type_table< + /**/ table_item, table_item, + table_item>; +}; + +CATCH_TEST_CASE("map_struct1") +{ + using int_table = map_struct::int_table; + + using Tii = int_table::find::type; + CATCH_CHECK(Tii::value); + + using Tid = int_table::find::type; + CATCH_CHECK(Tid::value); + + using Tdi = int_table::find::type; + CATCH_CHECK(Tdi::value); + + using Tic = int_table::find::type; + CATCH_CHECK(!Tic::value); + + using Tic = int_table::find::type; + CATCH_CHECK(!Tic::value); +} diff --git a/tests/common/type_util1.cpp b/tests/common/type_util1.cpp index e1bafe8..a471559 100644 --- a/tests/common/type_util1.cpp +++ b/tests/common/type_util1.cpp @@ -1,84 +1,84 @@ -/*------------------------------------------------------------------------- - @@COPYRIGHT@@ - *-----------------------------------------------------------------------*/ - -#include - -/* Testing headers: */ -#include "catch_runner.h" - -struct scoop1 -{ - const scoop1& actual() const; -}; - -struct scoop2 -{ - scoop2& actual() const; -}; - -struct scoop3 -{ - scoop3& actual(); -}; - -struct scoop4 -{ - const scoop4& actual(); -}; - -template struct scoop_base -{ - T& actual(); -}; - -struct scoop5 : scoop_base -{}; - -CATCH_TEST_CASE("is_statically_polymorphic1") -{ - CATCH_CHECK(!cml::is_statically_polymorphic::value); -} - -CATCH_TEST_CASE("is_statically_polymorphic2") -{ - CATCH_CHECK(cml::is_statically_polymorphic::value); - CATCH_CHECK(cml::is_statically_polymorphic::value); - CATCH_CHECK(cml::is_statically_polymorphic::value); - CATCH_CHECK(cml::is_statically_polymorphic::value); -} - -CATCH_TEST_CASE("actual_type_of1") -{ - CATCH_CHECK((std::is_same, int>::value)); - CATCH_CHECK((std::is_same, int>::value)); - CATCH_CHECK((std::is_same, int>::value)); - CATCH_CHECK((std::is_same, int>::value)); -} - -CATCH_TEST_CASE("actual_type_of2") -{ - CATCH_CHECK((std::is_same, scoop5>::value)); - CATCH_CHECK( - (std::is_same>, scoop5>::value)); -} - -CATCH_TEST_CASE("actual_operand_type_of1") -{ - CATCH_CHECK((std::is_same, int&>::value)); - CATCH_CHECK((std::is_same, - int const&>::value)); - CATCH_CHECK( - (std::is_same, int&&>::value)); -} - -CATCH_TEST_CASE("actual_operand_type_of2") -{ - CATCH_CHECK((std::is_same&>, - scoop5&>::value)); - CATCH_CHECK( - (std::is_same const&>, - scoop5 const&>::value)); - CATCH_CHECK((std::is_same&&>, - scoop5&&>::value)); -} +/*------------------------------------------------------------------------- + @@COPYRIGHT@@ + *-----------------------------------------------------------------------*/ + +#include + +/* Testing headers: */ +#include "catch_runner.h" + +struct scoop1 +{ + const scoop1& actual() const; +}; + +struct scoop2 +{ + scoop2& actual() const; +}; + +struct scoop3 +{ + scoop3& actual(); +}; + +struct scoop4 +{ + const scoop4& actual(); +}; + +template struct scoop_base +{ + T& actual(); +}; + +struct scoop5 : scoop_base +{}; + +CATCH_TEST_CASE("is_statically_polymorphic1") +{ + CATCH_CHECK(!cml::is_statically_polymorphic::value); +} + +CATCH_TEST_CASE("is_statically_polymorphic2") +{ + CATCH_CHECK(cml::is_statically_polymorphic::value); + CATCH_CHECK(cml::is_statically_polymorphic::value); + CATCH_CHECK(cml::is_statically_polymorphic::value); + CATCH_CHECK(cml::is_statically_polymorphic::value); +} + +CATCH_TEST_CASE("actual_type_of1") +{ + CATCH_CHECK((std::is_same, int>::value)); + CATCH_CHECK((std::is_same, int>::value)); + CATCH_CHECK((std::is_same, int>::value)); + CATCH_CHECK((std::is_same, int>::value)); +} + +CATCH_TEST_CASE("actual_type_of2") +{ + CATCH_CHECK((std::is_same, scoop5>::value)); + CATCH_CHECK( + (std::is_same>, scoop5>::value)); +} + +CATCH_TEST_CASE("actual_operand_type_of1") +{ + CATCH_CHECK((std::is_same, int&>::value)); + CATCH_CHECK((std::is_same, + int const&>::value)); + CATCH_CHECK( + (std::is_same, int&&>::value)); +} + +CATCH_TEST_CASE("actual_operand_type_of2") +{ + CATCH_CHECK((std::is_same&>, + scoop5&>::value)); + CATCH_CHECK( + (std::is_same const&>, + scoop5 const&>::value)); + CATCH_CHECK((std::is_same&&>, + scoop5&&>::value)); +} diff --git a/tests/main/CMakeLists.txt b/tests/main/CMakeLists.txt index 91db1a7..ddff8e8 100644 --- a/tests/main/CMakeLists.txt +++ b/tests/main/CMakeLists.txt @@ -1,35 +1,35 @@ -# -------------------------------------------------------------------------- -# @@COPYRIGHT@@ -# -------------------------------------------------------------------------- - -# Allow finding Catch2 locally first: -find_package(Catch2 3.7.1 CONFIG QUIET) - -# If not found or already pulled, pull Catch2 at v3.7.1 -if(NOT Catch2_FOUND) - include(FetchContent) - - FetchContent_Declare( - Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.7.1 - ) - - FetchContent_MakeAvailable(Catch2) -endif() - -add_library(cml_test_main INTERFACE catch_runner.h) -target_include_directories(cml_test_main - INTERFACE ${CMAKE_CURRENT_LIST_DIR} ${CML_ROOT} -) -target_link_libraries(cml_test_main - INTERFACE Catch2::Catch2WithMain -) - -set_target_properties(cml_test_main - PROPERTIES FOLDER "cml-tests/main" -) - -get_target_property(_path cml_test_main SOURCE_DIR) -get_target_property(_sources cml_test_main SOURCES) +# -------------------------------------------------------------------------- +# @@COPYRIGHT@@ +# -------------------------------------------------------------------------- + +# Allow finding Catch2 locally first: +find_package(Catch2 3.7.1 CONFIG QUIET) + +# If not found or already pulled, pull Catch2 at v3.7.1 +if(NOT Catch2_FOUND) + include(FetchContent) + + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.7.1 + ) + + FetchContent_MakeAvailable(Catch2) +endif() + +add_library(cml_test_main INTERFACE catch_runner.h) +target_include_directories(cml_test_main + INTERFACE ${CMAKE_CURRENT_LIST_DIR} ${CML_ROOT} +) +target_link_libraries(cml_test_main + INTERFACE Catch2::Catch2WithMain +) + +set_target_properties(cml_test_main + PROPERTIES FOLDER "cml-tests/main" +) + +get_target_property(_path cml_test_main SOURCE_DIR) +get_target_property(_sources cml_test_main SOURCES) source_group(TREE "${_path}" FILES ${_sources}) \ No newline at end of file diff --git a/tests/main/catch.hpp b/tests/main/catch.hpp index 08a0a02..018fde5 100644 --- a/tests/main/catch.hpp +++ b/tests/main/catch.hpp @@ -1,17851 +1,17851 @@ -/* - * Catch v2.13.4 - * Generated: 2020-12-29 14:48:00.116107 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -// start catch.hpp - - -#define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 13 -#define CATCH_VERSION_PATCH 4 - -#ifdef __clang__ -# pragma clang system_header -#elif defined __GNUC__ -# pragma GCC system_header -#endif - -// start catch_suppress_warnings.h - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" -# endif -#elif defined __GNUC__ - // Because REQUIREs trigger GCC's -Wparentheses, and because still - // supported version of g++ have only buggy support for _Pragmas, - // Wparentheses have to be suppressed globally. -# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details - -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wpadded" -#endif -// end catch_suppress_warnings.h -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -# define CATCH_CONFIG_ALL_PARTS -#endif - -// In the impl file, we want to have access to all parts of the headers -// Can also be used to sanely support PCHs -#if defined(CATCH_CONFIG_ALL_PARTS) -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif -# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -# endif -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) -// start catch_platform.h - -#ifdef __APPLE__ -# include -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS -#endif - -// end catch_platform.h - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// start catch_user_interfaces.h - -namespace Catch { - unsigned int rngSeed(); -} - -// end catch_user_interfaces.h -// start catch_tag_alias_autoregistrar.h - -// start catch_common.h - -// start catch_compiler_capabilities.h - -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -#ifdef __cplusplus - -# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -# define CATCH_CPP14_OR_GREATER -# endif - -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif - -#endif - -// We have to avoid both ICC and Clang, because they try to mask themselves -// as gcc, and we want only GCC in this block -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) - -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) - -#endif - -#if defined(__clang__) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) - -// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug -// which results in calls to destructors being emitted for each temporary, -// without a matching initialization. In practice, this can result in something -// like `std::string::~string` being called on an uninitialized value. -// -// For example, this code will likely segfault under IBM XL: -// ``` -// REQUIRE(std::string("12") + "34" == "1234") -// ``` -// -// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. -# if !defined(__ibmxl__) && !defined(__CUDACC__) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ -# endif - -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) - -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Assume that non-Windows platforms support posix signals by default -#if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif - -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif - -#ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# define CATCH_CONFIG_COLOUR_NONE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Android somehow still does not support std::to_string -#if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Not all Windows environments support SEH properly -#if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH -#endif - -//////////////////////////////////////////////////////////////////////////////// -// PS4 -#if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ - -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE -// some versions of cygwin (most) do not support std::to_string. Use the libstd check. -// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 -# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ - && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) - -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING - -# endif -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#if defined(_MSC_VER) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) - -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif - -// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ -// _MSVC_TRADITIONAL == 0 means new conformant preprocessor -// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif // MSVC_TRADITIONAL -# endif // __clang__ - -#endif // _MSC_VER - -#if defined(_REENTRANT) || defined(_MSC_VER) -// Enable async processing, as -pthread is specified or no additional linking is required -# define CATCH_INTERNAL_CONFIG_USE_ASYNC -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// -// Check if we are compiled with -fno-exceptions or equivalent -#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED -#endif - -//////////////////////////////////////////////////////////////////////////////// -// DJGPP -#ifdef __DJGPP__ -# define CATCH_INTERNAL_CONFIG_NO_WCHAR -#endif // __DJGPP__ - -//////////////////////////////////////////////////////////////////////////////// -// Embarcadero C++Build -#if defined(__BORLANDC__) - #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// Use of __COUNTER__ is suppressed during code analysis in -// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly -// handled by it. -// Otherwise all supported compilers support COUNTER macro, -// but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// RTX is a special version of Windows that is real time. -// This means that it is detected as Windows, but does not provide -// the same set of capabilities as real Windows does. -#if defined(UNDER_RTSS) || defined(RTX64_BUILD) - #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH - #define CATCH_INTERNAL_CONFIG_NO_ASYNC - #define CATCH_CONFIG_COLOUR_NONE -#endif - -#if !defined(_GLIBCXX_USE_C99_MATH_TR1) -#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Various stdlib support checks that require __has_include -#if defined(__has_include) - // Check if string_view is available and usable - #if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW - #endif - - // Check if optional is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if byte is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # include - # if __cpp_lib_byte > 0 - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE - # endif - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if variant is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 - # include - # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # define CATCH_CONFIG_NO_CPP17_VARIANT - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__clang__) && (__clang_major__ < 8) - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // defined(__has_include) - -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER -#endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif -// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. -#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) -# define CATCH_CONFIG_WCHAR -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) -# define CATCH_CONFIG_CPP17_OPTIONAL -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) -# define CATCH_CONFIG_CPP17_STRING_VIEW -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) -# define CATCH_CONFIG_CPP17_VARIANT -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) -# define CATCH_CONFIG_CPP17_BYTE -#endif - -#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) -# define CATCH_CONFIG_POLYFILL_ISNAN -#endif - -#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) -# define CATCH_CONFIG_USE_ASYNC -#endif - -#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) -# define CATCH_CONFIG_ANDROID_LOGWRITE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) -# define CATCH_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Even if we do not think the compiler has that warning, we still have -// to provide a macro that can be used by the code. -#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -#endif - -// The goal of this macro is to avoid evaluation of the arguments, but -// still have the compiler warn on problems inside... -#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) -#endif - -#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#elif defined(__clang__) && (__clang_major__ < 5) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -#define CATCH_TRY if ((true)) -#define CATCH_CATCH_ALL if ((false)) -#define CATCH_CATCH_ANON(type) if ((false)) -#else -#define CATCH_TRY try -#define CATCH_CATCH_ALL catch (...) -#define CATCH_CATCH_ANON(type) catch (type) -#endif - -#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) -#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#endif - -// end catch_compiler_capabilities.h -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#include -#include -#include - -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy {}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - -namespace Catch { - - struct CaseSensitive { enum Choice { - Yes, - No - }; }; - - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; - - protected: - NonCopyable(); - virtual ~NonCopyable(); - }; - - struct SourceLineInfo { - - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo( SourceLineInfo&& ) noexcept = default; - SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - - bool empty() const noexcept { return file[0] == '\0'; } - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // Bring in operator<< from global namespace into Catch namespace - // This is necessary because the overload of operator<< above makes - // lookup stop at namespace Catch - using ::operator<<; - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -// end catch_common.h -namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - -// end catch_tag_alias_autoregistrar.h -// start catch_test_registry.h - -// start catch_interfaces_testcase.h - -#include - -namespace Catch { - - class TestSpec; - - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool isThrowSafe( TestCase const& testCase, IConfig const& config ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -// end catch_interfaces_testcase.h -// start catch_stringref.h - -#include -#include -#include -#include - -namespace Catch { - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. - class StringRef { - public: - using size_type = std::size_t; - using const_iterator = const char*; - - private: - static constexpr auto s_empty = ""; - - char const* m_start = s_empty; - size_type m_size = 0; - - public: // construction - constexpr StringRef() noexcept = default; - - StringRef( char const* rawChars ) noexcept; - - constexpr StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - explicit operator std::string() const { - return std::string(m_start, m_size); - } - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != (StringRef const& other) const noexcept -> bool { - return !(*this == other); - } - - auto operator[] ( size_type index ) const noexcept -> char { - assert(index < m_size); - return m_start[index]; - } - - public: // named queries - constexpr auto empty() const noexcept -> bool { - return m_size == 0; - } - constexpr auto size() const noexcept -> size_type { - return m_size; - } - - // Returns the current start pointer. If the StringRef is not - // null-terminated, throws std::domain_exception - auto c_str() const -> char const*; - - public: // substrings and searches - // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, size()). - // If start > size(), then the substring is empty. - auto substr( size_type start, size_type length ) const noexcept -> StringRef; - - // Returns the current start pointer. May not be null-terminated. - auto data() const noexcept -> char const*; - - constexpr auto isNullTerminated() const noexcept -> bool { - return m_start[m_size] == '\0'; - } - - public: // iterators - constexpr const_iterator begin() const { return m_start; } - constexpr const_iterator end() const { return m_start + m_size; } - }; - - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - - constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } -} // namespace Catch - -constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -// end catch_stringref.h -// start catch_preprocessor.hpp - - -#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ -#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) - -#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ -// MSVC needs more evaluations -#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) -#else -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) -#endif - -#define CATCH_REC_END(...) -#define CATCH_REC_OUT - -#define CATCH_EMPTY() -#define CATCH_DEFER(id) id CATCH_EMPTY() - -#define CATCH_REC_GET_END2() 0, CATCH_REC_END -#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 -#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 -#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT -#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) -#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) - -#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) - -#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) - -// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, -// and passes userdata as the first parameter to each invocation, -// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) -#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) -#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ -#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ -#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) -#else -// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) -#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) -#endif - -#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ -#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) - -#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) - -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) -#else -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) -#endif - -#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ - CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) - -#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) -#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) -#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) -#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) -#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) -#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) -#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) -#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) -#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) -#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) - -#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N - -#define INTERNAL_CATCH_TYPE_GEN\ - template struct TypeList {};\ - template\ - constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ - template class...> struct TemplateTypeList{};\ - template class...Cs>\ - constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ - template\ - struct append;\ - template\ - struct rewrap;\ - template class, typename...>\ - struct create;\ - template class, typename>\ - struct convert;\ - \ - template \ - struct append { using type = T; };\ - template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ - template< template class L1, typename...E1, typename...Rest>\ - struct append, TypeList, Rest...> { using type = L1; };\ - \ - template< template class Container, template class List, typename...elems>\ - struct rewrap, List> { using type = TypeList>; };\ - template< template class Container, template class List, class...Elems, typename...Elements>\ - struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ - \ - template