com.epam.deltix.util.collections.AtomicArrayList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of timebase-collections Show documentation
Show all versions of timebase-collections Show documentation
Timebase Common utilities and collections
The newest version!
/*
* Copyright 2021 EPAM Systems, Inc
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Licensed under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.epam.deltix.util.collections;
import java.util.Objects;
import com.epam.deltix.util.lang.Bits;
/**
* Single writer with many readers. If you want to use with many writers you should synchronize writes.
* Use read operations independently.
*
* Add operation is O(n) - Write
* Remove operation is O(n) - Write
* Contains operation is O(n) - Read
* Visit operation is O(n) - Read
* Size operation is O(1) - Read
* Get operation is O(1). - Read
*
*/
public final class AtomicArrayList implements AtomicContainer {
private static final int MIN_CAPACITY = 16;
private static final int NO_FREE_CELL = -1;
private static final int DUPLICATE = -2;
private static final int NO_ELEMENT = -3;
private volatile UnsafeReferenceArray array;
private volatile int head = 0;
private volatile int size = 0;
public AtomicArrayList(int initialCapacity) {
array = new UnsafeReferenceArray<>(Math.max(Bits.nextPowerOfTwo(initialCapacity), MIN_CAPACITY));
}
/**
* Tries to find a free cell in array. If found then sets e to it otherwise creates new double sized array.
*/
@Override
public void add(E e) {
Objects.requireNonNull(e);
int head = this.head;
UnsafeReferenceArray array = this.array;
int index = findFreeCell(array);
add(index, e, head, array);
}
@Override
public boolean addIfAbsent(E e) {
Objects.requireNonNull(e);
int head = this.head;
UnsafeReferenceArray array = this.array;
int index = findFreeCellWithoutDuplicate(e, head, array);
if (index != DUPLICATE) {
add(index, e, head, array);
return true;
}
return false;
}
@Override
public boolean remove(E e) {
if (e != null) {
int head = this.head;
UnsafeReferenceArray array = this.array;
int index = findElement(e, head, array);
if (index != NO_ELEMENT) {
array.setOrdered(index, null);
size--;
}
}
return false;
}
@Override
public int size() {
return size;
}
@Override
public E get(int index) {
int head = this.head;
UnsafeReferenceArray array = this.array;
if (index >= head)
return null;
return array.getVolatile(index);
}
@Override
public boolean contains(E e) {
if (e != null) {
int head = this.head;
UnsafeReferenceArray array = this.array;
for (int i = 0; i < head; i++) {
E obj = array.getVolatile(i);
if (e.equals(obj))
return true;
}
}
return false;
}
@Override
public void visit(Visitor visitor) {
Objects.requireNonNull(visitor);
int head = this.head;
UnsafeReferenceArray array = this.array;
for (int i = 0; i < head; i++) {
E e = array.getVolatile(i);
if (e != null) {
boolean stop = !visitor.visit(e);
if (stop)
break;
}
}
}
private void add(int index, E e, int head, UnsafeReferenceArray array) {
if (index == NO_FREE_CELL) {
UnsafeReferenceArray newArray = new UnsafeReferenceArray<>(array.length() << 1, array);
newArray.set(head, e);
this.array = newArray;
this.head = head + 1;
} else {
array.setOrdered(index, e);
if (index == head)
this.head = head + 1;
}
size++;
}
private int findFreeCell(UnsafeReferenceArray array) {
for (int i = 0; i < array.length(); i++)
if (array.get(i) == null)
return i;
return NO_FREE_CELL;
}
private int findFreeCellWithoutDuplicate(E e, int head, UnsafeReferenceArray array) {
int index = array.length() == head ? NO_FREE_CELL : head;
for (int i = head - 1; i >= 0; i--) {
E cell = array.get(i);
if (cell == null)
index = i;
else if (e.equals(cell))
return DUPLICATE;
}
return index;
}
private int findElement(E e, int head, UnsafeReferenceArray array) {
for (int i = 0; i < head; i++) {
E obj = array.get(i);
if (e.equals(obj))
return i;
}
return NO_ELEMENT;
}
}