From bb555aee25de67b568390f4d76ae9b9a1678a065 Mon Sep 17 00:00:00 2001
From: Thibault Hallouin <thibault.hallouin@inrae.fr>
Date: Fri, 2 Sep 2022 15:44:33 +0200
Subject: [PATCH] change masking conditions parameter type for strings

In order to be an accessible parameter type for Python (and hopefully
R in the future) bindings, `std::string` needed to be replaced with
`std::array<char, 32>`, a fixed-length string type.
---
 include/evalhyd/evald.hpp  |  5 +++--
 include/evalhyd/evalp.hpp  |  5 +++--
 src/masks.hpp              |  5 ++++-
 tests/test_determinist.cpp | 13 ++++++++-----
 tests/test_probabilist.cpp | 11 +++++++----
 5 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/include/evalhyd/evald.hpp b/include/evalhyd/evald.hpp
index 2254c91..448c573 100644
--- a/include/evalhyd/evald.hpp
+++ b/include/evalhyd/evald.hpp
@@ -3,6 +3,7 @@
 
 #include <unordered_map>
 #include <vector>
+#include <array>
 #include <stdexcept>
 #include <xtensor/xexpression.hpp>
 #include <xtensor/xarray.hpp>
@@ -98,7 +99,7 @@ namespace evalhyd
     ///       of them.
     ///       shape: ({... ,} time)
     ///
-    ///    m_cdt: ``xt::xtensor<std::string, N>``, optional
+    ///    m_cdt: ``xt::xtensor<std::array<char, 32>, N>``, optional
     ///       Masking conditions to use to generate temporal subsets. Each
     ///       condition consists in a string and can be specified on observed
     ///       streamflow values or on time indices. If provided in combination
@@ -158,7 +159,7 @@ namespace evalhyd
             const double exponent = 1,
             double epsilon = -9,
             const xt::xtensor<bool, N>& t_msk = {},
-            const xt::xtensor<std::string, N>& m_cdt = {}
+            const xt::xtensor<std::array<char, 32>, N>& m_cdt = {}
     )
     {
         // initialise a mask if none provided
diff --git a/include/evalhyd/evalp.hpp b/include/evalhyd/evalp.hpp
index c832682..349e7ea 100644
--- a/include/evalhyd/evalp.hpp
+++ b/include/evalhyd/evalp.hpp
@@ -4,6 +4,7 @@
 #include <utility>
 #include <unordered_map>
 #include <vector>
+#include <array>
 #include <xtensor/xtensor.hpp>
 #include <xtensor/xarray.hpp>
 #include <xtensor/xview.hpp>
@@ -52,7 +53,7 @@ namespace evalhyd
     ///       many sets of metrics are returned as they are masks provided.
     ///       shape: (sites, subsets, time)
     ///
-    ///    m_cdt: ``xt::xtensor<std::string, 2>``, optional
+    ///    m_cdt: ``xt::xtensor<std::array<char, 32>, 2>``, optional
     ///       Masking conditions to use to generate temporal subsets. Each
     ///       condition consists in a string and can be specified on observed
     ///       streamflow values or on time indices. If provided in combination
@@ -103,7 +104,7 @@ namespace evalhyd
             const std::vector<std::string>& metrics,
             const xt::xtensor<double, 2>& q_thr = {},
             const xt::xtensor<bool, 3>& t_msk = {},
-            const xt::xtensor<std::string, 2>& m_cdt = {}
+            const xt::xtensor<std::array<char, 32>, 2>& m_cdt = {}
     )
     {
         // check that the metrics to be computed are valid
diff --git a/src/masks.hpp b/src/masks.hpp
index c10572c..3991790 100644
--- a/src/masks.hpp
+++ b/src/masks.hpp
@@ -4,6 +4,8 @@
 #include <map>
 #include <set>
 #include <vector>
+#include <array>
+#include <string>
 #include <regex>
 
 #include <xtensor/xexpression.hpp>
@@ -130,10 +132,11 @@ namespace evalhyd
 
         /// Function to generate temporal mask based on masking conditions
         inline xt::xtensor<bool, 1> generate_mask_from_conditions(
-                const std::string& msk_str, const xt::xtensor<double, 1>& q_obs
+                const std::array<char, 32>& msk_char_arr, const xt::xtensor<double, 1>& q_obs
         )
         {
             // parse string to identify masking conditions
+            std::string msk_str(msk_char_arr.begin(), msk_char_arr.end());
             msk_tree subset = parse_masking_conditions(msk_str);
 
             // initialise a boolean expression for the masks
diff --git a/tests/test_determinist.cpp b/tests/test_determinist.cpp
index 0d4c43c..bf753fe 100644
--- a/tests/test_determinist.cpp
+++ b/tests/test_determinist.cpp
@@ -1,5 +1,6 @@
 #include <fstream>
 #include <vector>
+#include <array>
 #include <gtest/gtest.h>
 #include <xtensor/xtensor.hpp>
 #include <xtensor/xview.hpp>
@@ -219,8 +220,9 @@ TEST(DeterministTests, TestMaskingConditions)
     // conditions on streamflow ________________________________________________
 
     // compute scores using masking conditions on streamflow to subset whole record
-    xt::xtensor<std::string, 2> q_conditions =
-            {{"q{<2000,>3000}"}};
+    xt::xtensor<std::array<char, 32>, 2> q_conditions ={
+            {{"q{<2000,>3000}"}}
+    };
 
     std::vector<xt::xarray<double>> metrics_q_conditioned =
             evalhyd::evald<2>(
@@ -249,8 +251,9 @@ TEST(DeterministTests, TestMaskingConditions)
     // conditions on temporal indices __________________________________________
 
     // compute scores using masking conditions on time indices to subset whole record
-    xt::xtensor<std::string, 2> t_conditions =
-            {{"t{0,1,2,3,4,5:97,97,98,99}"}};
+    xt::xtensor<std::array<char, 32>, 2> t_conditions = {
+            {{"t{0,1,2,3,4,5:97,97,98,99}"}}
+    };
 
     std::vector<xt::xarray<double>> metrics_t_conditioned =
             evalhyd::evald<2>(
@@ -285,7 +288,7 @@ TEST(DeterministTests, TestMissingData)
     // read in data
     std::ifstream ifs;
     ifs.open("./data/q_obs.csv");
-    xt::xtensor<double, 2> observed =xt::load_csv<int>(ifs);
+    xt::xtensor<double, 2> observed = xt::load_csv<int>(ifs);
     ifs.close();
 
     ifs.open("./data/q_prd.csv");
diff --git a/tests/test_probabilist.cpp b/tests/test_probabilist.cpp
index 3746308..ec65961 100644
--- a/tests/test_probabilist.cpp
+++ b/tests/test_probabilist.cpp
@@ -1,5 +1,6 @@
 #include <fstream>
 #include <vector>
+#include <array>
 #include <gtest/gtest.h>
 #include <xtensor/xtensor.hpp>
 #include <xtensor/xmanipulation.hpp>
@@ -195,8 +196,9 @@ TEST(ProbabilistTests, TestMaskingConditions)
     // conditions on streamflow ________________________________________________
 
     // compute scores using masking conditions on streamflow to subset whole record
-    xt::xtensor<std::string, 2> q_conditions =
-            {{"q{<2000,>3000}"}};
+    xt::xtensor<std::array<char, 32>, 2> q_conditions = {
+            {{"q{<2000,>3000}"}}
+    };
 
     std::vector<xt::xarray<double>> metrics_q_conditioned =
             evalhyd::evalp(
@@ -227,8 +229,9 @@ TEST(ProbabilistTests, TestMaskingConditions)
     // conditions on temporal indices __________________________________________
 
     // compute scores using masking conditions on time indices to subset whole record
-    xt::xtensor<std::string, 2> t_conditions =
-            {{"t{0,1,2,3,4,5:97,97,98,99}"}};
+    xt::xtensor<std::array<char, 32>, 2> t_conditions = {
+            {{"t{0,1,2,3,4,5:97,97,98,99}"}}
+    };
 
     std::vector<xt::xarray<double>> metrics_t_conditioned =
             evalhyd::evalp(
-- 
GitLab