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.offheapstruct; 018 019import com.alexkasko.unsafe.bytearray.ByteArrayTool; 020import com.alexkasko.unsafe.offheap.OffHeapDisposable; 021import com.alexkasko.unsafe.offheap.OffHeapDisposableIterator; 022import com.alexkasko.unsafe.offheap.OffHeapMemory; 023 024/** 025 * <p>Implementation of off-heap array of structs (memory areas of equal sizes). 026 * 027 * <p>Default implementation uses {@code sun.misc.Unsafe}, with all operations guarded with {@code assert} keyword. 028 * With assertions enabled in runtime ({@code -ea} java switch) {@link AssertionError} 029 * will be thrown on illegal index access. Without assertions illegal index will crash JVM. 030 * 031 * <p>Array won't be zeroed after creation (will contain garbage by default). 032 * Allocated memory may be freed manually using {@link #free()} (thread-safe 033 * and may be called multiple times) or it will be freed after {@link com.alexkasko.unsafe.offheapstruct.OffHeapStructArray} 034 * instance will be garbage collected. 035 * 036 * @author alexkasko 037 * Date: 7/3/13 038 */ 039public class OffHeapStructArray implements OffHeapStructCollection, OffHeapDisposable { 040 041 private final OffHeapMemory ohm; 042 private final int structLength; 043 044 /** 045 * Constructor 046 * 047 * @param size array size 048 * @param structLength length of struct in bytes, must be >= {@code 8} 049 */ 050 public OffHeapStructArray(long size, int structLength) { 051 if(structLength < 8) throw new IllegalArgumentException( 052 "structLength must be greater or equal to 8, but was: [" + structLength + "]"); 053 this.structLength = structLength; 054 this.ohm = OffHeapMemory.allocateMemory(size * structLength); 055 } 056 057 /** 058 * Constructor, uses {@link com.alexkasko.unsafe.offheap.OnHeapMemory} underneath 059 * effectively making this instance an <b>OnHeap</b> collection 060 * 061 * @param bt byte array tool to manage on-heap memory of this collection 062 * @param size array size 063 * @param structLength length of struct in bytes, must be >= {@code 8} 064 */ 065 public OffHeapStructArray(ByteArrayTool bt, int size, int structLength) { 066 if(structLength < 8) throw new IllegalArgumentException( 067 "structLength must be greater or equal to 8, but was: [" + structLength + "]"); 068 this.structLength = structLength; 069 this.ohm = OffHeapMemory.allocateMemoryOnHeap(bt, size * structLength); 070 } 071 072 /** 073 * Private constructor for {@link #clone()} support 074 * 075 * @param ohm cloned memory 076 * @param structLength struct length 077 */ 078 private OffHeapStructArray(OffHeapMemory ohm, int structLength) { 079 this.ohm = ohm; 080 this.structLength = structLength; 081 } 082 083 /** 084 * Returns length of the single struct in bytes 085 * 086 * @return length of the single struct in bytes 087 */ 088 @Override 089 public int structLength() { 090 return structLength; 091 } 092 093 /** 094 * Returns number of elements in this array 095 * 096 * @return number of elements in this array 097 */ 098 @Override 099 public long size() { 100 return ohm.length() / structLength; 101 } 102 103 /** 104 * Frees allocated memory, may be called multiple times from any thread 105 */ 106 @Override 107 public void free() { 108 ohm.free(); 109 } 110 111 /** 112 * {@inheritDoc} 113 */ 114 @Override 115 public OffHeapDisposableIterator<byte[]> iterator() { 116 return new OffHeapStructIterator(this); 117 } 118 119 /** 120 * Whether unsafe implementation of {@link OffHeapMemory} is used 121 * 122 * @return whether unsafe implementation of {@link OffHeapMemory} is used 123 */ 124 public boolean isUnsafe() { 125 return ohm.isUnsafe(); 126 } 127 128 /** 129 * Copies struct on specified index into specified buffer 130 * 131 * @param index array index 132 * @param buffer buffer to copy struct into 133 */ 134 @Override 135 public void get(long index, byte[] buffer) { 136 ohm.get(index * structLength, buffer); 137 } 138 139 /** 140 * Copies struct on specified index into specified buffer 141 * 142 * @param index array index 143 * @param buffer buffer to copy struct into 144 * @param bufferPos start position in specified buffer 145 */ 146 public void get(long index, byte[] buffer, int bufferPos) { 147 ohm.get(index * structLength, buffer, bufferPos, structLength); 148 } 149 150 /** 151 * Copies part of struct on specified index into specified buffer 152 * 153 * @param index array index 154 * @param pos position in struct 155 * @param buffer buffer to copy struct into 156 * @param bufferPos start position in specified buffer 157 * @param length number of bytes to copy 158 */ 159 @Override 160 public void get(long index, int pos, byte[] buffer, int bufferPos, int length) { 161 ohm.get(index * structLength + pos, buffer, bufferPos, length); 162 } 163 164 /** 165 * Copies specified struct contents onto specified index 166 * 167 * @param index array index 168 * @param struct struct to copy into array 169 */ 170 @Override 171 public void set(long index, byte[] struct) { 172 ohm.put(index * structLength, struct); 173 } 174 175 /** 176 * Copies specified struct contents onto specified index 177 * 178 * @param index array index 179 * @param struct struct to copy into array 180 * @param structPos start position in specified struct 181 */ 182 public void set(long index, byte[] struct, int structPos) { 183 ohm.put(index * structLength, struct, structPos, structLength); 184 } 185 186 /** 187 * Gets byte from struct on specified index with specified offset 188 * 189 * @param index array index 190 * @param offset struct offset 191 * @return byte 192 */ 193 @Override 194 public byte getByte(long index, int offset) { 195 assert offset <= structLength - 1 : offset; 196 return ohm.getByte(index * structLength + offset); 197 } 198 199 /** 200 * Puts byte into struct onto specified index with specified offset 201 * 202 * @param index array index 203 * @param offset struct offset 204 * @param value value 205 */ 206 @Override 207 public void putByte(long index, int offset, byte value) { 208 assert offset <= structLength - 1 : offset; 209 ohm.putByte(index * structLength + offset, value); 210 } 211 212 /** 213 * Gets one byte (stored as one signed byte) from struct on specified index 214 * with specified offset, converts it to unsigned and returns it as short 215 * 216 * @param index array index 217 * @param offset struct offset 218 * @return unsigned byte as short 219 */ 220 @Override 221 public short getUnsignedByte(long index, int offset) { 222 assert offset <= structLength - 1 : offset; 223 return ohm.getUnsignedByte(index * structLength + offset); 224 } 225 226 /** 227 * Puts short with value from 0 to 255 inclusive into struct onto specified 228 * index with specified offset as one signed byte 229 * 230 * @param index array index 231 * @param offset struct offset 232 * @param value unsigned byte 233 */ 234 @Override 235 public void putUnsignedByte(long index, int offset, short value) { 236 assert offset <= structLength - 1 : offset; 237 ohm.putUnsignedByte(index * structLength + offset, value); 238 } 239 240 /** 241 * Gets two bytes as short from struct on specified index with specified offset 242 * 243 * @param index array index 244 * @param offset struct offset 245 * @return short value 246 */ 247 @Override 248 public short getShort(long index, int offset) { 249 assert offset <= structLength - 2 : offset; 250 return ohm.getShort(index * structLength + offset); 251 } 252 253 /** 254 * Puts short into struct onto specified index with specified offset as two bytes 255 * 256 * @param index array index 257 * @param offset struct offset 258 * @param value short value 259 */ 260 @Override 261 public void putShort(long index, int offset, short value) { 262 assert offset <= structLength - 2 : offset; 263 ohm.putShort(index * structLength + offset, value); 264 } 265 266 /** 267 * Gets unsigned short (stored as two bytes) from struct on specified index 268 * with specified offset and returns it as int 269 * 270 * @param index array index 271 * @param offset struct offset 272 * @return unsigned short as int 273 */ 274 @Override 275 public int getUnsignedShort(long index, int offset) { 276 assert offset <= structLength - 2 : offset; 277 return ohm.getUnsignedShort(index * structLength + offset); 278 } 279 280 /** 281 * Puts int with value from 0 to 65535 inclusive into struct onto specified 282 * index with specified offset as two bytes 283 * 284 * @param index array index 285 * @param offset struct offset 286 * @param value unsigned short as int 287 */ 288 @Override 289 public void putUnsignedShort(long index, int offset, int value) { 290 assert offset <= structLength - 2 : offset; 291 ohm.putUnsignedShort(index * structLength + offset, value); 292 } 293 294 /** 295 * Gets four bytes as int from struct on specified index with specified offset 296 * 297 * @param index array index 298 * @param offset struct offset 299 * @return int value 300 */ 301 @Override 302 public int getInt(long index, int offset) { 303 assert offset <= structLength - 4 : offset; 304 return ohm.getInt(index * structLength + offset); 305 } 306 307 /** 308 * Puts int into struct onto specified index with specified offset as four bytes 309 * 310 * @param index array index 311 * @param offset struct offset 312 * @param value int value 313 */ 314 @Override 315 public void putInt(long index, int offset, int value) { 316 assert offset <= structLength - 4 : offset; 317 ohm.putInt(index * structLength + offset, value); 318 } 319 320 /** 321 * Gets unsigned int (stored as 4 bytes) and returns it as long 322 * from struct on specified index with specified offset 323 * 324 * @param index array index 325 * @param offset struct offset 326 * @return unsigned int as long 327 */ 328 @Override 329 public long getUnsignedInt(long index, int offset) { 330 assert offset <= structLength - 4 : offset; 331 return ohm.getUnsignedInt(index * structLength + offset); 332 } 333 334 /** 335 * Puts long value from 0 to 4294967295 inclusive into struct onto specified index 336 * with specified offset as four bytes 337 * 338 * @param index array index 339 * @param offset struct offset 340 * @param value unsigned int as long 341 */ 342 @Override 343 public void putUnsignedInt(long index, int offset, long value) { 344 assert offset <= structLength - 4 : offset; 345 ohm.putUnsignedInt(index * structLength + offset, value); 346 } 347 348 /** 349 * Gets long from struct on specified index with specified offset 350 * 351 * @param index array index 352 * @param offset struct offset 353 * @return long value 354 */ 355 @Override 356 public long getLong(long index, int offset) { 357 assert offset <= structLength - 8 : offset; 358 return ohm.getLong(index * structLength + offset); 359 } 360 361 /** 362 * Puts long into struct onto specified index with specified offset as eight bytes 363 * 364 * @param index array index 365 * @param offset struct offset 366 * @param value long value 367 */ 368 @Override 369 public void putLong(long index, int offset, long value) { 370 assert offset <= structLength - 8 : offset; 371 ohm.putLong(index * structLength + offset, value); 372 } 373 374 /** 375 * {@inheritDoc} 376 */ 377 @Override 378 public OffHeapStructArray clone() { 379 OffHeapMemory cloned = ohm.clone(); 380 return new OffHeapStructArray(cloned, structLength); 381 } 382 383 /** 384 * {@inheritDoc} 385 */ 386 @Override 387 public String toString() { 388 final StringBuilder sb = new StringBuilder(); 389 sb.append("OffHeapStructArray"); 390 sb.append("{ohm=").append(ohm); 391 sb.append(", structLength=").append(structLength); 392 sb.append('}'); 393 return sb.toString(); 394 } 395}