Uh oh!
There was an error while loading. Please reload this page.
ARROW-1491: [C++] Add casting implementations from strings to numbers or boolean - #1387
ARROW-1491: [C++] Add casting implementations from strings to numbers or boolean#1387Licht-T wants to merge 10 commits into
Conversation
a13c5e0 to
491e5ebCompare491e5eb to
a12eb38Comparea12eb38 to
8a6470cCompare
xhochy
left a comment
There was a problem hiding this comment.
Code looks good, I would like to see one minor comment why we need the separation for INT8.
| std::function<out_type(const std::string&)> cast_func; | ||
| if (output->type->id() == Type::INT8 || output->type->id() == Type::UINT8) { | ||
| cast_func = [](const std::string& s) { | ||
| return boost::numeric_cast<out_type>(boost::lexical_cast<int>(s)); |
There was a problem hiding this comment.
Can you add a comment why this special case is needed?
| #include <boost/algorithm/string.hpp> | ||
| #include <boost/lexical_cast.hpp> | ||
| #include <boost/numeric/conversion/cast.hpp> |
There was a problem hiding this comment.
Is it possible to not rely on Boost for this, e.g. are there some alternatives in the STL or that we can access otherwise? I will review the rest in more detail later
There was a problem hiding this comment.
Seems that boost::numeric_cast and boost::lexical_cast are not replaceable by STL.
STL has std::to_string, but it does not support small size ints.
http://en.cppreference.com/w/cpp/string/basic_string/to_string
There was a problem hiding this comment.
Wouldn't it be ok in the of small size ints just to upcast them? This should not affect performance as it's a small temporary.
| return boost::numeric_cast<out_type>(boost::lexical_cast<int>(s)); | ||
| }; | ||
| } else { | ||
| cast_func = [](const std::string& s) { return boost::lexical_cast<out_type>(s); }; |
There was a problem hiding this comment.
I think C++11 Lambdas actually incur more overhead than an inlined function. We should instead introduce an auxiliary numeric cast functor that does this switch at compile-time (resulting in an inlined function in the inner loop for all possible types) rather than runtime
| if (input_array.null_count() > 0) { | ||
| std::stringstream ss; | ||
| ss << "Failed to cast NA into " << output->type->ToString(); | ||
| ctx->SetStatus(Status(StatusCode::SerializationError, ss.str())); |
There was a problem hiding this comment.
If the input has nulls, then the output should have nulls in the same locations
| ss << "Failed to cast NA into " << output->type->ToString(); | ||
| ctx->SetStatus(Status(StatusCode::SerializationError, ss.str())); | ||
| return; | ||
| } |
There was a problem hiding this comment.
If the input has nulls, then the output should have nulls in the same locations (like the other cast functions)
| TEST_F(TestCast, StringToNumber) { | ||
| CastOptions options; | ||
| vector<bool> is_valid = {true, true, true, true, true}; |
There was a problem hiding this comment.
Can you modify the unit tests to propagate nulls?
| CheckCase<StringType, std::string, FloatType, float>(utf8(), v_float, is_valid, | ||
| float32(), e_float, options); | ||
| CheckCase<StringType, std::string, DoubleType, double>(utf8(), v_float, is_valid, | ||
| float64(), e_double, options); |
There was a problem hiding this comment.
Can you test with a non-zero offset (e.g. foo->Slice(2))?
There was a problem hiding this comment.
@wesm It seems that the sliced pattern is already tested in CheckCase method.
https://github.com/Licht-T/arrow/blob/master/cpp/src/arrow/compute/compute-test.cc#L123
wesm
commented
Dec 20, 2017
@Licht-T I will do a bit of work on this patch tomorrow or Friday for further review |
Licht-T
commented
Dec 25, 2017
Thanks @wesm! I was busy but now I am okay. Would you mind if I help? |
wesm
commented
Dec 25, 2017
Sure please go ahead |
Licht-T
commented
Jan 10, 2018
@wesm Now, all fixed. |
wesm
commented
Jan 10, 2018
I will review again when I can |
xhochy
commented
Jan 14, 2018
This PR looks good besides the dependency on Boost. Probably we need this to get it working but in the longterm, we should get rid of it again. |
| typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, int8_t>::value && | ||
| !std::is_same<T, uint8_t>::value, | ||
| T>::type | ||
| castStringToNumeric(const std::string& s) { |
| template <typename T> | ||
| typename std::enable_if<std::is_same<T, int8_t>::value || std::is_same<T, uint8_t>::value, | ||
| T>::type | ||
| castStringToNumeric(const std::string& s) { |
| auto out_data = GetMutableValues<out_type>(output, 1); | ||
| std::function<out_type(const std::string&)> cast_func; |
There was a problem hiding this comment.
Is this variable used anywhere? It looks like you might've replaced it with the castStringToNumeric function.
| try { | ||
| *out_data++ = castStringToNumeric<out_type>(s); | ||
| } catch (...) { |
There was a problem hiding this comment.
Is there a specific exception that can be caught here?
There was a problem hiding this comment.
I'm concerned about propagating the actual error message instead of just saying "Cast from X to Y failed".
cpcloud
commented
Feb 16, 2018
I'm taking over this PR, will put up a new one based on this one. |
The implementation for numbers uses C++ `istringstream`. This makes casting a bit lenient (it will probably accept whitespace). This is a rewrite of #1387 Author: Antoine Pitrou <antoine@python.org> Closes#2362 from pitrou/ARROW-1491-cast-string-to-number and squashes the following commits: c7db1b0 <Antoine Pitrou> Use trait "enable_if_number" 5a9c9a0 <Antoine Pitrou> Use `istringstream` for locale-independent parsing c84aac8 <Antoine Pitrou> ARROW-1491: Add casting from strings to numbers and booleans
wesm
commented
Aug 6, 2018
Superseded by #2362 |
This closes ARROW-1491.