blob: e49788491691a6525b4eda6b621f53230cbc59c5 [file]
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2026 Pavel Guzenfeld
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#if EIGEN_MAX_CPP_VER >= 17 && EIGEN_COMP_CXXVER >= 17
template <typename Scalar>
void check_vector_bindings() {
// Vector2
{
Matrix<Scalar, 2, 1> v;
v << Scalar(1), Scalar(2);
auto [x, y] = v;
VERIFY_IS_EQUAL(x, Scalar(1));
VERIFY_IS_EQUAL(y, Scalar(2));
}
// Vector3
{
Matrix<Scalar, 3, 1> v;
v << Scalar(3), Scalar(4), Scalar(5);
auto [x, y, z] = v;
VERIFY_IS_EQUAL(x, Scalar(3));
VERIFY_IS_EQUAL(y, Scalar(4));
VERIFY_IS_EQUAL(z, Scalar(5));
}
// Vector4
{
Matrix<Scalar, 4, 1> v;
v << Scalar(6), Scalar(7), Scalar(8), Scalar(9);
auto [a, b, c, d] = v;
VERIFY_IS_EQUAL(a, Scalar(6));
VERIFY_IS_EQUAL(b, Scalar(7));
VERIFY_IS_EQUAL(c, Scalar(8));
VERIFY_IS_EQUAL(d, Scalar(9));
}
// 1x1 matrix (scalar-like)
{
Matrix<Scalar, 1, 1> s;
s << Scalar(42);
auto [val] = s;
VERIFY_IS_EQUAL(val, Scalar(42));
}
// RowVector
{
Matrix<Scalar, 1, 3> rv;
rv << Scalar(10), Scalar(20), Scalar(30);
auto [a, b, c] = rv;
VERIFY_IS_EQUAL(a, Scalar(10));
VERIFY_IS_EQUAL(b, Scalar(20));
VERIFY_IS_EQUAL(c, Scalar(30));
}
}
template <typename Scalar>
void check_array_bindings() {
// Array3
{
Array<Scalar, 3, 1> a;
a << Scalar(100), Scalar(200), Scalar(300);
auto [x, y, z] = a;
VERIFY_IS_EQUAL(x, Scalar(100));
VERIFY_IS_EQUAL(y, Scalar(200));
VERIFY_IS_EQUAL(z, Scalar(300));
}
// Array2
{
Array<Scalar, 2, 1> a;
a << Scalar(10), Scalar(20);
auto [x, y] = a;
VERIFY_IS_EQUAL(x, Scalar(10));
VERIFY_IS_EQUAL(y, Scalar(20));
}
}
template <typename Scalar>
void check_reference_bindings() {
// Mutable reference binding
{
Matrix<Scalar, 3, 1> v;
v << Scalar(1), Scalar(2), Scalar(3);
auto& [x, y, z] = v;
x = Scalar(10);
y = Scalar(20);
z = Scalar(30);
VERIFY_IS_EQUAL(v(0), Scalar(10));
VERIFY_IS_EQUAL(v(1), Scalar(20));
VERIFY_IS_EQUAL(v(2), Scalar(30));
}
// Const reference binding
{
const Matrix<Scalar, 3, 1> v(Scalar(4), Scalar(5), Scalar(6));
const auto& [x, y, z] = v;
VERIFY_IS_EQUAL(x, Scalar(4));
VERIFY_IS_EQUAL(y, Scalar(5));
VERIFY_IS_EQUAL(z, Scalar(6));
}
// Array mutable reference binding
{
Array<Scalar, 2, 1> a;
a << Scalar(7), Scalar(8);
auto& [x, y] = a;
x = Scalar(70);
VERIFY_IS_EQUAL(a(0), Scalar(70));
VERIFY_IS_EQUAL(a(1), Scalar(8));
}
}
template <typename Scalar>
void check_matrix_bindings() {
// 2x2 matrix (column-major order)
{
Matrix<Scalar, 2, 2> m;
m << Scalar(1), Scalar(2), Scalar(3), Scalar(4);
auto [m00, m10, m01, m11] = m;
// Column-major: (0,0), (1,0), (0,1), (1,1)
VERIFY_IS_EQUAL(m00, Scalar(1));
VERIFY_IS_EQUAL(m10, Scalar(3));
VERIFY_IS_EQUAL(m01, Scalar(2));
VERIFY_IS_EQUAL(m11, Scalar(4));
}
}
template <typename Scalar>
void check_storage_order_semantics() {
// Row vectors are forced to RowMajor by Eigen (a 1xN can't meaningfully be
// column-major). Ensure decomposition still matches the single-row layout.
{
Matrix<Scalar, 1, 3> rv;
rv << Scalar(1), Scalar(2), Scalar(3);
auto [a, b, c] = rv;
VERIFY_IS_EQUAL(a, Scalar(1));
VERIFY_IS_EQUAL(b, Scalar(2));
VERIFY_IS_EQUAL(c, Scalar(3));
}
// Nx1 column vectors are ColMajor regardless and decompose top-to-bottom.
{
Matrix<Scalar, 3, 1> cv;
cv << Scalar(4), Scalar(5), Scalar(6);
auto [a, b, c] = cv;
VERIFY_IS_EQUAL(a, Scalar(4));
VERIFY_IS_EQUAL(b, Scalar(5));
VERIFY_IS_EQUAL(c, Scalar(6));
}
// 2D ColMajor matrix decomposes in column-major order: (0,0),(1,0),(0,1),(1,1).
// 2D RowMajor is rejected via static_assert — see failtest/structured_bindings_rowmajor.cpp.
{
Matrix<Scalar, 2, 2, ColMajor> m;
m << Scalar(1), Scalar(2), Scalar(3), Scalar(4);
auto [m00, m10, m01, m11] = m;
VERIFY_IS_EQUAL(m00, Scalar(1));
VERIFY_IS_EQUAL(m10, Scalar(3));
VERIFY_IS_EQUAL(m01, Scalar(2));
VERIFY_IS_EQUAL(m11, Scalar(4));
}
}
void check_tuple_size() {
STATIC_CHECK((std::tuple_size<Vector2d>::value == 2));
STATIC_CHECK((std::tuple_size<Vector3f>::value == 3));
STATIC_CHECK((std::tuple_size<Vector4i>::value == 4));
STATIC_CHECK((std::tuple_size<Matrix2d>::value == 4));
STATIC_CHECK((std::tuple_size<Matrix3f>::value == 9));
STATIC_CHECK((std::tuple_size<Array3i>::value == 3));
STATIC_CHECK((std::tuple_size<Array<double, 2, 1>>::value == 2));
STATIC_CHECK((std::tuple_size<Matrix<float, 1, 1>>::value == 1));
STATIC_CHECK((std::tuple_size<RowVector3d>::value == 3));
}
void check_tuple_element() {
STATIC_CHECK((std::is_same<std::tuple_element_t<0, Vector3d>, double>::value));
STATIC_CHECK((std::is_same<std::tuple_element_t<1, Vector3f>, float>::value));
STATIC_CHECK((std::is_same<std::tuple_element_t<2, Vector4i>, int>::value));
STATIC_CHECK((std::is_same<std::tuple_element_t<0, Array3i>, int>::value));
}
EIGEN_DECLARE_TEST(structured_bindings) {
CALL_SUBTEST_1(check_vector_bindings<double>());
CALL_SUBTEST_1(check_vector_bindings<float>());
CALL_SUBTEST_1(check_vector_bindings<int>());
CALL_SUBTEST_2(check_array_bindings<double>());
CALL_SUBTEST_2(check_array_bindings<int>());
CALL_SUBTEST_3(check_reference_bindings<double>());
CALL_SUBTEST_3(check_reference_bindings<float>());
CALL_SUBTEST_4(check_matrix_bindings<double>());
CALL_SUBTEST_4(check_matrix_bindings<int>());
CALL_SUBTEST_5(check_tuple_size());
CALL_SUBTEST_5(check_tuple_element());
CALL_SUBTEST_6(check_storage_order_semantics<double>());
CALL_SUBTEST_6(check_storage_order_semantics<int>());
}
#else
EIGEN_DECLARE_TEST(structured_bindings) {
// Structured bindings require C++17.
VERIFY(true);
}
#endif