From 9aa915a5df949e6c726bdccca361e8bb09f4ae63 Mon Sep 17 00:00:00 2001
From: Vojtech Moravec <vojtech.moravec.st@vsb.cz>
Date: Mon, 10 Aug 2020 12:22:44 +0200
Subject: [PATCH] Move last VQ loading logic to loaders.

In this commit we moved the last vector type Vector1D loading to
abstract loaders. As stated before, this makes to code faster and more
memory friendly.
---
 .../azgracompress/io/loader/BasicLoader.java  | 58 ++++++++++++++++++-
 .../azgracompress/io/loader/IPlaneLoader.java | 21 +++++++
 .../io/loader/ImageJBufferLoader.java         |  7 ++-
 .../io/loader/RawDataLoader.java              |  7 ++-
 .../azgracompress/io/loader/SCIFIOLoader.java | 31 ++--------
 5 files changed, 96 insertions(+), 28 deletions(-)

diff --git a/src/main/java/azgracompress/io/loader/BasicLoader.java b/src/main/java/azgracompress/io/loader/BasicLoader.java
index 3e11384..04330f0 100644
--- a/src/main/java/azgracompress/io/loader/BasicLoader.java
+++ b/src/main/java/azgracompress/io/loader/BasicLoader.java
@@ -26,11 +26,67 @@ public abstract class BasicLoader {
     public abstract int[] loadPlaneData(final int plane) throws IOException;
 
     protected int valueAt(final int plane, final int offset) {
+        new Exception().printStackTrace(System.err);
         assert (false) : "Unimplemented overload of BasicLoader::valueAt()";
         return Integer.MIN_VALUE;
     }
 
-    protected int[][] loadBlocksImplLoadPlaneData(final V2i blockDim, final Range<Integer> planeRange) throws IOException {
+    protected int[][] loadRowVectorsImplByLoadPlaneData(final int vectorSize, final Range<Integer> planeRange) throws IOException {
+        final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize);
+        final int vectorCount = dims.getZ() * dims.getY() * rowVectorCount;
+
+        int[][] rowVectors = new int[vectorCount][vectorSize];
+
+        int vectorIndex = 0;
+        int baseX;
+
+        for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) {
+            final int[] planeData = loadPlaneData(plane);
+            for (int row = 0; row < dims.getY(); row++) {
+                for (int rowVectorIndex = 0; rowVectorIndex < rowVectorCount; rowVectorIndex++) {
+                    // Copy single vector.
+                    baseX = rowVectorIndex * vectorSize;
+
+                    for (int vectorX = 0; vectorX < vectorSize; vectorX++) {
+                        if (baseX + vectorX >= dims.getY())
+                            break;
+                        rowVectors[vectorIndex][vectorX] = planeData[Chunk2D.index((baseX + vectorX), row, dims.getY())];
+                    }
+                    ++vectorIndex;
+                }
+            }
+        }
+        return rowVectors;
+    }
+
+    protected int[][] loadRowVectorsImplByValueAt(final int vectorSize, final Range<Integer> planeRange) {
+        final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize);
+        final int vectorCount = dims.getZ() * dims.getY() * rowVectorCount;
+
+        int[][] rowVectors = new int[vectorCount][vectorSize];
+
+        int vectorIndex = 0;
+        int baseX;
+
+        for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) {
+            for (int row = 0; row < dims.getY(); row++) {
+                for (int rowVectorIndex = 0; rowVectorIndex < rowVectorCount; rowVectorIndex++) {
+                    // Copy single vector.
+                    baseX = rowVectorIndex * vectorSize;
+
+                    for (int vectorX = 0; vectorX < vectorSize; vectorX++) {
+                        if (baseX + vectorX >= dims.getY())
+                            break;
+                        rowVectors[vectorIndex][vectorX] = valueAt(plane, Chunk2D.index((baseX + vectorX), row, dims.getY()));
+                    }
+                    ++vectorIndex;
+                }
+            }
+        }
+        return rowVectors;
+    }
+
+    protected int[][] loadBlocksImplByLoadPlaneData(final V2i blockDim, final Range<Integer> planeRange) throws IOException {
         final int blockSize = blockDim.multiplyTogether();
         final int planeCount = planeRange.getTo() - planeRange.getFrom();
         final int blockCount = planeCount * Chunk2D.calculateRequiredChunkCount(dims.toV2i(), blockDim);
diff --git a/src/main/java/azgracompress/io/loader/IPlaneLoader.java b/src/main/java/azgracompress/io/loader/IPlaneLoader.java
index 7e20bac..db338cf 100644
--- a/src/main/java/azgracompress/io/loader/IPlaneLoader.java
+++ b/src/main/java/azgracompress/io/loader/IPlaneLoader.java
@@ -54,6 +54,27 @@ public interface IPlaneLoader {
      */
     int[] loadAllPlanesU16Data() throws IOException;
 
+    /**
+     * Load row vectors from the entire dataset.
+     *
+     * @param vectorSize Width of the row vector.
+     * @return Row vector data from the entire dataset.
+     * @throws IOException When fails to load plane data.
+     */
+    default int[][] loadRowVectors(final int vectorSize) throws IOException {
+        return loadRowVectors(vectorSize, new Range<>(0, getImageDimensions().getZ()));
+    }
+
+    /**
+     * Load row vectors from specified plane range in the dataset.
+     *
+     * @param vectorSize Width of the row vector.
+     * @param planeRange Source plane range.
+     * @return Row vector data from the specified plane range.
+     * @throws IOException When fails to load plane data.
+     */
+    int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) throws IOException;
+
     /**
      * Load blocks from the entire dataset.
      *
diff --git a/src/main/java/azgracompress/io/loader/ImageJBufferLoader.java b/src/main/java/azgracompress/io/loader/ImageJBufferLoader.java
index c43bcfc..baea7c9 100644
--- a/src/main/java/azgracompress/io/loader/ImageJBufferLoader.java
+++ b/src/main/java/azgracompress/io/loader/ImageJBufferLoader.java
@@ -93,7 +93,12 @@ public final class ImageJBufferLoader extends BasicLoader implements IPlaneLoade
     }
 
     @Override
-    public int[][] loadBlocks(V2i blockDim, Range<Integer> planeRange) throws IOException {
+    public int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) {
+        return loadRowVectorsImplByValueAt(vectorSize, planeRange);
+    }
+
+    @Override
+    public int[][] loadBlocks(V2i blockDim, Range<Integer> planeRange) {
         return loadBlocksImplByValueAt(blockDim, planeRange);
     }
 
diff --git a/src/main/java/azgracompress/io/loader/RawDataLoader.java b/src/main/java/azgracompress/io/loader/RawDataLoader.java
index 701a509..385f17f 100644
--- a/src/main/java/azgracompress/io/loader/RawDataLoader.java
+++ b/src/main/java/azgracompress/io/loader/RawDataLoader.java
@@ -117,9 +117,14 @@ public final class RawDataLoader extends BasicLoader implements IPlaneLoader {
         return values;
     }
 
+    @Override
+    public int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) throws IOException {
+        return loadRowVectorsImplByLoadPlaneData(vectorSize, planeRange);
+    }
+
     @Override
     public int[][] loadBlocks(V2i blockDim, Range<Integer> planeRange) throws IOException {
-        return loadBlocksImplLoadPlaneData(blockDim, planeRange);
+        return loadBlocksImplByLoadPlaneData(blockDim, planeRange);
     }
 
     @Override
diff --git a/src/main/java/azgracompress/io/loader/SCIFIOLoader.java b/src/main/java/azgracompress/io/loader/SCIFIOLoader.java
index 4e15166..7b4d012 100644
--- a/src/main/java/azgracompress/io/loader/SCIFIOLoader.java
+++ b/src/main/java/azgracompress/io/loader/SCIFIOLoader.java
@@ -16,10 +16,6 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader {
     private final FileInputData inputDataInfo;
     private final Reader reader;
 
-    // Current plane buffer
-    private int currentPlaneIndex = -1;
-    private int[] currentPlaneData;
-
     /**
      * Create SCIFIO reader from input file.
      *
@@ -33,26 +29,6 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader {
         this.reader = ScifioWrapper.getReader(this.inputDataInfo.getFilePath());
     }
 
-//    @Override
-//    protected int valueAt(int plane, int offset) {
-//        // TODO(Moravec): Measure if caching the current plane byte buffer make any sense.
-//        if (plane != currentPlaneIndex) {
-//            currentPlaneIndex = plane;
-//            try {
-//                currentPlaneData = TypeConverter.unsignedShortBytesToIntArray(reader.openPlane(0, currentPlaneIndex).getBytes());
-//            } catch (FormatException e) {
-//                System.err.println(e.toString());
-//                e.printStackTrace();
-//                assert (false) : "FormatException in SCIFIOLoader::valueAt()";
-//            } catch (IOException e) {
-//                System.err.println(e.toString());
-//                e.printStackTrace();
-//                assert (false) : "IOException in SCIFIOLoader::valueAt()";
-//            }
-//        }
-//        return currentPlaneData[offset];
-//    }
-
     @Override
     public int[] loadPlaneData(final int plane) throws IOException {
         byte[] planeBytes;
@@ -129,9 +105,14 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader {
         return values;
     }
 
+    @Override
+    public int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) throws IOException {
+        return loadRowVectorsImplByLoadPlaneData(vectorSize, planeRange);
+    }
+
     @Override
     public int[][] loadBlocks(V2i blockDim, Range<Integer> planeRange) throws IOException {
-        return loadBlocksImplLoadPlaneData(blockDim, planeRange);
+        return loadBlocksImplByLoadPlaneData(blockDim, planeRange);
     }
 
     @Override
-- 
GitLab