Fixing github C.I.

This commit is contained in:
Christophe
2025-09-30 17:36:08 +02:00
committed by Christophe
parent e771488592
commit c10f4f2352
7 changed files with 137 additions and 120 deletions

View File

@@ -14,25 +14,25 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [windows-latest, windows-2019]
os: [windows-latest, windows-2022]
toolkit: [v143, v142, v141, v140]
std: [98, 11, 14, 17, 20]
config: [Debug, Release]
exclude:
- os: windows-2019
- os: windows-2022
toolkit: v143
- os: windows-2019
- os: windows-2022
toolkit: v142
- os: windows-latest
toolkit: v140
- os: windows-latest
toolkit: v141
- os: windows-2019
- os: windows-2022
std: 20
- os: windows-2019
- os: windows-2022
toolkit: v140
std: 17
- os: windows-2019
- os: windows-2022
toolkit: v140
std: 14
@@ -49,7 +49,10 @@ jobs:
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
- name: CMake Version
run: cmake --version
uses: lukka/get-cmake@latest
with:
cmakeVersion: 3.22.1
- run: cmake --version
- name: Run with automagic detection
run: |
@@ -110,11 +113,11 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-20.04]
os: [ubuntu-latest, ubuntu-22.04]
std: [98, 11, 14, 17, 20]
config: [Debug, Release]
exclude:
- os: ubuntu-20.04
- os: ubuntu-22.04
std: 20
- os: ubuntu-latest
std: 98
@@ -132,7 +135,10 @@ jobs:
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
- name: CMake Version
run: cmake --version
uses: lukka/get-cmake@latest
with:
cmakeVersion: 3.22.1
- run: cmake --version
- name: Run with automagic detection
run: |
cmake -S. -B ./build_auto -DGLM_BUILD_TESTS=ON
@@ -205,7 +211,10 @@ jobs:
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
- name: CMake Version
run: cmake --version
uses: lukka/get-cmake@latest
with:
cmakeVersion: 3.22.1
- run: cmake --version
- name: Run with automagic detection
run: |
cmake -S. -B ./build_auto -DGLM_BUILD_TESTS=ON
@@ -267,7 +276,10 @@ jobs:
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
- name: CMake Version
run: cmake --version
uses: lukka/get-cmake@latest
with:
cmakeVersion: 3.22.1
- run: cmake --version
- name: Run with automagic detection
run: |
cmake -S. -B ./build_auto -DGLM_BUILD_TESTS=ON

View File

@@ -42,6 +42,7 @@ if(GLM_ENABLE_CXX_20)
message(STATUS "GLM: Disable -Wc++98-compat warnings")
add_compile_options(-Wno-c++98-compat)
add_compile_options(-Wno-c++98-compat-pedantic)
add_compile_options(-Wno-switch-default)
endif()
if(NOT GLM_QUIET)
message(STATUS "GLM: Build with C++20 features")
@@ -54,6 +55,7 @@ elseif(GLM_ENABLE_CXX_17)
message(STATUS "GLM: Disable -Wc++98-compat warnings")
add_compile_options(-Wno-c++98-compat)
add_compile_options(-Wno-c++98-compat-pedantic)
add_compile_options(-Wno-switch-default)
endif()
if(NOT GLM_QUIET)
message(STATUS "GLM: Build with C++17 features")
@@ -66,6 +68,7 @@ elseif(GLM_ENABLE_CXX_14)
message(STATUS "GLM: Disable -Wc++98-compat warnings")
add_compile_options(-Wno-c++98-compat)
add_compile_options(-Wno-c++98-compat-pedantic)
add_compile_options(-Wno-switch-default)
endif()
if(NOT GLM_QUIET)
message(STATUS "GLM: Build with C++14 features")
@@ -78,6 +81,7 @@ elseif(GLM_ENABLE_CXX_11)
message(STATUS "GLM: Disable -Wc++98-compat warnings")
add_compile_options(-Wno-c++98-compat)
add_compile_options(-Wno-c++98-compat-pedantic)
add_compile_options(-Wno-switch-default)
endif()
if(NOT GLM_QUIET)
message(STATUS "GLM: Build with C++11 features")
@@ -86,6 +90,9 @@ elseif(GLM_ENABLE_CXX_11)
elseif(GLM_ENABLE_CXX_98)
set(CMAKE_CXX_STANDARD 98)
add_definitions(-DGLM_FORCE_CXX98)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wno-switch-default)
endif()
if(NOT GLM_QUIET)
message(STATUS "GLM: Build with C++98 features")
endif()
@@ -95,6 +102,7 @@ else()
message(STATUS "GLM: Disable -Wc++98-compat warnings")
add_compile_options(-Wno-c++98-compat)
add_compile_options(-Wno-c++98-compat-pedantic)
add_compile_options(-Wno-switch-default)
endif()
if(NOT GLM_QUIET)
message(STATUS "GLM: Build with C++ features auto detection")

View File

@@ -545,71 +545,71 @@ namespace detail
#if GLM_ARCH & GLM_ARCH_NEON_BIT
namespace glm {
namespace detail {
template<qualifier Q>
struct convert_vec3_to_vec4W0<float, Q, true>
namespace detail {
template<qualifier Q>
struct convert_vec3_to_vec4W0<float, Q, true>
{
GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<3, float, Q> const& a)
{
GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<3, float, Q> const& a)
{
vec<4, float, Q> v;
static const uint32x4_t mask = { 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
v.data = vbslq_f32(mask, a.data, vdupq_n_f32(0));
return v;
}
};
template<qualifier Q>
struct convert_vec4_to_vec3<float, Q, true> {
GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<4, float, Q> const& a)
{
vec<3, float, Q> v;
v.data = a.data;
return v;
}
};
template<length_t L, qualifier Q>
struct compute_splat<L, float, Q, true> {
template<int c>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, float, Q> call(vec<L, float, Q> const& a)
{
(void)a;
}
template<>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, float, Q> call<0>(vec<L, float, Q> const& a)
{
vec<L, float, Q> Result;
Result.data = vdupq_lane_f32(vget_low_f32(a.data), 0);
return Result;
}
template<>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, float, Q> call<1>(vec<L, float, Q> const& a)
{
vec<L, float, Q> Result;
Result.data = vdupq_lane_f32(vget_low_f32(a.data), 1);
return Result;
}
template<>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, float, Q> call<2>(vec<L, float, Q> const& a)
{
vec<L, float, Q> Result;
Result.data = vdupq_lane_f32(vget_high_f32(a.data), 0);
return Result;
}
template<>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, float, Q> call<3>(vec<L, float, Q> const& a)
{
vec<L, float, Q> Result;
Result.data = vdupq_lane_f32(vget_high_f32(a.data), 1);
return Result;
}
vec<4, float, Q> v;
static const uint32x4_t mask = { 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
v.data = vbslq_f32(mask, a.data, vdupq_n_f32(0));
return v;
}
};
template<qualifier Q>
struct convert_vec4_to_vec3<float, Q, true> {
GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<4, float, Q> const& a)
{
vec<3, float, Q> v;
v.data = a.data;
return v;
}
};
/* compute_splat is never called?
template<length_t L, qualifier Q>
struct compute_splat<L, float, Q, true> {
template<int c>
GLM_FUNC_QUALIFIER static vec<L, float, Q> call(vec<L, float, Q> const& a)
{
(void)a;
}
template<>
GLM_FUNC_QUALIFIER static vec<L, float, Q> call<0>(vec<L, float, Q> const& a)
{
vec<L, float, Q> Result;
Result.data = vdupq_lane_f32(vget_low_f32(a.data), 0);
return Result;
}
template<>
GLM_FUNC_QUALIFIER static vec<L, float, Q> call<1>(vec<L, float, Q> const& a)
{
vec<L, float, Q> Result;
Result.data = vdupq_lane_f32(vget_low_f32(a.data), 1);
return Result;
}
template<>
GLM_FUNC_QUALIFIER static vec<L, float, Q> call<2>(vec<L, float, Q> const& a)
{
vec<L, float, Q> Result;
Result.data = vdupq_lane_f32(vget_high_f32(a.data), 0);
return Result;
}
template<>
GLM_FUNC_QUALIFIER static vec<L, float, Q> call<3>(vec<L, float, Q> const& a)
{
vec<L, float, Q> Result;
Result.data = vdupq_lane_f32(vget_high_f32(a.data), 1);
return Result;
}
};
*/
}//namespace detail
}//namespace glm
#endif //GLM_ARCH & GLM_ARCH_NEON_BIT

View File

@@ -394,6 +394,7 @@ namespace detail
switch(fmt.order)
{
default:
case io::column_major:
{
for(length_t i(0); i < rows; ++i)

View File

@@ -10,6 +10,7 @@ namespace glm {
namespace neon {
static inline float32x4_t dupq_lane(float32x4_t vsrc, int lane) {
switch(lane) {
default: assert(false); //Unreachable code executed!
#if GLM_ARCH & GLM_ARCH_ARMV8_BIT
case 0: return vdupq_laneq_f32(vsrc, 0);
case 1: return vdupq_laneq_f32(vsrc, 1);
@@ -22,12 +23,12 @@ namespace glm {
case 3: return vdupq_n_f32(vgetq_lane_f32(vsrc, 3));
#endif
}
assert(false); //Unreachable code executed!
return vdupq_n_f32(0.0f);
}
static inline float32x2_t dup_lane(float32x4_t vsrc, int lane) {
switch(lane) {
default: assert(false); //Unreachable code executed!
#if GLM_ARCH & GLM_ARCH_ARMV8_BIT
case 0: return vdup_laneq_f32(vsrc, 0);
case 1: return vdup_laneq_f32(vsrc, 1);
@@ -40,84 +41,80 @@ namespace glm {
case 3: return vdup_n_f32(vgetq_lane_f32(vsrc, 3));
#endif
}
assert(false); //Unreachable code executed!
return vdup_n_f32(0.0f);
}
static inline float32x4_t copy_lane(float32x4_t vdst, int dlane, float32x4_t vsrc, int slane) {
#if GLM_ARCH & GLM_ARCH_ARMV8_BIT
switch(dlane) {
default:
case 0:
switch(slane) {
default: assert(false); //Unreachable code executed!
case 0: return vcopyq_laneq_f32(vdst, 0, vsrc, 0);
case 1: return vcopyq_laneq_f32(vdst, 0, vsrc, 1);
case 2: return vcopyq_laneq_f32(vdst, 0, vsrc, 2);
case 3: return vcopyq_laneq_f32(vdst, 0, vsrc, 3);
}
assert(false); //Unreachable code executed!
break;
case 1:
switch(slane) {
default: assert(false); //Unreachable code executed!
case 0: return vcopyq_laneq_f32(vdst, 1, vsrc, 0);
case 1: return vcopyq_laneq_f32(vdst, 1, vsrc, 1);
case 2: return vcopyq_laneq_f32(vdst, 1, vsrc, 2);
case 3: return vcopyq_laneq_f32(vdst, 1, vsrc, 3);
}
assert(false); //Unreachable code executed!
break;
case 2:
switch(slane) {
default: assert(false); //Unreachable code executed!
case 0: return vcopyq_laneq_f32(vdst, 2, vsrc, 0);
case 1: return vcopyq_laneq_f32(vdst, 2, vsrc, 1);
case 2: return vcopyq_laneq_f32(vdst, 2, vsrc, 2);
case 3: return vcopyq_laneq_f32(vdst, 2, vsrc, 3);
}
assert(false); //Unreachable code executed!
break;
case 3:
switch(slane) {
default: assert(false); //Unreachable code executed!
case 0: return vcopyq_laneq_f32(vdst, 3, vsrc, 0);
case 1: return vcopyq_laneq_f32(vdst, 3, vsrc, 1);
case 2: return vcopyq_laneq_f32(vdst, 3, vsrc, 2);
case 3: return vcopyq_laneq_f32(vdst, 3, vsrc, 3);
}
assert(false); //Unreachable code executed!
break;
}
#else
float l;
switch(slane) {
default: assert(false); //Unreachable code executed!
case 0: l = vgetq_lane_f32(vsrc, 0); break;
case 1: l = vgetq_lane_f32(vsrc, 1); break;
case 2: l = vgetq_lane_f32(vsrc, 2); break;
case 3: l = vgetq_lane_f32(vsrc, 3); break;
default:
assert(false); //Unreachable code executed!
}
switch(dlane) {
default: assert(false); //Unreachable code executed!
case 0: return vsetq_lane_f32(l, vdst, 0);
case 1: return vsetq_lane_f32(l, vdst, 1);
case 2: return vsetq_lane_f32(l, vdst, 2);
case 3: return vsetq_lane_f32(l, vdst, 3);
}
#endif
assert(false); //Unreachable code executed!
return vdupq_n_f32(0.0f);
}
static inline float32x4_t mul_lane(float32x4_t v, float32x4_t vlane, int lane) {
#if GLM_ARCH & GLM_ARCH_ARMV8_BIT
switch(lane) {
switch(lane) {
default: assert(false); return vdupq_n_f32(0.0f); //Unreachable code executed!
case 0: return vmulq_laneq_f32(v, vlane, 0); break;
case 1: return vmulq_laneq_f32(v, vlane, 1); break;
case 2: return vmulq_laneq_f32(v, vlane, 2); break;
case 3: return vmulq_laneq_f32(v, vlane, 3); break;
default:
assert(false); //Unreachable code executed!
}
assert(false); //Unreachable code executed!
return vdupq_n_f32(0.0f);
#else
return vmulq_f32(v, dupq_lane(vlane, lane));
#endif
@@ -147,7 +144,6 @@ namespace glm {
default:
assert(false); //Unreachable code executed!
}
assert(false); //Unreachable code executed!
return vdupq_n_f32(0.0f);
# undef FMADD_LANE
#else

View File

@@ -33,7 +33,7 @@ static int test_log2()
Error += glm::abs(double(A) - B) <= 24 ? 0 : 1;
assert(!Error);
std::printf("Log2(%d) error A=%d, B=%d\n", 1 << i, A, B);
std::printf("Log2(%d) error A=%u, B=%u\n", 1 << i, A, B);
}
std::printf("log2 error=%d\n", Error);

View File

@@ -51,7 +51,7 @@ namespace
else if (typeid(T) == typeid(glm::mat<4, 4, U,P>)) { ostr << "mat4x4"; }
else { ostr << "unknown"; }
ostr << '<' << typeid(U).name() << ',' << P << '>';
ostr << "<" << typeid(U).name() << "," << P << ">";
return ostr.str();
}
@@ -60,7 +60,7 @@ namespace
template<typename T, glm::qualifier P, typename OS>
static int test_io_quat(OS& os)
{
os << '\n' << typeid(OS).name() << '\n';
os << "\n" << typeid(OS).name() << "\n";
glm::qua<T, P> const q(1, 0, 0, 0);
@@ -68,14 +68,14 @@ static int test_io_quat(OS& os)
glm::io::basic_format_saver<typename OS::char_type> const iofs(os);
os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2)
<< type_name<T, P>(os, q) << ": " << q << '\n';
<< type_name<T, P>(os, q) << ": " << q << "\n";
}
{
glm::io::basic_format_saver<typename OS::char_type> const iofs(os);
os << glm::io::unformatted
<< type_name<T, P>(os, q) << ": " << q << '\n';
<< type_name<T, P>(os, q) << ": " << q << "\n";
}
return 0;
@@ -84,22 +84,22 @@ static int test_io_quat(OS& os)
template<typename T, glm::qualifier P, typename OS>
static int test_io_vec(OS& os)
{
os << '\n' << typeid(OS).name() << '\n';
os << "\n" << typeid(OS).name() << "\n";
glm::vec<2, T,P> const v2(0, 1);
glm::vec<3, T,P> const v3(2, 3, 4);
glm::vec<4, T,P> const v4(5, 6, 7, 8);
os << type_name<T,P>(os, v2) << ": " << v2 << '\n'
<< type_name<T,P>(os, v3) << ": " << v3 << '\n'
<< type_name<T,P>(os, v4) << ": " << v4 << '\n';
os << type_name<T,P>(os, v2) << ": " << v2 << "\n"
<< type_name<T,P>(os, v3) << ": " << v3 << "\n"
<< type_name<T,P>(os, v4) << ": " << v4 << "\n";
glm::io::basic_format_saver<typename OS::char_type> const iofs(os);
os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2)
<< type_name<T,P>(os, v2) << ": " << v2 << '\n'
<< type_name<T,P>(os, v3) << ": " << v3 << '\n'
<< type_name<T,P>(os, v4) << ": " << v4 << '\n';
<< type_name<T,P>(os, v2) << ": " << v2 << "\n"
<< type_name<T,P>(os, v3) << ": " << v3 << "\n"
<< type_name<T,P>(os, v4) << ": " << v4 << "\n";
return 0;
}
@@ -107,7 +107,7 @@ static int test_io_vec(OS& os)
template<typename T, glm::qualifier P, typename OS>
static int test_io_mat(OS& os, glm::io::order_type otype)
{
os << '\n' << typeid(OS).name() << '\n';
os << "\n" << typeid(OS).name() << "\n";
glm::vec<2, T,P> const v2_1( 0, 1);
glm::vec<2, T,P> const v2_2( 2, 3);
@@ -126,27 +126,27 @@ static int test_io_mat(OS& os, glm::io::order_type otype)
os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2)
<< glm::io::order(otype)
<< "mat2x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 2, T,P>(v2_1, v2_2) << '\n'
<< "mat2x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 3, T,P>(v3_1, v3_2) << '\n'
<< "mat2x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 4, T,P>(v4_1, v4_2) << '\n'
<< "mat3x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 2, T,P>(v2_1, v2_2, v2_3) << '\n'
<< "mat3x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 3, T,P>(v3_1, v3_2, v3_3) << '\n'
<< "mat3x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 4, T,P>(v4_1, v4_2, v4_3) << '\n'
<< "mat4x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 2, T,P>(v2_1, v2_2, v2_3, v2_4) << '\n'
<< "mat4x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 3, T,P>(v3_1, v3_2, v3_3, v3_4) << '\n'
<< "mat4x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 4, T,P>(v4_1, v4_2, v4_3, v4_4) << '\n';
<< "mat2x2<" << typeid(T).name() << "," << P << ">: " << glm::mat<2, 2, T,P>(v2_1, v2_2) << "\n"
<< "mat2x3<" << typeid(T).name() << "," << P << ">: " << glm::mat<2, 3, T,P>(v3_1, v3_2) << "\n"
<< "mat2x4<" << typeid(T).name() << "," << P << ">: " << glm::mat<2, 4, T,P>(v4_1, v4_2) << "\n"
<< "mat3x2<" << typeid(T).name() << "," << P << ">: " << glm::mat<3, 2, T,P>(v2_1, v2_2, v2_3) << "\n"
<< "mat3x3<" << typeid(T).name() << "," << P << ">: " << glm::mat<3, 3, T,P>(v3_1, v3_2, v3_3) << "\n"
<< "mat3x4<" << typeid(T).name() << "," << P << ">: " << glm::mat<3, 4, T,P>(v4_1, v4_2, v4_3) << "\n"
<< "mat4x2<" << typeid(T).name() << "," << P << ">: " << glm::mat<4, 2, T,P>(v2_1, v2_2, v2_3, v2_4) << "\n"
<< "mat4x3<" << typeid(T).name() << "," << P << ">: " << glm::mat<4, 3, T,P>(v3_1, v3_2, v3_3, v3_4) << "\n"
<< "mat4x4<" << typeid(T).name() << "," << P << ">: " << glm::mat<4, 4, T,P>(v4_1, v4_2, v4_3, v4_4) << "\n";
os << glm::io::unformatted
<< glm::io::order(otype)
<< "mat2x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 2, T,P>(v2_1, v2_2) << '\n'
<< "mat2x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 3, T,P>(v3_1, v3_2) << '\n'
<< "mat2x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 4, T,P>(v4_1, v4_2) << '\n'
<< "mat3x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 2, T,P>(v2_1, v2_2, v2_3) << '\n'
<< "mat3x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 3, T,P>(v3_1, v3_2, v3_3) << '\n'
<< "mat3x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 4, T,P>(v4_1, v4_2, v4_3) << '\n'
<< "mat4x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 2, T,P>(v2_1, v2_2, v2_3, v2_4) << '\n'
<< "mat4x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 3, T,P>(v3_1, v3_2, v3_3, v3_4) << '\n'
<< "mat4x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 4, T,P>(v4_1, v4_2, v4_3, v4_4) << '\n';
<< "mat2x2<" << typeid(T).name() << "," << P << ">: " << glm::mat<2, 2, T,P>(v2_1, v2_2) << "\n"
<< "mat2x3<" << typeid(T).name() << "," << P << ">: " << glm::mat<2, 3, T,P>(v3_1, v3_2) << "\n"
<< "mat2x4<" << typeid(T).name() << "," << P << ">: " << glm::mat<2, 4, T,P>(v4_1, v4_2) << "\n"
<< "mat3x2<" << typeid(T).name() << "," << P << ">: " << glm::mat<3, 2, T,P>(v2_1, v2_2, v2_3) << "\n"
<< "mat3x3<" << typeid(T).name() << "," << P << ">: " << glm::mat<3, 3, T,P>(v3_1, v3_2, v3_3) << "\n"
<< "mat3x4<" << typeid(T).name() << "," << P << ">: " << glm::mat<3, 4, T,P>(v4_1, v4_2, v4_3) << "\n"
<< "mat4x2<" << typeid(T).name() << "," << P << ">: " << glm::mat<4, 2, T,P>(v2_1, v2_2, v2_3, v2_4) << "\n"
<< "mat4x3<" << typeid(T).name() << "," << P << ">: " << glm::mat<4, 3, T,P>(v3_1, v3_2, v3_3, v3_4) << "\n"
<< "mat4x4<" << typeid(T).name() << "," << P << ">: " << glm::mat<4, 4, T,P>(v4_1, v4_2, v4_3, v4_4) << "\n";
return 0;
}