From dc28e1b34d44ca4a1e8fc880791289f8cab72c5a Mon Sep 17 00:00:00 2001 From: Rok Date: Tue, 22 Feb 2022 13:23:00 +0100 Subject: [PATCH] add DayHoursBetween --- .../compute/kernels/scalar_temporal_binary.cc | 305 ++++++++++++++++++ .../compute/kernels/scalar_temporal_test.cc | 24 ++ 2 files changed, 329 insertions(+) diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal_binary.cc b/cpp/src/arrow/compute/kernels/scalar_temporal_binary.cc index e73c89857b5..2e84ad2d4e5 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal_binary.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal_binary.cc @@ -61,10 +61,16 @@ using arrow_vendored::date::literals::sun; using arrow_vendored::date::literals::thu; using arrow_vendored::date::literals::wed; using internal::applicator::ScalarBinaryNotNullStatefulEqualTypes; +using internal::applicator::SimpleBinary; using DayOfWeekState = OptionsWrapper; using WeekState = OptionsWrapper; +const std::shared_ptr& DayHoursType() { + static auto type = struct_({field("days", int32()), field("hours", int32())}); + return type; +} + Status CheckTimezones(const ExecBatch& batch) { const auto& timezone = GetInputTimezone(batch.values[0]); for (int i = 1; i < batch.num_values(); i++) { @@ -275,6 +281,272 @@ struct DayTimeBetween { Localizer localizer_; }; +template +std::array GetDayHoursBetween(int64_t arg0, int64_t arg1, + Localizer&& localizer) { + auto from = localizer.template ConvertTimePoint(arg0); + auto to = localizer.template ConvertTimePoint(arg1); + const int32_t num_days = + static_cast((floor(to) - floor(from)).count()); + auto from_time = static_cast( + std::chrono::duration_cast(from - floor(from)) + .count()); + auto to_time = static_cast( + std::chrono::duration_cast(to - floor(to)) + .count()); + const int32_t num_millis = to_time - from_time; + return {num_days, num_millis / 3600000}; +} + +template +struct DayHoursBetweenWrapper { + static Result> Get(const Scalar& arg0, const Scalar& arg1) { + const auto& arg0_val = internal::UnboxScalar::Unbox(arg0); + const auto& arg1_val = internal::UnboxScalar::Unbox(arg1); + return GetDayHoursBetween(arg0_val, arg1_val, NonZonedLocalizer{}); + } +}; + +template +struct DayHoursBetweenWrapper { + static Result> Get(const Scalar& arg0, const Scalar& arg1) { + const auto& arg0_val = internal::UnboxScalar::Unbox(arg0); + const auto& arg1_val = internal::UnboxScalar::Unbox(arg1); + const auto& timezone0 = GetInputTimezone(arg0); + const auto& timezone1 = GetInputTimezone(arg1); + if (timezone0 != timezone1) { + return Status::Invalid(timezone0, " != ", timezone1); + } + if (timezone0.empty()) { + return GetDayHoursBetween(arg0_val, arg1_val, NonZonedLocalizer{}); + } else { + ARROW_ASSIGN_OR_RAISE(auto tz, LocateZone(timezone0)); + return GetDayHoursBetween(arg0_val, arg1_val, ZonedLocalizer{tz}); + } + } +}; + +template +struct DayHoursBetweenVisitValueFunction { + static Result> + Get(const std::vector& field_builders, const ArrayData&, const ArrayData&, + StructBuilder* struct_builder) { + return [=](typename InType::c_type arg0, typename InType::c_type arg1) { + const auto day_hours_between = + GetDayHoursBetween(arg0, arg1, NonZonedLocalizer{}); + field_builders[0]->UnsafeAppend(day_hours_between[0]); + field_builders[1]->UnsafeAppend(day_hours_between[1]); + DCHECK_OK(struct_builder->Append()); + }; + } +}; + +template +struct DayHoursBetweenVisitValueFunction { + static Result< + std::function> + Get(const std::vector& field_builders, const ArrayData& in0, + const ArrayData& in1, StructBuilder* struct_builder) { + const auto& timezone0 = GetInputTimezone(in0); + const auto& timezone1 = GetInputTimezone(in1); + if (timezone0 != timezone1) { + return Status::Invalid(timezone0, " != ", timezone1); + } + if (timezone0.empty()) { + return [=](TimestampType::c_type arg0, TimestampType::c_type arg1) { + const auto day_hours_between = + GetDayHoursBetween(arg0, arg1, NonZonedLocalizer{}); + field_builders[0]->UnsafeAppend(day_hours_between[0]); + field_builders[1]->UnsafeAppend(day_hours_between[1]); + DCHECK_OK(struct_builder->Append()); + }; + } + ARROW_ASSIGN_OR_RAISE(auto tz, LocateZone(timezone0)); + return [=](TimestampType::c_type arg0, TimestampType::c_type arg1) { + const auto day_hours_between = + GetDayHoursBetween(arg0, arg1, ZonedLocalizer{tz}); + field_builders[0]->UnsafeAppend(day_hours_between[0]); + field_builders[1]->UnsafeAppend(day_hours_between[1]); + DCHECK_OK(struct_builder->Append()); + }; + } +}; + +template +struct DayHoursBetweenVisitValueFunction2 { + static Result> Get( + const std::vector& field_builders, const Scalar& in0, + const ArrayData&, StructBuilder* struct_builder) { + const auto& in0_val = internal::UnboxScalar::Unbox(in0); + + return [=](typename InType::c_type arg1) { + const auto day_hours_between = + GetDayHoursBetween(in0_val, arg1, NonZonedLocalizer{}); + field_builders[0]->UnsafeAppend(day_hours_between[0]); + field_builders[1]->UnsafeAppend(day_hours_between[1]); + return struct_builder->Append(); + }; + } + + static Result> Get( + const std::vector& field_builders, const ArrayData&, + const Scalar& in1, StructBuilder* struct_builder) { + const auto& in1_val = internal::UnboxScalar::Unbox(in1); + + return [=](typename InType::c_type arg0) { + const auto day_hours_between = + GetDayHoursBetween(arg0, in1_val, NonZonedLocalizer{}); + field_builders[0]->UnsafeAppend(day_hours_between[0]); + field_builders[1]->UnsafeAppend(day_hours_between[1]); + return struct_builder->Append(); + }; + } +}; + +template +struct DayHoursBetweenVisitValueFunction2 { + static Result> Get( + const std::vector& field_builders, const Scalar& in0, + const ArrayData&, StructBuilder* struct_builder) { + const auto& in0_val = internal::UnboxScalar::Unbox(in0); + + return [=](typename TimestampType::c_type arg1) { + const auto day_hours_between = + GetDayHoursBetween(in0_val, arg1, NonZonedLocalizer{}); + field_builders[0]->UnsafeAppend(day_hours_between[0]); + field_builders[1]->UnsafeAppend(day_hours_between[1]); + return struct_builder->Append(); + }; + } + + static Result> Get( + const std::vector& field_builders, const ArrayData&, + const Scalar& in1, StructBuilder* struct_builder) { + const auto& in1_val = internal::UnboxScalar::Unbox(in1); + + return [=](typename TimestampType::c_type arg0) { + const auto day_hours_between = + GetDayHoursBetween(arg0, in1_val, NonZonedLocalizer{}); + field_builders[0]->UnsafeAppend(day_hours_between[0]); + field_builders[1]->UnsafeAppend(day_hours_between[1]); + return struct_builder->Append(); + }; + } +}; + +template +struct DayHoursBetween { + static Status Call(KernelContext* ctx, const Scalar& arg0, const Scalar& arg1, + Scalar* out) { + if (arg0.is_valid && arg1.is_valid) { + ARROW_ASSIGN_OR_RAISE(auto day_hours_between, + (DayHoursBetweenWrapper::Get(arg0, arg1))); + ScalarVector values = {std::make_shared(day_hours_between[0]), + std::make_shared(day_hours_between[1])}; + *checked_cast(out) = StructScalar(std::move(values), DayHoursType()); + } else { + out->is_valid = false; + } + return Status::OK(); + } + + static Status Call(KernelContext* ctx, const ArrayData& arg0, const ArrayData& arg1, + ArrayData* out) { + using BuilderType = typename TypeTraits::BuilderType; + + std::unique_ptr array_builder; + RETURN_NOT_OK(MakeBuilder(ctx->memory_pool(), DayHoursType(), &array_builder)); + StructBuilder* struct_builder = checked_cast(array_builder.get()); + + if (arg0.length != arg1.length) { + return Status::Invalid(arg0.length, " != ", arg1.length); + } + RETURN_NOT_OK(struct_builder->Reserve(arg0.length)); + + std::vector field_builders; + field_builders.reserve(2); + for (int i = 0; i < 2; i++) { + field_builders.push_back( + checked_cast(struct_builder->field_builder(i))); + RETURN_NOT_OK(field_builders[i]->Reserve(1)); + } + + auto visit_null = [=]() { DCHECK_OK(struct_builder->AppendNull()); }; + std::function visit_value; + ARROW_ASSIGN_OR_RAISE( + visit_value, + (DayHoursBetweenVisitValueFunction::Get( + field_builders, arg0, arg1, struct_builder))); + + VisitTwoArrayValuesInline(arg0, arg1, visit_value, + visit_null); + std::shared_ptr out_array; + RETURN_NOT_OK(struct_builder->Finish(&out_array)); + *out = *std::move(out_array->data()); + + return Status::OK(); + } + + static Status Call(KernelContext* ctx, const ArrayData& arg0, const Scalar& arg1, + ArrayData* out) { + using BuilderType = typename TypeTraits::BuilderType; + std::unique_ptr array_builder; + RETURN_NOT_OK(MakeBuilder(ctx->memory_pool(), DayHoursType(), &array_builder)); + StructBuilder* struct_builder = checked_cast(array_builder.get()); + RETURN_NOT_OK(struct_builder->Reserve(arg0.length)); + + std::vector field_builders; + field_builders.reserve(2); + for (int i = 0; i < 2; i++) { + field_builders.push_back( + checked_cast(struct_builder->field_builder(i))); + RETURN_NOT_OK(field_builders[i]->Reserve(1)); + } + auto visit_null = [=]() { return struct_builder->AppendNull(); }; + std::function visit_value; + ARROW_ASSIGN_OR_RAISE( + visit_value, + (DayHoursBetweenVisitValueFunction2::Get( + field_builders, arg0, arg1, struct_builder))); + RETURN_NOT_OK(VisitArrayDataInline(arg0, visit_value, + visit_null)); + std::shared_ptr out_array; + RETURN_NOT_OK(struct_builder->Finish(&out_array)); + *out = *std::move(out_array->data()); + return Status::OK(); + } + + static Status Call(KernelContext* ctx, const Scalar& arg0, const ArrayData& arg1, + ArrayData* out) { + using BuilderType = typename TypeTraits::BuilderType; + std::unique_ptr array_builder; + RETURN_NOT_OK(MakeBuilder(ctx->memory_pool(), DayHoursType(), &array_builder)); + StructBuilder* struct_builder = checked_cast(array_builder.get()); + RETURN_NOT_OK(struct_builder->Reserve(arg1.length)); + + std::vector field_builders; + field_builders.reserve(2); + for (int i = 0; i < 2; i++) { + field_builders.push_back( + checked_cast(struct_builder->field_builder(i))); + RETURN_NOT_OK(field_builders[i]->Reserve(1)); + } + auto visit_null = [=]() { return struct_builder->AppendNull(); }; + std::function visit_value; + ARROW_ASSIGN_OR_RAISE( + visit_value, + (DayHoursBetweenVisitValueFunction2::Get( + field_builders, arg0, arg1, struct_builder))); + RETURN_NOT_OK(VisitArrayDataInline(arg1, visit_value, + visit_null)); + std::shared_ptr out_array; + RETURN_NOT_OK(struct_builder->Finish(&out_array)); + *out = *std::move(out_array->data()); + return Status::OK(); + } +}; + template struct UnitsBetween { UnitsBetween(const FunctionOptions* options, Localizer&& localizer) @@ -343,6 +615,31 @@ struct BinaryTemporalFactory { } }; +template