commit 55e7bb014cd21b1fb72d6a9e171023cef1656f0e
parent 445452b3275043ae99b5bb767cc1e6828e19aaf8
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date: Sun, 3 Dec 2023 23:49:13 +0000
Move some tests to internal/
Diffstat:
38 files changed, 716 insertions(+), 758 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -107,23 +107,6 @@ if (KFR_ENABLE_CAPI_BUILD AND NOT KFR_ENABLE_DFT_NP)
"KFR_ENABLE_CAPI_BUILD requires KFR_ENABLE_DFT_NP to be enabled")
endif ()
-function (add_arch_library NAME ARCH SRCS DEFS)
- add_library(${NAME}_${ARCH} ${SRCS})
- target_link_libraries(${NAME}_${ARCH} kfr)
- target_set_arch(${NAME}_${ARCH} PRIVATE ${ARCH})
- target_compile_options(${NAME}_${ARCH} PRIVATE ${DEFS})
- target_link_libraries(${NAME}_all INTERFACE ${NAME}_${ARCH})
-endfunction ()
-
-add_subdirectory(src/dsp)
-add_subdirectory(src/io)
-if (KFR_ENABLE_DFT)
- add_subdirectory(src/dft)
-endif ()
-if (KFR_ENABLE_CAPI_BUILD)
- add_subdirectory(src/capi)
-endif ()
-
if (NOT KFR_ARCH)
set(KFR_ARCH target)
endif ()
@@ -179,7 +162,7 @@ if (KFR_ARCH IN_LIST DETECT_NAMES)
else ()
message(
STATUS
- "Default CPU architecture for KFR is ${KFR_ARCH} (set by cmake variable)"
+ "Default CPU architecture for KFR is ${KFR_ARCH} (set by KFR_ARCH)"
)
endif ()
@@ -195,7 +178,19 @@ if (NOT KFR_ARCHS)
endif ()
endif ()
-string (REPLACE ";" ", " KFR_ARCHS_COMMA "${KFR_ARCHS}")
+if (KFR_ENABLE_MULTIARCH)
+ message(
+ STATUS
+ "Runtime dispatch is enabled for architectures: ${KFR_ARCHS} (set KFR_ARCHS to change, set KFR_ENABLE_MULTIARCH=OFF to disable)"
+ )
+else ()
+ message(
+ STATUS
+ "Runtime dispatch is disabled. Set KFR_ENABLE_MULTIARCH=ON to enable"
+ )
+endif ()
+
+string(REPLACE ";" ", " KFR_ARCHS_COMMA "${KFR_ARCHS}")
if (KFR_ENABLE_MULTIARCH)
add_compile_definitions(KFR_ENABLED_ARCHS="${KFR_ARCHS_COMMA}")
@@ -260,10 +255,14 @@ if (KFR_EXTENDED_TESTS)
target_compile_definitions(kfr INTERFACE -DKFR_EXTENDED_TESTS)
endif ()
-# if (X86) add_executable(detect_cpu
-# ${CMAKE_CURRENT_SOURCE_DIR}/cmake/detect_cpu.cpp)
-# target_link_libraries(detect_cpu PRIVATE kfr) target_set_arch(detect_cpu
-# PRIVATE generic) endif ()
+add_subdirectory(src/dsp)
+add_subdirectory(src/io)
+if (KFR_ENABLE_DFT)
+ add_subdirectory(src/dft)
+endif ()
+if (KFR_ENABLE_CAPI_BUILD)
+ add_subdirectory(src/capi)
+endif ()
if (ENABLE_EXAMPLES)
add_subdirectory(examples)
diff --git a/include/kfr/base.hpp b/include/kfr/base.hpp
@@ -26,6 +26,7 @@
#include "base/basic_expressions.hpp"
#include "base/conversion.hpp"
+#include "base/endianness.hpp"
#include "base/expression.hpp"
#include "base/filter.hpp"
#include "base/fraction.hpp"
@@ -41,4 +42,5 @@
#include "base/small_buffer.hpp"
#include "base/state_holder.hpp"
#include "base/tensor.hpp"
+#include "base/transpose.hpp"
#include "base/univector.hpp"
diff --git a/include/kfr/dft.hpp b/include/kfr/dft.hpp
@@ -24,6 +24,7 @@
#include "base.hpp"
+#include "dft/cache.hpp"
#include "dft/convolution.hpp"
#include "dft/fft.hpp"
#include "dft/reference_dft.hpp"
diff --git a/include/kfr/dsp.hpp b/include/kfr/dsp.hpp
@@ -31,7 +31,6 @@
#include "dsp/ebu.hpp"
#include "dsp/fir.hpp"
#include "dsp/fir_design.hpp"
-#include "dsp/fracdelay.hpp"
#include "dsp/goertzel.hpp"
#include "dsp/iir_design.hpp"
#include "dsp/mixdown.hpp"
diff --git a/include/kfr/dsp/delay.hpp b/include/kfr/dsp/delay.hpp
@@ -29,6 +29,7 @@
#include "../base/expression.hpp"
#include "../base/state_holder.hpp"
#include "../base/univector.hpp"
+#include "fir.hpp"
namespace kfr
{
@@ -180,5 +181,19 @@ KFR_INTRINSIC expression_delay<samples, E1, true, STag> delay(delay_state<T, sam
static_assert(STag == tag_dynamic_vector || (samples >= 1 && samples < 1024), "");
return expression_delay<samples, E1, true, STag>(std::forward<E1>(e1), state);
}
+
+/**
+ * @brief Returns template expression that applies a fractional delay to the input
+ * @param e1 an input expression
+ * @param e1 a fractional delay in range 0..1
+ */
+template <typename T, typename E1>
+KFR_INTRINSIC expression_short_fir<2, T, expression_value_type<E1>, E1> fracdelay(E1&& e1, T delay)
+{
+ if (CMT_UNLIKELY(delay < 0))
+ delay = 0;
+ univector<T, 2> taps({ 1 - delay, delay });
+ return expression_short_fir<2, T, expression_value_type<E1>, E1>(std::forward<E1>(e1), taps);
+}
} // namespace CMT_ARCH_NAME
} // namespace kfr
diff --git a/include/kfr/dsp/fracdelay.hpp b/include/kfr/dsp/fracdelay.hpp
@@ -1,45 +0,0 @@
-/** @addtogroup fir
- * @{
- */
-/*
- Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com)
- This file is part of KFR
-
- KFR is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
-
- KFR is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with KFR.
-
- If GPL is not suitable for your project, you must purchase a commercial license to use KFR.
- Buying a commercial license is mandatory as soon as you develop commercial activities without
- disclosing the source code of your own applications.
- See https://www.kfrlib.com for details.
- */
-#pragma once
-
-#include "fir.hpp"
-
-namespace kfr
-{
-
-inline namespace CMT_ARCH_NAME
-{
-
-template <typename T, typename E1>
-KFR_INTRINSIC expression_short_fir<2, T, expression_value_type<E1>, E1> fracdelay(E1&& e1, T delay)
-{
- if (CMT_UNLIKELY(delay < 0))
- delay = 0;
- univector<T, 2> taps({ 1 - delay, delay });
- return expression_short_fir<2, T, expression_value_type<E1>, E1>(std::forward<E1>(e1), taps);
-}
-} // namespace CMT_ARCH_NAME
-} // namespace kfr
diff --git a/include/kfr/math/impl/atan.hpp b/include/kfr/math/impl/atan.hpp
@@ -25,6 +25,7 @@
#include "../../simd/constants.hpp"
#include "../../simd/impl/function.hpp"
#include "../../simd/operators.hpp"
+#include "../../simd/comparison.hpp"
#include "../../simd/select.hpp"
#include "../sin_cos.hpp"
diff --git a/sources.cmake b/sources.cmake
@@ -64,7 +64,6 @@ set(
${PROJECT_SOURCE_DIR}/include/kfr/dsp/ebu.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fir.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fir_design.hpp
- ${PROJECT_SOURCE_DIR}/include/kfr/dsp/fracdelay.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/goertzel.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/iir_design.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/mixdown.hpp
@@ -262,7 +261,6 @@ set(
${PROJECT_SOURCE_DIR}/include/kfr/dsp/ebu.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fir.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fir_design.hpp
- ${PROJECT_SOURCE_DIR}/include/kfr/dsp/fracdelay.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/goertzel.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/iir_design.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/mixdown.hpp
@@ -363,7 +361,6 @@ set(
${PROJECT_SOURCE_DIR}/include/kfr/dsp/ebu.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fir.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fir_design.hpp
- ${PROJECT_SOURCE_DIR}/include/kfr/dsp/fracdelay.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/goertzel.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/iir_design.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/mixdown.hpp
@@ -481,30 +478,40 @@ set(
set(
KFR_UNITTEST_SRC
+ ${PROJECT_SOURCE_DIR}/tests/unit/cometa.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/base.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/basic_expressions.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/conversion.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/fraction.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/generators.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/handle.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/base/math_expressions.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/random.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/reduce.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/shape.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/base/simd_expressions.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/std_ambiguities.cpp
${PROJECT_SOURCE_DIR}/tests/unit/base/tensor.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/base/univector.cpp
${PROJECT_SOURCE_DIR}/tests/unit/dsp/biquad.cpp
${PROJECT_SOURCE_DIR}/tests/unit/dsp/biquad_design.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/dsp/delay.cpp
${PROJECT_SOURCE_DIR}/tests/unit/dsp/dsp.cpp
${PROJECT_SOURCE_DIR}/tests/unit/dsp/ebu.cpp
${PROJECT_SOURCE_DIR}/tests/unit/dsp/fir.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/dsp/goertzel.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/dsp/mixdown.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/dsp/oscillators.cpp
${PROJECT_SOURCE_DIR}/tests/unit/dsp/sample_rate_conversion.cpp
${PROJECT_SOURCE_DIR}/tests/unit/dsp/units.cpp
${PROJECT_SOURCE_DIR}/tests/unit/dsp/window.cpp
${PROJECT_SOURCE_DIR}/tests/unit/graphics/color.cpp
${PROJECT_SOURCE_DIR}/tests/unit/graphics/geometry.cpp
${PROJECT_SOURCE_DIR}/tests/unit/graphics/graphics.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/io/audiofile.cpp
${PROJECT_SOURCE_DIR}/tests/unit/math/asin_acos.cpp
${PROJECT_SOURCE_DIR}/tests/unit/math/atan.cpp
+ ${PROJECT_SOURCE_DIR}/tests/unit/math/complex_math.cpp
${PROJECT_SOURCE_DIR}/tests/unit/math/hyperbolic.cpp
${PROJECT_SOURCE_DIR}/tests/unit/math/log_exp.cpp
${PROJECT_SOURCE_DIR}/tests/unit/math/math.cpp
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
@@ -60,7 +60,7 @@ if (KFR_ENABLE_CAPI_BUILD)
endif ()
if (KFR_ENABLE_ASMTEST)
- add_executable(asm_test asm_test.cpp)
+ add_executable(asm_test internal/asm_test.cpp)
target_link_libraries(asm_test kfr)
target_set_arch(asm_test PRIVATE avx2)
target_compile_definitions(asm_test PRIVATE KFR_SHOW_NOT_OPTIMIZED)
@@ -80,11 +80,6 @@ if (KFR_ENABLE_ASMTEST)
endif ()
set(ALL_TESTS_CPP
- base_test.cpp
- complex_test.cpp
- dsp_test.cpp
- expression_test.cpp
- io_test.cpp
${KFR_UNITTEST_SRC})
if (KFR_ENABLE_DFT)
@@ -98,7 +93,7 @@ if (KFR_REGENERATE_TESTS)
find_package(GMP)
if (MPFR_FOUND AND GMP_FOUND)
- add_executable(generate_data generate_data.cpp)
+ add_executable(generate_data internal/generate_data.cpp)
target_link_libraries(generate_data kfr)
target_include_directories(generate_data PRIVATE ${MPFR_INCLUDE_DIR}
${GMP_INCLUDE_DIR})
diff --git a/tests/all_tests.cpp b/tests/all_tests.cpp
@@ -13,24 +13,6 @@
using namespace kfr;
-#ifdef KFR_MULTI_ARCH
-
-#define FORCE_LINK(arch) \
- namespace arch \
- { \
- extern void force_link(); \
- void (*p)() = &force_link; \
- }
-
-FORCE_LINK(sse2)
-FORCE_LINK(sse3)
-FORCE_LINK(ssse3)
-FORCE_LINK(sse41)
-FORCE_LINK(avx)
-FORCE_LINK(avx2)
-// FORCE_LINK(avx512)
-#endif
-
int main()
{
println(library_version(), " running on ", cpu_runtime());
diff --git a/tests/all_tests_merged.cpp b/tests/all_tests_merged.cpp
@@ -1,25 +0,0 @@
-#include <kfr/cident.h>
-
-CMT_PRAGMA_GNU(GCC diagnostic push)
-CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wparentheses")
-
-#include "auto_test.cpp"
-
-#include "base_test.cpp"
-#include "complex_test.cpp"
-#include "dsp_test.cpp"
-#include "expression_test.cpp"
-#include "intrinsic_test.cpp"
-#include "io_test.cpp"
-#include "resampler_test.cpp"
-
-#ifndef KFR_NO_DFT
-#include "dft_test.cpp"
-#endif
-
-namespace CMT_ARCH_NAME
-{
-void force_link() {}
-} // namespace CMT_ARCH_NAME
-
-CMT_PRAGMA_GNU(GCC diagnostic pop)
diff --git a/tests/base_test.cpp b/tests/base_test.cpp
@@ -1,122 +0,0 @@
-/**
- * KFR (https://www.kfrlib.com)
- * Copyright (C) 2016-2023 Dan Cazarin
- * See LICENSE.txt for details
- */
-
-#include <kfr/testo/testo.hpp>
-
-// #include <kfr/io.hpp>
-#include <kfr/base.hpp>
-
-using namespace kfr;
-
-namespace CMT_ARCH_NAME
-{
-
-TEST(test_basic)
-{
- // How to make a vector:
-
- // * Use constructor
- const vec<double, 4> first{ 1, 2.5, -infinity, 3.1415926 };
- CHECK(first == vec<double, 4>{ 1, 2.5, -infinity, 3.1415926 });
-
- // * Use make_vector function
- const auto second = make_vector(-1, +1);
- CHECK(second == vec<int, 2>{ -1, 1 });
-
- // * Convert from vector of other type:
- const vec<int, 4> int_vector{ 10, 20, 30, 40 };
- const vec<double, 4> double_vector = cast<double>(int_vector);
- CHECK(double_vector == vec<double, 4>{ 10, 20, 30, 40 });
-
- // * Concat two vectors:
- const vec<int, 1> left_part{ 1 };
- const vec<int, 1> right_part{ 2 };
- const vec<int, 2> pair{ left_part, right_part };
- CHECK(pair == vec<int, 2>{ 1, 2 });
-
- // * Same, but using make_vector and concat:
- const vec<int, 2> pair2 = concat(make_vector(10), make_vector(20));
- CHECK(pair2 == vec<int, 2>{ 10, 20 });
-
- // * Repeat vector multiple times:
- const vec<short, 8> repeated = repeat<4>(make_vector<short>(0, -1));
- CHECK(repeated == vec<short, 8>{ 0, -1, 0, -1, 0, -1, 0, -1 });
-
- // * Use enumerate to generate sequence of numbers:
- const vec<int, 8> eight = enumerate<int, 8>();
- CHECK(eight == vec<int, 8>{ 0, 1, 2, 3, 4, 5, 6, 7 });
-
- // * Vectors can be of any length...
- const vec<int, 1> one{ 42 };
- const vec<int, 2> two = concat(one, make_vector(42));
- CHECK(two == vec<int, 2>{ 42, 42 });
-
- const vec<u8, 256> very_long_vector = repeat<64>(make_vector<u8>(1, 2, 4, 8));
- CHECK(slice<0, 17>(very_long_vector) ==
- vec<unsigned char, 17>{ 1, 2, 4, 8, 1, 2, 4, 8, 1, 2, 4, 8, 1, 2, 4, 8, 1 });
-
- // * ...really any:
- using big_vector = vec<i16, 107>;
- big_vector v107 = enumerate<i16, 107>();
- CHECK(hadd(v107) == static_cast<short>(5671));
-
- using color = vec<u8, 3>;
- const color green = cast<u8>(make_vector(0.0, 1.0, 0.0) * 255);
- CHECK(green == vec<unsigned char, 3>{ 0, 255, 0 });
-
- // Vectors support all standard operators:
- const auto op1 = make_vector(0, 1, 10, 100);
- const auto op2 = make_vector(20, 2, -2, 200);
- const auto result = op1 * op2 - 4;
- CHECK(result == vec<int, 4>{ -4, -2, -24, 19996 });
-
- // * Transform vector:
- const vec<int, 8> numbers1 = enumerate<int, 8>();
- const vec<int, 8> numbers2 = enumerate<int, 8>() + 100;
- CHECK(odd(numbers1) == vec<int, 4>{ 1, 3, 5, 7 });
- CHECK(even(numbers2) == vec<int, 4>{ 100, 102, 104, 106 });
-
- CHECK(subadd(pack(0, 1, 2, 3, 4, 5, 6, 7), pack(10, 10, 10, 10, 10, 10, 10, 10)) ==
- pack(-10, 11, -8, 13, -6, 15, -4, 17));
- CHECK(addsub(pack(0, 1, 2, 3, 4, 5, 6, 7), pack(10, 10, 10, 10, 10, 10, 10, 10)) ==
- pack(10, -9, 12, -7, 14, -5, 16, -3));
-
- CHECK(digitreverse4(pack(0.f, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)) ==
- pack(0.f, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15));
-
- CHECK(inrange(pack(1, 2, 3), 1, 3) == make_mask<int>(true, true, true));
- CHECK(inrange(pack(1, 2, 3), 1, 2) == make_mask<int>(true, true, false));
- CHECK(inrange(pack(1, 2, 3), 1, 1) == make_mask<int>(true, false, false));
-}
-
-TEST(ctti) { CHECK(cometa::type_name<float>() == std::string("float")); }
-
-#ifdef KFR_USE_STD_ALLOCATION
-TEST(std_allocation)
-{
- univector<float> u;
- std::vector<float>& v = u;
-
- std::vector<float> v2{ 1, 2, 3, 4 };
-
- // Technically an UB but ok with all sane compilers
- reinterpret_cast<univector<float>&>(v2) += 100.f;
- CHECK(v2[0] == 101);
- CHECK(v2[1] == 102);
- CHECK(v2[2] == 103);
- CHECK(v2[3] == 104);
-}
-#endif
-
-} // namespace CMT_ARCH_NAME
-
-#ifndef KFR_NO_MAIN
-int main()
-{
- println(library_version());
- return testo::run_all("", true);
-}
-#endif
diff --git a/tests/complex_test.cpp b/tests/complex_test.cpp
@@ -1,233 +0,0 @@
-/**
- * KFR (https://www.kfrlib.com)
- * Copyright (C) 2016-2023 Dan Cazarin
- * See LICENSE.txt for details
- */
-
-#include <kfr/testo/testo.hpp>
-
-#include <complex>
-#include <kfr/base.hpp>
-#include <kfr/io.hpp>
-
-using namespace kfr;
-
-namespace CMT_ARCH_NAME
-{
-
-TEST(complex_vector)
-{
- const vec<c32, 1> c32x1{ c32{ 0, 1 } };
- CHECK(c32x1.flatten()[0] == 0.0f);
- CHECK(c32x1.flatten()[1] == 1.0f);
-
- const vec<c32, 2> c32x2{ c32{ 0, 1 }, c32{ 2, 3 } };
- CHECK(c32x2.flatten()[0] == 0.0f);
- CHECK(c32x2.flatten()[1] == 1.0f);
- CHECK(c32x2.flatten()[2] == 2.0f);
- CHECK(c32x2.flatten()[3] == 3.0f);
-
- const vec<c32, 3> c32x3{ c32{ 0, 1 }, c32{ 2, 3 }, c32{ 4, 5 } };
- CHECK(c32x3.flatten()[0] == 0.0f);
- CHECK(c32x3.flatten()[1] == 1.0f);
- CHECK(c32x3.flatten()[2] == 2.0f);
- CHECK(c32x3.flatten()[3] == 3.0f);
- CHECK(c32x3.flatten()[4] == 4.0f);
- CHECK(c32x3.flatten()[5] == 5.0f);
-
- const vec<c32, 1> c32s = 2;
- CHECK(c32s.flatten()[0] == 2.f);
- CHECK(c32s.flatten()[1] == 0.f);
-}
-
-TEST(complex_cast)
-{
- const vec<f32, 4> v1 = bitcast<f32>(make_vector(c32{ 0, 1 }, c32{ 2, 3 }));
- CHECK(v1.flatten()[0] == 0.f);
- CHECK(v1.flatten()[1] == 1.f);
- CHECK(v1.flatten()[2] == 2.f);
- CHECK(v1.flatten()[3] == 3.f);
-
- const vec<c32, 1> v2 = bitcast<c32>(make_vector(1.f, 2.f));
- CHECK(v2.flatten()[0] == 1.f);
- CHECK(v2.flatten()[1] == 2.f);
-
- const vec<c32, 2> v3 = make_vector(1.f, 2.f);
- CHECK(v3.flatten()[0] == 1.f);
- CHECK(v3.flatten()[1] == 0.f);
- CHECK(v3.flatten()[2] == 2.f);
- CHECK(v3.flatten()[3] == 0.f);
-
- const vec<c32, 2> v4 = make_vector(1, 2);
- CHECK(v4.flatten()[0] == 1.f);
- CHECK(v4.flatten()[1] == 0.f);
- CHECK(v4.flatten()[2] == 2.f);
- CHECK(v4.flatten()[3] == 0.f);
-
- CHECK(zerovector<c32, 4>() == make_vector(c32{ 0, 0 }, c32{ 0, 0 }, c32{ 0, 0 }, c32{ 0, 0 }));
- CHECK(enumerate<c32, 4>() == make_vector(c32{ 0, 0 }, c32{ 1, 0 }, c32{ 2, 0 }, c32{ 3, 0 }));
-}
-
-TEST(complex_math)
-{
- const vec<c32, 1> a{ c32{ 1, 2 } };
- const vec<c32, 1> b{ c32{ 3, 4 } };
- CHECK(c32(vec<c32, 1>(2)[0]) == c32{ 2, 0 });
- CHECK(a + b == make_vector(c32{ 4, 6 }));
- CHECK(a - b == make_vector(c32{ -2, -2 }));
- CHECK(a * b == make_vector(c32{ -5, 10 }));
- CHECK(a * vec<c32, 1>(2) == make_vector(c32{ 2, 4 }));
- CHECK(a * 2 == make_vector(c32{ 2, 4 }));
- CHECK(a / b == make_vector(c32{ 0.44f, 0.08f }));
- CHECK(-a == make_vector(c32{ -1, -2 }));
-
- CHECK(real(a) == make_vector(1.f));
- CHECK(imag(a) == make_vector(2.f));
-
- CHECK(make_complex(5.f, 7) == c32{ 5.f, 7.f });
- CHECK(make_complex(make_vector(5.f, 8.f), make_vector(7.f, 9.f)) ==
- make_vector(c32{ 5.f, 7.f }, c32{ 8.f, 9.f }));
-
- CHECK(cabs(c32{ 3.f, 4.f }) == 5.f);
- CHECK(cabs(make_vector(c32{ 3.f, 4.f })) == make_vector(5.f));
-
- CHECK(cabs(-3.f) == 3.f);
- CHECK(cabs(make_vector(-3.f)) == make_vector(3.f));
-
- CHECK(carg(c32{ +1.f, 0.f }) == 0.f);
- CHECK(carg(c32{ 0.f, +1.f }) == c_pi<float> / 2);
- CHECK(carg(c32{ 0.f, -1.f }) == -c_pi<float> / 2);
- CHECK(carg(c32{ -1.f, 0.f }) == c_pi<float>);
-
- testo::epsilon_scope<void> eps(5);
-
- CHECK(csin(c32{ 1.f, 1.f }) == c32{ 1.2984575814159773f, 0.634963914784736f });
- CHECK(ccos(c32{ 1.f, 1.f }) == c32{ 0.8337300251311489f, -0.9888977057628651f });
- CHECK(csinh(c32{ 1.f, 1.f }) == c32{ 0.634963914784736f, 1.2984575814159773f });
- CHECK(ccosh(c32{ 1.f, 1.f }) == c32{ 0.8337300251311489f, 0.9888977057628651f });
-
- CHECK(clog(c32{ 1.f, 1.f }) == c32{ 0.34657359027997264f, 0.7853981633974483f });
- CHECK(clog2(c32{ 1.f, 1.f }) == c32{ 0.5f, 1.1330900354567983f });
- CHECK(clog10(c32{ 1.f, 1.f }) == c32{ 0.15051499783199057f, 0.3410940884604603f });
-
- CHECK(cexp(c32{ 1.f, 1.f }) == c32{ 1.4686939399158849f, 2.2873552871788423f });
- CHECK(cexp2(c32{ 1.f, 1.f }) == c32{ 1.5384778027279442f, 1.2779225526272695f });
- CHECK(cexp10(c32{ 1.f, 1.f }) == c32{ -6.682015101903131f, 7.439803369574931f });
-
-#ifdef CMT_NATIVE_F64
- CHECK(csin(c64{ 1.0, 1.0 }) == c64{ 1.2984575814159773, 0.634963914784736 });
- CHECK(ccos(c64{ 1.0, 1.0 }) == c64{ 0.8337300251311489, -0.9888977057628651 });
- CHECK(csinh(c64{ 1.0, 1.0 }) == c64{ 0.634963914784736, 1.2984575814159773 });
- CHECK(ccosh(c64{ 1.0, 1.0 }) == c64{ 0.8337300251311489, 0.9888977057628651 });
- CHECK(clog(c64{ 1.0, 1.0 }) == c64{ 0.34657359027997264, 0.7853981633974483 });
- CHECK(cexp(c64{ 1.0, 1.0 }) == c64{ 1.4686939399158849, 2.2873552871788423 });
-#endif
-}
-
-TEST(complex_read_write)
-{
- c32 buffer[8] = { c32{ 1, 2 }, c32{ 3, 4 }, c32{ 5, 6 }, c32{ 7, 8 },
- c32{ 9, 10 }, c32{ 11, 12 }, c32{ 13, 14 }, c32{ 15, 16 } };
-
- CHECK(read<4>(buffer) == make_vector(c32{ 1, 2 }, c32{ 3, 4 }, c32{ 5, 6 }, c32{ 7, 8 }));
- CHECK(read<3>(buffer + 1) == make_vector(c32{ 3, 4 }, c32{ 5, 6 }, c32{ 7, 8 }));
- write(buffer + 2, make_vector(c32{ 10, 11 }, c32{ 12, 13 }));
- CHECK(read<4>(buffer) == make_vector(c32{ 1, 2 }, c32{ 3, 4 }, c32{ 10, 11 }, c32{ 12, 13 }));
-}
-
-TEST(complex_shuffle)
-{
- const vec<c32, 2> a{ c32{ 0, 1 }, c32{ 2, 3 } };
- CHECK(reverse(a) == make_vector(c32{ 2, 3 }, c32{ 0, 1 }));
-}
-
-TEST(complex_basic_expressions)
-{
- const univector<c32, 15> uv1 = zeros();
- CHECK(uv1[0] == c32{ 0, 0 });
- CHECK(uv1[1] == c32{ 0, 0 });
- CHECK(uv1[2] == c32{ 0, 0 });
- CHECK(uv1[14] == c32{ 0, 0 });
- const univector<c32, 15> uv2 = ones();
- CHECK(uv2[0] == c32{ 1, 0 });
- CHECK(uv2[1] == c32{ 1, 0 });
- CHECK(uv2[2] == c32{ 1, 0 });
- CHECK(uv2[14] == c32{ 1, 0 });
- const univector<c32, 15> uv3 = counter();
- CHECK(uv3[0] == c32{ 0, 0 });
- CHECK(uv3[1] == c32{ 1, 0 });
- CHECK(uv3[2] == c32{ 2, 0 });
- CHECK(uv3[14] == c32{ 14, 0 });
-}
-
-TEST(complex_functions)
-{
- CHECK(csqr(complex<f32>(4.f, 0.f)) == c32{ 16.f, 0.f });
- CHECK(csqrt(complex<f32>(16.f, 0.f)) == c32{ 4.f, 0.f });
-
- CHECK(csqr(complex<f32>(1.f, 4.f)) == c32{ -15.f, 8.f });
-
- CHECK(csqrt(complex<f32>(15.f, 8.f)) == c32{ 4.f, 1.f });
- CHECK(csqrt(complex<f32>(-15.f, 8.f)) == c32{ 1.f, 4.f });
- CHECK(csqrt(complex<f32>(15.f, -8.f)) == c32{ 4.f, -1.f });
- CHECK(csqrt(complex<f32>(-15.f, -8.f)) == c32{ 1.f, -4.f });
-}
-
-TEST(complex_function_expressions)
-{
- const univector<c32, 4> uv1 = sqr(counter());
- CHECK(uv1[0] == c32{ 0, 0 });
- CHECK(uv1[1] == c32{ 1, 0 });
- CHECK(uv1[2] == c32{ 4, 0 });
- CHECK(uv1[3] == c32{ 9, 0 });
-
- const univector<c32, 4> uv2 = uv1 * 2.f;
- CHECK(uv2[0] == c32{ 0, 0 });
- CHECK(uv2[1] == c32{ 2, 0 });
- CHECK(uv2[2] == c32{ 8, 0 });
- CHECK(uv2[3] == c32{ 18, 0 });
-
- const univector<f32, 4> uv3 = real(uv2);
- CHECK(uv3[0] == 0.f);
- CHECK(uv3[1] == 2.f);
- CHECK(uv3[2] == 8.f);
- CHECK(uv3[3] == 18.f);
- testo::assert_is_same<c32, expression_value_type<decltype(uv2)>>();
- testo::assert_is_same<f32, expression_value_type<decltype(uv3)>>();
- testo::assert_is_same<f32, expression_value_type<decltype(real(uv2))>>();
-}
-
-TEST(static_tests)
-{
- static_assert(is_numeric<vec<complex<float>, 4>>, "");
- static_assert(is_numeric_args<vec<complex<float>, 4>>, "");
-
- static_assert(sizeof(vec<c32, 4>) == sizeof(vec<f32, 8>), "");
- static_assert(vec<f32, 4>::size() == 4, "");
- static_assert(vec<c32, 4>::size() == 4, "");
- static_assert(vec<f32, 4>::scalar_size() == 4, "");
- static_assert(vec<c32, 4>::scalar_size() == 8, "");
- testo::assert_is_same<subtype<complex<i32>>, i32>();
- testo::assert_is_same<vec<c32, 4>::value_type, c32>();
- testo::assert_is_same<vec<c32, 4>::scalar_type, f32>();
- testo::assert_is_same<vec<f32, 4>::value_type, f32>();
- testo::assert_is_same<vec<f32, 4>::scalar_type, f32>();
- testo::assert_is_same<vec<c32, 1>, decltype(make_vector(c32{ 0, 0 }))>();
- testo::assert_is_same<vec<c32, 2>, decltype(make_vector(c32{ 0, 0 }, 4))>();
- testo::assert_is_same<ftype<complex<i32>>, complex<f32>>();
- testo::assert_is_same<ftype<complex<i64>>, complex<f64>>();
- testo::assert_is_same<ftype<vec<complex<i32>, 4>>, vec<complex<f32>, 4>>();
- testo::assert_is_same<ftype<vec<complex<i64>, 8>>, vec<complex<f64>, 8>>();
-
- testo::assert_is_same<std::common_type_t<complex<int>, double>, complex<double>>();
-}
-} // namespace CMT_ARCH_NAME
-
-#ifndef KFR_NO_MAIN
-int main()
-{
- println(library_version());
-
- return testo::run_all("", true);
-}
-#endif
diff --git a/tests/dsp_test.cpp b/tests/dsp_test.cpp
@@ -1,137 +0,0 @@
-/**
- * KFR (https://www.kfrlib.com)
- * Copyright (C) 2016-2023 Dan Cazarin
- * See LICENSE.txt for details
- */
-
-#include <kfr/testo/testo.hpp>
-
-#include <kfr/base.hpp>
-#include <kfr/dsp.hpp>
-#include <kfr/io.hpp>
-
-#include <complex>
-#include <numeric>
-
-using namespace kfr;
-
-namespace CMT_ARCH_NAME
-{
-
-TEST(goertzel)
-{
- testo::epsilon_scope<float> e(100);
- univector<float, 16> a;
- a = sinenorm(phasor(0.125f));
-
- float omega = c_pi<float, 2> * 0.125f;
-
- complex<float> c;
- process(goertzel(c, omega), a);
- CHECK(cabs(c) == 8.f);
-
- complex<float> cs[3];
- float omegas[3] = { omega, omega, omega };
- process(goertzel(cs, omegas), a);
- println(cs[0]);
- CHECK(cabs(cs[0]) == 8.f);
- CHECK(cabs(cs[1]) == 8.f);
- CHECK(cabs(cs[2]) == 8.f);
-}
-
-TEST(delay)
-{
- const univector<float, 33> v1 = counter() + 100;
- CHECK_EXPRESSION(delay(v1), 33, [](size_t i) { return i < 1 ? 0.f : (i - 1) + 100.f; });
-
- CHECK_EXPRESSION(delay<3>(v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
-
- delay_state<float, 3> state1;
- CHECK_EXPRESSION(delay(state1, v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
-
- delay_state<float, 3, tag_dynamic_vector> state2;
- CHECK_EXPRESSION(delay(state2, v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
-}
-
-TEST(fracdelay)
-{
- univector<double, 5> a({ 1, 2, 3, 4, 5 });
- univector<double, 5> b = fracdelay(a, 0.5);
- CHECK(rms(b - univector<double>({ 0.5, 1.5, 2.5, 3.5, 4.5 })) < constants<double>::epsilon * 5);
-
- b = fracdelay(a, 0.1);
- CHECK(rms(b - univector<double>({ 0.9, 1.9, 2.9, 3.9, 4.9 })) < constants<double>::epsilon * 5);
-
- b = fracdelay(a, 0.0);
- CHECK(rms(b - univector<double>({ 1, 2, 3, 4, 5 })) < constants<double>::epsilon * 5);
-
- b = fracdelay(a, 1.0);
- CHECK(rms(b - univector<double>({ 0, 1, 2, 3, 4 })) < constants<double>::epsilon * 5);
-}
-
-TEST(mixdown)
-{
- CHECK_EXPRESSION(mixdown(counter(), counter() * 2 + 100), infinite_size,
- [](size_t i) { return i + i * 2 + 100; });
-}
-
-TEST(mixdown_stereo)
-{
- const univector<double, 21> left = counter();
- const univector<double, 21> right = counter() * 2 + 100;
- univector<double, 21> mid;
- univector<double, 21> side;
- unpack(mid, side) = mixdown_stereo(left, right, matrix_sum_diff());
-
- CHECK_EXPRESSION(mid, 21, [](size_t i) { return i + i * 2.0 + 100.0; });
- CHECK_EXPRESSION(side, 21, [](size_t i) { return i - (i * 2.0 + 100.0); });
-}
-
-TEST(sine_type)
-{
- double ph = 0.0;
- using T = decltype(sine(ph));
- static_assert(std::is_same_v<T, double>);
-}
-
-TEST(phasor)
-{
- constexpr fbase sr = 44100.0;
- univector<fbase, 100> v1 = sinenorm(phasor(15000, sr));
- univector<fbase, 100> v2 = sin(constants<fbase>::pi_s(2) * counter(0, 15000 / sr));
- CHECK(rms(v1 - v2) < 1.e-5);
-}
-
-template <typename E, typename T, size_t size>
-void test_ir(E&& e, const univector<T, size>& test_vector)
-{
- substitute(e, to_handle(unitimpulse<T>()));
- const univector<T, size> ir = e;
- println(absmaxof(ir - test_vector));
-}
-
-TEST(gen_sin)
-{
- kfr::univector<kfr::fbase> x;
- constexpr size_t size = 132;
- kfr::fbase step = kfr::c_pi<kfr::fbase> / (size + 1);
- kfr::univector<kfr::fbase> up;
- up = kfr::truncate(kfr::gen_sin<kfr::fbase>(kfr::c_pi<kfr::fbase> / 2, step), size);
-
- kfr::univector<kfr::fbase> up2(size);
- for (int i = 0; i < size; ++i)
- {
- up2[i] = std::sin(kfr::c_pi<kfr::fbase> / 2 + i * step);
- }
- CHECK(rms(up - up2) < 0.00001);
-}
-
-} // namespace CMT_ARCH_NAME
-
-#ifndef KFR_NO_MAIN
-int main(int argc, char* argv[])
-{
- println(library_version());
- return testo::run_all(argc > 1 ? argv[1] : "", true);
-}
-#endif
diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp
@@ -1,53 +0,0 @@
-/**
- * KFR (https://www.kfrlib.com)
- * Copyright (C) 2016-2023 Dan Cazarin
- * See LICENSE.txt for details
- */
-
-#include <kfr/testo/testo.hpp>
-
-#include <kfr/base.hpp>
-#include <kfr/cometa/function.hpp>
-#include <kfr/dsp.hpp>
-#include <kfr/io.hpp>
-
-using namespace kfr;
-
-namespace CMT_ARCH_NAME
-{
-
-TEST(univector_assignment)
-{
- univector<int> x = truncate(counter(), 10);
- CHECK(x.size() == 10u);
-
- univector<int> y;
- y = truncate(counter(), 10);
- CHECK(y.size() == 10u);
-}
-
-TEST(mix)
-{
- CHECK_EXPRESSION(mix(sequence(0, 0.5f, 1, 0.5f), counter(), counter() * 10), infinite_size,
- [](size_t i) {
- return mix(std::array<float, 4>{ 0, 0.5f, 1, 0.5f }[i % 4], i, i * 10);
- });
-}
-
-TEST(expression_mask)
-{
- univector<float> x(100);
- univector<float> y(100);
- x = select(x > y, 0.5f, 0.1f) * (y - x) + x;
-}
-
-} // namespace CMT_ARCH_NAME
-
-#ifndef KFR_NO_MAIN
-int main()
-{
- println(library_version());
-
- return testo::run_all("", true);
-}
-#endif
diff --git a/tests/asm_test.cpp b/tests/internal/asm_test.cpp
diff --git a/tests/generate_data.cpp b/tests/internal/generate_data.cpp
diff --git a/tests/io_test.cpp b/tests/io_test.cpp
@@ -1,85 +0,0 @@
-/**
- * KFR (https://www.kfrlib.com)
- * Copyright (C) 2016-2023 Dan Cazarin
- * See LICENSE.txt for details
- */
-
-#include <kfr/testo/testo.hpp>
-
-#include <kfr/base.hpp>
-#include <kfr/cometa/function.hpp>
-#include <kfr/io.hpp>
-
-using namespace kfr;
-
-namespace CMT_ARCH_NAME
-{
-
-#ifndef KFR_DISABLE_WAV
-TEST(write_wav_file)
-{
- audio_writer_wav<float> writer(open_file_for_writing(KFR_FILEPATH("temp_audio_file.wav")),
- audio_format{});
- univector<float> data(44100 * 2);
- data = sin(counter() * 0.01f);
- size_t wr = writer.write(data.data(), data.size());
- CHECK(wr == data.size());
- CHECK(umax(writer.format().length) == data.size() / 2);
-}
-
-TEST(read_wav_file)
-{
- audio_reader_wav<float> reader(open_file_for_reading(KFR_FILEPATH("temp_audio_file.wav")));
- CHECK(reader.format().channels == 2u);
- CHECK(reader.format().type == audio_sample_type::i16);
- CHECK(reader.format().samplerate == 44100);
- univector<float> data(44100 * 2);
- CHECK(umax(reader.format().length) == data.size() / 2);
- size_t rd = reader.read(data.data(), data.size());
- CHECK(rd == data.size());
- CHECK(absmaxof(data - render(sin(counter() * 0.01f), data.size())) < 0.0001f);
-}
-#endif
-
-#ifndef KFR_DISABLE_FLAC
-TEST(read_flac_file)
-{
- audio_reader_flac<float> reader(
- open_file_for_reading(KFR_FILEPATH(KFR_SRC_DIR "/tests/test-audio/sine.flac")));
- CHECK(reader.format().channels == 2u);
- CHECK(reader.format().type == audio_sample_type::i32);
- CHECK(reader.format().samplerate == 44100);
- univector<float> data(44100 * 2);
- CHECK(reader.format().length == data.size() / 2);
- size_t rd = reader.read(data.data(), data.size());
- CHECK(rd == data.size());
- CHECK(absmaxof(data - render(sin(counter() * 0.01f), data.size())) < 0.0001f);
-}
-#endif
-
-#ifndef KFR_DISABLE_MP3
-TEST(read_mp3_file)
-{
- audio_reader_mp3<float> reader(
- open_file_for_reading(KFR_FILEPATH(KFR_SRC_DIR "/tests/test-audio/sine.mp3")));
- CHECK(reader.format().channels == 2u);
- CHECK(reader.format().type == audio_sample_type::i16);
- CHECK(reader.format().samplerate == 44100);
- univector<float> data(44100 * 2);
- CHECK(reader.format().length >= data.size() / 2);
- size_t rd = reader.read(data.data(), data.size());
- CHECK(rd == data.size());
- data = data.slice(2402, 2 * 44100); // MP3 format delay
- CHECK(absmaxof(data - render(sin(counter() * 0.01f), data.size())) < 0.005f);
-}
-#endif
-} // namespace CMT_ARCH_NAME
-
-#ifndef KFR_NO_MAIN
-int main()
-{
- println(library_version());
-
- return testo::run_all("", true);
-}
-#endif
diff --git a/tests/unit/base/generators.cpp b/tests/unit/base/generators.cpp
@@ -30,4 +30,20 @@ TEST(test_gen_expj)
// In most cases error is much lower (less than 0.00001)
}
+TEST(gen_sin)
+{
+ kfr::univector<kfr::fbase> x;
+ constexpr size_t size = 132;
+ kfr::fbase step = kfr::c_pi<kfr::fbase> / (size + 1);
+ kfr::univector<kfr::fbase> up;
+ up = kfr::truncate(kfr::gen_sin<kfr::fbase>(kfr::c_pi<kfr::fbase> / 2, step), size);
+
+ kfr::univector<kfr::fbase> up2(size);
+ for (int i = 0; i < size; ++i)
+ {
+ up2[i] = std::sin(kfr::c_pi<kfr::fbase> / 2 + i * step);
+ }
+ CHECK(rms(up - up2) < 0.00001);
+}
+
} // namespace CMT_ARCH_NAME
diff --git a/tests/unit/base/math_expressions.cpp b/tests/unit/base/math_expressions.cpp
@@ -0,0 +1,60 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/testo/testo.hpp>
+
+#include <kfr/base/simd_expressions.hpp>
+#include <kfr/base/math_expressions.hpp>
+#include <kfr/base/univector.hpp>
+
+using namespace kfr;
+
+namespace CMT_ARCH_NAME
+{
+
+TEST(complex_basic_expressions)
+{
+ const univector<c32, 15> uv1 = zeros();
+ CHECK(uv1[0] == c32{ 0, 0 });
+ CHECK(uv1[1] == c32{ 0, 0 });
+ CHECK(uv1[2] == c32{ 0, 0 });
+ CHECK(uv1[14] == c32{ 0, 0 });
+ const univector<c32, 15> uv2 = ones();
+ CHECK(uv2[0] == c32{ 1, 0 });
+ CHECK(uv2[1] == c32{ 1, 0 });
+ CHECK(uv2[2] == c32{ 1, 0 });
+ CHECK(uv2[14] == c32{ 1, 0 });
+ const univector<c32, 15> uv3 = counter();
+ CHECK(uv3[0] == c32{ 0, 0 });
+ CHECK(uv3[1] == c32{ 1, 0 });
+ CHECK(uv3[2] == c32{ 2, 0 });
+ CHECK(uv3[14] == c32{ 14, 0 });
+}
+
+TEST(complex_function_expressions)
+{
+ const univector<c32, 4> uv1 = sqr(counter());
+ CHECK(uv1[0] == c32{ 0, 0 });
+ CHECK(uv1[1] == c32{ 1, 0 });
+ CHECK(uv1[2] == c32{ 4, 0 });
+ CHECK(uv1[3] == c32{ 9, 0 });
+
+ const univector<c32, 4> uv2 = uv1 * 2.f;
+ CHECK(uv2[0] == c32{ 0, 0 });
+ CHECK(uv2[1] == c32{ 2, 0 });
+ CHECK(uv2[2] == c32{ 8, 0 });
+ CHECK(uv2[3] == c32{ 18, 0 });
+
+ const univector<f32, 4> uv3 = real(uv2);
+ CHECK(uv3[0] == 0.f);
+ CHECK(uv3[1] == 2.f);
+ CHECK(uv3[2] == 8.f);
+ CHECK(uv3[3] == 18.f);
+ testo::assert_is_same<c32, expression_value_type<decltype(uv2)>>();
+ testo::assert_is_same<f32, expression_value_type<decltype(uv3)>>();
+ testo::assert_is_same<f32, expression_value_type<decltype(real(uv2))>>();
+}
+} // namespace CMT_ARCH_NAME
diff --git a/tests/unit/base/simd_expressions.cpp b/tests/unit/base/simd_expressions.cpp
@@ -0,0 +1,33 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/base/basic_expressions.hpp>
+#include <kfr/base/simd_expressions.hpp>
+#include <kfr/base/univector.hpp>
+#include <kfr/io/tostring.hpp>
+
+namespace kfr
+{
+inline namespace CMT_ARCH_NAME
+{
+
+TEST(expression_mask)
+{
+ univector<float> x(100);
+ univector<float> y(100);
+ x = select(x > y, 0.5f, 0.1f) * (y - x) + x;
+}
+
+TEST(mix)
+{
+ CHECK_EXPRESSION(mix(sequence(0, 0.5f, 1, 0.5f), counter(), counter() * 10), infinite_size,
+ [](size_t i) {
+ return mix(std::array<float, 4>{ 0, 0.5f, 1, 0.5f }[i % 4], i, i * 10);
+ });
+}
+
+} // namespace CMT_ARCH_NAME
+} // namespace kfr
diff --git a/tests/unit/base/univector.cpp b/tests/unit/base/univector.cpp
@@ -0,0 +1,44 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/base/basic_expressions.hpp>
+#include <kfr/base/univector.hpp>
+#include <kfr/io/tostring.hpp>
+
+namespace kfr
+{
+inline namespace CMT_ARCH_NAME
+{
+
+TEST(univector_assignment)
+{
+ univector<int> x = truncate(counter(), 10);
+ CHECK(x.size() == 10u);
+
+ univector<int> y;
+ y = truncate(counter(), 10);
+ CHECK(y.size() == 10u);
+}
+
+#ifdef KFR_USE_STD_ALLOCATION
+TEST(std_allocation)
+{
+ univector<float> u;
+ std::vector<float>& v = u;
+
+ std::vector<float> v2{ 1, 2, 3, 4 };
+
+ // Technically an UB but ok with all sane compilers
+ reinterpret_cast<univector<float>&>(v2) += 100.f;
+ CHECK(v2[0] == 101);
+ CHECK(v2[1] == 102);
+ CHECK(v2[2] == 103);
+ CHECK(v2[3] == 104);
+}
+#endif
+
+} // namespace CMT_ARCH_NAME
+} // namespace kfr
diff --git a/tests/unit/cometa.cpp b/tests/unit/cometa.cpp
@@ -0,0 +1,19 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/cometa.hpp>
+#include <kfr/cometa/ctti.hpp>
+#include <kfr/testo/testo.hpp>
+
+namespace kfr
+{
+
+TEST(ctti)
+{
+ CHECK(cometa::type_name<float>() == std::string("float"));
+ CHECK(cometa::type_name<int>() == std::string("int"));
+}
+} // namespace kfr
diff --git a/tests/unit/dsp/delay.cpp b/tests/unit/dsp/delay.cpp
@@ -0,0 +1,47 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/testo/testo.hpp>
+
+#include <kfr/base.hpp>
+#include <kfr/dsp/delay.hpp>
+
+using namespace kfr;
+
+namespace CMT_ARCH_NAME
+{
+
+TEST(delay)
+{
+ const univector<float, 33> v1 = counter() + 100;
+ CHECK_EXPRESSION(delay(v1), 33, [](size_t i) { return i < 1 ? 0.f : (i - 1) + 100.f; });
+
+ CHECK_EXPRESSION(delay<3>(v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
+
+ delay_state<float, 3> state1;
+ CHECK_EXPRESSION(delay(state1, v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
+
+ delay_state<float, 3, tag_dynamic_vector> state2;
+ CHECK_EXPRESSION(delay(state2, v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
+}
+
+TEST(fracdelay)
+{
+ univector<double, 5> a({ 1, 2, 3, 4, 5 });
+ univector<double, 5> b = fracdelay(a, 0.5);
+ CHECK(rms(b - univector<double>({ 0.5, 1.5, 2.5, 3.5, 4.5 })) < constants<double>::epsilon * 5);
+
+ b = fracdelay(a, 0.1);
+ CHECK(rms(b - univector<double>({ 0.9, 1.9, 2.9, 3.9, 4.9 })) < constants<double>::epsilon * 5);
+
+ b = fracdelay(a, 0.0);
+ CHECK(rms(b - univector<double>({ 1, 2, 3, 4, 5 })) < constants<double>::epsilon * 5);
+
+ b = fracdelay(a, 1.0);
+ CHECK(rms(b - univector<double>({ 0, 1, 2, 3, 4 })) < constants<double>::epsilon * 5);
+}
+
+} // namespace CMT_ARCH_NAME
diff --git a/tests/unit/dsp/goertzel.cpp b/tests/unit/dsp/goertzel.cpp
@@ -0,0 +1,38 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/testo/testo.hpp>
+
+#include <kfr/base.hpp>
+#include <kfr/dsp.hpp>
+
+using namespace kfr;
+
+namespace CMT_ARCH_NAME
+{
+
+TEST(goertzel)
+{
+ testo::epsilon_scope<float> e(100);
+ univector<float, 16> a;
+ a = sinenorm(phasor(0.125f));
+
+ float omega = c_pi<float, 2> * 0.125f;
+
+ complex<float> c;
+ process(goertzel(c, omega), a);
+ CHECK(cabs(c) == 8.f);
+
+ complex<float> cs[3];
+ float omegas[3] = { omega, omega, omega };
+ process(goertzel(cs, omegas), a);
+ println(cs[0]);
+ CHECK(cabs(cs[0]) == 8.f);
+ CHECK(cabs(cs[1]) == 8.f);
+ CHECK(cabs(cs[2]) == 8.f);
+}
+
+} // namespace CMT_ARCH_NAME
diff --git a/tests/unit/dsp/mixdown.cpp b/tests/unit/dsp/mixdown.cpp
@@ -0,0 +1,36 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/base/reduce.hpp>
+#include <kfr/base/simd_expressions.hpp>
+#include <kfr/base/univector.hpp>
+#include <kfr/dsp/mixdown.hpp>
+
+namespace kfr
+{
+inline namespace CMT_ARCH_NAME
+{
+
+TEST(mixdown)
+{
+ CHECK_EXPRESSION(mixdown(counter(), counter() * 2 + 100), infinite_size,
+ [](size_t i) { return i + i * 2 + 100; });
+}
+
+TEST(mixdown_stereo)
+{
+ const univector<double, 21> left = counter();
+ const univector<double, 21> right = counter() * 2 + 100;
+ univector<double, 21> mid;
+ univector<double, 21> side;
+ unpack(mid, side) = mixdown_stereo(left, right, matrix_sum_diff());
+
+ CHECK_EXPRESSION(mid, 21, [](size_t i) { return i + i * 2.0 + 100.0; });
+ CHECK_EXPRESSION(side, 21, [](size_t i) { return i - (i * 2.0 + 100.0); });
+}
+
+} // namespace CMT_ARCH_NAME
+} // namespace kfr
diff --git a/tests/unit/dsp/oscillators.cpp b/tests/unit/dsp/oscillators.cpp
@@ -0,0 +1,31 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/testo/testo.hpp>
+
+#include <kfr/base.hpp>
+#include <kfr/dsp/oscillators.hpp>
+
+using namespace kfr;
+
+namespace CMT_ARCH_NAME
+{
+
+TEST(sine_type)
+{
+ double ph = 0.0;
+ using T = decltype(sine(ph));
+ static_assert(std::is_same_v<T, double>);
+}
+
+TEST(phasor)
+{
+ constexpr fbase sr = 44100.0;
+ univector<fbase, 100> v1 = sinenorm(phasor(15000, sr));
+ univector<fbase, 100> v2 = sin(constants<fbase>::pi_s(2) * counter(0, 15000 / sr));
+ CHECK(rms(v1 - v2) < 1.e-5);
+}
+} // namespace CMT_ARCH_NAME
diff --git a/tests/unit/io/audiofile.cpp b/tests/unit/io/audiofile.cpp
@@ -0,0 +1,72 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/io/audiofile.hpp>
+#include <kfr/testo/testo.hpp>
+#include <kfr/base.hpp>
+
+namespace kfr
+{
+
+#ifndef KFR_DISABLE_WAV
+TEST(write_wav_file)
+{
+ audio_writer_wav<float> writer(open_file_for_writing(KFR_FILEPATH("temp_audio_file.wav")),
+ audio_format{});
+ univector<float> data(44100 * 2);
+ data = sin(counter() * 0.01f);
+ size_t wr = writer.write(data.data(), data.size());
+ CHECK(wr == data.size());
+ CHECK(umax(writer.format().length) == data.size() / 2);
+}
+
+TEST(read_wav_file)
+{
+ audio_reader_wav<float> reader(open_file_for_reading(KFR_FILEPATH("temp_audio_file.wav")));
+ CHECK(reader.format().channels == 2u);
+ CHECK(reader.format().type == audio_sample_type::i16);
+ CHECK(reader.format().samplerate == 44100);
+ univector<float> data(44100 * 2);
+ CHECK(umax(reader.format().length) == data.size() / 2);
+ size_t rd = reader.read(data.data(), data.size());
+ CHECK(rd == data.size());
+ CHECK(absmaxof(data - render(sin(counter() * 0.01f), data.size())) < 0.0001f);
+}
+#endif
+
+#ifndef KFR_DISABLE_FLAC
+TEST(read_flac_file)
+{
+ audio_reader_flac<float> reader(
+ open_file_for_reading(KFR_FILEPATH(KFR_SRC_DIR "/tests/test-audio/sine.flac")));
+ CHECK(reader.format().channels == 2u);
+ CHECK(reader.format().type == audio_sample_type::i32);
+ CHECK(reader.format().samplerate == 44100);
+ univector<float> data(44100 * 2);
+ CHECK(reader.format().length == data.size() / 2);
+ size_t rd = reader.read(data.data(), data.size());
+ CHECK(rd == data.size());
+ CHECK(absmaxof(data - render(sin(counter() * 0.01f), data.size())) < 0.0001f);
+}
+#endif
+
+#ifndef KFR_DISABLE_MP3
+TEST(read_mp3_file)
+{
+ audio_reader_mp3<float> reader(
+ open_file_for_reading(KFR_FILEPATH(KFR_SRC_DIR "/tests/test-audio/sine.mp3")));
+ CHECK(reader.format().channels == 2u);
+ CHECK(reader.format().type == audio_sample_type::i16);
+ CHECK(reader.format().samplerate == 44100);
+ univector<float> data(44100 * 2);
+ CHECK(reader.format().length >= data.size() / 2);
+ size_t rd = reader.read(data.data(), data.size());
+ CHECK(rd == data.size());
+ data = data.slice(2402, 2 * 44100); // MP3 format delay
+ CHECK(absmaxof(data - render(sin(counter() * 0.01f), data.size())) < 0.005f);
+}
+#endif
+} // namespace kfr
diff --git a/tests/unit/math/asin_acos.cpp b/tests/unit/math/asin_acos.cpp
@@ -3,7 +3,7 @@
* Copyright (C) 2016-2023 Dan Cazarin
* See LICENSE.txt for details
*/
-#include "../../numeric_tests.hpp"
+#include "../numeric_tests.hpp"
#include <kfr/math/asin_acos.hpp>
diff --git a/tests/unit/math/atan.cpp b/tests/unit/math/atan.cpp
@@ -4,7 +4,7 @@
* See LICENSE.txt for details
*/
-#include "../../numeric_tests.hpp"
+#include "../numeric_tests.hpp"
#include <kfr/math/atan.hpp>
diff --git a/tests/unit/math/complex_math.cpp b/tests/unit/math/complex_math.cpp
@@ -0,0 +1,84 @@
+/**
+ * KFR (https://www.kfrlib.com)
+ * Copyright (C) 2016-2023 Dan Cazarin
+ * See LICENSE.txt for details
+ */
+
+#include <kfr/math/complex_math.hpp>
+
+namespace kfr
+{
+inline namespace CMT_ARCH_NAME
+{
+
+TEST(complex_math)
+{
+ const vec<c32, 1> a{ c32{ 1, 2 } };
+ const vec<c32, 1> b{ c32{ 3, 4 } };
+ CHECK(c32(vec<c32, 1>(2)[0]) == c32{ 2, 0 });
+ CHECK(a + b == make_vector(c32{ 4, 6 }));
+ CHECK(a - b == make_vector(c32{ -2, -2 }));
+ CHECK(a * b == make_vector(c32{ -5, 10 }));
+ CHECK(a * vec<c32, 1>(2) == make_vector(c32{ 2, 4 }));
+ CHECK(a * 2 == make_vector(c32{ 2, 4 }));
+ CHECK(a / b == make_vector(c32{ 0.44f, 0.08f }));
+ CHECK(-a == make_vector(c32{ -1, -2 }));
+
+ CHECK(real(a) == make_vector(1.f));
+ CHECK(imag(a) == make_vector(2.f));
+
+ CHECK(make_complex(5.f, 7) == c32{ 5.f, 7.f });
+ CHECK(make_complex(make_vector(5.f, 8.f), make_vector(7.f, 9.f)) ==
+ make_vector(c32{ 5.f, 7.f }, c32{ 8.f, 9.f }));
+
+ CHECK(cabs(c32{ 3.f, 4.f }) == 5.f);
+ CHECK(cabs(make_vector(c32{ 3.f, 4.f })) == make_vector(5.f));
+
+ CHECK(cabs(-3.f) == 3.f);
+ CHECK(cabs(make_vector(-3.f)) == make_vector(3.f));
+
+ CHECK(carg(c32{ +1.f, 0.f }) == 0.f);
+ CHECK(carg(c32{ 0.f, +1.f }) == c_pi<float> / 2);
+ CHECK(carg(c32{ 0.f, -1.f }) == -c_pi<float> / 2);
+ CHECK(carg(c32{ -1.f, 0.f }) == c_pi<float>);
+
+ testo::epsilon_scope<void> eps(5);
+
+ CHECK(csin(c32{ 1.f, 1.f }) == c32{ 1.2984575814159773f, 0.634963914784736f });
+ CHECK(ccos(c32{ 1.f, 1.f }) == c32{ 0.8337300251311489f, -0.9888977057628651f });
+ CHECK(csinh(c32{ 1.f, 1.f }) == c32{ 0.634963914784736f, 1.2984575814159773f });
+ CHECK(ccosh(c32{ 1.f, 1.f }) == c32{ 0.8337300251311489f, 0.9888977057628651f });
+
+ CHECK(clog(c32{ 1.f, 1.f }) == c32{ 0.34657359027997264f, 0.7853981633974483f });
+ CHECK(clog2(c32{ 1.f, 1.f }) == c32{ 0.5f, 1.1330900354567983f });
+ CHECK(clog10(c32{ 1.f, 1.f }) == c32{ 0.15051499783199057f, 0.3410940884604603f });
+
+ CHECK(cexp(c32{ 1.f, 1.f }) == c32{ 1.4686939399158849f, 2.2873552871788423f });
+ CHECK(cexp2(c32{ 1.f, 1.f }) == c32{ 1.5384778027279442f, 1.2779225526272695f });
+ CHECK(cexp10(c32{ 1.f, 1.f }) == c32{ -6.682015101903131f, 7.439803369574931f });
+
+#ifdef CMT_NATIVE_F64
+ CHECK(csin(c64{ 1.0, 1.0 }) == c64{ 1.2984575814159773, 0.634963914784736 });
+ CHECK(ccos(c64{ 1.0, 1.0 }) == c64{ 0.8337300251311489, -0.9888977057628651 });
+ CHECK(csinh(c64{ 1.0, 1.0 }) == c64{ 0.634963914784736, 1.2984575814159773 });
+ CHECK(ccosh(c64{ 1.0, 1.0 }) == c64{ 0.8337300251311489, 0.9888977057628651 });
+ CHECK(clog(c64{ 1.0, 1.0 }) == c64{ 0.34657359027997264, 0.7853981633974483 });
+ CHECK(cexp(c64{ 1.0, 1.0 }) == c64{ 1.4686939399158849, 2.2873552871788423 });
+#endif
+}
+
+TEST(complex_functions)
+{
+ CHECK(csqr(complex<f32>(4.f, 0.f)) == c32{ 16.f, 0.f });
+ CHECK(csqrt(complex<f32>(16.f, 0.f)) == c32{ 4.f, 0.f });
+
+ CHECK(csqr(complex<f32>(1.f, 4.f)) == c32{ -15.f, 8.f });
+
+ CHECK(csqrt(complex<f32>(15.f, 8.f)) == c32{ 4.f, 1.f });
+ CHECK(csqrt(complex<f32>(-15.f, 8.f)) == c32{ 1.f, 4.f });
+ CHECK(csqrt(complex<f32>(15.f, -8.f)) == c32{ 4.f, -1.f });
+ CHECK(csqrt(complex<f32>(-15.f, -8.f)) == c32{ 1.f, -4.f });
+}
+
+} // namespace CMT_ARCH_NAME
+} // namespace kfr
diff --git a/tests/unit/math/hyperbolic.cpp b/tests/unit/math/hyperbolic.cpp
@@ -4,7 +4,7 @@
* See LICENSE.txt for details
*/
-#include "../../numeric_tests.hpp"
+#include "../numeric_tests.hpp"
#include <kfr/math/hyperbolic.hpp>
diff --git a/tests/unit/math/log_exp.cpp b/tests/unit/math/log_exp.cpp
@@ -3,7 +3,7 @@
* Copyright (C) 2016-2023 Dan Cazarin
* See LICENSE.txt for details
*/
-#include "../../numeric_tests.hpp"
+#include "../numeric_tests.hpp"
#include <kfr/math/log_exp.hpp>
diff --git a/tests/unit/math/sin_cos.cpp b/tests/unit/math/sin_cos.cpp
@@ -3,7 +3,7 @@
* Copyright (C) 2016-2023 Dan Cazarin
* See LICENSE.txt for details
*/
-#include "../../numeric_tests.hpp"
+#include "../numeric_tests.hpp"
#include <kfr/math/sin_cos.hpp>
diff --git a/tests/unit/math/tan.cpp b/tests/unit/math/tan.cpp
@@ -3,7 +3,7 @@
* Copyright (C) 2016-2023 Dan Cazarin
* See LICENSE.txt for details
*/
-#include "../../numeric_tests.hpp"
+#include "../numeric_tests.hpp"
#include <kfr/math/tan.hpp>
diff --git a/tests/numeric_tests.hpp b/tests/unit/numeric_tests.hpp
diff --git a/tests/unit/simd/complex.cpp b/tests/unit/simd/complex.cpp
@@ -5,11 +5,13 @@
*/
#include <kfr/simd/complex.hpp>
+#include <kfr/simd/read_write.hpp>
namespace kfr
{
inline namespace CMT_ARCH_NAME
{
+
TEST(complex_convertible)
{
static_assert(std::is_convertible<float, complex<float>>::value, "");
@@ -35,5 +37,101 @@ TEST(complex_convertible)
CHECK(static_cast<vec<complex<double>, 2>>(vec<complex<float>, 2>{ c32{ 1.f, 2.f }, c32{ 1.f, 2.f } }) ==
vec<complex<double>, 2>{ c64{ 1., 2. }, c64{ 1., 2. } });
}
+
+TEST(complex_static_tests)
+{
+ static_assert(is_numeric<vec<complex<float>, 4>>, "");
+ static_assert(is_numeric_args<vec<complex<float>, 4>>, "");
+
+ static_assert(sizeof(vec<c32, 4>) == sizeof(vec<f32, 8>), "");
+ static_assert(vec<f32, 4>::size() == 4, "");
+ static_assert(vec<c32, 4>::size() == 4, "");
+ static_assert(vec<f32, 4>::scalar_size() == 4, "");
+ static_assert(vec<c32, 4>::scalar_size() == 8, "");
+ testo::assert_is_same<subtype<complex<i32>>, i32>();
+ testo::assert_is_same<vec<c32, 4>::value_type, c32>();
+ testo::assert_is_same<vec<c32, 4>::scalar_type, f32>();
+ testo::assert_is_same<vec<f32, 4>::value_type, f32>();
+ testo::assert_is_same<vec<f32, 4>::scalar_type, f32>();
+ testo::assert_is_same<vec<c32, 1>, decltype(make_vector(c32{ 0, 0 }))>();
+ testo::assert_is_same<vec<c32, 2>, decltype(make_vector(c32{ 0, 0 }, 4))>();
+ testo::assert_is_same<ftype<complex<i32>>, complex<f32>>();
+ testo::assert_is_same<ftype<complex<i64>>, complex<f64>>();
+ testo::assert_is_same<ftype<vec<complex<i32>, 4>>, vec<complex<f32>, 4>>();
+ testo::assert_is_same<ftype<vec<complex<i64>, 8>>, vec<complex<f64>, 8>>();
+
+ testo::assert_is_same<std::common_type_t<complex<int>, double>, complex<double>>();
+}
+
+TEST(complex_shuffle)
+{
+ const vec<c32, 2> a{ c32{ 0, 1 }, c32{ 2, 3 } };
+ CHECK(reverse(a) == make_vector(c32{ 2, 3 }, c32{ 0, 1 }));
+}
+
+TEST(complex_read_write)
+{
+ c32 buffer[8] = { c32{ 1, 2 }, c32{ 3, 4 }, c32{ 5, 6 }, c32{ 7, 8 },
+ c32{ 9, 10 }, c32{ 11, 12 }, c32{ 13, 14 }, c32{ 15, 16 } };
+
+ CHECK(read<4>(buffer) == make_vector(c32{ 1, 2 }, c32{ 3, 4 }, c32{ 5, 6 }, c32{ 7, 8 }));
+ CHECK(read<3>(buffer + 1) == make_vector(c32{ 3, 4 }, c32{ 5, 6 }, c32{ 7, 8 }));
+ write(buffer + 2, make_vector(c32{ 10, 11 }, c32{ 12, 13 }));
+ CHECK(read<4>(buffer) == make_vector(c32{ 1, 2 }, c32{ 3, 4 }, c32{ 10, 11 }, c32{ 12, 13 }));
+}
+
+TEST(complex_cast)
+{
+ const vec<f32, 4> v1 = bitcast<f32>(make_vector(c32{ 0, 1 }, c32{ 2, 3 }));
+ CHECK(v1.flatten()[0] == 0.f);
+ CHECK(v1.flatten()[1] == 1.f);
+ CHECK(v1.flatten()[2] == 2.f);
+ CHECK(v1.flatten()[3] == 3.f);
+
+ const vec<c32, 1> v2 = bitcast<c32>(make_vector(1.f, 2.f));
+ CHECK(v2.flatten()[0] == 1.f);
+ CHECK(v2.flatten()[1] == 2.f);
+
+ const vec<c32, 2> v3 = make_vector(1.f, 2.f);
+ CHECK(v3.flatten()[0] == 1.f);
+ CHECK(v3.flatten()[1] == 0.f);
+ CHECK(v3.flatten()[2] == 2.f);
+ CHECK(v3.flatten()[3] == 0.f);
+
+ const vec<c32, 2> v4 = make_vector(1, 2);
+ CHECK(v4.flatten()[0] == 1.f);
+ CHECK(v4.flatten()[1] == 0.f);
+ CHECK(v4.flatten()[2] == 2.f);
+ CHECK(v4.flatten()[3] == 0.f);
+
+ CHECK(zerovector<c32, 4>() == make_vector(c32{ 0, 0 }, c32{ 0, 0 }, c32{ 0, 0 }, c32{ 0, 0 }));
+ CHECK(enumerate<c32, 4>() == make_vector(c32{ 0, 0 }, c32{ 1, 0 }, c32{ 2, 0 }, c32{ 3, 0 }));
+}
+
+TEST(complex_vector)
+{
+ const vec<c32, 1> c32x1{ c32{ 0, 1 } };
+ CHECK(c32x1.flatten()[0] == 0.0f);
+ CHECK(c32x1.flatten()[1] == 1.0f);
+
+ const vec<c32, 2> c32x2{ c32{ 0, 1 }, c32{ 2, 3 } };
+ CHECK(c32x2.flatten()[0] == 0.0f);
+ CHECK(c32x2.flatten()[1] == 1.0f);
+ CHECK(c32x2.flatten()[2] == 2.0f);
+ CHECK(c32x2.flatten()[3] == 3.0f);
+
+ const vec<c32, 3> c32x3{ c32{ 0, 1 }, c32{ 2, 3 }, c32{ 4, 5 } };
+ CHECK(c32x3.flatten()[0] == 0.0f);
+ CHECK(c32x3.flatten()[1] == 1.0f);
+ CHECK(c32x3.flatten()[2] == 2.0f);
+ CHECK(c32x3.flatten()[3] == 3.0f);
+ CHECK(c32x3.flatten()[4] == 4.0f);
+ CHECK(c32x3.flatten()[5] == 5.0f);
+
+ const vec<c32, 1> c32s = 2;
+ CHECK(c32s.flatten()[0] == 2.f);
+ CHECK(c32s.flatten()[1] == 0.f);
+}
+
} // namespace CMT_ARCH_NAME
} // namespace kfr
diff --git a/tests/unit/simd/shuffle.cpp b/tests/unit/simd/shuffle.cpp
@@ -186,5 +186,84 @@ TEST(enumerate)
CHECK(enumerate(vec_shape<int, 8>{}, 3) == vec{ 0, 3, 6, 9, 12, 15, 18, 21 });
CHECK(enumerate(vec_shape<int, 7>{}, 3) == vec{ 0, 3, 6, 9, 12, 15, 18 });
}
+
+
+TEST(test_basic)
+{
+ // How to make a vector:
+
+ // * Use constructor
+ const vec<double, 4> first{ 1, 2.5, -infinity, 3.1415926 };
+ CHECK(first == vec<double, 4>{ 1, 2.5, -infinity, 3.1415926 });
+
+ // * Use make_vector function
+ const auto second = make_vector(-1, +1);
+ CHECK(second == vec<int, 2>{ -1, 1 });
+
+ // * Convert from vector of other type:
+ const vec<int, 4> int_vector{ 10, 20, 30, 40 };
+ const vec<double, 4> double_vector = cast<double>(int_vector);
+ CHECK(double_vector == vec<double, 4>{ 10, 20, 30, 40 });
+
+ // * Concat two vectors:
+ const vec<int, 1> left_part{ 1 };
+ const vec<int, 1> right_part{ 2 };
+ const vec<int, 2> pair{ left_part, right_part };
+ CHECK(pair == vec<int, 2>{ 1, 2 });
+
+ // * Same, but using make_vector and concat:
+ const vec<int, 2> pair2 = concat(make_vector(10), make_vector(20));
+ CHECK(pair2 == vec<int, 2>{ 10, 20 });
+
+ // * Repeat vector multiple times:
+ const vec<short, 8> repeated = repeat<4>(make_vector<short>(0, -1));
+ CHECK(repeated == vec<short, 8>{ 0, -1, 0, -1, 0, -1, 0, -1 });
+
+ // * Use enumerate to generate sequence of numbers:
+ const vec<int, 8> eight = enumerate<int, 8>();
+ CHECK(eight == vec<int, 8>{ 0, 1, 2, 3, 4, 5, 6, 7 });
+
+ // * Vectors can be of any length...
+ const vec<int, 1> one{ 42 };
+ const vec<int, 2> two = concat(one, make_vector(42));
+ CHECK(two == vec<int, 2>{ 42, 42 });
+
+ const vec<u8, 256> very_long_vector = repeat<64>(make_vector<u8>(1, 2, 4, 8));
+ CHECK(slice<0, 17>(very_long_vector) ==
+ vec<unsigned char, 17>{ 1, 2, 4, 8, 1, 2, 4, 8, 1, 2, 4, 8, 1, 2, 4, 8, 1 });
+
+ // * ...really any:
+ using big_vector = vec<i16, 107>;
+ big_vector v107 = enumerate<i16, 107>();
+ CHECK(hadd(v107) == static_cast<short>(5671));
+
+ using color = vec<u8, 3>;
+ const color green = cast<u8>(make_vector(0.0, 1.0, 0.0) * 255);
+ CHECK(green == vec<unsigned char, 3>{ 0, 255, 0 });
+
+ // Vectors support all standard operators:
+ const auto op1 = make_vector(0, 1, 10, 100);
+ const auto op2 = make_vector(20, 2, -2, 200);
+ const auto result = op1 * op2 - 4;
+ CHECK(result == vec<int, 4>{ -4, -2, -24, 19996 });
+
+ // * Transform vector:
+ const vec<int, 8> numbers1 = enumerate<int, 8>();
+ const vec<int, 8> numbers2 = enumerate<int, 8>() + 100;
+ CHECK(odd(numbers1) == vec<int, 4>{ 1, 3, 5, 7 });
+ CHECK(even(numbers2) == vec<int, 4>{ 100, 102, 104, 106 });
+
+ CHECK(subadd(pack(0, 1, 2, 3, 4, 5, 6, 7), pack(10, 10, 10, 10, 10, 10, 10, 10)) ==
+ pack(-10, 11, -8, 13, -6, 15, -4, 17));
+ CHECK(addsub(pack(0, 1, 2, 3, 4, 5, 6, 7), pack(10, 10, 10, 10, 10, 10, 10, 10)) ==
+ pack(10, -9, 12, -7, 14, -5, 16, -3));
+
+ CHECK(digitreverse4(pack(0.f, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)) ==
+ pack(0.f, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15));
+
+ CHECK(inrange(pack(1, 2, 3), 1, 3) == make_mask<int>(true, true, true));
+ CHECK(inrange(pack(1, 2, 3), 1, 2) == make_mask<int>(true, true, false));
+ CHECK(inrange(pack(1, 2, 3), 1, 1) == make_mask<int>(true, false, false));
+}
} // namespace CMT_ARCH_NAME
} // namespace kfr