package org.maachang.leveldb ;

import java.lang.reflect.Field;

/**
 * sun.misc.Unsafe.
 * 
 * @version 2014/06/19
 * @author  masahito suzuki
 * @since   leveldb-1.0.0
 */
public final class Unsafe {
    
    public static final sun.misc.Unsafe unsafe ;
    public static final boolean UNSAFE_MODE ;
    public static final boolean BIG_ENDIAN ;
    
    static {
        
        ////////////////
        // unsafe取得.
        ////////////////
        sun.misc.Unsafe u = null ;
        try {
            Field f = sun.misc.Unsafe.class.getDeclaredField( "theUnsafe" ) ;
            f.setAccessible(true) ;
            u = (sun.misc.Unsafe) f.get(null) ;
        } catch (Exception e) {
        }
        unsafe = u ;
        UNSAFE_MODE = ( u != null ) ;
        u = null ;
        
        /////////////////////
        // エンディアン取得.
        /////////////////////
        boolean md = false ;
        
        if( unsafe != null ) {
            long a = unsafe.allocateMemory(8);
            try {
                unsafe.putLong(a, 0x0102030405060708L);
                byte b = unsafe.getByte(a);
                switch (b) {
                case 0x01: md = true ; break;
                case 0x08: md = false ; break ;
                default:
                    md = false ;
                }
            } finally {
                unsafe.freeMemory(a);
            }
        }
        else {
            long a = jni.malloc(8);
            try {
                jni.putLong(a, 0x0102030405060708L);
                byte b = jni.getByte(a);
                switch (b) {
                case 0x01: md = true ; break;
                case 0x08: md = false ; break ;
                default:
                    md = false ;
                }
            } finally {
                jni.free(a);
            }
        }
        BIG_ENDIAN = md ;
    }
    
    /**
     * sun.misc.Unsafeオブジェクトを取得.
     * @return sun.misc.Unsafe オブジェクトが返されます.
     */
    public static final sun.misc.Unsafe get() {
        return unsafe;
    }
    
    /**
     * shortSwap.
     */
    public static final short swap(final short x) {
        return (short)((x << 8) | ((x >> 8) & 0x000000ff));
    }
    
    /**
     * charSwap.
     */
    public static final char swap(final char x) {
        return (char)((x << 8) | ((x >> 8) & 0x000000ff));
    }
    
    /**
     * intSwap.
     */
    public static final int swap(final int x) {
        return (
            ( ( x & 0x000000ff ) << 24 ) |
            ( ( x & 0x0000ff00 ) << 8 ) |
            ( ( x & 0x00ff0000 ) >> 8 ) |
          ( ( ( x & 0xff000000 ) >> 24 ) & 0x000000ff )
        ) ;
    }
    
    /**
     * longSwap.
     */
    public static final long swap(final long x) {
        return (
            ( ( x & 0x00000000000000ffL ) << 56L ) |
            ( ( x & 0x000000000000ff00L ) << 40L ) |
            ( ( x & 0x0000000000ff0000L ) << 24L ) |
            ( ( x & 0x00000000ff000000L ) << 8L )  |
            ( ( x & 0x000000ff00000000L ) >> 8L )  |
            ( ( x & 0x0000ff0000000000L ) >> 24L ) |
            ( ( x & 0x00ff000000000000L ) >> 40L ) |
          ( ( ( x & 0xff00000000000000L ) >> 56L ) & 0x00000000000000ff )
        ) ;
    }
}

