Rename xxx.lttng to xxx.lttng.core
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / event / TmfTimestamp.java
index 4fc0382838c63f51706a182ab1ff34aa46e06217..0708e277212645882d9b8251570ec05993e6b06b 100644 (file)
@@ -8,11 +8,11 @@
  * 
  * Contributors:
  *   Francois Chouinard - Initial API and implementation
+ *   Thomas Gatterweh  - Updated scaling / synchronization
  *******************************************************************************/
 
 package org.eclipse.linuxtools.tmf.event;
 
-
 /**
  * <b><u>TmfTimestamp</u></b>
  * <p>
@@ -41,7 +41,7 @@ package org.eclipse.linuxtools.tmf.event;
  * Notice that the adjusted timestamp value could be negative e.g. for events
  * that occurred before t0 wrt the reference clock.
  */
-public class TmfTimestamp implements Cloneable {
+public class TmfTimestamp implements Cloneable, Comparable<TmfTimestamp> {
 
        // ------------------------------------------------------------------------
     // Attributes
@@ -158,30 +158,22 @@ public class TmfTimestamp implements Cloneable {
      */
     public TmfTimestamp synchronize(long offset, byte newScale) throws ArithmeticException {
 
-        /*
-         * A java <code>long</code> has a maximum of 19 significant digits.
-         * (-9,223,372,036,854,775,808 .. +9,223,372,036,854,775,807)
-         * 
-         * It is therefore useless to try to synchronize 2 timestamps whose
-         * difference in scale exceeds that value.
-         */
-        int MAX_SCALING = 19;
-
-       long newValue = fValue;
+        long newValue = fValue;
         long newPrecision = fPrecision;
 
+        // Handle the easy case
+        if (fScale == newScale && offset == 0)
+               return this;
+        
         // Determine the scaling factor
         if (fScale != newScale) {
             int scaleDiff = Math.abs(fScale - newScale);
             // Let's try to be realistic...
-            if (scaleDiff > MAX_SCALING) {
-                throw new ArithmeticException("Scaling exception");
-            }
-            // Not pretty...
-            long scalingFactor = 1;
-            for (int i = 0; i < scaleDiff; i++) {
-                scalingFactor *= 10;
+            if (scaleDiff >= scalingFactors.length) {
+                throw new ArithmeticException("Scaling exception"); //$NON-NLS-1$
             }
+            // Adjust the timestamp
+            long scalingFactor = scalingFactors[scaleDiff];
             if (newScale < fScale) {
                 newValue *= scalingFactor;
                 newPrecision *= scalingFactor;
@@ -191,9 +183,64 @@ public class TmfTimestamp implements Cloneable {
             }
         }
 
-        return new TmfTimestamp(newValue + offset, newScale, newPrecision);
+        if (offset < 0) {
+               newValue = (newValue < Long.MIN_VALUE - offset) ? Long.MIN_VALUE : newValue + offset;
+        } else {
+               newValue = (newValue > Long.MAX_VALUE - offset) ? Long.MAX_VALUE : newValue + offset;
+        }
+
+        return new TmfTimestamp(newValue, newScale, newPrecision);
     }
 
+    private static final long scalingFactors[] = new long[] {
+       1L,
+       10L,
+       100L,
+       1000L,
+       10000L,
+       100000L,
+       1000000L,
+       10000000L,
+       100000000L,
+       1000000000L,
+       10000000000L,
+       100000000000L,
+       1000000000000L,
+       10000000000000L,
+       100000000000000L,
+       1000000000000000L,
+       10000000000000000L,
+       100000000000000000L,
+       1000000000000000000L,
+    };
+
+    private static final long scalingLimits[] = new long[] {
+       Long.MAX_VALUE / 1L,
+       Long.MAX_VALUE / 10L,
+       Long.MAX_VALUE / 100L,
+       Long.MAX_VALUE / 1000L,
+       Long.MAX_VALUE / 10000L,
+       Long.MAX_VALUE / 100000L,
+       Long.MAX_VALUE / 1000000L,
+       Long.MAX_VALUE / 10000000L,
+       Long.MAX_VALUE / 100000000L,
+       Long.MAX_VALUE / 1000000000L,
+       Long.MAX_VALUE / 10000000000L,
+       Long.MAX_VALUE / 100000000000L,
+       Long.MAX_VALUE / 1000000000000L,
+       Long.MAX_VALUE / 10000000000000L,
+       Long.MAX_VALUE / 100000000000000L,
+       Long.MAX_VALUE / 1000000000000000L,
+       Long.MAX_VALUE / 10000000000000000L,
+       Long.MAX_VALUE / 100000000000000000L,
+       Long.MAX_VALUE / 1000000000000000000L,
+    };
+
+    public static long getScalingFactor(byte scale)
+    {
+       return scalingFactors[scale];
+    }
+    
     /**
      * Compute the adjustment, in the reference scale, needed to synchronize
      * this timestamp with a reference timestamp.
@@ -209,6 +256,23 @@ public class TmfTimestamp implements Cloneable {
         return ts2.fValue - ts1.fValue;
     }
 
+    /**
+     * Compute the delta between two timestamps (adjusted to scale of current timestamp).
+     * 
+     * @param reference the reference timestamp to synchronize with
+     * @return the delta timestamp 
+     * @throws ArithmeticException
+     */
+    public TmfTimestamp getDelta(TmfTimestamp other) throws ArithmeticException {
+        TmfTimestamp newSecond = other;
+        if ((fScale != other.fScale) || (fPrecision != other.fPrecision)) {
+            newSecond = other.synchronize(0, fScale);
+        }
+        return new TmfTimestamp(fValue - newSecond.fValue,
+                                fScale, 
+                                newSecond.fPrecision > fPrecision ? newSecond.fPrecision : fPrecision);
+    }
+
     /**
      * Compare with another timestamp
      * 
@@ -220,42 +284,71 @@ public class TmfTimestamp implements Cloneable {
      */
     public int compareTo(final TmfTimestamp other, boolean withinPrecision) {
 
-       // If values have the same time scale, perform the comparison
-        if (fScale == other.fScale) {
-            if (withinPrecision) {
-                if ((fValue + fPrecision) < (other.fValue - other.fPrecision))
-                    return -1;
-                if ((fValue - fPrecision) > (other.fValue + other.fPrecision))
-                    return 1;
-                return 0;
-            }
-            return (fValue == other.fValue) ? 0 : (fValue < other.fValue) ? -1 : 1;
-        }
+               // If values have the same time scale, perform the comparison
+               if (fScale == other.fScale) {
+                       if (withinPrecision)
+                               return compareWithinPrecision(this.fValue, this.fPrecision, other.fValue, other.fPrecision);
+                       else
+                               return compareNoPrecision(this.fValue, other.fValue);
+               }
 
-        // If values have different time scales, adjust to the finest one and
-        // then compare. If the scaling difference is too large, revert to
-        // some heuristics. Hopefully, nobody will try to compare galactic and
-        // quantic clock events...
-        byte newScale = (fScale < other.fScale) ? fScale : other.fScale;
-        try {
-            TmfTimestamp ts1 = this.synchronize(0, newScale);
-            TmfTimestamp ts2 = other.synchronize(0, newScale);
-            return ts1.compareTo(ts2, withinPrecision);
-        } catch (ArithmeticException e) {
-            if ((fValue == 0) || (other.fValue == 0)) {
-                return (fValue == other.fValue) ? 0
-                        : (fValue < other.fValue) ? -1 : 1;
-            }
-            if ((fValue > 0) && (other.fValue > 0)) {
-                return (fScale < other.fScale) ? -1 : 1;
-            }
-            if ((fValue < 0) && (other.fValue < 0)) {
-                return (fScale > other.fScale) ? -1 : 1;
-            }
-            return (fValue < 0) ? -1 : 1;
-        }
+               // If values have different time scales, adjust to the finest one and
+               // then compare. If the scaling difference is too large, revert to
+               // some heuristics. Hopefully, nobody will try to compare galactic and
+               // quantic clock events...
+               int scaleDiff = Math.abs(fScale - other.fScale);
+               long factor, limit;
+               if (scaleDiff < scalingFactors.length) {
+                       factor = scalingFactors[scaleDiff];
+                       limit = scalingLimits[scaleDiff];
+               } else {
+                       factor = 0;
+                       limit = 0; // !!! 0 can always be scaled!!!
+               }
+
+               if (fScale < other.fScale) {
+                       // this has finer scale, so other should be scaled
+                       if (withinPrecision)
+                               if (other.fValue > limit || other.fValue < -limit
+                                               || other.fPrecision > limit
+                                               || other.fPrecision < -limit)
+                                       return other.fValue > 0 ? -1 : +1; // other exceeds scaling limit
+                               else
+                                       return compareWithinPrecision(this.fValue, this.fPrecision,
+                                                       other.fValue * factor, other.fPrecision * factor);
+                       else if (other.fValue > limit || other.fValue < -limit)
+                               return other.fValue > 0 ? -1 : +1; // other exceeds scaling limit
+                       else
+                               return compareNoPrecision(this.fValue, other.fValue * factor);
+               } else {
+                       // other has finer scale, so this should be scaled
+                       if (withinPrecision)
+                               if (this.fValue > limit || this.fValue < -limit
+                                               || this.fPrecision > limit || this.fPrecision < -limit)
+                                       return this.fValue > 0 ? +1 : -1; // we exceed scaling limit
+                               else
+                                       return compareWithinPrecision(this.fValue * factor,
+                                                       this.fPrecision * factor, other.fValue,
+                                                       other.fPrecision);
+                       else if (this.fValue > limit || this.fValue < -limit)
+                               return this.fValue > 0 ? +1 : -1; // we exceed scaling limit
+                       else
+                               return compareNoPrecision(this.fValue * factor, other.fValue);
+               }
     }
 
+       private static int compareNoPrecision(long thisValue, long otherValue) {
+               return (thisValue == otherValue) ? 0 : (thisValue < otherValue) ? -1 : 1;
+       }
+
+       private static int compareWithinPrecision(long thisValue, long thisPrecision, long otherValue, long otherPrecision) {
+               if ((thisValue + thisPrecision) < (otherValue - otherPrecision))
+                       return -1;
+               if ((thisValue - thisPrecision) > (otherValue + otherPrecision))
+                       return 1;
+               return 0;
+       }
+
        // ------------------------------------------------------------------------
     // Object
        // ------------------------------------------------------------------------
@@ -278,6 +371,7 @@ public class TmfTimestamp implements Cloneable {
     }
 
     @Override
+    @SuppressWarnings("nls")
     public String toString() {
        return "[TmfTimestamp(" + fValue + "," + fScale + "," + fPrecision + ")]";
     }
@@ -295,4 +389,9 @@ public class TmfTimestamp implements Cloneable {
                return clone;
     }
 
-}
\ No newline at end of file
+       @Override
+       public int compareTo(TmfTimestamp o) {
+               return compareTo(o, false);
+       }
+
+}
This page took 0.026761 seconds and 5 git commands to generate.