LCOV - code coverage report
Current view: top level - elsa/core/tests - test_DataHandlerMap.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 699 699 100.0 %
Date: 2022-08-25 03:05:39 Functions: 40 40 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file test_DataHandlerMap.cpp
       3             :  *
       4             :  * @brief Tests for DataHandlerMaps - DataHandlerMapCPU and DataHandlerMapGPU
       5             :  *
       6             :  * @author David Frank - initial code
       7             :  * @author Tobias Lasser - rewrite and code coverage
       8             :  * @author Jens Petit - refactoring into TEMPLATE_PRODUCT_TEST_CASE
       9             :  */
      10             : 
      11             : #include "doctest/doctest.h"
      12             : #include "DataHandlerMapCPU.h"
      13             : #include "DataHandlerCPU.h"
      14             : #include "testHelpers.h"
      15             : 
      16             : #ifdef ELSA_CUDA_VECTOR
      17             : #include "DataHandlerGPU.h"
      18             : #include "DataHandlerMapGPU.h"
      19             : #endif
      20             : 
      21             : using namespace elsa;
      22             : using namespace elsa;
      23             : 
      24             : // for testing the copy-on-write mechanism
      25             : template <typename data_t>
      26             : long elsa::useCount(const DataHandlerCPU<data_t>& dh)
      27         306 : {
      28         306 :     return dh._data.use_count();
      29         306 : }
      30             : 
      31             : #ifdef ELSA_CUDA_VECTOR
      32             : // for testing the copy-on-write mechanism
      33             : template <typename data_t>
      34             : long elsa::useCount(const DataHandlerGPU<data_t>& dh)
      35             : {
      36             :     return dh._data.use_count();
      37             : }
      38             : #endif
      39             : 
      40             : // Helper to provide the correct map based on the handler type
      41             : template <typename Handler>
      42             : struct MapToHandler {
      43             :     using map =
      44             :         std::conditional_t<std::is_same_v<DataHandlerCPU<typename Handler::value_type>, Handler>,
      45             :                            DataHandlerMapCPU<typename Handler::value_type>,
      46             : #ifdef ELSA_CUDA_VECTOR
      47             :                            DataHandlerMapGPU<typename Handler::value_type>>;
      48             : #else
      49             :                            DataHandlerMapCPU<typename Handler::value_type>>;
      50             : #endif
      51             : };
      52             : 
      53             : using CPUTypeTuple =
      54             :     std::tuple<DataHandlerCPU<float>, DataHandlerCPU<double>, DataHandlerCPU<complex<float>>,
      55             :                DataHandlerCPU<complex<double>>, DataHandlerCPU<index_t>>;
      56             : 
      57             : TYPE_TO_STRING(DataHandlerCPU<float>);
      58             : TYPE_TO_STRING(DataHandlerCPU<double>);
      59             : TYPE_TO_STRING(DataHandlerCPU<index_t>);
      60             : TYPE_TO_STRING(DataHandlerCPU<complex<float>>);
      61             : TYPE_TO_STRING(DataHandlerCPU<complex<double>>);
      62             : 
      63             : #ifdef ELSA_CUDA_VECTOR
      64             : using GPUTypeTuple =
      65             :     std::tuple<DataHandlerGPU<float>, DataHandlerGPU<double>, DataHandlerGPU<complex<float>>,
      66             :                DataHandlerGPU<complex<double>>, DataHandlerGPU<index_t>>;
      67             : 
      68             : TYPE_TO_STRING(DataHandlerGPU<float>);
      69             : TYPE_TO_STRING(DataHandlerGPU<double>);
      70             : TYPE_TO_STRING(DataHandlerGPU<index_t>);
      71             : TYPE_TO_STRING(DataHandlerGPU<complex<float>>);
      72             : TYPE_TO_STRING(DataHandlerGPU<complex<double>>);
      73             : #endif
      74             : 
      75             : TEST_SUITE_BEGIN("core");
      76             : 
      77             : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing construction", TestType,
      78             :                           datahandlermap_construction)
      79          10 : {
      80          10 :     using data_t = typename TestType::value_type;
      81             : 
      82          10 :     GIVEN("a certain size")
      83          10 :     {
      84          10 :         index_t size = 314;
      85             : 
      86          10 :         WHEN("constructing with a given vector")
      87          10 :         {
      88           5 :             Vector_t<data_t> randVec{size * 2};
      89           5 :             randVec.setRandom();
      90           5 :             const TestType dh{randVec};
      91           5 :             const auto dhMap = dh.getBlock(size / 3, size / 3);
      92             : 
      93           5 :             THEN("the DataHandlerMap references the actual vector")
      94           5 :             {
      95           5 :                 REQUIRE_EQ(dhMap->getSize(), size / 3);
      96             : 
      97         525 :                 for (index_t i = 0; i < size / 3; ++i)
      98           5 :                     REQUIRE_EQ(&(*dhMap)[i], &dh[i + size / 3]);
      99           5 :             }
     100           5 :         }
     101             : 
     102          10 :         WHEN("copy constructing")
     103          10 :         {
     104           5 :             Vector_t<data_t> randVec{size * 2};
     105           5 :             randVec.setRandom();
     106           5 :             const TestType dh{randVec};
     107           5 :             const auto dhMap = dh.getBlock(size / 3, size / 3);
     108             : 
     109           5 :             const auto& dhMapRef = static_cast<const typename MapToHandler<TestType>::map&>(*dhMap);
     110             : 
     111           5 :             const auto dhMapCopy = dhMapRef;
     112             : 
     113           5 :             THEN("the copy references the actual vector")
     114           5 :             {
     115           5 :                 REQUIRE_EQ(dhMap->getSize(), size / 3);
     116             : 
     117         525 :                 for (index_t i = 0; i < size / 3; ++i)
     118           5 :                     REQUIRE_EQ(&dhMapCopy[i], &dh[i + size / 3]);
     119           5 :             }
     120           5 :         }
     121          10 :     }
     122          10 : }
     123             : 
     124             : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing equality operator", TestType,
     125             :                           datahandlermap_eqoperator)
     126          20 : {
     127          20 :     using data_t = typename TestType::value_type;
     128             : 
     129          20 :     GIVEN("some DataHandlerMap")
     130          20 :     {
     131          20 :         index_t size = 314;
     132          20 :         Vector_t<data_t> randVec{size};
     133          20 :         randVec.setRandom();
     134             : 
     135          20 :         const TestType realDh{randVec};
     136          20 :         const auto dhPtr = realDh.getBlock(0, size);
     137          20 :         const auto& dh = *dhPtr;
     138             : 
     139          20 :         WHEN("comparing to a handler with a different size")
     140          20 :         {
     141           5 :             const TestType dh2{size + 1};
     142           5 :             THEN("the result is false")
     143           5 :             {
     144           5 :                 REQUIRE_FALSE(dh == dh2);
     145           5 :                 REQUIRE_FALSE(dh == *dh2.getBlock(0, size + 1));
     146           5 :             }
     147           5 :         }
     148             : 
     149          20 :         WHEN("comparing to a shallow copy or view of the handler")
     150          20 :         {
     151           5 :             const auto dh2 = realDh;
     152           5 :             THEN("the result is true")
     153           5 :             {
     154           5 :                 REQUIRE_EQ(dh, dh2);
     155           5 :                 REQUIRE_EQ(dh, *realDh.getBlock(0, size));
     156           5 :             }
     157           5 :         }
     158             : 
     159          20 :         WHEN("comparing to a deep copy or a view of the deep copy")
     160          20 :         {
     161           5 :             const TestType dh2{randVec};
     162           5 :             THEN("the result is true")
     163           5 :             {
     164           5 :                 REQUIRE_EQ(dh, dh2);
     165           5 :                 REQUIRE_EQ(dh, *dh2.getBlock(0, size));
     166           5 :             }
     167           5 :         }
     168             : 
     169          20 :         WHEN("comparing to a handler or map with different data")
     170          20 :         {
     171           5 :             randVec[0] += 1;
     172           5 :             const TestType dh2{randVec};
     173           5 :             THEN("the result is false")
     174           5 :             {
     175           5 :                 REQUIRE_FALSE(dh == dh2);
     176           5 :                 REQUIRE_FALSE(dh == *dh2.getBlock(0, size));
     177           5 :             }
     178           5 :         }
     179          20 :     }
     180          20 : }
     181             : 
     182             : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing assignment to DataHandlerMap", TestType,
     183             :                           datahandlermap_assign)
     184         140 : {
     185         140 :     using data_t = typename TestType::value_type;
     186         140 :     using MapType = typename MapToHandler<TestType>::map;
     187             : 
     188         140 :     const index_t size = 314;
     189             : 
     190             :     // Constructo DataHandler with 2x the size
     191         140 :     TestType dh{2 * size};
     192         140 :     dh = 0;
     193             : 
     194             :     // Create map to the first half of the DH
     195         140 :     const auto dhMap = dh.getBlock(0, size);
     196             : 
     197         140 :     REQUIRE_EQ(dhMap->getSize(), size);
     198         140 :     REQUIRE_EQ(dhMap->getSize(), dh.getSize() / 2);
     199             : 
     200         140 :     GIVEN("A reference to the concrete DataHandlerMap (TestType)")
     201         140 :     {
     202          10 :         auto& dhMapRef = static_cast<typename MapToHandler<TestType>::map&>(*dhMap);
     203             : 
     204          10 :         WHEN("Copy-assigning a DataHandler with the same size to the map")
     205          10 :         {
     206           5 :             Vector_t<data_t> randVec{size};
     207           5 :             randVec.setRandom();
     208           5 :             const TestType dh2{randVec};
     209           5 :             const auto dh2Map = dh2.getBlock(0, size);
     210           5 :             const auto& dh2MapRef = static_cast<const MapType&>(*dh2Map);
     211             : 
     212           5 :             dhMapRef = dh2MapRef;
     213             : 
     214           5 :             THEN("a deep copy is performed")
     215           5 :             {
     216           5 :                 REQUIRE_EQ(useCount(dh), 1);
     217           5 :                 REQUIRE_EQ(useCount(dh2), 1);
     218             : 
     219           5 :                 REQUIRE_EQ(dhMapRef, dh2);
     220           5 :                 REQUIRE_UNARY(isCwiseApprox(dhMapRef, dh2MapRef));
     221             : 
     222           5 :                 REQUIRE_EQ(&dh[0], &dhMapRef[0]);
     223           5 :                 REQUIRE_NE(&dh[0], &dh2MapRef[0]);
     224             : 
     225             :                 // Changing the original DataHandler, doesn't change the new one
     226           5 :                 dh[0] *= 4;
     227             : 
     228           5 :                 THEN("Changing the original DataHandler doesn't affect the new one")
     229           5 :                 {
     230           5 :                     REQUIRE_UNARY(checkApproxEq(dh[0], dhMapRef[0]));
     231           5 :                     REQUIRE_UNARY(checkApproxNe(dh[0], dh2[0]));
     232           5 :                     REQUIRE_UNARY(checkApproxNe(dh[0], dh2MapRef[0]));
     233           5 :                 }
     234           5 :             }
     235           5 :         }
     236             : 
     237          10 :         WHEN("Copy-assigning a DataHandler with a different size to the map")
     238          10 :         {
     239           5 :             const TestType dh2{3 * size};
     240           5 :             const auto dh2Map = dh2.getBlock(0, 3 * size);
     241           5 :             const auto& dh2MapRef =
     242           5 :                 static_cast<const typename MapToHandler<TestType>::map&>(*dh2Map);
     243             : 
     244           5 :             THEN("the assignment throws") { REQUIRE_THROWS(dhMapRef = dh2MapRef); }
     245           5 :         }
     246          10 :     }
     247             : 
     248         140 :     GIVEN("Given the base pointer to the map")
     249         140 :     {
     250          60 :         Vector_t<data_t> randVec{size};
     251          60 :         randVec.setRandom();
     252          60 :         const std::unique_ptr<const DataHandler<data_t>> dh2Ptr =
     253          60 :             std::make_unique<const TestType>(randVec);
     254             : 
     255          60 :         WHEN("Copy-assigning a DataHandler base pointer of the same size")
     256          60 :         {
     257             :             // TODO: why do we need dhCopy?
     258           5 :             const auto dhCopy = dh;
     259           5 :             *dhMap = *dh2Ptr;
     260           5 :             THEN("a deep copy is performed")
     261           5 :             {
     262           5 :                 REQUIRE_EQ(useCount(dh), 1);
     263           5 :                 REQUIRE_EQ(useCount(dhCopy), 1);
     264             : 
     265        1575 :                 for (index_t i = 0; i < size; i++)
     266           5 :                     REQUIRE_EQ(dh[i], (*dh2Ptr)[i]);
     267             : 
     268           5 :                 REQUIRE_EQ(*dhMap, *dh2Ptr);
     269           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     270             : 
     271             :                 // Changing the original DataHandler, doesn't change the new one
     272           5 :                 dh[0] *= 2;
     273             : 
     274           5 :                 THEN("Changing the original DataHandler doesn't affect the new one")
     275           5 :                 {
     276           5 :                     REQUIRE_UNARY(checkApproxEq((*dhMap)[0], dh[0]));
     277           5 :                     REQUIRE_UNARY(checkApproxNe((*dhMap)[0], (*dh2Ptr)[0]));
     278           5 :                 }
     279           5 :             }
     280           5 :         }
     281             : 
     282          60 :         WHEN("Copy-assigning a DataHandler base pointer of a different size")
     283          60 :         {
     284           5 :             const std::unique_ptr<DataHandler<data_t>> bigDh = std::make_unique<TestType>(2 * size);
     285           5 :             THEN("The assigning throws") { REQUIRE_THROWS(*dhMap = *bigDh); }
     286           5 :         }
     287             : 
     288          60 :         WHEN("Copy-assigning a block of a DataHandlerMap though the base pointer")
     289          60 :         {
     290          10 :             const auto dhCopy = dh;
     291          10 :             Vector_t<data_t> randVec{2 * size};
     292          10 :             randVec.setRandom();
     293             : 
     294          10 :             const TestType dh2{randVec};
     295          10 :             const auto dh2Map = dh2.getBlock(0, size);
     296             : 
     297          10 :             WHEN("The sizes of the block and DataHandler are the same")
     298          10 :             {
     299           5 :                 *dhMap = *dh2Map;
     300           5 :                 THEN("a deep copy is performed")
     301           5 :                 {
     302           5 :                     REQUIRE_EQ(useCount(dh), 1);
     303           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     304             : 
     305        1575 :                     for (index_t i = 0; i < size; i++)
     306           5 :                         REQUIRE_EQ(dh[i], dh2[i]);
     307             : 
     308           5 :                     REQUIRE_EQ(*dhMap, *dh2Map);
     309           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     310           5 :                 }
     311           5 :             }
     312             : 
     313          10 :             WHEN("The sizes of the block and DataHandler are different")
     314          10 :             {
     315           5 :                 const auto bigDh = dh2.getBlock(0, 2 * size);
     316           5 :                 THEN("Assignment throws") { REQUIRE_THROWS(*dhMap = *bigDh); }
     317           5 :             }
     318          10 :         }
     319             : 
     320          60 :         WHEN("Copy-assigning a full DataHandlerMap (aka a view) through the base pointers")
     321          60 :         {
     322          10 :             const auto dhCopy = dh;
     323          10 :             Vector_t<data_t> randVec{size};
     324          10 :             randVec.setRandom();
     325             : 
     326          10 :             const TestType dh2{randVec};
     327          10 :             const auto dh2Map = dh2.getBlock(0, size);
     328             : 
     329          10 :             WHEN("The sizes are the same")
     330          10 :             {
     331           5 :                 *dhMap = *dh2Map;
     332           5 :                 THEN("a deep copy is performed")
     333           5 :                 {
     334           5 :                     REQUIRE_EQ(useCount(dh), 1);
     335           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     336             : 
     337        1575 :                     for (index_t i = 0; i < size; i++)
     338           5 :                         REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     339             : 
     340           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     341           5 :                 }
     342           5 :             }
     343             : 
     344          10 :             WHEN("The sizes are different")
     345          10 :             {
     346           5 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     347           5 :                     std::make_unique<TestType>(2 * size);
     348           5 :                 THEN("sizes must match") { REQUIRE_THROWS(*dhMap = *bigDh->getBlock(0, 2 * size)); }
     349           5 :             }
     350          10 :         }
     351             : 
     352          60 :         WHEN("\"move\" assigning a DataHandlerMap through the base pointer")
     353          60 :         {
     354          10 :             Vector_t<data_t> randVec{size};
     355          10 :             randVec.setRandom();
     356          10 :             const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
     357             : 
     358          10 :             WHEN("The sizes are the same")
     359          10 :             {
     360           5 :                 const auto dhCopy = dh;
     361             : 
     362           5 :                 *dhMap = std::move(*dh2Ptr);
     363           5 :                 THEN("a deep copy is performed")
     364           5 :                 {
     365           5 :                     REQUIRE_EQ(useCount(dh), 1);
     366           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     367             : 
     368        1575 :                     for (index_t i = 0; i < size; i++)
     369           5 :                         REQUIRE_UNARY(checkApproxEq(dh[i], (*dh2Ptr)[i]));
     370             : 
     371           5 :                     REQUIRE_EQ(*dhMap, *dh2Ptr);
     372           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     373           5 :                 }
     374           5 :             }
     375             : 
     376          10 :             WHEN("The sizes are different")
     377          10 :             {
     378           5 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     379           5 :                     std::make_unique<TestType>(2 * size);
     380           5 :                 THEN("the assignment throws") { REQUIRE_THROWS(*dhMap = std::move(*bigDh)); }
     381           5 :             }
     382          10 :         }
     383             : 
     384          60 :         WHEN("\"move\" assigning a block of a  DataHandlerMap through the base pointer")
     385          60 :         {
     386          10 :             const auto dhCopy = dh;
     387          10 :             Vector_t<data_t> randVec{2 * size};
     388          10 :             randVec.setRandom();
     389          10 :             TestType dh2{randVec};
     390          10 :             const auto dh2Map = dh2.getBlock(0, size);
     391             : 
     392          10 :             WHEN("The sizes are the same")
     393          10 :             {
     394           5 :                 *dhMap = std::move(*dh2Map);
     395           5 :                 THEN("a deep copy is performed")
     396           5 :                 {
     397           5 :                     REQUIRE_EQ(useCount(dh), 1);
     398           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     399             : 
     400        1575 :                     for (index_t i = 0; i < size; i++)
     401           5 :                         REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     402             : 
     403           5 :                     REQUIRE_EQ(*dhMap, *dh2Map);
     404           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     405           5 :                 }
     406           5 :             }
     407             : 
     408          10 :             WHEN("The sizes are different")
     409          10 :             {
     410           5 :                 const auto bigDh = dh2.getBlock(0, 2 * size);
     411           5 :                 THEN("the assignment throws") { REQUIRE_THROWS(*dhMap = std::move(*bigDh)); }
     412           5 :             }
     413          10 :         }
     414             : 
     415          60 :         WHEN("\"move\" assigning a full DataHandlerMap (aka a view) through the base pointer")
     416          60 :         {
     417          10 :             const auto dhCopy = dh;
     418          10 :             Vector_t<data_t> randVec{size};
     419          10 :             randVec.setRandom();
     420          10 :             TestType dh2{randVec};
     421          10 :             const auto dh2Map = dh2.getBlock(0, size);
     422             : 
     423          10 :             WHEN("The sizes are the same")
     424          10 :             {
     425           5 :                 *dhMap = std::move(*dh2Map);
     426           5 :                 THEN("a deep copy is performed")
     427           5 :                 {
     428           5 :                     REQUIRE_EQ(useCount(dh), 1);
     429           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     430             : 
     431        1575 :                     for (index_t i = 0; i < size; i++)
     432           5 :                         REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     433             : 
     434           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     435           5 :                 }
     436           5 :             }
     437             : 
     438          10 :             WHEN("The sizes are different")
     439          10 :             {
     440           5 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     441           5 :                     std::make_unique<TestType>(2 * size);
     442           5 :                 THEN("the assignment throws") { REQUIRE_THROWS(*dhMap = std::move(*bigDh)); }
     443           5 :             }
     444          10 :         }
     445          60 :     }
     446             : 
     447         140 :     GIVEN("A reference to a full concrete DataHandlerMap (aka a view)")
     448         140 :     {
     449          10 :         index_t size = 314;
     450          10 :         TestType dh{size};
     451          10 :         const auto dhMap = dh.getBlock(0, size);
     452          10 :         auto& dhMapRef = static_cast<MapType&>(*dhMap);
     453             : 
     454          10 :         WHEN("Copy-assigning an equally sized view to the map")
     455          10 :         {
     456           5 :             const TestType dh2{size};
     457           5 :             const auto dh2Map = dh2.getBlock(0, size);
     458           5 :             const auto& dh2MapRef = static_cast<const MapType&>(*dh2Map);
     459           5 :             dhMapRef = dh2MapRef;
     460             : 
     461           5 :             THEN("a shallow copy is performed")
     462           5 :             {
     463           5 :                 REQUIRE_EQ(useCount(dh), 2);
     464           5 :                 REQUIRE_EQ(dh, dh2);
     465           5 :                 REQUIRE_EQ(dh, dhMapRef);
     466           5 :                 REQUIRE_EQ(dh, dh2MapRef);
     467           5 :                 dhMapRef[0] = 1;
     468           5 :                 REQUIRE_EQ(&dhMapRef[0], &dh[0]);
     469           5 :                 REQUIRE_NE(&dhMapRef[0], &dh2MapRef[0]);
     470           5 :             }
     471           5 :         }
     472          10 :         WHEN("Copy-assigning an differently sized view to the map")
     473          10 :         {
     474           5 :             const TestType dh2{3 * size};
     475           5 :             const auto dh2Map = dh2.getBlock(0, 3 * size);
     476           5 :             const auto& dh2MapRef = static_cast<const MapType&>(*dh2Map);
     477             : 
     478           5 :             THEN("The assigning throws") { REQUIRE_THROWS(dhMapRef = dh2MapRef); }
     479           5 :         }
     480          10 :     }
     481             : 
     482         140 :     GIVEN("a full DataHandlerMap (aka a view)")
     483         140 :     {
     484          60 :         index_t size = 314;
     485          60 :         TestType dh{size};
     486          60 :         const auto dhMap = dh.getBlock(0, size);
     487             : 
     488          60 :         WHEN("copy assigning a DataHandlerMap through base pointers")
     489          60 :         {
     490          10 :             Vector_t<data_t> randVec{size};
     491          10 :             randVec.setRandom();
     492          10 :             const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
     493             : 
     494          10 :             THEN("sizes must match")
     495          10 :             {
     496           5 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     497           5 :                     std::make_unique<TestType>(2 * size);
     498           5 :                 REQUIRE_THROWS(*dhMap = *bigDh);
     499           5 :             }
     500             : 
     501          10 :             *dhMap = *dh2Ptr;
     502          10 :             THEN("a shallow copy is performed")
     503          10 :             {
     504           5 :                 REQUIRE_EQ(useCount(dh), 2);
     505           5 :                 REQUIRE_EQ(dh, *dh2Ptr);
     506           5 :                 REQUIRE_EQ(*dhMap, *dh2Ptr);
     507           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     508           5 :                 dh[0] = 1;
     509           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     510           5 :                 REQUIRE_NE(&dh[0], &(*dh2Ptr)[0]);
     511           5 :             }
     512          10 :         }
     513             : 
     514          60 :         WHEN("copy assigning a partial DataHandlerMap through base pointers")
     515          60 :         {
     516          10 :             const auto dhCopy = dh;
     517          10 :             Vector_t<data_t> randVec{2 * size};
     518          10 :             randVec.setRandom();
     519          10 :             const TestType dh2{randVec};
     520          10 :             const auto dh2Map = dh2.getBlock(0, size);
     521             : 
     522          10 :             THEN("sizes must match")
     523          10 :             {
     524           5 :                 const auto bigDh = dh2.getBlock(0, 2 * size);
     525           5 :                 REQUIRE_THROWS(*dhMap = *bigDh);
     526           5 :             }
     527             : 
     528          10 :             *dhMap = *dh2Map;
     529          10 :             THEN("a deep copy is performed")
     530          10 :             {
     531           5 :                 REQUIRE_EQ(useCount(dh), 1);
     532           5 :                 REQUIRE_EQ(useCount(dhCopy), 1);
     533             : 
     534        1575 :                 for (index_t i = 0; i < size; i++)
     535           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     536             : 
     537           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     538           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     539           5 :             }
     540          10 :         }
     541             : 
     542          60 :         WHEN("copy assigning a full DataHandlerMap (aka a view) through base pointers")
     543          60 :         {
     544          10 :             Vector_t<data_t> randVec{size};
     545          10 :             randVec.setRandom();
     546          10 :             const TestType dh2{randVec};
     547          10 :             const auto dh2Map = dh2.getBlock(0, size);
     548             : 
     549          10 :             THEN("sizes must match")
     550          10 :             {
     551           5 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     552           5 :                     std::make_unique<TestType>(2 * size);
     553           5 :                 REQUIRE_THROWS(*dhMap = *bigDh->getBlock(0, 2 * size));
     554           5 :             }
     555             : 
     556          10 :             *dhMap = *dh2Map;
     557          10 :             THEN("a shallow copy is performed")
     558          10 :             {
     559           5 :                 REQUIRE_EQ(useCount(dh), 2);
     560           5 :                 REQUIRE_EQ(dh, dh2);
     561           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     562           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     563           5 :                 dh[0] = 1;
     564           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     565           5 :                 REQUIRE_NE(&dh[0], &dh2[0]);
     566           5 :             }
     567          10 :         }
     568             : 
     569          60 :         WHEN("\"move\" assigning a DataHandler through base pointers")
     570          60 :         {
     571          10 :             Vector_t<data_t> randVec{size};
     572          10 :             randVec.setRandom();
     573          10 :             const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
     574             : 
     575          10 :             THEN("sizes must match")
     576          10 :             {
     577           5 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     578           5 :                     std::make_unique<TestType>(2 * size);
     579           5 :                 REQUIRE_THROWS(*dhMap = std::move(*bigDh));
     580           5 :             }
     581             : 
     582          10 :             *dhMap = std::move(*dh2Ptr);
     583          10 :             THEN("a shallow copy is performed")
     584          10 :             {
     585           5 :                 REQUIRE_EQ(useCount(dh), 2);
     586           5 :                 REQUIRE_EQ(dh, *dh2Ptr);
     587           5 :                 REQUIRE_EQ(*dhMap, *dh2Ptr);
     588           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     589           5 :                 dh[0] = 1;
     590           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     591           5 :                 REQUIRE_NE(&dh[0], &(*dh2Ptr)[0]);
     592           5 :             }
     593          10 :         }
     594             : 
     595          60 :         WHEN("\"move\" assigning a partial DataHandlerMap through base pointers")
     596          60 :         {
     597          10 :             const auto dhCopy = dh;
     598          10 :             Vector_t<data_t> randVec{2 * size};
     599          10 :             randVec.setRandom();
     600          10 :             TestType dh2{randVec};
     601          10 :             const auto dh2Map = dh2.getBlock(0, size);
     602             : 
     603          10 :             THEN("sizes must match")
     604          10 :             {
     605           5 :                 const auto bigDh = dh2.getBlock(0, 2 * size);
     606           5 :                 REQUIRE_THROWS(*dhMap = std::move(*bigDh));
     607           5 :             }
     608             : 
     609          10 :             *dhMap = std::move(*dh2Map);
     610          10 :             THEN("a deep copy is performed")
     611          10 :             {
     612           5 :                 REQUIRE_EQ(useCount(dh), 1);
     613           5 :                 REQUIRE_EQ(useCount(dhCopy), 1);
     614             : 
     615        1575 :                 for (index_t i = 0; i < size; i++)
     616           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     617             : 
     618           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     619           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     620           5 :             }
     621          10 :         }
     622             : 
     623          60 :         WHEN("\"move\" assigning a full DataHandlerMap (aka a view) through base pointers")
     624          60 :         {
     625          10 :             Vector_t<data_t> randVec{size};
     626          10 :             randVec.setRandom();
     627          10 :             TestType dh2{randVec};
     628          10 :             const auto dh2Map = dh2.getBlock(0, size);
     629             : 
     630          10 :             THEN("sizes must match")
     631          10 :             {
     632           5 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     633           5 :                     std::make_unique<TestType>(2 * size);
     634           5 :                 REQUIRE_THROWS(*dhMap = std::move(*bigDh->getBlock(0, 2 * size)));
     635           5 :             }
     636             : 
     637          10 :             *dhMap = std::move(*dh2Map);
     638          10 :             THEN("a shallow copy is performed")
     639          10 :             {
     640           5 :                 REQUIRE_EQ(useCount(dh), 2);
     641           5 :                 REQUIRE_EQ(dh, dh2);
     642           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     643           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     644           5 :                 dh[0] = 1;
     645           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     646           5 :                 REQUIRE_NE(&dh[0], &dh2[0]);
     647           5 :             }
     648          10 :         }
     649          60 :     }
     650         140 : }
     651             : 
     652             : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing clone()", TestType, datahandlermap_clone)
     653          10 : {
     654          10 :     using data_t = typename TestType::value_type;
     655             : 
     656          10 :     GIVEN("a full DataHandlerMap (aka a view)")
     657          10 :     {
     658           5 :         index_t size = 728;
     659           5 :         Vector_t<data_t> dataVec(size);
     660           5 :         dataVec.setRandom();
     661           5 :         TestType realDh(dataVec);
     662           5 :         auto dhPtr = realDh.getBlock(0, size);
     663           5 :         auto& dh = *dhPtr;
     664             : 
     665           5 :         WHEN("cloning")
     666           5 :         {
     667           5 :             auto dhClone = dh.clone();
     668             : 
     669           5 :             THEN("a shallow copy is produced")
     670           5 :             {
     671           5 :                 REQUIRE_NE(dhClone.get(), &dh);
     672             : 
     673           5 :                 REQUIRE_EQ(dhClone->getSize(), dh.getSize());
     674             : 
     675           5 :                 REQUIRE_EQ(useCount(realDh), 2);
     676             : 
     677           5 :                 REQUIRE_EQ(*dhClone, dh);
     678             : 
     679           5 :                 dh[0] = 1;
     680           5 :                 REQUIRE_NE(*dhClone, dh);
     681           5 :             }
     682           5 :         }
     683           5 :     }
     684             : 
     685          10 :     GIVEN("a partial DataHandlerMap")
     686          10 :     {
     687           5 :         index_t size = 728;
     688           5 :         Vector_t<data_t> dataVec(size);
     689           5 :         dataVec.setRandom();
     690           5 :         TestType realDh(dataVec);
     691           5 :         auto dhPtr = realDh.getBlock(0, size / 2);
     692           5 :         auto& dh = *dhPtr;
     693             : 
     694           5 :         WHEN("a deep copy is produced")
     695           5 :         {
     696           5 :             auto dhClone = dh.clone();
     697             : 
     698           5 :             THEN("everything matches")
     699           5 :             {
     700           5 :                 REQUIRE_NE(dhClone.get(), &dh);
     701             : 
     702           5 :                 REQUIRE_EQ(dhClone->getSize(), dh.getSize());
     703             : 
     704           5 :                 REQUIRE_EQ(useCount(realDh), 1);
     705             : 
     706           5 :                 REQUIRE_EQ(dh, *dhClone);
     707           5 :             }
     708           5 :         }
     709           5 :     }
     710          10 : }
     711             : 
     712             : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing the reduction operations", TestType,
     713             :                           datahandlermap_reduction)
     714          10 : {
     715          10 :     using data_t = typename TestType::value_type;
     716             : 
     717          10 :     GIVEN("some DataHandlerMap")
     718          10 :     {
     719          10 :         index_t size = 284;
     720             : 
     721          10 :         WHEN("putting in some random data")
     722          10 :         {
     723          10 :             auto randVec = generateRandomMatrix<data_t>(size * 2);
     724          10 :             TestType realDh(randVec);
     725          10 :             auto dhPtr = realDh.getBlock(size / 3, size);
     726          10 :             auto& dh = *dhPtr;
     727             : 
     728          10 :             THEN("the reductions work as expected")
     729          10 :             {
     730           5 :                 REQUIRE_UNARY(checkApproxEq(dh.sum(), randVec.middleRows(size / 3, size).sum()));
     731           5 :                 REQUIRE_EQ(dh.l0PseudoNorm(),
     732           5 :                            (randVec.middleRows(size / 3, size).array().cwiseAbs()
     733           5 :                             >= std::numeric_limits<GetFloatingPointType_t<data_t>>::epsilon())
     734           5 :                                .count());
     735           5 :                 REQUIRE_UNARY(checkApproxEq(
     736           5 :                     dh.l1Norm(), randVec.middleRows(size / 3, size).array().abs().sum()));
     737           5 :                 REQUIRE_UNARY(checkApproxEq(
     738           5 :                     dh.lInfNorm(), randVec.middleRows(size / 3, size).array().abs().maxCoeff()));
     739           5 :                 REQUIRE_UNARY(checkApproxEq(dh.squaredL2Norm(),
     740           5 :                                             randVec.middleRows(size / 3, size).squaredNorm()));
     741           5 :                 REQUIRE_UNARY(
     742           5 :                     checkApproxEq(dh.l2Norm(), randVec.middleRows(size / 3, size).norm()));
     743             : 
     744           5 :                 auto randVec2 = generateRandomMatrix<data_t>(size);
     745           5 :                 TestType realDh2(randVec2);
     746           5 :                 auto dh2Ptr = realDh2.getBlock(0, size);
     747           5 :                 auto& dh2 = *dh2Ptr;
     748           5 :                 REQUIRE_UNARY(
     749           5 :                     checkApproxEq(dh.dot(dh2), randVec.middleRows(size / 3, size).dot(randVec2)));
     750             : 
     751           5 :                 TestType dhCPU(randVec2);
     752           5 :                 REQUIRE_UNARY(
     753           5 :                     checkApproxEq(dh.dot(dhCPU), randVec.middleRows(size / 3, size).dot(randVec2)));
     754           5 :             }
     755             : 
     756          10 :             THEN("the dot product expects correctly sized arguments")
     757          10 :             {
     758           5 :                 index_t wrongSize = size - 1;
     759           5 :                 Vector_t<data_t> randVec2(wrongSize);
     760           5 :                 randVec2.setRandom();
     761           5 :                 TestType dh2(randVec2);
     762             : 
     763           5 :                 REQUIRE_THROWS_AS(dh.dot(dh2), InvalidArgumentError);
     764           5 :             }
     765          10 :         }
     766          10 :     }
     767          10 : }
     768             : 
     769             : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing the element-wise operations", TestType,
     770             :                           datahandlermap_elemwise)
     771          15 : {
     772          15 :     using data_t = typename TestType::value_type;
     773             : 
     774          15 :     GIVEN("some DataHandlerMap")
     775          15 :     {
     776          15 :         index_t size = 567;
     777             : 
     778          15 :         WHEN("putting in some random data")
     779          15 :         {
     780          15 :             auto randVec = generateRandomMatrix<data_t>(size);
     781          15 :             TestType realDh(randVec);
     782             : 
     783          15 :             auto dhPtr = realDh.getBlock(0, size);
     784          15 :             auto& dh = static_cast<typename MapToHandler<TestType>::map&>(*dhPtr);
     785             : 
     786          15 :             THEN("the element-wise binary vector operations work as expected")
     787          15 :             {
     788           5 :                 TestType bigDh{2 * size};
     789             : 
     790           5 :                 REQUIRE_THROWS(dh += bigDh);
     791           5 :                 REQUIRE_THROWS(dh -= bigDh);
     792           5 :                 REQUIRE_THROWS(dh *= bigDh);
     793           5 :                 REQUIRE_THROWS(dh /= bigDh);
     794             : 
     795           5 :                 TestType realOldDh(randVec);
     796           5 :                 auto oldDhPtr = realOldDh.getBlock(0, size);
     797           5 :                 auto& oldDh = static_cast<typename MapToHandler<TestType>::map&>(*oldDhPtr);
     798             : 
     799           5 :                 auto randVec2 = generateRandomMatrix<data_t>(size);
     800             : 
     801           5 :                 TestType dhCPU(randVec2);
     802           5 :                 auto dh2Ptr = dhCPU.getBlock(0, size);
     803           5 :                 auto& dh2 = *dh2Ptr;
     804             : 
     805           5 :                 dh += dh2;
     806        2840 :                 for (index_t i = 0; i < size; ++i)
     807           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + dh2[i]));
     808             : 
     809           5 :                 dh = oldDh;
     810           5 :                 dh += dhCPU;
     811        2840 :                 for (index_t i = 0; i < size; ++i)
     812           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + dhCPU[i]));
     813             : 
     814           5 :                 dh = oldDh;
     815           5 :                 dh -= dh2;
     816        2840 :                 for (index_t i = 0; i < size; ++i)
     817           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - dh2[i]));
     818             : 
     819           5 :                 dh = oldDh;
     820           5 :                 dh -= dhCPU;
     821        2840 :                 for (index_t i = 0; i < size; ++i)
     822           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - dhCPU[i]));
     823             : 
     824           5 :                 dh = oldDh;
     825           5 :                 dh *= dh2;
     826        2840 :                 for (index_t i = 0; i < size; ++i)
     827           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * dh2[i]));
     828             : 
     829           5 :                 dh = oldDh;
     830           5 :                 dh *= dhCPU;
     831        2840 :                 for (index_t i = 0; i < size; ++i)
     832           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * dhCPU[i]));
     833             : 
     834           5 :                 dh = oldDh;
     835           5 :                 dh /= dh2;
     836        2840 :                 for (index_t i = 0; i < size; ++i)
     837        2835 :                     if (dh2[i] != data_t(0))
     838             :                         // due to floating point arithmetic less precision
     839        2835 :                         REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / dh2[i]));
     840             : 
     841           5 :                 dh = oldDh;
     842           5 :                 dh /= dhCPU;
     843        2840 :                 for (index_t i = 0; i < size; ++i)
     844        2835 :                     if (dhCPU[i] != data_t(0))
     845             :                         // due to floating point arithmetic less precision
     846        2835 :                         REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / dhCPU[i]));
     847           5 :             }
     848             : 
     849          15 :             THEN("the element-wise binary scalar operations work as expected")
     850          15 :             {
     851           5 :                 TestType realOldDh(randVec);
     852           5 :                 auto oldDhPtr = realOldDh.getBlock(0, size);
     853           5 :                 auto& oldDh = static_cast<typename MapToHandler<TestType>::map&>(*oldDhPtr);
     854           5 :                 data_t scalar = std::is_integral_v<data_t> ? 3 : data_t(3.5f);
     855             : 
     856           5 :                 dh += scalar;
     857        2840 :                 for (index_t i = 0; i < size; ++i)
     858           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + scalar));
     859             : 
     860           5 :                 dh = oldDh;
     861           5 :                 dh -= scalar;
     862        2840 :                 for (index_t i = 0; i < size; ++i)
     863           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - scalar));
     864             : 
     865           5 :                 dh = oldDh;
     866           5 :                 dh *= scalar;
     867        2840 :                 for (index_t i = 0; i < size; ++i)
     868           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * scalar));
     869             : 
     870           5 :                 dh = oldDh;
     871           5 :                 dh /= scalar;
     872        2840 :                 for (index_t i = 0; i < size; ++i)
     873           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / scalar));
     874           5 :             }
     875             : 
     876          15 :             THEN("the element-wise assignment of a scalar works as expected")
     877          15 :             {
     878           5 :                 auto scalar = std::is_integral_v<data_t> ? data_t(47) : data_t(47.11f);
     879             : 
     880           5 :                 dh = scalar;
     881        2840 :                 for (index_t i = 0; i < size; ++i)
     882           5 :                     REQUIRE_UNARY(checkApproxEq(dh[i], scalar));
     883           5 :             }
     884          15 :         }
     885          15 :     }
     886          15 : }
     887             : 
     888             : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing referencing blocks", TestType,
     889             :                           datahandlermap_blockref)
     890          10 : {
     891          10 :     using data_t = typename TestType::value_type;
     892             : 
     893          10 :     GIVEN("some DataHandlerMap")
     894          10 :     {
     895           5 :         index_t size = 728;
     896           5 :         Vector_t<data_t> dataVec(size);
     897           5 :         TestType realDh(dataVec);
     898           5 :         auto dhPtr = realDh.getBlock(0, size);
     899           5 :         auto& dh = *dhPtr;
     900             : 
     901           5 :         WHEN("getting the reference to a block")
     902           5 :         {
     903           5 :             REQUIRE_THROWS(dh.getBlock(size, 1));
     904           5 :             REQUIRE_THROWS(dh.getBlock(0, size + 1));
     905             : 
     906           5 :             auto dhBlock = dh.getBlock(size / 3, size / 2);
     907             : 
     908           5 :             THEN("returned data handler references the correct elements")
     909           5 :             {
     910           5 :                 REQUIRE_EQ(dhBlock->getSize(), size / 2);
     911             : 
     912        1825 :                 for (index_t i = 0; i < size / 2; i++)
     913           5 :                     REQUIRE_EQ(&(*dhBlock)[i], &dh[i + size / 3]);
     914           5 :             }
     915           5 :         }
     916           5 :     }
     917             : 
     918          10 :     GIVEN("a const DataHandlerMap")
     919          10 :     {
     920           5 :         index_t size = 728;
     921           5 :         Vector_t<data_t> dataVec(size);
     922           5 :         const TestType realDh(dataVec);
     923           5 :         auto dhPtr = realDh.getBlock(0, size);
     924           5 :         auto& dh = *dhPtr;
     925             : 
     926           5 :         WHEN("getting the reference to a block")
     927           5 :         {
     928           5 :             REQUIRE_THROWS(dh.getBlock(size, 1));
     929           5 :             REQUIRE_THROWS(dh.getBlock(0, size + 1));
     930             : 
     931           5 :             auto dhBlock = dh.getBlock(size / 3, size / 2);
     932             : 
     933           5 :             THEN("returned data handler references the correct elements")
     934           5 :             {
     935           5 :                 REQUIRE_EQ(dhBlock->getSize(), size / 2);
     936             : 
     937        1825 :                 for (index_t i = 0; i < size / 2; i++)
     938           5 :                     REQUIRE_EQ(&(*dhBlock)[i], &dh[i + size / 3]);
     939           5 :             }
     940           5 :         }
     941           5 :     }
     942          10 : }
     943             : 
     944             : // "instantiate" the test templates for CPU types
     945             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_construction, CPUTypeTuple);
     946             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_eqoperator, CPUTypeTuple);
     947             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_assign, CPUTypeTuple);
     948             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_clone, CPUTypeTuple);
     949             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_reduction, CPUTypeTuple);
     950             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_elemwise, CPUTypeTuple);
     951             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_blockref, CPUTypeTuple);
     952             : 
     953             : #ifdef ELSA_CUDA_VECTOR
     954             : // "instantiate" the test templates for GPU types
     955             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_construction, GPUTypeTuple);
     956             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_eqoperator, GPUTypeTuple);
     957             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_assign, GPUTypeTuple);
     958             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_clone, GPUTypeTuple);
     959             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_reduction, GPUTypeTuple);
     960             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_elemwise, GPUTypeTuple);
     961             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_blockref, GPUTypeTuple);
     962             : #endif
     963             : 
     964             : TEST_SUITE_END();

Generated by: LCOV version 1.14