hu.akarnokd.rxjava3.util.SpmcLinkedArrayQueue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rxjava3-extensions Show documentation
Show all versions of rxjava3-extensions Show documentation
RxJava 3.x extra sources, operators and components and ports of many 1.x companion libraries.
/*
* Copyright 2016-2019 David Karnok
*
* 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 hu.akarnokd.rxjava3.util;
import java.util.concurrent.atomic.*;
import io.reactivex.rxjava3.internal.functions.ObjectHelper;
import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue;
/**
* A single-producer multiple-conumer queue implementation with array islands.
*
* @param the item type to be queued
* @since 0.18.8
*/
public final class SpmcLinkedArrayQueue implements SimplePlainQueue {
ARA producerArray;
int producerIndex;
final AtomicReference consumerArray;
public SpmcLinkedArrayQueue(int capacity) {
ARA a = new ARA(Math.max(2, capacity) + 1);
this.producerArray = a;
this.consumerArray = new AtomicReference(a);
}
@Override
public boolean offer(T value) {
ObjectHelper.requireNonNull(value, "value is null");
ARA pa = producerArray;
int pi = producerIndex;
if (pi == pa.length() - 1) {
ARA next = new ARA(pa.length());
producerArray = next;
next.lazySet(0, value);
pa.soNext(next);
pi = 1;
} else {
pa.lazySet(pi, value);
pi++;
}
producerIndex = pi;
return true;
}
@Override
public boolean offer(T v1, T v2) {
ObjectHelper.requireNonNull(v1, "v1 is null");
ObjectHelper.requireNonNull(v2, "v2 is null");
ARA pa = producerArray;
int pi = producerIndex;
if (pi == pa.length() - 1) {
ARA next = new ARA(pa.length());
producerArray = next;
next.lazySet(0, v1);
next.lazySet(1, v2);
pa.soNext(next);
pi = 2;
} else {
pa.lazySet(pi + 1, v2);
pa.lazySet(pi, v1);
pi += 2;
}
producerIndex = pi;
return true;
}
@Override
public boolean isEmpty() {
AtomicReference ca = consumerArray;
ARA a = ca.get();
AtomicInteger index = a.index;
for (;;) {
int idx = index.get();
if (idx < a.length() - 1) {
Object o = a.get(idx);
if (idx == index.get()) {
return o == null;
}
} else {
ARA b = a.lvNext();
if (b != null) {
a = b;
index = b.index;
} else {
return true;
}
}
}
}
@Override
public void clear() {
while (poll() != null) { }
}
@SuppressWarnings("unchecked")
@Override
public T poll() {
AtomicReference ca = consumerArray;
ARA a = ca.get();
AtomicInteger index = a.index;
for (;;) {
int idx = index.get();
if (idx < a.length() - 1) {
Object o = a.get(idx);
if (idx == index.get()) {
if (o == null) {
return null;
}
if (index.compareAndSet(idx, idx + 1)) {
a.lazySet(idx, null);
return (T)o;
}
}
} else {
ARA b = a.lvNext();
if (b != null) {
ca.compareAndSet(a, b);
a = ca.get();
index = a.index;
} else {
return null;
}
}
}
}
static final class ARA extends AtomicReferenceArray