From 3367abda39762f9250cd5f043eb6154f2a192b37 Mon Sep 17 00:00:00 2001 From: Sharang Gupta Date: Thu, 22 Oct 2026 00:23:14 +0100 Subject: [PATCH 1/3] GH-200: Keep registered type count when transferring a DenseUnionVector DenseUnionVector's transfer pair copied the type fields and type map into the target vector but left the target's nextTypeId at zero. The target therefore behaved as if no types were registered: transferring it again created no child transfer pairs and produced a vector whose values read back as null. Copy nextTypeId alongside the other type metadata when the transfer pairs are created, so both transfer() and splitAndTransfer() leave the target with the same registered types as the source. Closes #200. --- .../codegen/templates/DenseUnionVector.java | 1 + .../arrow/vector/TestDenseUnionVector.java | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/vector/src/main/codegen/templates/DenseUnionVector.java b/vector/src/main/codegen/templates/DenseUnionVector.java index e9a9a2878b..d955992de9 100644 --- a/vector/src/main/codegen/templates/DenseUnionVector.java +++ b/vector/src/main/codegen/templates/DenseUnionVector.java @@ -631,6 +631,7 @@ private void createTransferPairs() { to.childVectors[i] = dstVec; internalTransferPairs[i] = srcVec.makeTransferPair(dstVec); } + to.nextTypeId = nextTypeId; } @Override diff --git a/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java b/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java index 9ac30730c4..bbc09d15fe 100644 --- a/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java +++ b/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java @@ -191,6 +191,40 @@ public void testTransfer() throws Exception { } } + @Test + public void testTransferOfTransferredVector() { + try (DenseUnionVector srcVector = newIntAndBitVector(); + DenseUnionVector intermediate = + new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null); + DenseUnionVector destVector = + new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null)) { + srcVector.makeTransferPair(intermediate).transfer(); + + intermediate.makeTransferPair(destVector).transfer(); + + assertEquals(2, destVector.getValueCount()); + assertEquals(5, destVector.getObject(0)); + assertEquals(true, destVector.getObject(1)); + } + } + + @Test + public void testTransferOfSplitAndTransferredVector() { + try (DenseUnionVector srcVector = newIntAndBitVector(); + DenseUnionVector intermediate = + new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null); + DenseUnionVector destVector = + new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null)) { + srcVector.makeTransferPair(intermediate).splitAndTransfer(0, 2); + + intermediate.makeTransferPair(destVector).transfer(); + + assertEquals(2, destVector.getValueCount()); + assertEquals(5, destVector.getObject(0)); + assertEquals(true, destVector.getObject(1)); + } + } + @Test public void testSplitAndTransfer() throws Exception { try (DenseUnionVector sourceVector = @@ -686,6 +720,19 @@ public void testChildVectorValueCounts() { } } + private DenseUnionVector newIntAndBitVector() { + DenseUnionVector vector = new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null); + vector.allocateNew(); + byte intTypeId = vector.registerNewTypeId(Field.nullable("", MinorType.INT.getType())); + vector.setTypeId(0, intTypeId); + vector.setSafe(0, newIntHolder(5)); + byte bitTypeId = vector.registerNewTypeId(Field.nullable("", MinorType.BIT.getType())); + vector.setTypeId(1, bitTypeId); + vector.setSafe(1, newBitHolder(true)); + vector.setValueCount(2); + return vector; + } + private static NullableIntHolder newIntHolder(int value) { final NullableIntHolder holder = new NullableIntHolder(); holder.isSet = 1; From f41e9a8c542c75de8041e2fb4437d6ca1b2ec543 Mon Sep 17 00:00:00 2001 From: Sharang Gupta Date: Thu, 22 Oct 2026 08:38:55 +0100 Subject: [PATCH 2/3] GH-200: Test a second transfer for every vector kind Replace the two DenseUnionVector-only tests with a parameterized test in TestSplitAndTransfer. For 18 vector kinds it transfers, or splits and transfers, a populated vector, transfers the result again, and compares it with the original using VectorEqualsVisitor. Without the fix only the DenseUnionVector cases fail. --- .../arrow/vector/TestDenseUnionVector.java | 47 ---- .../arrow/vector/TestSplitAndTransfer.java | 237 ++++++++++++++++++ 2 files changed, 237 insertions(+), 47 deletions(-) diff --git a/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java b/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java index bbc09d15fe..9ac30730c4 100644 --- a/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java +++ b/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java @@ -191,40 +191,6 @@ public void testTransfer() throws Exception { } } - @Test - public void testTransferOfTransferredVector() { - try (DenseUnionVector srcVector = newIntAndBitVector(); - DenseUnionVector intermediate = - new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null); - DenseUnionVector destVector = - new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null)) { - srcVector.makeTransferPair(intermediate).transfer(); - - intermediate.makeTransferPair(destVector).transfer(); - - assertEquals(2, destVector.getValueCount()); - assertEquals(5, destVector.getObject(0)); - assertEquals(true, destVector.getObject(1)); - } - } - - @Test - public void testTransferOfSplitAndTransferredVector() { - try (DenseUnionVector srcVector = newIntAndBitVector(); - DenseUnionVector intermediate = - new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null); - DenseUnionVector destVector = - new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null)) { - srcVector.makeTransferPair(intermediate).splitAndTransfer(0, 2); - - intermediate.makeTransferPair(destVector).transfer(); - - assertEquals(2, destVector.getValueCount()); - assertEquals(5, destVector.getObject(0)); - assertEquals(true, destVector.getObject(1)); - } - } - @Test public void testSplitAndTransfer() throws Exception { try (DenseUnionVector sourceVector = @@ -720,19 +686,6 @@ public void testChildVectorValueCounts() { } } - private DenseUnionVector newIntAndBitVector() { - DenseUnionVector vector = new DenseUnionVector(EMPTY_SCHEMA_PATH, allocator, null, null); - vector.allocateNew(); - byte intTypeId = vector.registerNewTypeId(Field.nullable("", MinorType.INT.getType())); - vector.setTypeId(0, intTypeId); - vector.setSafe(0, newIntHolder(5)); - byte bitTypeId = vector.registerNewTypeId(Field.nullable("", MinorType.BIT.getType())); - vector.setTypeId(1, bitTypeId); - vector.setSafe(1, newBitHolder(true)); - vector.setValueCount(2); - return vector; - } - private static NullableIntHolder newIntHolder(int value) { final NullableIntHolder holder = new NullableIntHolder(); holder.isSet = 1; diff --git a/vector/src/test/java/org/apache/arrow/vector/TestSplitAndTransfer.java b/vector/src/test/java/org/apache/arrow/vector/TestSplitAndTransfer.java index adf4eba10c..ff4c98009d 100644 --- a/vector/src/test/java/org/apache/arrow/vector/TestSplitAndTransfer.java +++ b/vector/src/test/java/org/apache/arrow/vector/TestSplitAndTransfer.java @@ -17,6 +17,7 @@ package org.apache.arrow.vector; import static java.util.Arrays.asList; +import static org.apache.arrow.vector.testing.ValueVectorDataPopulator.setVector; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -26,17 +27,28 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; import org.apache.arrow.memory.BufferAllocator; import org.apache.arrow.memory.RootAllocator; +import org.apache.arrow.vector.compare.VectorEqualsVisitor; import org.apache.arrow.vector.complex.DenseUnionVector; import org.apache.arrow.vector.complex.FixedSizeListVector; +import org.apache.arrow.vector.complex.LargeListVector; import org.apache.arrow.vector.complex.LargeListViewVector; import org.apache.arrow.vector.complex.ListVector; +import org.apache.arrow.vector.complex.ListViewVector; import org.apache.arrow.vector.complex.MapVector; import org.apache.arrow.vector.complex.StructVector; import org.apache.arrow.vector.complex.UnionVector; +import org.apache.arrow.vector.complex.impl.UnionMapWriter; +import org.apache.arrow.vector.holders.NullableBitHolder; +import org.apache.arrow.vector.holders.NullableIntHolder; +import org.apache.arrow.vector.types.Types.MinorType; import org.apache.arrow.vector.types.pojo.ArrowType; import org.apache.arrow.vector.types.pojo.ArrowType.Struct; import org.apache.arrow.vector.types.pojo.Field; @@ -44,9 +56,15 @@ import org.apache.arrow.vector.util.TransferPair; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Named; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class TestSplitAndTransfer { + private static final int POPULATED_VALUE_COUNT = 3; + private BufferAllocator allocator; @BeforeEach @@ -977,4 +995,223 @@ public void testMapVectorZeroStartIndexAndLength() { newMapVector.clear(); } } + + /** + * Vectors of each kind, populated with {@link #POPULATED_VALUE_COUNT} values. A transfer pair + * that misses part of the vector's state only shows when its target is transferred again, as with + * the type ids of {@link DenseUnionVector} (GH-200). + */ + static Stream populatedVectorKinds() { + return Stream.of( + vectorKind( + "IntVector", + vectorAllocator -> { + IntVector vector = new IntVector("vector", vectorAllocator); + setVector(vector, 1, null, 3); + return vector; + }), + vectorKind( + "BitVector", + vectorAllocator -> { + BitVector vector = new BitVector("vector", vectorAllocator); + setVector(vector, 1, null, 0); + return vector; + }), + vectorKind( + "VarCharVector", + vectorAllocator -> { + VarCharVector vector = new VarCharVector("vector", vectorAllocator); + setVector(vector, "a", null, "c"); + return vector; + }), + vectorKind( + "LargeVarCharVector", + vectorAllocator -> { + LargeVarCharVector vector = new LargeVarCharVector("vector", vectorAllocator); + setVector(vector, "a", null, "c"); + return vector; + }), + vectorKind( + "ViewVarCharVector", + vectorAllocator -> { + ViewVarCharVector vector = new ViewVarCharVector("vector", vectorAllocator); + setVector(vector, "a", null, "c"); + return vector; + }), + vectorKind( + "VarBinaryVector", + vectorAllocator -> { + VarBinaryVector vector = new VarBinaryVector("vector", vectorAllocator); + setVector(vector, new byte[] {1, 2}, null, new byte[] {3}); + return vector; + }), + vectorKind( + "LargeVarBinaryVector", + vectorAllocator -> { + LargeVarBinaryVector vector = new LargeVarBinaryVector("vector", vectorAllocator); + setVector(vector, new byte[] {1, 2}, null, new byte[] {3}); + return vector; + }), + vectorKind( + "ViewVarBinaryVector", + vectorAllocator -> { + ViewVarBinaryVector vector = new ViewVarBinaryVector("vector", vectorAllocator); + setVector(vector, new byte[] {1, 2}, null, new byte[] {3}); + return vector; + }), + vectorKind( + "FixedSizeBinaryVector", + vectorAllocator -> { + FixedSizeBinaryVector vector = + new FixedSizeBinaryVector("vector", vectorAllocator, 2); + setVector(vector, new byte[] {1, 2}, null, new byte[] {5, 6}); + return vector; + }), + vectorKind( + "ListVector", + vectorAllocator -> { + ListVector vector = ListVector.empty("vector", vectorAllocator); + setVector(vector, asList(1, 2), null, asList(3)); + return vector; + }), + vectorKind( + "LargeListVector", + vectorAllocator -> { + LargeListVector vector = LargeListVector.empty("vector", vectorAllocator); + setVector(vector, asList(1, 2), null, asList(3)); + return vector; + }), + vectorKind( + "FixedSizeListVector", + vectorAllocator -> { + FixedSizeListVector vector = FixedSizeListVector.empty("vector", 2, vectorAllocator); + setVector(vector, asList(1, 2), null, asList(3, 4)); + return vector; + }), + vectorKind( + "ListViewVector", + vectorAllocator -> { + ListViewVector vector = ListViewVector.empty("vector", vectorAllocator); + setVector(vector, asList(1, 2), asList(), asList(3)); + return vector; + }), + vectorKind( + "LargeListViewVector", + vectorAllocator -> { + LargeListViewVector vector = LargeListViewVector.empty("vector", vectorAllocator); + setVector(vector, asList(1, 2), asList(), asList(3)); + return vector; + }), + vectorKind( + "MapVector", + vectorAllocator -> { + MapVector vector = MapVector.empty("vector", vectorAllocator, false); + UnionMapWriter writer = vector.getWriter(); + writer.allocate(); + for (int i = 0; i < POPULATED_VALUE_COUNT; i++) { + writer.setPosition(i); + writer.startMap(); + writer.startEntry(); + writer.key().integer().writeInt(i); + writer.value().integer().writeInt(i * 10); + writer.endEntry(); + writer.endMap(); + } + writer.setValueCount(POPULATED_VALUE_COUNT); + return vector; + }), + vectorKind( + "StructVector", + vectorAllocator -> { + StructVector vector = StructVector.empty("vector", vectorAllocator); + Map> children = new LinkedHashMap<>(); + children.put("a", asList(1, null, 3)); + children.put("b", asList(4, 5, 6)); + setVector(vector, children); + return vector; + }), + vectorKind( + "UnionVector", + vectorAllocator -> { + UnionVector vector = new UnionVector("vector", vectorAllocator, null, null); + vector.allocateNew(); + vector.setType(0, MinorType.INT); + vector.setSafe(0, intHolder(5)); + vector.setType(1, MinorType.BIT); + vector.setSafe(1, bitHolder(true)); + vector.setType(2, MinorType.INT); + vector.setSafe(2, intHolder(7)); + vector.setValueCount(POPULATED_VALUE_COUNT); + return vector; + }), + vectorKind( + "DenseUnionVector", + vectorAllocator -> { + DenseUnionVector vector = new DenseUnionVector("vector", vectorAllocator, null, null); + vector.allocateNew(); + byte intTypeId = + vector.registerNewTypeId(Field.nullable("", MinorType.INT.getType())); + byte bitTypeId = + vector.registerNewTypeId(Field.nullable("", MinorType.BIT.getType())); + vector.setTypeId(0, intTypeId); + vector.setSafe(0, intHolder(5)); + vector.setTypeId(1, bitTypeId); + vector.setSafe(1, bitHolder(true)); + vector.setTypeId(2, intTypeId); + vector.setSafe(2, intHolder(7)); + vector.setValueCount(POPULATED_VALUE_COUNT); + return vector; + })); + } + + @ParameterizedTest + @MethodSource("populatedVectorKinds") + public void testTransferOfTransferredVector(Function populated) { + assertTransferredTwiceKeepsValues(populated, TransferPair::transfer); + } + + @ParameterizedTest + @MethodSource("populatedVectorKinds") + public void testTransferOfSplitAndTransferredVector( + Function populated) { + assertTransferredTwiceKeepsValues( + populated, pair -> pair.splitAndTransfer(0, POPULATED_VALUE_COUNT)); + } + + private void assertTransferredTwiceKeepsValues( + Function populated, Consumer firstTransfer) { + try (ValueVector expected = populated.apply(allocator); + ValueVector source = populated.apply(allocator)) { + TransferPair first = source.getTransferPair(allocator); + try (ValueVector intermediate = first.getTo()) { + firstTransfer.accept(first); + TransferPair second = intermediate.getTransferPair(allocator); + try (ValueVector target = second.getTo()) { + second.transfer(); + assertTrue( + VectorEqualsVisitor.vectorEquals(expected, target), + () -> "expected " + expected + " but was " + target); + } + } + } + } + + private static Arguments vectorKind( + String name, Function populate) { + return Arguments.of(Named.of(name, populate)); + } + + private static NullableIntHolder intHolder(int value) { + NullableIntHolder holder = new NullableIntHolder(); + holder.isSet = 1; + holder.value = value; + return holder; + } + + private static NullableBitHolder bitHolder(boolean value) { + NullableBitHolder holder = new NullableBitHolder(); + holder.isSet = 1; + holder.value = value ? 1 : 0; + return holder; + } } From 7f8447ec48fb4cb0948c8407c0fa4953e59bb98f Mon Sep 17 00:00:00 2001 From: Sharang Gupta Date: Sat, 7 Nov 2026 08:23:49 +0000 Subject: [PATCH 3/3] GH-200: Map transferred children by type id DenseUnionVector keeps typeFields and childVectors by type id and maps the i-th registered type to its id through typeMapFields, but the transfer pair indexed them by i. With declared type ids such as [5, 10], the target's setValueCount then failed on a null child, and splitAndTransfer indexed per-type arrays of length nextTypeId by type id. --- .../codegen/templates/DenseUnionVector.java | 26 +++++--- .../arrow/vector/TestDenseUnionVector.java | 64 +++++++++++++++++++ 2 files changed, 80 insertions(+), 10 deletions(-) diff --git a/vector/src/main/codegen/templates/DenseUnionVector.java b/vector/src/main/codegen/templates/DenseUnionVector.java index d955992de9..4cc859653a 100644 --- a/vector/src/main/codegen/templates/DenseUnionVector.java +++ b/vector/src/main/codegen/templates/DenseUnionVector.java @@ -103,7 +103,8 @@ public class DenseUnionVector extends AbstractContainerVector implements FieldVe */ private Field[] typeFields = new Field[Byte.MAX_VALUE + 1]; /** - * The index is the index into the typeFields array, and the value is the logical field id. + * The index is the order in which the type was registered, and the value is its type id, i.e. + * the index into the typeFields and childVectors arrays. */ private byte[] typeMapFields = new byte[Byte.MAX_VALUE + 1]; @@ -623,12 +624,16 @@ public TransferImpl(DenseUnionVector to) { } private void createTransferPairs() { + // Expects the i-th registered type to be the i-th child of the internal struct. Type + // fields and child vectors are indexed by its type id, which differs from i when the + // union declares type ids. for (int i = 0; i < nextTypeId; i++) { + byte typeId = typeMapFields[i]; ValueVector srcVec = internalStruct.getVectorById(i); ValueVector dstVec = to.internalStruct.getVectorById(i); - to.typeFields[i] = typeFields[i]; - to.typeMapFields[i] = typeMapFields[i]; - to.childVectors[i] = dstVec; + to.typeFields[typeId] = typeFields[typeId]; + to.typeMapFields[i] = typeId; + to.childVectors[typeId] = dstVec; internalTransferPairs[i] = srcVec.makeTransferPair(dstVec); } to.nextTypeId = nextTypeId; @@ -647,7 +652,7 @@ public void transfer() { for (int i = 0; i < nextTypeId; i++) { if (internalTransferPairs[i] != null) { internalTransferPairs[i].transfer(); - to.childVectors[i] = internalTransferPairs[i].getTo(); + to.childVectors[typeMapFields[i]] = internalTransferPairs[i].getTo(); } } to.valueCount = valueCount; @@ -670,8 +675,8 @@ public void splitAndTransfer(int startIndex, int length) { to.reallocOffsetBuffer(); } - int [] typeCounts = new int[nextTypeId]; - int [] typeStarts = new int[nextTypeId]; + int [] typeCounts = new int[Byte.MAX_VALUE + 1]; + int [] typeStarts = new int[Byte.MAX_VALUE + 1]; for (int i = 0; i < typeCounts.length; i++) { typeCounts[i] = 0; typeStarts[i] = -1; @@ -690,9 +695,10 @@ public void splitAndTransfer(int startIndex, int length) { // transfer vector values for (int i = 0; i < nextTypeId; i++) { - if (typeCounts[i] > 0 && typeStarts[i] != -1) { - internalTransferPairs[i].splitAndTransfer(typeStarts[i], typeCounts[i]); - to.childVectors[i] = internalTransferPairs[i].getTo(); + byte typeId = typeMapFields[i]; + if (typeCounts[typeId] > 0 && typeStarts[typeId] != -1) { + internalTransferPairs[i].splitAndTransfer(typeStarts[typeId], typeCounts[typeId]); + to.childVectors[typeId] = internalTransferPairs[i].getTo(); } } diff --git a/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java b/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java index 9ac30730c4..dfe5e01297 100644 --- a/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java +++ b/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java @@ -191,6 +191,48 @@ public void testTransfer() throws Exception { } } + @Test + public void testTransferWithDeclaredTypeIds() { + try (DenseUnionVector srcVector = newVectorWithTypeIds5And10()) { + Field srcField = srcVector.getField(); + TransferPair pair = srcVector.getTransferPair(allocator); + try (DenseUnionVector destVector = (DenseUnionVector) pair.getTo()) { + pair.transfer(); + destVector.setValueCount(3); + + assertEquals(srcField, destVector.getField()); + assertEquals(5, destVector.getObject(0)); + assertEquals(true, destVector.getObject(1)); + assertEquals(7, destVector.getObject(2)); + + TransferPair secondPair = destVector.getTransferPair(allocator); + try (DenseUnionVector secondDestVector = (DenseUnionVector) secondPair.getTo()) { + secondPair.transfer(); + + assertEquals(srcField, secondDestVector.getField()); + assertEquals(3, secondDestVector.getValueCount()); + assertEquals(5, secondDestVector.getObject(0)); + assertEquals(true, secondDestVector.getObject(1)); + assertEquals(7, secondDestVector.getObject(2)); + } + } + } + } + + @Test + public void testSplitAndTransferWithDeclaredTypeIds() { + try (DenseUnionVector srcVector = newVectorWithTypeIds5And10()) { + TransferPair pair = srcVector.getTransferPair(allocator); + try (DenseUnionVector destVector = (DenseUnionVector) pair.getTo()) { + pair.splitAndTransfer(1, 2); + + assertEquals(2, destVector.getValueCount()); + assertEquals(true, destVector.getObject(0)); + assertEquals(7, destVector.getObject(1)); + } + } + } + @Test public void testSplitAndTransfer() throws Exception { try (DenseUnionVector sourceVector = @@ -706,4 +748,26 @@ private static NullableFloat4Holder newFloat4Holder(float value) { holder.value = value; return holder; } + + /** Returns a dense union with declared type ids 5 (int) and 10 (bit), as IPC can produce. */ + private DenseUnionVector newVectorWithTypeIds5And10() { + Field field = + new Field( + "u", + FieldType.nullable(new ArrowType.Union(UnionMode.Dense, new int[] {5, 10})), + List.of( + Field.nullable("i", MinorType.INT.getType()), + Field.nullable("b", MinorType.BIT.getType()))); + DenseUnionVector vector = (DenseUnionVector) field.createVector(allocator); + vector.allocateNew(); + vector.setTypeId(0, (byte) 5); + vector.setSafe(0, newIntHolder(5)); + vector.setTypeId(1, (byte) 10); + vector.setSafe(1, newBitHolder(true)); + vector.setTypeId(2, (byte) 5); + vector.setSafe(2, newIntHolder(7)); + vector.setValueCount(3); + return vector; + } + }