@@ -113,6 +113,23 @@ public void copyTo(int srcIndex, byte[] dest, int destPos, int count)
113113 @ Override
114114 public void copyFrom (byte [] src , int srcPos , int destIndex , int count )
115115 throws IndexOutOfBoundsException , PyException {
116+ copyFrom (src , srcPos , 1 , destIndex , count );
117+ }
118+
119+ /**
120+ * Generalisation of {@link PyBuffer#copyFrom(byte[], int, int, int)} to allow a stride within
121+ * the source array.
122+ *
123+ * @param src source byte array
124+ * @param srcPos byte-index location in source of first byte to copy
125+ * @param srcStride byte-index increment from one item to the next
126+ * @param destIndex starting item-index in the destination (i.e. <code>this</code>)
127+ * @param count number of items to copy in
128+ * @throws IndexOutOfBoundsException if access out of bounds in source or destination
129+ * @throws PyException (TypeError) if read-only buffer
130+ */
131+ protected void copyFrom (byte [] src , int srcPos , int srcStride , int destIndex , int count )
132+ throws IndexOutOfBoundsException , PyException {
116133
117134 checkWritable ();
118135
@@ -123,16 +140,19 @@ public void copyFrom(byte[] src, int srcPos, int destIndex, int count)
123140 int skip = stride - itemsize ;
124141 int d = byteIndex (destIndex );
125142
143+ int srcSkip = srcStride - itemsize ;
144+
126145 // Strategy depends on whether items are laid end-to-end or there are gaps
127- if (skip == 0 ) {
146+ if (skip == 0 && srcSkip == 0 ) {
128147 // Straight copy of contiguous bytes
129148 System .arraycopy (src , srcPos , storage , d , count * itemsize );
130149 } else {
131- // Non-contiguous copy: single byte items
132150 int limit = d + count * stride , s = srcPos ;
133151 if (itemsize == 1 ) {
152+ // Non-contiguous copy: single byte items
134153 for (; d != limit ; d += stride ) {
135- storage [d ] = src [s ++];
154+ storage [d ] = src [s ];
155+ s += srcStride ;
136156 }
137157 } else {
138158 // Non-contiguous copy: itemsize bytes then skip to next item
@@ -141,6 +161,7 @@ public void copyFrom(byte[] src, int srcPos, int destIndex, int count)
141161 while (d < t ) {
142162 storage [d ++] = src [s ++];
143163 }
164+ s += srcSkip ;
144165 }
145166 }
146167 }
@@ -149,56 +170,41 @@ public void copyFrom(byte[] src, int srcPos, int destIndex, int count)
149170
150171 @ Override
151172 public void copyFrom (PyBuffer src ) throws IndexOutOfBoundsException , PyException {
152- if (src instanceof BaseArrayBuffer ) {
173+ if (src instanceof BaseArrayBuffer && !this .overlaps ((BaseArrayBuffer )src )) {
174+ // We can do this efficiently, copying between arrays.
153175 copyFromArrayBuffer ((BaseArrayBuffer )src );
154176 } else {
155177 super .copyFrom (src );
156178 }
157179 }
158180
181+ private boolean overlaps (BaseArrayBuffer src ) {
182+ if (src .storage != this .storage ) {
183+ return false ;
184+ } else {
185+ int low = calcLeastIndex (), high = calcGreatestIndex ();
186+ int srcLow = src .calcLeastIndex (), srcHigh = src .calcGreatestIndex ();
187+ return (srcHigh >= low && high >= srcLow );
188+ }
189+ }
190+
159191 private void copyFromArrayBuffer (BaseArrayBuffer src ) throws IndexOutOfBoundsException ,
160192 PyException {
161193
162- checkWritable ();
163194 src .checkDimension (1 );
164195
165196 int itemsize = getItemsize ();
166197 int count = getSize ();
167198
168- // Block operation if different item or overall size (permit reshape)
199+ // Block operation if different item or overall size
169200 if (src .getItemsize () != itemsize || src .getSize () != count ) {
170201 throw differentStructure ();
171202 }
172203
173- for (int i = 0 ; i < count ; i ++) {
174- int s = src .byteIndex (i ), d = byteIndex (i );
175- for (int j = 0 ; j < itemsize ; j ++) {
176- storage [d ++] = src .byteAtImpl (s ++);
177- }
178- }
204+ // We depend on the striding copyFrom() acting directly on the source storage
205+ copyFrom (src .storage , src .index0 , src .strides [0 ], 0 , count );
179206 }
180207
181- /**
182- * Copy blocks of bytes, equally spaced in the source array, to locations equally spaced in the
183- * destination array, which may be the same array. The byte at
184- * <code>src[srcPos+k*srcStride+j]</code> will be copied to
185- * <code>dst[dstPos+k*dstStride+j]</code> for <code>0≤k<count</code> and
186- * <code>0≤j<size</code>. When the source and destination are the same array, the method
187- * deals correctly with the risk that a byte gets written under the alias <code>dst[x]</code>
188- * before it should have been copied referenced as <code>src[y]</code>.
189- *
190- * @param size of the blocks of bytes
191- * @param src the source array
192- * @param srcPos the position of the first block in the source
193- * @param srcStride the interval between the start of each block in the source
194- * @param dst the destination array
195- * @param dstPos the position of the first block in the destination
196- * @param dstStride the interval between the start of each block in the destination
197- * @param count the number of blocks to copy
198- */
199- private static void slicedArrayCopy (int size , byte [] src , int srcPos , int srcStride ,
200- byte [] dst , int dstPos , int dstStride , int count ) {}
201-
202208 @ Override
203209 protected ByteBuffer getNIOByteBufferImpl () {
204210 // The buffer spans the whole storage, which may include data not in the view
0 commit comments