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.offheaplong; 018 019import com.alexkasko.unsafe.offheap.OffHeapDisposable; 020import com.alexkasko.unsafe.offheap.OffHeapDisposableIterator; 021import com.alexkasko.unsafe.offheap.OffHeapMemory; 022 023import java.util.Iterator; 024 025/** 026 * <p>Implementation of array-list of long using {@link com.alexkasko.unsafe.offheap.OffHeapMemory}. 027 * Memory area will be allocated another time and copied on elements adding. This class doesn't support elements removing. 028 * {@link #get(long)} and {@link #set(long, long)} access operations indexes are checked using {@code assert} keyword 029 * (indexes between size and capacity will be rejected). 030 * 031 * <p>Default implementation uses {@code sun.misc.Unsafe}, with all operations guarded with {@code assert} keyword. 032 * With assertions enabled in runtime ({@code -ea} java switch) {@link AssertionError} 033 * will be thrown on illegal index access. Without assertions illegal index will crash JVM. 034 * 035 * <p>Allocated memory may be freed manually using {@link #free()} (thread-safe 036 * and may be called multiple times) or it will be freed after {@link OffHeapLongArray} 037 * will be garbage collected. 038 * 039 * <p>Note: while class implements Iterable, iterator will create new autoboxed Long object 040 * <b>on every</b> {@code next()} call, this behaviour is inevitable with iterators in java 6/7. 041 * 042 * @author alexkasko 043 * Date: 3/1/13 044 */ 045public class OffHeapLongArrayList implements OffHeapLongAddressable, OffHeapDisposable, Iterable<Long> { 046 private static final int MIN_CAPACITY_INCREMENT = 12; 047 private static final int ELEMENT_LENGTH = 8; 048 049 private OffHeapMemory ohm; 050 private long size; 051 private long capacity; 052 053 /** 054 * Constructor, {@code 12} is used as initial capacity 055 */ 056 public OffHeapLongArrayList() { 057 this(MIN_CAPACITY_INCREMENT); 058 } 059 060 /** 061 * Constructor 062 * 063 * @param capacity initial capacity 064 */ 065 public OffHeapLongArrayList(long capacity) { 066 this.capacity = capacity; 067 this.ohm = OffHeapMemory.allocateMemory(capacity * ELEMENT_LENGTH); 068 } 069 070 /** 071 * Adds element to the end of this list. Memory area will be allocated another time and copied 072 * on capacity exceed. 073 * 074 * @param value value to add 075 */ 076 public void add(long value) { 077 OffHeapMemory oh = ohm; 078 long s = size; 079 if (s == capacity) { 080 long len = s + (s < (MIN_CAPACITY_INCREMENT / 2) ? MIN_CAPACITY_INCREMENT : s >> 1); 081 OffHeapMemory newOhm = OffHeapMemory.allocateMemory(len * ELEMENT_LENGTH); 082 // maybe it's better to use Unsafe#reallocateMemory here 083 oh.copy(0, newOhm, 0, oh.length()); 084 oh.free(); 085 ohm = newOhm; 086 capacity = len; 087 } 088 size = s + 1; 089 set(s, value); 090 } 091 092 /** 093 * Whether unsafe implementation of {@link OffHeapMemory} is used 094 * 095 * @return whether unsafe implementation of {@link OffHeapMemory} is used 096 */ 097 public boolean isUnsafe() { 098 return ohm.isUnsafe(); 099 } 100 101 /** 102 * Gets the element at position {@code index} from {@code 0} to {@code size-1} 103 * 104 * @param index list index 105 * @return long value 106 */ 107 @Override 108 public long get(long index) { 109 assert index < size : index; 110 return ohm.getLong(index * ELEMENT_LENGTH); 111 } 112 113 /** 114 * Sets the element at position {@code index} (from {@code 0} to {@code size-1}) to the given value 115 * 116 * @param index list index 117 * @param value long value 118 */ 119 @Override 120 public void set(long index, long value) { 121 assert index < size : index; 122 ohm.putLong(index * ELEMENT_LENGTH, value); 123 } 124 125 /** 126 * Returns number of elements in list 127 * 128 * @return number of elements in list 129 */ 130 @Override 131 public long size() { 132 return size; 133 } 134 135 /** 136 * Returns number of elements list may contain without additional memory allocation 137 * 138 * @return number of elements list may contain without additional memory allocation 139 */ 140 public long capacity() { 141 return capacity; 142 } 143 144 /** 145 * Frees allocated memory, may be called multiple times from any thread 146 */ 147 @Override 148 public void free() { 149 ohm.free(); 150 } 151 152 /** 153 * {@inheritDoc} 154 */ 155 @Override 156 public OffHeapDisposableIterator<Long> iterator() { 157 return new OffHeapLongIterator(this); 158 } 159 160 /** 161 * Resets the collection setting size to 0. 162 * Actual memory contents stays untouched. 163 */ 164 public void reset() { 165 this.size = 0; 166 } 167 168 /** 169 * {@inheritDoc} 170 */ 171 @Override 172 public String toString() { 173 final StringBuilder sb = new StringBuilder(); 174 sb.append("OffHeapLongArrayList"); 175 sb.append("{size=").append(size()); 176 sb.append(", capacity=").append(capacity); 177 sb.append(", unsafe=").append(isUnsafe()); 178 sb.append('}'); 179 return sb.toString(); 180 } 181}