@@ -912,6 +912,13 @@ private void splitAndTransferViewBufferAndDataBuffer(
912912 viewBuffer .getInt (
913913 ((long ) i * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH + BUF_INDEX_WIDTH );
914914 final ArrowBuf dataBuf = dataBuffers .get (readBufIndex );
915+ if (readBufOffset < 0
916+ || ((long ) readBufOffset + (long ) stringLength ) > dataBuf .capacity ()) {
917+ throw new IndexOutOfBoundsException (
918+ String .format (
919+ "index: %d, length: %d (expected: range(0, %d))" ,
920+ readBufOffset , stringLength , dataBuf .capacity ()));
921+ }
915922
916923 // allocate data buffer
917924 ArrowBuf currentDataBuf = target .allocateOrGetLastDataBuffer (stringLength );
@@ -1432,7 +1439,7 @@ public void copyFrom(int fromIndex, int thisIndex, ValueVector from) {
14321439 BitVectorHelper .unsetBit (validityBuffer , thisIndex );
14331440 } else {
14341441 final int viewLength = from .getDataBuffer ().getInt ((long ) fromIndex * ELEMENT_SIZE );
1435- copyFromNotNull (fromIndex , thisIndex , from , viewLength );
1442+ copyFromNotNull (from , fromIndex , thisIndex , viewLength );
14361443 }
14371444 lastSet = thisIndex ;
14381445 }
@@ -1454,39 +1461,35 @@ public void copyFromSafe(int fromIndex, int thisIndex, ValueVector from) {
14541461 } else {
14551462 final int viewLength = from .getDataBuffer ().getInt ((long ) fromIndex * ELEMENT_SIZE );
14561463 handleSafe (thisIndex , viewLength );
1457- copyFromNotNull (fromIndex , thisIndex , from , viewLength );
1464+ copyFromNotNull (from , fromIndex , thisIndex , viewLength );
14581465 }
14591466 lastSet = thisIndex ;
14601467 }
14611468
1462- private void copyFromNotNull (int fromIndex , int thisIndex , ValueVector from , int viewLength ) {
1469+ private void copyFromNotNull (ValueVector from , int fromIndex , int thisIndex , int viewLength ) {
14631470 BitVectorHelper .setBit (validityBuffer , thisIndex );
14641471 final int start = thisIndex * ELEMENT_SIZE ;
14651472 final int copyStart = fromIndex * ELEMENT_SIZE ;
14661473 if (viewLength > INLINE_SIZE ) {
1467- final int bufIndex =
1468- from .getDataBuffer ()
1469- .getInt (((long ) fromIndex * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH );
1470- final int dataOffset =
1471- from .getDataBuffer ()
1472- .getInt (
1473- ((long ) fromIndex * ELEMENT_SIZE )
1474- + LENGTH_WIDTH
1475- + PREFIX_WIDTH
1476- + BUF_INDEX_WIDTH );
1477- final ArrowBuf dataBuf = ((BaseVariableWidthViewVector ) from ).dataBuffers .get (bufIndex );
1478- final ArrowBuf thisDataBuf = allocateOrGetLastDataBuffer (viewLength );
1479-
1480- viewBuffer .setBytes (start , from .getDataBuffer (), copyStart , LENGTH_WIDTH + PREFIX_WIDTH );
1481- int writePosition = start + LENGTH_WIDTH + PREFIX_WIDTH ;
1482- // set buf id
1483- viewBuffer .setInt (writePosition , dataBuffers .size () - 1 );
1484- writePosition += BUF_INDEX_WIDTH ;
1485- // set offset
1486- viewBuffer .setInt (writePosition , (int ) thisDataBuf .writerIndex ());
1487-
1488- thisDataBuf .setBytes (thisDataBuf .writerIndex (), dataBuf , dataOffset , viewLength );
1489- thisDataBuf .writerIndex (thisDataBuf .writerIndex () + viewLength );
1474+ BaseVariableWidthViewVector fromVector = (BaseVariableWidthViewVector ) from ;
1475+ fromVector .getData (
1476+ fromIndex ,
1477+ (dataBuf , dataOffset , dataLength ) -> {
1478+ assert dataLength == viewLength ;
1479+ viewBuffer .setBytes (
1480+ start , fromVector .getDataBuffer (), copyStart , LENGTH_WIDTH + PREFIX_WIDTH );
1481+ //noinspection resource
1482+ final ArrowBuf thisDataBuf = allocateOrGetLastDataBuffer (viewLength );
1483+ int writePosition = start + LENGTH_WIDTH + PREFIX_WIDTH ;
1484+ // set buf id
1485+ viewBuffer .setInt (writePosition , dataBuffers .size () - 1 );
1486+ writePosition += BUF_INDEX_WIDTH ;
1487+ // set offset
1488+ viewBuffer .setInt (writePosition , (int ) thisDataBuf .writerIndex ());
1489+ thisDataBuf .setBytes (thisDataBuf .writerIndex (), dataBuf , dataOffset , viewLength );
1490+ thisDataBuf .writerIndex (thisDataBuf .writerIndex () + viewLength );
1491+ return null ;
1492+ });
14901493 } else {
14911494 from .getDataBuffer ().getBytes (copyStart , viewBuffer , start , ELEMENT_SIZE );
14921495 }
@@ -1502,16 +1505,12 @@ public ArrowBufPointer getDataPointer(int index, ArrowBufPointer reuse) {
15021505 if (isNull (index )) {
15031506 reuse .set (null , 0 , 0 );
15041507 } else {
1505- int length = getValueLength (index );
1506- if (length < INLINE_SIZE ) {
1507- int start = index * ELEMENT_SIZE + LENGTH_WIDTH ;
1508- reuse .set (viewBuffer , start , length );
1509- } else {
1510- final int bufIndex =
1511- viewBuffer .getInt (((long ) index * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH );
1512- ArrowBuf dataBuf = dataBuffers .get (bufIndex );
1513- reuse .set (dataBuf , 0 , length );
1514- }
1508+ getData (
1509+ index ,
1510+ (buf , offset , length ) -> {
1511+ reuse .set (buf , offset , length );
1512+ return null ;
1513+ });
15151514 }
15161515 return reuse ;
15171516 }
@@ -1526,19 +1525,45 @@ public int hashCode(int index, ArrowBufHasher hasher) {
15261525 if (isNull (index )) {
15271526 return ArrowBufPointer .NULL_HASH_CODE ;
15281527 }
1529- final int length = getValueLength (index );
1530- if (length < INLINE_SIZE ) {
1531- int start = index * ELEMENT_SIZE + LENGTH_WIDTH ;
1532- return ByteFunctionHelpers .hash (hasher , this .getDataBuffer (), start , start + length );
1533- } else {
1534- final int bufIndex =
1528+ return getData (
1529+ index ,
1530+ (buf , offset , length ) -> ByteFunctionHelpers .hash (hasher , buf , offset , offset + length ));
1531+ }
1532+
1533+ @ FunctionalInterface
1534+ protected interface ViewElementConsumer <T > {
1535+ T consume (ArrowBuf buf , int offset , int length );
1536+ }
1537+
1538+ /** Helper to get a single view value with sanity checking. */
1539+ protected <T > T getData (int index , ViewElementConsumer <T > consumer ) {
1540+ final int dataLength = getValueLength (index );
1541+ final ArrowBuf dataBuffer ;
1542+ final int dataOffset ;
1543+ if (dataLength > INLINE_SIZE ) {
1544+ final int bufferIndex =
15351545 viewBuffer .getInt (((long ) index * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH );
1536- final int dataOffset =
1546+ dataOffset =
15371547 viewBuffer .getInt (
15381548 ((long ) index * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH + BUF_INDEX_WIDTH );
1539- ArrowBuf dataBuf = dataBuffers .get (bufIndex );
1540- return ByteFunctionHelpers .hash (hasher , dataBuf , dataOffset , dataOffset + length );
1549+ dataBuffer = dataBuffers .get (bufferIndex );
1550+ } else {
1551+ dataBuffer = viewBuffer ;
1552+ dataOffset = index * ELEMENT_SIZE + BUF_INDEX_WIDTH ;
1553+ }
1554+ if (dataOffset < 0
1555+ || dataLength < 0
1556+ || ((long ) dataOffset + (long ) dataLength ) > dataBuffer .capacity ()) {
1557+ // In this case we don't check BOUNDS_CHECKING_ENABLED
1558+ // Likely this check is redundant, but we are trying to check eagerly before downstream code
1559+ // potentially
1560+ // tries to allocate based on the given dataLength
1561+ throw new IndexOutOfBoundsException (
1562+ String .format (
1563+ "index: %d, length: %d (expected: range(0, %d))" ,
1564+ dataOffset , dataLength , dataBuffer .capacity ()));
15411565 }
1566+ return consumer .consume (dataBuffer , dataOffset , dataLength );
15421567 }
15431568
15441569 /**
@@ -1555,42 +1580,16 @@ public int hashCode(int index, ArrowBufHasher hasher) {
15551580 * @return byte array containing the data of the element
15561581 */
15571582 protected byte [] getData (int index ) {
1558- final int dataLength = getValueLength (index );
1559- byte [] result = new byte [dataLength ];
1560- if (dataLength > INLINE_SIZE ) {
1561- // data is in the data buffer
1562- // get buffer index
1563- final int bufferIndex =
1564- viewBuffer .getInt (((long ) index * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH );
1565- // get data offset
1566- final int dataOffset =
1567- viewBuffer .getInt (
1568- ((long ) index * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH + BUF_INDEX_WIDTH );
1569- dataBuffers .get (bufferIndex ).getBytes (dataOffset , result , 0 , dataLength );
1570- } else {
1571- // data is in the view buffer
1572- viewBuffer .getBytes ((long ) index * ELEMENT_SIZE + BUF_INDEX_WIDTH , result , 0 , dataLength );
1573- }
1574- return result ;
1583+ return getData (index , ArrowBuf ::getBytesAsArray );
15751584 }
15761585
15771586 protected void getData (int index , ReusableBuffer <?> buffer ) {
1578- final int dataLength = getValueLength (index );
1579- if (dataLength > INLINE_SIZE ) {
1580- // data is in the data buffer
1581- // get buffer index
1582- final int bufferIndex =
1583- viewBuffer .getInt (((long ) index * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH );
1584- // get data offset
1585- final int dataOffset =
1586- viewBuffer .getInt (
1587- ((long ) index * ELEMENT_SIZE ) + LENGTH_WIDTH + PREFIX_WIDTH + BUF_INDEX_WIDTH );
1588- ArrowBuf dataBuf = dataBuffers .get (bufferIndex );
1589- buffer .set (dataBuf , dataOffset , dataLength );
1590- } else {
1591- // data is in the value buffer
1592- buffer .set (viewBuffer , ((long ) index * ELEMENT_SIZE ) + BUF_INDEX_WIDTH , dataLength );
1593- }
1587+ getData (
1588+ index ,
1589+ (buf , offset , length ) -> {
1590+ buffer .set (buf , offset , length );
1591+ return null ;
1592+ });
15941593 }
15951594
15961595 @ Override
0 commit comments