From 5b67cd0ee59327c14f931cd565ff5b7fae90db62 Mon Sep 17 00:00:00 2001
From: Vojtech Moravec <vojtech.moravec.st@vsb.cz>
Date: Thu, 22 Oct 2020 10:06:33 +0200
Subject: [PATCH] Add loadPlanesU16DataTo2dArray API to IPlaneLoader.

---
 .../cz/it4i/qcmp/io/loader/IPlaneLoader.java  | 14 ++++
 .../cz/it4i/qcmp/io/loader/RawDataLoader.java | 68 +++++++++++++------
 2 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/src/main/java/cz/it4i/qcmp/io/loader/IPlaneLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/IPlaneLoader.java
index 9352e1f..a864ac6 100644
--- a/src/main/java/cz/it4i/qcmp/io/loader/IPlaneLoader.java
+++ b/src/main/java/cz/it4i/qcmp/io/loader/IPlaneLoader.java
@@ -62,6 +62,20 @@ public interface IPlaneLoader {
      */
     int[] loadPlanesU16Data(int[] planes) throws IOException;
 
+    /**
+     * Load data of multiple specified planes. This functions exists, next to loadPlaneData, because some loaders
+     * can take advantage in loading multiple planes in one call context.
+     * <p>
+     * Data are stored in 2D array.
+     *
+     * @param planes Zero based plane indices.
+     * @return Planes data concatenated in single array.
+     * @throws IOException when fails to load plane data.
+     */
+    default int[][] loadPlanesU16DataTo2dArray(final int[] planes) throws IOException {
+        throw new IOException("Not Implemented in the current loader.");
+    }
+
     /**
      * Load all planes data of the image dataset.
      *
diff --git a/src/main/java/cz/it4i/qcmp/io/loader/RawDataLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/RawDataLoader.java
index e6f310c..55f0e85 100644
--- a/src/main/java/cz/it4i/qcmp/io/loader/RawDataLoader.java
+++ b/src/main/java/cz/it4i/qcmp/io/loader/RawDataLoader.java
@@ -15,6 +15,10 @@ import java.util.Arrays;
 public final class RawDataLoader extends BasicLoader implements IPlaneLoader {
     private final FileInputData inputDataInfo;
 
+    private interface StorePlaneDataCallback {
+        void store(final int planeOffset, final int[] planeData);
+    }
+
     public RawDataLoader(final FileInputData inputDataInfo) {
         super(inputDataInfo.getDimensions());
         this.inputDataInfo = inputDataInfo;
@@ -61,51 +65,71 @@ public final class RawDataLoader extends BasicLoader implements IPlaneLoader {
         return TypeConverter.unsignedShortBytesToIntArray(buffer);
     }
 
-    @Override
-    public int[] loadPlanesU16Data(final int[] planes) throws IOException {
+    private void loadPlanesU16DataImpl(final int[] planes, final StorePlaneDataCallback storeCallback) throws IOException {
         if (planes.length < 1) {
-            return new int[0];
+            return;
         } else if (planes.length == 1) {
-            return loadPlaneData(planes[0]);
+            storeCallback.store(0, loadPlaneData(planes[0]));
         }
 
         final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY();
-        final long planeDataSize = 2 * (long) planeValueCount;
-
-        final long totalValueCount = (long) planeValueCount * planes.length;
-
-        if (totalValueCount > (long) Integer.MAX_VALUE) {
-            throw new IOException("Integer count is too big.");
-        }
+        final int planeDataSize = 2 * planeValueCount;
 
-        final int[] values = new int[(int) totalValueCount];
+        final byte[] planeBuffer = new byte[planeDataSize];
 
         Arrays.sort(planes);
-
-        try (final FileInputStream fileStream = new FileInputStream(inputDataInfo.getFilePath());
-             final DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) {
-
+        int planeOffset = 0;
+        try (final FileInputStream fileStream = new FileInputStream(inputDataInfo.getFilePath())) {
             int lastIndex = 0;
-            int valIndex = 0;
-
             for (final int planeIndex : planes) {
                 // Skip specific number of bytes to get to the next plane.
                 final int requestedSkip = (planeIndex == 0) ? 0 : ((planeIndex - lastIndex) - 1) * (int) planeDataSize;
                 lastIndex = planeIndex;
 
-                final int actualSkip = dis.skipBytes(requestedSkip);
+                final long actualSkip = fileStream.skip(requestedSkip);
                 if (requestedSkip != actualSkip) {
                     throw new IOException("Skip operation failed.");
                 }
 
-                for (int i = 0; i < planeValueCount; i++) {
-                    values[valIndex++] = dis.readUnsignedShort();
+                int toRead = planeDataSize;
+                while (toRead > 0) {
+                    final int read = fileStream.read(planeBuffer, planeDataSize - toRead, toRead);
+                    assert (read > 0);
+                    toRead -= read;
                 }
 
+                storeCallback.store(planeOffset, TypeConverter.unsignedShortBytesToIntArray(planeBuffer));
+                ++planeOffset;
             }
         }
+    }
 
-        return values;
+    @Override
+    public int[][] loadPlanesU16DataTo2dArray(final int[] planes) throws IOException {
+        final int[][] data = new int[planes.length][];
+
+        loadPlanesU16DataImpl(planes, (index, planeData) -> {
+            data[index] = planeData;
+        });
+
+        return data;
+    }
+
+    @Override
+    public int[] loadPlanesU16Data(final int[] planes) throws IOException {
+
+        final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY();
+        final long totalValueCount = (long) planeValueCount * planes.length;
+        if (totalValueCount > (long) Integer.MAX_VALUE) {
+            throw new IOException("Integer count is too big.");
+        }
+        final int[] data = new int[(int) totalValueCount];
+
+        loadPlanesU16DataImpl(planes, (index, planeData) -> {
+            System.arraycopy(planeData, 0, data, (index * planeValueCount), planeValueCount);
+        });
+
+        return data;
     }
 
     @Override
-- 
GitLab