001/*
002 * Copyright 2013 Alex Kasko (alexkasko.com)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.alexkasko.unsafe.bytearray;
018
019/**
020 * Front-end class for operations over byte arrays. Default implementation uses {@code sun.misc.Unsafe}
021 * with {@code assert} boundary checks. To enable boundary check use {@code -ea} java switch,
022 * without boundary checks invalid input will crash (segfault) JVM.
023 * Fallback implementation uses standard byte array access and bit shifting.
024 * Unsafe implementation uses native endianness (LE on most platforms). Fallback implementation uses Little Endian byte order.
025 *
026 * @author alexkasko
027 * Date: 12/11/12
028 */
029public abstract class ByteArrayTool {
030
031    /**
032     * Instantiates unsafe tool, if proper {@code sun.misc.Unsafe} implementation is available.
033     * Otherwise instantiates fallback (bitshift) implementation.
034     * 
035     * @return tool instance
036     */
037    public static ByteArrayTool get() {
038        try {
039            return unsafe();
040        } catch (Exception e) {
041            return bitshift();
042        }
043    }
044
045    /**
046     * Instantiates unsafe tool
047     * 
048     * @return unsafe tool instance
049     * @throws Exception if proper {@code sun.misc.Unsafe} implementation is not available
050     */
051    public static ByteArrayTool unsafe() throws Exception {
052        try {
053            Class<? extends ByteArrayTool> unsafeBaaClass = ByteArrayTool.class
054                    .getClassLoader()
055                    .loadClass(ByteArrayTool.class.getPackage().getName() + ".UnsafeByteArrayTool")
056                    .asSubclass(ByteArrayTool.class);
057            return unsafeBaaClass.newInstance();
058        } catch (Throwable t) {
059            throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
060        }
061    }
062
063    /**
064     * Instantiates bitshift tool
065     * 
066     * @return bitshift tool instance
067     */
068    public static ByteArrayTool bitshift() {
069        return new BitShiftLittleEndianByteArrayTool();
070    }
071
072    /**
073     * Whether current tool instance uses {@code sun.misc.Unsafe}
074     * 
075     * @return whether unsafe
076     */
077    public abstract boolean isUnsafe();
078
079    /**
080     * Gets byte
081     * 
082     * @param data byte array
083     * @param offset byte array index
084     * @return byte
085     */
086    public abstract byte getByte(byte[] data, int offset);
087
088    /**
089     * Puts byte
090     *
091     * @param data byte array
092     * @param offset byte array index
093     * @param value value
094     */
095    public abstract void putByte(byte[] data, int offset, byte value);
096
097    /**
098     * Gets one byte (stored as one signed byte), converts it to unsigned
099     * and returns it as short
100     *
101     * @param data byte array
102     * @param offset byte array index
103     * @return unsigned byte as short
104     */
105    public abstract short getUnsignedByte(byte[] data, int offset);
106
107    /**
108     * Puts short with value from 0 to 255 inclusive into byte array as one
109     * signed byte
110     *
111     * @param data byte array
112     * @param offset byte array index
113     * @param value unsigned byte
114     */
115    public abstract void putUnsignedByte(byte[] data, int offset, short value);
116
117    /**
118     * Gets two bytes as short
119     *
120     * @param data byte array
121     * @param offset byte array offset
122     * @return short value
123     */
124    public abstract short getShort(byte[] data, int offset);
125
126    /**
127     * Puts short as two bytes
128     *
129     * @param data byte array
130     * @param offset byte array offset
131     * @param value short value
132     */
133    public abstract void putShort(byte[] data, int offset, short value);
134
135    /**
136     * Gets unsigned short (stored as two bytes) and returns it as int
137     *
138     * @param data byte array
139     * @param offset byte array offset
140     * @return unsigned short as int
141     */
142    public abstract int getUnsignedShort(byte[] data, int offset);
143
144    /**
145     * Puts int with value from 0 to 65535 inclusive as two bytes
146     *
147     * @param data byte array
148     * @param offset byte array offset
149     * @param value unsigned short as int
150     */
151    public abstract void putUnsignedShort(byte[] data, int offset, int value);
152
153    /**
154     * Gets four bytes as int
155     *
156     * @param data byte array
157     * @param offset byte array offset
158     * @return int value
159     */
160    public abstract int getInt(byte[] data, int offset);
161
162    /**
163     * Puts int as four bytes
164     *
165     * @param data byte array
166     * @param offset byte array offset
167     * @param value int value
168     */
169    public abstract void putInt(byte[] data, int offset, int value);
170
171    /**
172     * Gets unsigned int (stored as 4 bytes) and returns it as long
173     *
174     * @param data byte array
175     * @param offset byte array offset
176     * @return unsigned int as long
177     */
178    public abstract long getUnsignedInt(byte[] data, int offset);
179
180    /**
181     * Puts long value from 0 to 4294967295 inclusive as four bytes
182     *
183     * @param data byte array
184     * @param offset byte array offset
185     * @param value unsigned int as long
186     */
187    public abstract void putUnsignedInt(byte[] data, int offset, long value);
188
189    /**
190     * Gets long
191     *
192     * @param data byte array
193     * @param offset byte array offset
194     * @return long value
195     */
196    public abstract long getLong(byte[] data, int offset);
197
198    /**
199     * Puts long as eight bytes
200     *
201     * @param data byte array
202     * @param offset byte array offset
203     * @param value long value
204     */
205    public abstract void putLong(byte[] data, int offset, long value);
206
207    /**
208     * Copies part of one array into another. Unsafe implementation has less
209     * bounds checks (if assertions are disabled in runtime) then {@link System#arraycopy(Object, int, Object, int, int)}
210     * that is used by fallback implementation uses
211     *
212     * @param src source array
213     * @param srcPos source array position
214     * @param dest destination array
215     * @param destPos destination array position
216     * @param length length to copy
217     */
218    public abstract void copy(byte[] src, int srcPos, byte[] dest, int destPos, int length);
219}