Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions cpp/src/arrow/scalar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,16 @@ struct ScalarHashImpl {
}

Status Visit(const DayTimeIntervalScalar& s) {
return StdHash(s.value.days) & StdHash(s.value.milliseconds);
return StdHash(s.value.days) && StdHash(s.value.milliseconds);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, && is easier to understand. Just like a bash script, I know LHS will be evaluated before RHS, and RHS will only be evaluated if LHS is true.

}

Status Visit(const MonthDayNanoIntervalScalar& s) {
return StdHash(s.value.days) & StdHash(s.value.months) & StdHash(s.value.nanoseconds);
return StdHash(s.value.days) && StdHash(s.value.months) &&
StdHash(s.value.nanoseconds);
}

Status Visit(const Decimal128Scalar& s) {
return StdHash(s.value.low_bits()) & StdHash(s.value.high_bits());
return StdHash(s.value.low_bits()) && StdHash(s.value.high_bits());
}

Status Visit(const Decimal256Scalar& s) {
Expand Down Expand Up @@ -140,7 +141,7 @@ struct ScalarHashImpl {
Status ArrayHash(const Array& a) { return ArrayHash(*a.data()); }

Status ArrayHash(const ArrayData& a) {
RETURN_NOT_OK(StdHash(a.length) & StdHash(a.GetNullCount()));
RETURN_NOT_OK(StdHash(a.length) && StdHash(a.GetNullCount()));
if (a.buffers[0] != nullptr) {
// We can't visit values without unboxing the whole array, so only hash
// the null bitmap for now.
Expand Down
18 changes: 18 additions & 0 deletions cpp/src/arrow/status.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ class ARROW_MUST_USE_TYPE ARROW_EXPORT Status : public util::EqualityComparable<
// AND the statuses.
inline Status operator&(const Status& s) const noexcept;
inline Status operator&(Status&& s) const noexcept;
inline Status operator&&(const Status& s) const noexcept;
inline Status operator&&(Status&& s) const noexcept;
inline Status& operator&=(const Status& s) noexcept;
inline Status& operator&=(Status&& s) noexcept;

Expand Down Expand Up @@ -424,6 +426,22 @@ Status Status::operator&(Status&& s) const noexcept {
}
}

Status Status::operator&&(const Status& s) const noexcept {
if (ok()) {
return s;
} else {
return *this;
}
}

Status Status::operator&&(Status&& s) const noexcept {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: doesn't it make sense if we combine these two overloads into one function accepting a value parameter?

Status Status::operator&&(Status s) {
  if (ok()) {
    return s;
  } else {
    return *this;
  }
}

As s is a direct arugment, return s is same as return std::move(s) if RVO doesn't apply (a direct argument or stack variable returned is treated as rvalue, IIRC).
This function may introduce at most one additonal move to both the const& and && overloads. Maybe even no this overhead if RVO can apply to argument, or compiler can do some tricks, I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that having a non-reference parameter is preferable. We might still want two overloads, however, since we're copying in the case that *this is not ok:

Status Status::operator&&(Status s) const& noexcept {
  if (!ok()) return *this;
  return s;
}

Status Status::operator&&(Status s) && noexcept {
  if (!ok()) return std::move(*this);
  return s;
}

if (ok()) {
return std::move(s);
} else {
return *this;
}
}

Status& Status::operator&=(const Status& s) noexcept {
if (ok() && !s.ok()) {
CopyFrom(s);
Expand Down
19 changes: 16 additions & 3 deletions cpp/src/arrow/status_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ TEST(StatusTest, AndStatus) {
ASSERT_TRUE(res.IsInvalid());

// With rvalues
res = Status::OK() & Status::Invalid("foo");
res = Status::OK() && Status::Invalid("foo");
ASSERT_TRUE(res.IsInvalid());
res = Status::Invalid("foo") & Status::OK();
res = Status::Invalid("foo") && Status::OK();
ASSERT_TRUE(res.IsInvalid());
res = Status::Invalid("foo") & Status::IOError("bar");
res = Status::Invalid("foo") && Status::IOError("bar");
ASSERT_TRUE(res.IsInvalid());

res = Status::OK();
Expand All @@ -109,6 +109,19 @@ TEST(StatusTest, AndStatus) {
ASSERT_TRUE(res.IsInvalid());
}

Status PassingTaskWithSideEffect(bool* hit_side_effect) {
*hit_side_effect = true;
return Status::OK();
}

Status FailingTask() { return Status::Invalid("err"); }

TEST(StatusTest, SortCircuitAndStatus) {
bool hit_side_effect = false;
Status res = PassingTaskWithSideEffect(&hit_side_effect) && FailingTask();
ASSERT_TRUE(hit_side_effect);
}

TEST(StatusTest, TestEquality) {
ASSERT_EQ(Status(), Status::OK());
ASSERT_EQ(Status::Invalid("error"), Status::Invalid("error"));
Expand Down