Skip to content

Commit 22d35f6

Browse files
pedroerpmeta-codesync[bot]
authored andcommitted
test: Add makeMapVector overload with explicit offsets and sizes (facebookincubator#16749)
Summary: Pull Request resolved: facebookincubator#16749 Add a new `mapVector(offsets, sizes, keys, values, isNullAt)` overload to `VectorMaker` and the corresponding `makeMapVector` wrapper in `VectorTestBase`. Unlike the existing offsets-only overload (which derives sizes from consecutive offset differences), this variant accepts explicit sizes, enabling construction of MapVectors with non-consecutive or out-of-order layouts — useful for testing code that processes vectors produced by filters, slices, or other transformations. Reviewed By: Yuhta Differential Revision: D96238549 fbshipit-source-id: 64ad8de4c311c34688314cd8b50fd8f29cf34968
1 parent 1f4d5ff commit 22d35f6

File tree

4 files changed

+127
-15
lines changed

4 files changed

+127
-15
lines changed

velox/vector/tests/VectorMakerTest.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,76 @@ TEST_F(VectorMakerTest, mapVectorUsingKeyValueVectorsUnevenKeysValues) {
694694
EXPECT_THROW(maker_.mapVector({0, 2, 4}, keys, values), VeloxRuntimeError);
695695
}
696696

697+
TEST_F(VectorMakerTest, mapVectorWithExplicitSizesNoNulls) {
698+
// Keys/values laid out non-contiguously:
699+
// index: 0 1 2 3 4
700+
// key: 1 2 3 4 5
701+
// val: 10 20 30 40 50
702+
//
703+
// Row 0 -> offset=2, size=3 (indices 2,3,4)
704+
// Row 1 -> offset=0, size=2 (indices 0,1)
705+
auto keys = maker_.flatVector<int32_t>({1, 2, 3, 4, 5});
706+
auto values = maker_.flatVector<int64_t>({10, 20, 30, 40, 50});
707+
708+
auto mapVector = maker_.mapVector({2, 0}, {3, 2}, keys, values);
709+
710+
EXPECT_EQ(mapVector->size(), 2);
711+
EXPECT_EQ(mapVector->offsetAt(0), 2);
712+
EXPECT_EQ(mapVector->sizeAt(0), 3);
713+
EXPECT_EQ(mapVector->offsetAt(1), 0);
714+
EXPECT_EQ(mapVector->sizeAt(1), 2);
715+
EXPECT_FALSE(mapVector->isNullAt(0));
716+
EXPECT_FALSE(mapVector->isNullAt(1));
717+
}
718+
719+
TEST_F(VectorMakerTest, mapVectorWithExplicitSizesWithGaps) {
720+
// Rows reference non-adjacent regions, leaving a gap at indices 2-3.
721+
// index: 0 1 2 3 4 5
722+
// key: 1 2 9 9 3 4
723+
// val: 10 20 0 0 30 40
724+
//
725+
// Row 0 -> offset=0, size=2
726+
// Row 1 -> offset=4, size=2
727+
auto keys = maker_.flatVector<int32_t>({1, 2, 9, 9, 3, 4});
728+
auto values = maker_.flatVector<int64_t>({10, 20, 0, 0, 30, 40});
729+
730+
auto mapVector = maker_.mapVector({0, 4}, {2, 2}, keys, values);
731+
732+
EXPECT_EQ(mapVector->size(), 2);
733+
EXPECT_EQ(mapVector->offsetAt(0), 0);
734+
EXPECT_EQ(mapVector->sizeAt(0), 2);
735+
EXPECT_EQ(mapVector->offsetAt(1), 4);
736+
EXPECT_EQ(mapVector->sizeAt(1), 2);
737+
}
738+
739+
TEST_F(VectorMakerTest, mapVectorWithExplicitSizesWithNulls) {
740+
auto keys = maker_.flatVector<int32_t>({1, 2, 3, 4});
741+
auto values = maker_.flatVector<int64_t>({10, 20, 30, 40});
742+
743+
// Row 0 -> offset=2, size=2, not null
744+
// Row 1 -> null
745+
// Row 2 -> offset=0, size=2, not null
746+
auto mapVector = maker_.mapVector({2, 0, 0}, {2, 0, 2}, keys, values, {1});
747+
748+
EXPECT_EQ(mapVector->size(), 3);
749+
EXPECT_FALSE(mapVector->isNullAt(0));
750+
EXPECT_TRUE(mapVector->isNullAt(1));
751+
EXPECT_FALSE(mapVector->isNullAt(2));
752+
EXPECT_EQ(mapVector->offsetAt(0), 2);
753+
EXPECT_EQ(mapVector->sizeAt(0), 2);
754+
EXPECT_EQ(mapVector->sizeAt(1), 0);
755+
EXPECT_EQ(mapVector->offsetAt(2), 0);
756+
EXPECT_EQ(mapVector->sizeAt(2), 2);
757+
}
758+
759+
TEST_F(VectorMakerTest, mapVectorWithExplicitSizesMismatch) {
760+
auto keys = maker_.flatVector<int32_t>({1, 2});
761+
auto values = maker_.flatVector<int64_t>({10, 20});
762+
763+
// offsets and sizes must have the same length.
764+
EXPECT_THROW(maker_.mapVector({0}, {1, 1}, keys, values), VeloxRuntimeError);
765+
}
766+
697767
TEST_F(VectorMakerTest, mapVectorStringString) {
698768
auto mapVector = maker_.mapVector<std::string, std::string>({
699769
{{"a", "1"}, {"b", "2"}},

velox/vector/tests/utils/VectorMaker.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -247,34 +247,53 @@ MapVectorPtr VectorMaker::mapVector(
247247
const std::vector<vector_size_t>& nulls) {
248248
VELOX_CHECK_EQ(keys->size(), values->size());
249249

250+
// Derive sizes from consecutive offsets.
250251
const auto size = offsets.size();
251-
BufferPtr offsetsBuffer = allocateOffsets(size, pool_);
252-
BufferPtr sizesBuffer = allocateSizes(size, pool_);
253-
BufferPtr nullsBuffer = nullptr;
254-
auto rawOffsets = offsetsBuffer->asMutable<vector_size_t>();
255-
auto rawSizes = sizesBuffer->asMutable<vector_size_t>();
256-
257-
for (int i = 0; i < size - 1; i++) {
258-
rawSizes[i] = offsets[i + 1] - offsets[i];
252+
std::vector<vector_size_t> sizes(size);
253+
for (size_t i = 0; i + 1 < size; ++i) {
254+
sizes[i] = offsets[i + 1] - offsets[i];
255+
}
256+
if (size > 0) {
257+
sizes.back() = keys->size() - offsets.back();
259258
}
260-
rawSizes[size - 1] = keys->size() - offsets.back();
261259

262-
memcpy(rawOffsets, offsets.data(), size * sizeof(vector_size_t));
260+
return mapVector(offsets, sizes, keys, values, nulls);
261+
}
263262

263+
MapVectorPtr VectorMaker::mapVector(
264+
const std::vector<vector_size_t>& offsets,
265+
const std::vector<vector_size_t>& sizes,
266+
const VectorPtr& keys,
267+
const VectorPtr& values,
268+
const std::vector<vector_size_t>& nulls) {
269+
VELOX_CHECK_EQ(offsets.size(), sizes.size());
270+
271+
const auto numRows = offsets.size();
272+
BufferPtr offsetsBuffer = allocateOffsets(numRows, pool_);
273+
BufferPtr sizesBuffer = allocateSizes(numRows, pool_);
274+
memcpy(
275+
offsetsBuffer->asMutable<vector_size_t>(),
276+
offsets.data(),
277+
numRows * sizeof(vector_size_t));
278+
memcpy(
279+
sizesBuffer->asMutable<vector_size_t>(),
280+
sizes.data(),
281+
numRows * sizeof(vector_size_t));
282+
283+
BufferPtr nullsBuffer = nullptr;
264284
if (!nulls.empty()) {
265-
nullsBuffer = AlignedBuffer::allocate<bool>(size, pool_, bits::kNotNull);
285+
nullsBuffer = allocateNulls(numRows, pool_);
266286
auto rawNulls = nullsBuffer->asMutable<uint64_t>();
267-
268-
for (int i = 0; i < nulls.size(); i++) {
269-
bits::setNull(rawNulls, nulls[i]);
287+
for (const auto idx : nulls) {
288+
bits::setNull(rawNulls, idx);
270289
}
271290
}
272291

273292
return std::make_shared<MapVector>(
274293
pool_,
275294
MAP(keys->type(), values->type()),
276295
nullsBuffer,
277-
size,
296+
numRows,
278297
offsetsBuffer,
279298
sizesBuffer,
280299
keys,

velox/vector/tests/utils/VectorMaker.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,17 @@ class VectorMaker {
10501050
const VectorPtr& values,
10511051
const std::vector<vector_size_t>& nulls = {});
10521052

1053+
/// Create a MapVector from explicit offsets, sizes, and key/value vectors.
1054+
/// Unlike the offsets-only overload above, this allows non-consecutive or
1055+
/// out-of-order offsets (e.g. for testing vectors produced by filters or
1056+
/// slices). An optional nulls vector specifies which row indices are null.
1057+
MapVectorPtr mapVector(
1058+
const std::vector<vector_size_t>& offsets,
1059+
const std::vector<vector_size_t>& sizes,
1060+
const VectorPtr& keys,
1061+
const VectorPtr& values,
1062+
const std::vector<vector_size_t>& nulls = {});
1063+
10531064
private:
10541065
vector_size_t createOffsetsAndSizes(
10551066
vector_size_t size,

velox/vector/tests/utils/VectorTestBase.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,18 @@ class VectorTestBase {
664664
return vectorMaker_.mapVector(offsets, keyVector, valueVector, nulls);
665665
}
666666

667+
// Creates a MapVector with explicit offsets and sizes, allowing
668+
// non-consecutive or out-of-order layouts in the underlying key/value arrays.
669+
MapVectorPtr makeMapVector(
670+
const std::vector<vector_size_t>& offsets,
671+
const std::vector<vector_size_t>& sizes,
672+
const VectorPtr& keyVector,
673+
const VectorPtr& valueVector,
674+
const std::vector<vector_size_t>& nulls = {}) {
675+
return vectorMaker_.mapVector(
676+
offsets, sizes, keyVector, valueVector, nulls);
677+
}
678+
667679
MapVectorPtr makeAllNullMapVector(
668680
vector_size_t size,
669681
const TypePtr& keyType,

0 commit comments

Comments
 (0)