Skip to content

Commit 68f9a77

Browse files
authored
Fix CSV reader to handle 8-bit integers (#2904)
1 parent c88d087 commit 68f9a77

2 files changed

Lines changed: 96 additions & 1 deletion

File tree

include/xtensor/io/xcsv.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ namespace xt
6666
}
6767

6868
size_t last = cell.find_last_not_of(' ');
69-
return cell.substr(first, last == std::string::npos ? cell.size() : last + 1);
69+
return cell.substr(first, last == std::string::npos ? cell.size() : last - first + 1);
7070
}
7171

7272
template <>
@@ -93,6 +93,18 @@ namespace xt
9393
return std::stoi(cell);
9494
}
9595

96+
template <>
97+
inline signed char lexical_cast<signed char>(const std::string& cell)
98+
{
99+
return static_cast<signed char>(std::stoi(cell));
100+
}
101+
102+
template <>
103+
inline unsigned char lexical_cast<unsigned char>(const std::string& cell)
104+
{
105+
return static_cast<unsigned char>(std::stoul(cell));
106+
}
107+
96108
template <>
97109
inline long lexical_cast<long>(const std::string& cell)
98110
{

test/test_xcsv.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ namespace xt
4343
ASSERT_TRUE(all(equal(res, exp)));
4444
}
4545

46+
TEST(xcsv, load_binary_matrix)
47+
{
48+
const std::string source = "1,0,1\n"
49+
"0,1,1";
50+
51+
std::stringstream source_stream(source);
52+
53+
const xtensor<uint8_t, 2> res = load_csv<uint8_t>(source_stream);
54+
55+
const xtensor<uint8_t, 2> exp{{1, 0, 1}, {0, 1, 1}};
56+
57+
ASSERT_TRUE(all(equal(res, exp)));
58+
}
59+
4660
TEST(xcsv, load_double_with_options)
4761
{
4862
std::string source = "A B C D\n"
@@ -60,6 +74,56 @@ namespace xt
6074
ASSERT_TRUE(all(equal(res, exp)));
6175
}
6276

77+
TEST(xcsv, load_string_trims_cells)
78+
{
79+
const std::string source = " alpha , beta,gamma \n delta, epsilon , zeta ";
80+
81+
std::stringstream source_stream(source);
82+
83+
const xtensor<std::string, 2> res = load_csv<std::string>(source_stream);
84+
85+
ASSERT_EQ(res.shape()[0], std::size_t(2));
86+
ASSERT_EQ(res.shape()[1], std::size_t(3));
87+
ASSERT_EQ(res(0, 0), "alpha");
88+
ASSERT_EQ(res(0, 1), "beta");
89+
ASSERT_EQ(res(0, 2), "gamma");
90+
ASSERT_EQ(res(1, 0), "delta");
91+
ASSERT_EQ(res(1, 1), "epsilon");
92+
ASSERT_EQ(res(1, 2), "zeta");
93+
}
94+
95+
TEST(xcsv, load_file_uses_config)
96+
{
97+
const std::string source = "metadata\n"
98+
"//ignore this row\n"
99+
"1;2;3\n"
100+
"4;5;6\n"
101+
"7;8;9";
102+
103+
std::stringstream source_stream(source);
104+
xcsv_config config;
105+
config.delimiter = ';';
106+
config.skip_rows = 1;
107+
config.max_rows = 2;
108+
config.comments = "//";
109+
110+
xtensor<int, 2> res = {{0, 0, 0}};
111+
load_file(source_stream, res, config);
112+
113+
const xtensor<int, 2> exp{{1, 2, 3}, {4, 5, 6}};
114+
115+
ASSERT_TRUE(all(equal(res, exp)));
116+
}
117+
118+
TEST(xcsv, load_inconsistent_rows_throws)
119+
{
120+
const std::string source = "1,2,3\n4,5";
121+
122+
std::stringstream source_stream(source);
123+
124+
XT_EXPECT_THROW(load_csv<int>(source_stream), std::runtime_error);
125+
}
126+
63127
TEST(xcsv, dump_1D)
64128
{
65129
xtensor<double, 1> data{{1.0, 2.0, 3.0, 4.0}};
@@ -79,4 +143,23 @@ namespace xt
79143
dump_csv(res, data);
80144
ASSERT_EQ("1,2,3,4\n10,12,15,18\n", res.str());
81145
}
146+
147+
TEST(xcsv, dump_file_matches_dump_csv)
148+
{
149+
xtensor<int, 2> data{{1, 2}, {3, 4}};
150+
std::stringstream res;
151+
xcsv_config config;
152+
153+
dump_file(res, data, config);
154+
155+
ASSERT_EQ("1,2\n3,4\n", res.str());
156+
}
157+
158+
TEST(xcsv, dump_higher_dimension_throws)
159+
{
160+
xtensor<double, 3> data{{{1.0, 2.0}, {3.0, 4.0}}};
161+
std::stringstream res;
162+
163+
XT_EXPECT_THROW(dump_csv(res, data), std::runtime_error);
164+
}
82165
}

0 commit comments

Comments
 (0)