// Path: unsafe-tests/src/main/java/net/bramp/unsafe/examples/FourLongs.java
// public class FourLongs implements Comparable<FourLongs> {
//   public long a, b, c, d;
// 
//   public FourLongs() {
//     this(0, 0, 0, 0);
//   }
// 
//   /**
//    * Creates a new FourLongs.
//    *
//    * @param a 1st field
//    * @param b 2nd field
//    * @param c 3rd field
//    * @param d 4th field
//    */
//   public FourLongs(long a, long b, long c, long d) {
//     this.a = a;
//     this.b = b;
//     this.c = c;
//     this.d = d;
//   }
// 
//   @Override public String toString() {
//     return "FourLongs{" +
//         "a=0x" + Long.toHexString(a) + ", " +
//         "b=0x" + Long.toHexString(b) + ", " +
//         "c=0x" + Long.toHexString(c) + ", " +
//         "d=0x" + Long.toHexString(d) + '}';
//   }
// 
//   @Override public boolean equals(Object obj) {
//     if (this == obj) {
//       return true;
//     }
//     if (obj == null || getClass() != obj.getClass()) {
//       return false;
//     }
//     FourLongs fourLongs = (FourLongs) obj;
//     return Objects.equal(a, fourLongs.a)
//         && Objects.equal(b, fourLongs.b)
//         && Objects.equal(c, fourLongs.c)
//         && Objects.equal(d, fourLongs.d);
//   }
// 
//   @Override public int hashCode() {
//     return Objects.hashCode(a, b, c, d);
//   }
// 
//   @Override public int compareTo(FourLongs obj) {
//     return ComparisonChain.start()
//         .compare(a, obj.a)
//         .compare(b, obj.b)
//         .compare(c, obj.c)
//         .compare(d, obj.d)
//         .result();
//   }
// }
// 
// Path: unsafe-tests/src/main/java/net/bramp/unsafe/examples/UnalignedClass.java
// public class UnalignedClass implements Comparable<UnalignedClass> {
//   public final char c;
// 
//   public UnalignedClass(char c) {
//     this.c = c;
//   }
// 
//   public UnalignedClass(int i) {
//     this.c = (char)i;
//   }
// 
//   @Override
//   public String toString() {
//     return "UnalignedClass{c=" + (int)c + "}";
//   }
// 
//   @Override
//   public int compareTo(UnalignedClass obj) {
//     return ComparisonChain.start().compare(c, obj.c).result();
//   }
// 
//   @Override
//   public boolean equals(Object obj) {
//     return obj instanceof UnalignedClass && c == ((UnalignedClass)obj).c;
//   }
// }
// 
// Path: unsafe-helper/src/main/java/net/bramp/unsafe/UnsafeHelper.java
// public static long firstFieldOffset(Object obj) {
//   return firstFieldOffset(obj.getClass());
// }
// 
// Path: unsafe-helper/src/main/java/net/bramp/unsafe/UnsafeHelper.java
// public static long sizeOfFields(Object obj) {
//   return sizeOfFields(obj.getClass());
// }


import net.bramp.unsafe.examples.FourLongs;
import net.bramp.unsafe.examples.UnalignedClass;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import sun.misc.Unsafe;
import java.lang.reflect.InvocationTargetException;
import static net.bramp.unsafe.UnsafeHelper.firstFieldOffset;
import static net.bramp.unsafe.UnsafeHelper.sizeOfFields;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
  protected abstract UnsafeCopier createCopier(long offset, long length) throws Exception;
  protected abstract boolean supportsUnaligned();
  protected abstract int stride();

  /**
   * Ensure the test classes looks how we want
   */
  @BeforeClass
  public static void checkAssumptions() {
    // FourLongs is aligned and a multiple of 8 bytes
    assertTrue(firstFieldOffset(FourLongs.class) % 8 == 0);
    assertEquals(4 * 8, sizeOfFields(FourLongs.class));

    // UnalignedClass is not 8 byte aligned, and not a multiple of 8.
    assertTrue(firstFieldOffset(UnalignedClass.class) % 8 != 0);
    assertTrue(sizeOfFields(UnalignedClass.class) % 8 != 0);
  }

  @Test public void testZeroIterations() throws Exception {
    UnsafeCopier copier = createCopier(fourLongOffset, 0);
    FourLongs dest = test(copier, new FourLongs(1, 2, 3, 4), new FourLongs());
    assertEquals("Dest should remain unchanged with zero copies", new FourLongs(0, 0, 0, 0), dest);
  }

  @Test public void testOneIterations() throws Exception {
    UnsafeCopier copier = createCopier(fourLongOffset, 8);
    FourLongs dest = test(copier, new FourLongs(1, 2, 3, 4), new FourLongs());
    assertEquals("Dest should have just the first field altered", new FourLongs(1, 0, 0, 0), dest);
  }

// Path: unsafe-tests/src/main/java/net/bramp/unsafe/examples/FourLongs.java
// public class FourLongs implements Comparable<FourLongs> {
//   public long a, b, c, d;
// 
//   public FourLongs() {
//     this(0, 0, 0, 0);
//   }
// 
//   /**
//    * Creates a new FourLongs.
//    *
//    * @param a 1st field
//    * @param b 2nd field
//    * @param c 3rd field
//    * @param d 4th field
//    */
//   public FourLongs(long a, long b, long c, long d) {
//     this.a = a;
//     this.b = b;
//     this.c = c;
//     this.d = d;
//   }
// 
//   @Override public String toString() {
//     return "FourLongs{" +
//         "a=0x" + Long.toHexString(a) + ", " +
//         "b=0x" + Long.toHexString(b) + ", " +
//         "c=0x" + Long.toHexString(c) + ", " +
//         "d=0x" + Long.toHexString(d) + '}';
//   }
// 
//   @Override public boolean equals(Object obj) {
//     if (this == obj) {
//       return true;
//     }
//     if (obj == null || getClass() != obj.getClass()) {
//       return false;
//     }
//     FourLongs fourLongs = (FourLongs) obj;
//     return Objects.equal(a, fourLongs.a)
//         && Objects.equal(b, fourLongs.b)
//         && Objects.equal(c, fourLongs.c)
//         && Objects.equal(d, fourLongs.d);
//   }
// 
//   @Override public int hashCode() {
//     return Objects.hashCode(a, b, c, d);
//   }
// 
//   @Override public int compareTo(FourLongs obj) {
//     return ComparisonChain.start()
//         .compare(a, obj.a)
//         .compare(b, obj.b)
//         .compare(c, obj.c)
//         .compare(d, obj.d)
//         .result();
//   }
// }
// 
// Path: unsafe-tests/src/main/java/net/bramp/unsafe/examples/UnalignedClass.java
// public class UnalignedClass implements Comparable<UnalignedClass> {
//   public final char c;
// 
//   public UnalignedClass(char c) {
//     this.c = c;
//   }
// 
//   public UnalignedClass(int i) {
//     this.c = (char)i;
//   }
// 
//   @Override
//   public String toString() {
//     return "UnalignedClass{c=" + (int)c + "}";
//   }
// 
//   @Override
//   public int compareTo(UnalignedClass obj) {
//     return ComparisonChain.start().compare(c, obj.c).result();
//   }
// 
//   @Override
//   public boolean equals(Object obj) {
//     return obj instanceof UnalignedClass && c == ((UnalignedClass)obj).c;
//   }
// }
// 
// Path: unsafe-helper/src/main/java/net/bramp/unsafe/UnsafeHelper.java
// public static long firstFieldOffset(Object obj) {
//   return firstFieldOffset(obj.getClass());
// }
// 
// Path: unsafe-helper/src/main/java/net/bramp/unsafe/UnsafeHelper.java
// public static long sizeOfFields(Object obj) {
//   return sizeOfFields(obj.getClass());
// }


// Path: unsafe-unroller/src/test/java/net/bramp/unsafe/AbstractUnsafeCopierTest.java
import net.bramp.unsafe.examples.FourLongs;
import net.bramp.unsafe.examples.UnalignedClass;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import sun.misc.Unsafe;
import java.lang.reflect.InvocationTargetException;
import static net.bramp.unsafe.UnsafeHelper.firstFieldOffset;
import static net.bramp.unsafe.UnsafeHelper.sizeOfFields;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

  protected abstract UnsafeCopier createCopier(long offset, long length) throws Exception;
  protected abstract boolean supportsUnaligned();
  protected abstract int stride();

  /**
   * Ensure the test classes looks how we want
   */
  @BeforeClass
  public static void checkAssumptions() {
    // FourLongs is aligned and a multiple of 8 bytes
    assertTrue(firstFieldOffset(FourLongs.class) % 8 == 0);
    assertEquals(4 * 8, sizeOfFields(FourLongs.class));

    // UnalignedClass is not 8 byte aligned, and not a multiple of 8.
    assertTrue(firstFieldOffset(UnalignedClass.class) % 8 != 0);
    assertTrue(sizeOfFields(UnalignedClass.class) % 8 != 0);
  }

  @Test public void testZeroIterations() throws Exception {
    UnsafeCopier copier = createCopier(fourLongOffset, 0);
    FourLongs dest = test(copier, new FourLongs(1, 2, 3, 4), new FourLongs());
    assertEquals("Dest should remain unchanged with zero copies", new FourLongs(0, 0, 0, 0), dest);
  }

  @Test public void testOneIterations() throws Exception {
    UnsafeCopier copier = createCopier(fourLongOffset, 8);
    FourLongs dest = test(copier, new FourLongs(1, 2, 3, 4), new FourLongs());
    assertEquals("Dest should have just the first field altered", new FourLongs(1, 0, 0, 0), dest);
  }

  @Test public void testTwoIterations() throws Exception {