SERVER-126887 Add numeric cast overload that accepts TagValueView in SBE (#54394)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: evanbergeron <6565683+evanbergeron@users.noreply.github.com> GitOrigin-RevId: a546de94771b8c04746c7083daf78aa64280cdbe
This commit is contained in:
parent
67c6620a03
commit
8f8e471e1a
@ -2465,6 +2465,11 @@ inline T numericCast(TypeTags tag, Value val) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T numericCast(TagValueView v) noexcept {
|
||||
return numericCast<T>(v.tag, v.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a lossless numeric conversion from a value to a destination type denoted by the target
|
||||
* TypeTag. In the case that a conversion is lossy, we return Nothing.
|
||||
|
||||
@ -530,4 +530,25 @@ TEST_F(SbeValueTest, SortSpecCompareInvalid) {
|
||||
ASSERT_EQ(cmpTag, value::TypeTags::Nothing);
|
||||
ASSERT_EQ(cmpVal, 0);
|
||||
}
|
||||
TEST(SbeNumericCastTest, TagValueViewOverload) {
|
||||
using namespace value;
|
||||
|
||||
TagValueView v32{TypeTags::NumberInt32, bitcastFrom<int32_t>(7)};
|
||||
ASSERT_EQ(numericCast<int32_t>(v32), 7);
|
||||
ASSERT_EQ(numericCast<int64_t>(v32), int64_t{7});
|
||||
ASSERT_EQ(numericCast<double>(v32), 7.0);
|
||||
ASSERT_EQ(numericCast<Decimal128>(v32), Decimal128(7));
|
||||
|
||||
TagValueView v64{TypeTags::NumberInt64, bitcastFrom<int64_t>(100LL)};
|
||||
ASSERT_EQ(numericCast<int64_t>(v64), 100LL);
|
||||
ASSERT_EQ(numericCast<double>(v64), 100.0);
|
||||
|
||||
TagValueView vd{TypeTags::NumberDouble, bitcastFrom<double>(2.5)};
|
||||
ASSERT_EQ(numericCast<double>(vd), 2.5);
|
||||
|
||||
auto [decTag, decVal] = makeCopyDecimal(Decimal128("3.14"));
|
||||
ValueGuard guard{decTag, decVal};
|
||||
TagValueView vDec{decTag, decVal};
|
||||
ASSERT_EQ(numericCast<Decimal128>(vDec), Decimal128("3.14"));
|
||||
}
|
||||
} // namespace mongo::sbe
|
||||
|
||||
@ -1072,12 +1072,12 @@ value::TagValueMaybeOwned ByteCode::genericPow(value::TagValueView base,
|
||||
|
||||
if (base.tag == value::TypeTags::NumberDecimal ||
|
||||
exponent.tag == value::TypeTags::NumberDecimal) {
|
||||
auto baseDecimal = numericCast<Decimal128>(base.tag, base.value);
|
||||
auto exponenetDecimal = numericCast<Decimal128>(exponent.tag, exponent.value);
|
||||
if (baseDecimal == Decimal128("0") && exponenetDecimal < Decimal128("0")) {
|
||||
auto baseDecimal = numericCast<Decimal128>(base);
|
||||
auto exponentDecimal = numericCast<Decimal128>(exponent);
|
||||
if (baseDecimal == Decimal128("0") && exponentDecimal < Decimal128("0")) {
|
||||
return {false, value::TypeTags::Nothing, 0};
|
||||
}
|
||||
auto result = baseDecimal.power(exponenetDecimal);
|
||||
auto result = baseDecimal.power(exponentDecimal);
|
||||
auto [resTag, resValue] = value::makeCopyDecimal(result);
|
||||
return {true, resTag, resValue};
|
||||
}
|
||||
@ -1085,8 +1085,8 @@ value::TagValueMaybeOwned ByteCode::genericPow(value::TagValueView base,
|
||||
// If either argument is a double, return a double.
|
||||
if (base.tag == value::TypeTags::NumberDouble ||
|
||||
exponent.tag == value::TypeTags::NumberDouble) {
|
||||
auto baseDouble = numericCast<double>(base.tag, base.value);
|
||||
auto exponentDouble = numericCast<double>(exponent.tag, exponent.value);
|
||||
auto baseDouble = numericCast<double>(base);
|
||||
auto exponentDouble = numericCast<double>(exponent);
|
||||
if (baseDouble == 0 && exponentDouble < 0) {
|
||||
return {false, value::TypeTags::Nothing, 0};
|
||||
}
|
||||
@ -1221,13 +1221,13 @@ value::TagValueMaybeOwned ByteCode::genericAtan2(value::TagValueView operand1,
|
||||
case value::TypeTags::NumberInt32:
|
||||
case value::TypeTags::NumberInt64:
|
||||
case value::TypeTags::NumberDouble: {
|
||||
auto result = std::atan2(numericCast<double>(operand1.tag, operand1.value),
|
||||
numericCast<double>(operand2.tag, operand2.value));
|
||||
auto result =
|
||||
std::atan2(numericCast<double>(operand1), numericCast<double>(operand2));
|
||||
return {false, value::TypeTags::NumberDouble, value::bitcastFrom<double>(result)};
|
||||
}
|
||||
case value::TypeTags::NumberDecimal: {
|
||||
auto result = numericCast<Decimal128>(operand1.tag, operand1.value)
|
||||
.atan2(numericCast<Decimal128>(operand2.tag, operand2.value));
|
||||
auto result =
|
||||
numericCast<Decimal128>(operand1).atan2(numericCast<Decimal128>(operand2));
|
||||
auto [resTag, resValue] = value::makeCopyDecimal(result);
|
||||
return {true, resTag, resValue};
|
||||
}
|
||||
@ -1252,12 +1252,11 @@ value::TagValueMaybeOwned ByteCode::genericDegreesToRadians(value::TagValueView
|
||||
case value::TypeTags::NumberInt32:
|
||||
case value::TypeTags::NumberInt64:
|
||||
case value::TypeTags::NumberDouble: {
|
||||
auto result = numericCast<double>(operand.tag, operand.value) * kDoublePiOver180;
|
||||
auto result = numericCast<double>(operand) * kDoublePiOver180;
|
||||
return {false, value::TypeTags::NumberDouble, value::bitcastFrom<double>(result)};
|
||||
}
|
||||
case value::TypeTags::NumberDecimal: {
|
||||
auto result = numericCast<Decimal128>(operand.tag, operand.value)
|
||||
.multiply(Decimal128::kPiOver180);
|
||||
auto result = numericCast<Decimal128>(operand).multiply(Decimal128::kPiOver180);
|
||||
auto [resTag, resValue] = value::makeCopyDecimal(result);
|
||||
return {true, resTag, resValue};
|
||||
}
|
||||
@ -1274,12 +1273,11 @@ value::TagValueMaybeOwned ByteCode::genericRadiansToDegrees(value::TagValueView
|
||||
case value::TypeTags::NumberInt32:
|
||||
case value::TypeTags::NumberInt64:
|
||||
case value::TypeTags::NumberDouble: {
|
||||
auto result = numericCast<double>(operand.tag, operand.value) * kDouble180OverPi;
|
||||
auto result = numericCast<double>(operand) * kDouble180OverPi;
|
||||
return {false, value::TypeTags::NumberDouble, value::bitcastFrom<double>(result)};
|
||||
}
|
||||
case value::TypeTags::NumberDecimal: {
|
||||
auto result = numericCast<Decimal128>(operand.tag, operand.value)
|
||||
.multiply(Decimal128::k180OverPi);
|
||||
auto result = numericCast<Decimal128>(operand).multiply(Decimal128::k180OverPi);
|
||||
auto [resTag, resValue] = value::makeCopyDecimal(result);
|
||||
return {true, resTag, resValue};
|
||||
}
|
||||
|
||||
@ -1268,7 +1268,7 @@ value::TagValueMaybeOwned ByteCode::builtinAggExpMovingAvg(ArityType arity) {
|
||||
|
||||
auto currentResultTagVal = state->getAt(static_cast<size_t>(AggExpMovingAvgElems::kResult));
|
||||
|
||||
auto decimalVal = value::numericCast<Decimal128>(field.tag, field.value);
|
||||
auto decimalVal = value::numericCast<Decimal128>(field);
|
||||
auto result = [&]() {
|
||||
if (currentResultTagVal.tag == value::TypeTags::Null) {
|
||||
// Accumulator result has not been yet initialised. We will now
|
||||
|
||||
@ -291,7 +291,7 @@ value::TagValueMaybeOwned ByteCode::builtinDoubleDoubleSum(ArityType arity) {
|
||||
if (arg.tag == value::TypeTags::Date) {
|
||||
sum = sum.add(Decimal128(value::bitcastTo<int64_t>(arg.value)));
|
||||
} else {
|
||||
sum = sum.add(value::numericCast<Decimal128>(arg.tag, arg.value));
|
||||
sum = sum.add(value::numericCast<Decimal128>(arg));
|
||||
}
|
||||
}
|
||||
if (haveDate) {
|
||||
@ -305,11 +305,11 @@ value::TagValueMaybeOwned ByteCode::builtinDoubleDoubleSum(ArityType arity) {
|
||||
for (ArityType idx = 0; idx < arity; ++idx) {
|
||||
auto arg = viewFromStack(idx);
|
||||
if (arg.tag == value::TypeTags::NumberInt32) {
|
||||
sum.addInt(value::numericCast<int32_t>(arg.tag, arg.value));
|
||||
sum.addInt(value::numericCast<int32_t>(arg));
|
||||
} else if (arg.tag == value::TypeTags::NumberInt64) {
|
||||
sum.addLong(value::numericCast<int64_t>(arg.tag, arg.value));
|
||||
sum.addLong(value::numericCast<int64_t>(arg));
|
||||
} else if (arg.tag == value::TypeTags::NumberDouble) {
|
||||
sum.addDouble(value::numericCast<double>(arg.tag, arg.value));
|
||||
sum.addDouble(value::numericCast<double>(arg));
|
||||
} else if (arg.tag == value::TypeTags::Date) {
|
||||
sum.addLong(value::bitcastTo<int64_t>(arg.value));
|
||||
}
|
||||
|
||||
@ -84,9 +84,9 @@ value::TagValueMaybeOwned ByteCode::builtinNewArrayFromRange(ArityType arity) {
|
||||
}
|
||||
|
||||
// Cast to broader type 'int64_t' to prevent overflow during loop.
|
||||
auto startVal = value::numericCast<int64_t>(startView.tag, startView.value);
|
||||
auto endVal = value::numericCast<int64_t>(endView.tag, endView.value);
|
||||
auto stepVal = value::numericCast<int64_t>(stepView.tag, stepView.value);
|
||||
auto startVal = value::numericCast<int64_t>(startView);
|
||||
auto endVal = value::numericCast<int64_t>(endView);
|
||||
auto stepVal = value::numericCast<int64_t>(stepView);
|
||||
|
||||
if (stepVal == 0) {
|
||||
return {false, value::TypeTags::Nothing, 0};
|
||||
|
||||
@ -107,8 +107,8 @@ value::TagValueMaybeOwned ByteCode::builtinBitTestZero(ArityType arity) {
|
||||
return {false, value::TypeTags::Nothing, 0};
|
||||
}
|
||||
|
||||
auto maskNum = value::numericCast<int64_t>(mask.tag, mask.value);
|
||||
auto inputNum = value::numericCast<int64_t>(input.tag, input.value);
|
||||
auto maskNum = value::numericCast<int64_t>(mask);
|
||||
auto inputNum = value::numericCast<int64_t>(input);
|
||||
auto result = (maskNum & inputNum) == 0;
|
||||
return {false, value::TypeTags::Boolean, value::bitcastFrom<bool>(result)};
|
||||
}
|
||||
@ -123,8 +123,8 @@ value::TagValueMaybeOwned ByteCode::builtinBitTestMask(ArityType arity) {
|
||||
return {false, value::TypeTags::Nothing, 0};
|
||||
}
|
||||
|
||||
auto maskNum = value::numericCast<int64_t>(mask.tag, mask.value);
|
||||
auto inputNum = value::numericCast<int64_t>(input.tag, input.value);
|
||||
auto maskNum = value::numericCast<int64_t>(mask);
|
||||
auto inputNum = value::numericCast<int64_t>(input);
|
||||
auto result = (maskNum & inputNum) == maskNum;
|
||||
return {false, value::TypeTags::Boolean, value::bitcastFrom<bool>(result)};
|
||||
}
|
||||
|
||||
@ -80,13 +80,13 @@ value::TagValueMaybeOwned builtinDateHelper(DateFn computeDateFn,
|
||||
const auto tz = tzString == "" ? timeZoneDB->utcZone() : timeZoneDB->getTimeZone(tzString);
|
||||
|
||||
auto date = computeDateFn(tz,
|
||||
value::numericCast<int64_t>(yearOrWeekYear.tag, yearOrWeekYear.value),
|
||||
value::numericCast<int64_t>(monthOrWeek.tag, monthOrWeek.value),
|
||||
value::numericCast<int64_t>(day.tag, day.value),
|
||||
value::numericCast<int64_t>(hour.tag, hour.value),
|
||||
value::numericCast<int64_t>(minute.tag, minute.value),
|
||||
value::numericCast<int64_t>(second.tag, second.value),
|
||||
value::numericCast<int64_t>(millisecond.tag, millisecond.value));
|
||||
value::numericCast<int64_t>(yearOrWeekYear),
|
||||
value::numericCast<int64_t>(monthOrWeek),
|
||||
value::numericCast<int64_t>(day),
|
||||
value::numericCast<int64_t>(hour),
|
||||
value::numericCast<int64_t>(minute),
|
||||
value::numericCast<int64_t>(second),
|
||||
value::numericCast<int64_t>(millisecond));
|
||||
return {false, value::TypeTags::Date, value::bitcastFrom<int64_t>(date.asInt64())};
|
||||
}
|
||||
|
||||
|
||||
@ -49,9 +49,8 @@ value::TagValueMaybeOwned ByteCode::genericNewKeyString(ArityType arity,
|
||||
return {false, value::TypeTags::Nothing, 0};
|
||||
}
|
||||
|
||||
auto version = value::numericCast<int64_t>(versionView.tag, versionView.value);
|
||||
auto discriminator =
|
||||
value::numericCast<int64_t>(discriminatorView.tag, discriminatorView.value);
|
||||
auto version = value::numericCast<int64_t>(versionView);
|
||||
auto discriminator = value::numericCast<int64_t>(discriminatorView);
|
||||
if ((version < 0 || version > 1) || (discriminator < 0 || discriminator > 2)) {
|
||||
return {false, value::TypeTags::Nothing, 0};
|
||||
}
|
||||
@ -59,7 +58,7 @@ value::TagValueMaybeOwned ByteCode::genericNewKeyString(ArityType arity,
|
||||
auto ksVersion = static_cast<key_string::Version>(version);
|
||||
auto ksDiscriminator = static_cast<key_string::Discriminator>(discriminator);
|
||||
|
||||
uint32_t orderingBits = value::numericCast<int32_t>(orderingView.tag, orderingView.value);
|
||||
uint32_t orderingBits = value::numericCast<int32_t>(orderingView);
|
||||
|
||||
// Maximum number of orderings. An 'Ordering' cannot have more than 32 values at the moment.
|
||||
// Limit the usage to 32 bytes here anyway, because if that definition ever changes, the amount
|
||||
|
||||
Loading…
Reference in New Issue
Block a user