You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2021/05/23 10:54:22 UTC

svn commit: r1890133 - in /pdfbox/trunk/pdfbox/src: main/java/org/apache/pdfbox/cos/COSObjectKey.java test/java/org/apache/pdfbox/cos/COSObjectKeyTest.java

Author: lehmi
Date: Sun May 23 10:54:22 2021
New Revision: 1890133

URL: http://svn.apache.org/viewvc?rev=1890133&view=rev
Log:
PDFBOX-5151: optimize internal representation of an object key based on a proposal by Roland Meub

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObjectKey.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/COSObjectKeyTest.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObjectKey.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObjectKey.java?rev=1890133&r1=1890132&r2=1890133&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObjectKey.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObjectKey.java Sun May 23 10:54:22 2021
@@ -22,10 +22,14 @@ package org.apache.pdfbox.cos;
  * @author Michael Traut
  * 
  */
-public class COSObjectKey implements Comparable<COSObjectKey>
+public final class COSObjectKey implements Comparable<COSObjectKey>
 {
-    private final long number;
-    private final int generation;
+    private static final int GENERATION_OFFSET = Long.SIZE - Short.SIZE;
+    private static final long NUMBER_MASK = (long) Math.pow(2, GENERATION_OFFSET) - 1;
+    // combined number and generation
+    // The highest 16 bits hold the generation 0-65535
+    // The rest is used for the number (even though 34 bit are sufficient for 10 digits)
+    private final long numberAndGeneration;
     
     /**
      * Constructor.
@@ -45,8 +49,15 @@ public class COSObjectKey implements Com
      */
     public COSObjectKey(long num, int gen)
     {
-        number = num;
-        generation = gen;
+        if (num < 0)
+        {
+            throw new IllegalArgumentException("Object number must not be a negative value");
+        }
+        if (gen < 0)
+        {
+            throw new IllegalArgumentException("Generation number must not be a negative value");
+        }
+        numberAndGeneration = (long) gen << GENERATION_OFFSET | (num & NUMBER_MASK);
     }
 
     /**
@@ -56,9 +67,8 @@ public class COSObjectKey implements Com
     public boolean equals(Object obj)
     {
         COSObjectKey objToBeCompared = obj instanceof COSObjectKey ? (COSObjectKey)obj : null;
-        return objToBeCompared != null &&
-                objToBeCompared.getNumber() == getNumber() &&
-                objToBeCompared.getGeneration() == getGeneration();
+        return objToBeCompared != null
+                && objToBeCompared.numberAndGeneration == numberAndGeneration;
     }
 
     /**
@@ -68,7 +78,7 @@ public class COSObjectKey implements Com
      */
     public int getGeneration()
     {
-        return generation;
+        return (int) (numberAndGeneration >>> GENERATION_OFFSET);
     }
 
     /**
@@ -78,7 +88,7 @@ public class COSObjectKey implements Com
      */
     public long getNumber()
     {
-        return number;
+        return numberAndGeneration & NUMBER_MASK;
     }
 
     /**
@@ -87,26 +97,19 @@ public class COSObjectKey implements Com
     @Override
     public int hashCode()
     {
-        // most likely generation is 0. Shift number 4 times (fast as multiply)
-        // to support generation numbers up to 15
-        return Long.valueOf((number << 4) + generation).hashCode();
+        return Long.hashCode(numberAndGeneration);
     }
 
     @Override
     public String toString()
     {
-        return number + " " + generation + " R";
+        return Long.toString(getNumber()) + " " + Integer.toString(getGeneration()) + " R";
     }
 
     @Override
     public int compareTo(COSObjectKey other)
     {
-        int result = Long.compare(getNumber(), other.getNumber());
-        if (result == 0)
-        {
-            return Integer.compare(getGeneration(), other.getGeneration());
-        }
-        return result;
+        return Long.compare(numberAndGeneration, other.numberAndGeneration);
     }
 
 }

Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/COSObjectKeyTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/COSObjectKeyTest.java?rev=1890133&r1=1890132&r2=1890133&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/COSObjectKeyTest.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/COSObjectKeyTest.java Sun May 23 10:54:22 2021
@@ -17,18 +17,45 @@
 package org.apache.pdfbox.cos;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import org.junit.jupiter.api.Test;
 
 class COSObjectKeyTest
 {
     @Test
+    void testInputValues()
+    {
+        try
+        {
+            new COSObjectKey(-1L, 0);
+            fail("An IllegalArgumentException shouzld have been thrown");
+        }
+        catch (IllegalArgumentException exception)
+        {
+
+        }
+
+        try
+        {
+            new COSObjectKey(1L, -1);
+            fail("An IllegalArgumentException shouzld have been thrown");
+        }
+        catch (IllegalArgumentException exception)
+        {
+
+        }
+    }
+
+    @Test
     void compareToInputNotNullOutputZero()
     {
         // Arrange
-        final COSObjectKey objectUnderTest = new COSObjectKey(0L, 0);
-        final COSObjectKey other = new COSObjectKey(0L, 0);
+        final COSObjectKey objectUnderTest = new COSObjectKey(1L, 0);
+        final COSObjectKey other = new COSObjectKey(1L, 0);
 
         // Act
         final int retval = objectUnderTest.compareTo(other);
@@ -38,17 +65,46 @@ class COSObjectKeyTest
     }
 
     @Test
-    void compareToInputNotNullOutputPositive()
+    void compareToInputNotNullOutputNotNull()
     {
         // Arrange
-        final COSObjectKey objectUnderTest = new COSObjectKey(0L, 0);
-        final COSObjectKey other = new COSObjectKey(-9_223_372_036_854_775_808L, 0);
+        final COSObjectKey objectUnderTest = new COSObjectKey(1L, 0);
+        final COSObjectKey other = new COSObjectKey(9_999_999L, 0);
 
         // Act
-        final int retval = objectUnderTest.compareTo(other);
+        final int retvalNegative = objectUnderTest.compareTo(other);
+        final int retvalPositive = other.compareTo(objectUnderTest);
 
-        // Assert result
-        assertEquals(1, retval);
+        // Assert results
+        assertEquals(-1, retvalNegative);
+        assertEquals(1, retvalPositive);
+    }
+
+    @Test
+    void testEquals()
+    {
+        assertTrue(new COSObjectKey(100, 0).equals(new COSObjectKey(100, 0)));
+        assertFalse(new COSObjectKey(100, 0).equals(new COSObjectKey(101, 0)));
+    }
+
+    @Test
+    void testInternalRepresentation()
+    {
+        COSObjectKey key = new COSObjectKey(100, 0);
+        assertEquals(100, key.getNumber());
+        assertEquals(0, key.getGeneration());
+
+        key = new COSObjectKey(200, 4);
+        assertEquals(200, key.getNumber());
+        assertEquals(4, key.getGeneration());
+
+        key = new COSObjectKey(200000, 0);
+        assertEquals(200000, key.getNumber());
+        assertEquals(0, key.getGeneration());
+
+        key = new COSObjectKey(87654321, 123);
+        assertEquals(87654321, key.getNumber());
+        assertEquals(123, key.getGeneration());
     }
 
     @Test