#include "test.h" #include "fl/span.h" #include "fl/vector.h" #include "fl/array.h" using namespace fl; TEST_CASE("fl::span explicit conversions work correctly") { SUBCASE("fl::vector to fl::span conversions") { // Test const fl::vector -> fl::span fl::vector vec = {1, 2, 3, 4, 5}; // ✅ These explicit conversions should work fl::span const_span(vec); CHECK(const_span.size() == 5); CHECK(const_span[0] == 1); CHECK(const_span[4] == 5); // ✅ Mutable conversion should work fl::span mutable_span(vec); CHECK(mutable_span.size() == 5); mutable_span[0] = 10; CHECK(vec[0] == 10); // Verify it's a view, not a copy } SUBCASE("fl::array to fl::span conversions") { fl::array arr = {10, 20, 30, 40}; // ✅ These explicit conversions should work fl::span const_span(arr); CHECK(const_span.size() == 4); CHECK(const_span[0] == 10); CHECK(const_span[3] == 40); // ✅ Mutable conversion should work fl::span mutable_span(arr); CHECK(mutable_span.size() == 4); mutable_span[0] = 100; CHECK(arr[0] == 100); // Verify it's a view } SUBCASE("C-style array to fl::span conversions") { int c_array[] = {5, 10, 15, 20}; // ✅ These explicit conversions should work fl::span const_span(c_array); CHECK(const_span.size() == 4); CHECK(const_span[0] == 5); CHECK(const_span[3] == 20); // ✅ Mutable conversion should work fl::span mutable_span(c_array); CHECK(mutable_span.size() == 4); mutable_span[0] = 50; CHECK(c_array[0] == 50); // Verify it's a view } SUBCASE("const array to const span") { const int const_array[] = {100, 200, 300}; // ✅ Const array to const span should work fl::span const_span(const_array); CHECK(const_span.size() == 3); CHECK(const_span[0] == 100); CHECK(const_span[2] == 300); } } TEST_CASE("fl::span non-template function conversions work") { // These tests show that non-template functions CAN accept containers // via implicit conversion through our constructors auto process_const_span = [](fl::span data) -> int { int sum = 0; for (const auto& item : data) { sum += item; } return sum; }; auto modify_span = [](fl::span data) { for (auto& item : data) { item += 1; } }; SUBCASE("fl::vector implicit conversion to non-template function") { fl::vector vec = {1, 2, 3, 4, 5}; // ✅ This should work - implicit conversion to function parameter int result = process_const_span(vec); CHECK(result == 15); // ✅ Mutable function should work too modify_span(vec); CHECK(vec[0] == 2); CHECK(vec[4] == 6); } SUBCASE("fl::array implicit conversion to non-template function") { fl::array arr = {10, 20, 30}; // ✅ This should work int result = process_const_span(arr); CHECK(result == 60); // ✅ Mutable function should work modify_span(arr); CHECK(arr[0] == 11); CHECK(arr[2] == 31); } SUBCASE("C-style array implicit conversion to non-template function") { int c_array[] = {7, 14, 21}; // ✅ This should work int result = process_const_span(c_array); CHECK(result == 42); // ✅ Mutable function should work modify_span(c_array); CHECK(c_array[0] == 8); CHECK(c_array[2] == 22); } } TEST_CASE("fl::span limitations - template argument deduction") { // This test documents what DOESN'T work due to C++ language limitations SUBCASE("template functions cannot deduce from implicit conversions") { fl::vector vec = {1, 2, 3}; // ❌ This would NOT work (commented out to avoid compilation errors): // template void template_func(fl::span data) { ... } // template_func(vec); // Error: template argument deduction fails // ✅ This DOES work with explicit template parameters: auto template_func = [](fl::span data) -> int { int sum = 0; for (const auto& item : data) { sum += static_cast(item); } return sum; }; int result = template_func(fl::span(vec)); // Explicit conversion CHECK(result == 6); // 📝 This is correct C++ behavior - template argument deduction only // considers exact type matches, not constructor conversions } }