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
019import sun.misc.Unsafe;
020
021import java.lang.reflect.Field;
022
023/**
024 * Implementation of {@link ByteArrayTool} using {@code sun.misc.Unsafe}.
025 * All bound checks are done using {@code assert} keyword, they may be enabled
026 * with java {@code ea} switch.
027 *
028 * @author alexkasko
029 * Date: 12/11/12
030 */
031class UnsafeByteArrayTool extends ByteArrayTool {
032
033    private static final Unsafe UNSAFE;
034    private static final long BYTE_ARRAY_OFFSET;
035
036    static {
037        try {
038            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
039            theUnsafe.setAccessible(true);
040            UNSAFE = (Unsafe) theUnsafe.get(null);
041            int boo = UNSAFE.arrayBaseOffset(byte[].class);
042            // It seems not all Unsafe implementations implement the following method.
043            UNSAFE.copyMemory(new byte[1], boo, new byte[1], boo, 1);
044            BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
045        } catch (Exception e) {
046            throw new RuntimeException(e);
047        }
048    }
049
050    /**
051     * {@inheritDoc}
052     */
053    @Override
054    public boolean isUnsafe() {
055        return true;
056    }
057
058    /**
059     * {@inheritDoc}
060     */
061    @Override
062    public byte getByte(byte[] data, int offset) {
063        assert offset >= 0 : offset;
064        assert offset <= data.length - 1 : offset;
065        return UNSAFE.getByte(data, BYTE_ARRAY_OFFSET + offset);
066    }
067
068    /**
069     * {@inheritDoc}
070     */
071    @Override
072    public void putByte(byte[] data, int offset, byte value) {
073        assert offset >= 0 : offset;
074        assert offset <= data.length - 1 : offset;
075        UNSAFE.putByte(data, BYTE_ARRAY_OFFSET + offset, value);
076    }
077
078    /**
079     * {@inheritDoc}
080     */
081    @Override
082    public short getUnsignedByte(byte[] data, int offset) {
083        assert offset >= 0 : offset;
084        assert offset <= data.length - 1 : offset;
085        return (short) (UNSAFE.getByte(data, BYTE_ARRAY_OFFSET + offset) & 0xff);
086    }
087
088    /**
089     * {@inheritDoc}
090     */
091    @Override
092    public void putUnsignedByte(byte[] data, int offset, short value) {
093        assert offset >= 0 : offset;
094        assert offset <= data.length - 1 : offset;
095        assert value >= 0 : value;
096        assert value < 1<<8 : value;
097        UNSAFE.putByte(data, BYTE_ARRAY_OFFSET + offset, (byte) value);
098    }
099
100    /**
101     * {@inheritDoc}
102     */
103    @Override
104    public short getShort(byte[] data, int offset) {
105        assert offset >= 0 : offset;
106        assert offset <= data.length - 2 : offset;
107        return UNSAFE.getShort(data, BYTE_ARRAY_OFFSET + offset);
108    }
109
110    /**
111     * {@inheritDoc}
112     */
113    @Override
114    public void putShort(byte[] data, int offset, short value) {
115        assert offset >= 0 : offset;
116        assert offset <= data.length - 2 : offset;
117        UNSAFE.putShort(data, BYTE_ARRAY_OFFSET + offset, value);
118    }
119
120    /**
121     * {@inheritDoc}
122     */
123    @Override
124    public int getUnsignedShort(byte[] data, int offset) {
125        assert offset >= 0 : offset;
126        assert offset <= data.length - 2 : offset;
127        return UNSAFE.getShort(data, BYTE_ARRAY_OFFSET + offset) & 0xffff;
128
129    }
130
131    /**
132     * {@inheritDoc}
133     */
134    @Override
135    public void putUnsignedShort(byte[] data, int offset, int value) {
136        assert offset >= 0 : offset;
137        assert offset <= data.length - 2 : offset;
138        assert value >= 0 : value;
139        assert value < 1<<16 : value;
140        UNSAFE.putShort(data, BYTE_ARRAY_OFFSET + offset, (short) value);
141    }
142
143    /**
144     * {@inheritDoc}
145     */
146    @Override
147    public int getInt(byte[] data, int offset) {
148        assert offset >= 0 : offset;
149        assert offset <= data.length - 4 : offset;
150        return UNSAFE.getInt(data, BYTE_ARRAY_OFFSET + offset);
151    }
152
153    /**
154     * {@inheritDoc}
155     */
156    @Override
157    public void putInt(byte[] data, int offset, int value) {
158        assert offset >= 0 : offset;
159        assert offset <= data.length - 4 : offset;
160        UNSAFE.putInt(data, BYTE_ARRAY_OFFSET + offset, value);
161    }
162
163    /**
164     * {@inheritDoc}
165     */
166    @Override
167    public long getUnsignedInt(byte[] data, int offset) {
168        assert offset >= 0 : offset;
169        assert offset <= data.length - 4 : offset;
170        return UNSAFE.getInt(data, BYTE_ARRAY_OFFSET + offset) & 0xffffffffL;
171    }
172
173    /**
174     * {@inheritDoc}
175     */
176    @Override
177    public void putUnsignedInt(byte[] data, int offset, long value) {
178        assert offset >= 0 : offset;
179        assert offset <= data.length - 4 : offset;
180        assert value >= 0 : value;
181        assert value < 1L<<32 : value;
182        UNSAFE.putInt(data, BYTE_ARRAY_OFFSET + offset, (int) value);
183    }
184
185    /**
186     * {@inheritDoc}
187     */
188    @Override
189    public long getLong(byte[] data, int offset) {
190        assert offset >= 0 : offset;
191        assert offset <= data.length - 8 : offset;
192        return UNSAFE.getLong(data, BYTE_ARRAY_OFFSET + offset);
193    }
194
195    /**
196     * {@inheritDoc}
197     */
198    @Override
199    public void putLong(byte[] data, int offset, long value) {
200        assert offset >= 0 : offset;
201        assert offset <= data.length - 8 : offset;
202        UNSAFE.putLong(data, BYTE_ARRAY_OFFSET + offset, value);
203    }
204
205    /**
206     * {@inheritDoc}
207     */
208    @Override
209    public void copy(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
210        assert srcPos >= 0 : srcPos;
211        assert srcPos <= src.length - length : srcPos;
212        assert destPos >= 0 : destPos;
213        assert destPos <= dest.length - length : destPos;
214        UNSAFE.copyMemory(src, BYTE_ARRAY_OFFSET + srcPos, dest, BYTE_ARRAY_OFFSET + destPos, length);
215    }
216}