Don't add null to the list!
+ * @param value the value to append
+ */
+ public void add(T value) {
+ final int c = capacity;
+ int o = offset;
+ if (o == c) {
+ Object[] next = new Object[c + 1];
+ tail[c] = next;
+ tail = next;
+ o = 0;
+ }
+ tail[o] = value;
+ offset = o + 1;
+ }
+
+ /**
+ * Set a value as the first element of the list.
+ * @param value the value to set
+ */
+ public void setFirst(T value) {
+ head[0] = value;
+ }
+
+ /**
+ * Loops through all elements of the list.
+ * @param consumer the consumer of elements
+ */
+ @SuppressWarnings("unchecked")
+ public void forEach(Consumer super T> consumer) {
+ Object[] a = head;
+ final int c = capacity;
+ while (a != null) {
+ for (int i = 0; i < c; i++) {
+ Object o = a[i];
+ if (o == null) {
+ return;
+ }
+ consumer.accept((T)o);
+ }
+ a = (Object[])a[c];
+ }
+ }
+
+ /**
+ * Loops over all elements of the array until a null element is encountered or
+ * the given predicate returns true.
+ * @param consumer the consumer of values that returns true if the forEach should terminate
+ */
+ @SuppressWarnings("unchecked")
+ public void forEachWhile(Predicate super T> consumer) {
+ Object[] a = head;
+ final int c = capacity;
+ while (a != null) {
+ for (int i = 0; i < c; i++) {
+ Object o = a[i];
+ if (o == null) {
+ return;
+ }
+ if (consumer.test((T)o)) {
+ return;
+ }
+ }
+ a = (Object[])a[c];
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public
+ * IMPLEMENTATION NOTES:
+ * IMPLEMENTATION NOTES:
+ * IMPLEMENTATION NOTES:
+ * IMPLEMENTATION NOTES: Does not check for a subscription notification, see {@link #acceptFull(Object, Subscriber)}.
+ * @param o the notification object
+ * @param s the subscriber to call methods on
+ * @return true if the notification was a terminal event (i.e., complete or error)
+ * @see #acceptFull(Object, Subscriber)
+ */
+ @SuppressWarnings("unchecked")
+ public static The decrementing of the state is left to the drain callback.
+ * @param updater
+ * @param instance
+ * @param fastPath called if the instance is uncontended.
+ * @param queue called if the instance is contended to queue up work
+ * @param drain called if the instance transitions to the drain state successfully
+ */
+ public static The decrementing of the state is left to the drain callback.
+ * @param updater
+ * @param instance
+ * @param fastPath
+ * @param queue
+ * @param drain
+ */
+ public static The decrementing of the state is left to the drain callback.
+ * @param updater
+ * @param instance
+ * @param fastPath called if the instance is uncontended.
+ * @param queue called if the instance is contended to queue up work
+ * @param drain called if the instance transitions to the drain state successfully
+ */
+ public static The decrementing of the state is left to the drain callback.
+ * @param updater
+ * @param instance
+ * @param fastPath
+ * @param queue
+ * @param drain
+ */
+ public static Note that onSubscribe is not serialized in respect of the other methods so
+ * make sure the Subscription is set before any of the other methods are called.
+ *
+ * The implementation assumes that the actual Subscriber's methods don't throw.
+ *
+ * @param void forEachWhile(S state, BiPredicate super S, ? super T> consumer) {
+ Object[] a = head;
+ final int c = capacity;
+ while (a != null) {
+ for (int i = 0; i < c; i++) {
+ Object o = a[i];
+ if (o == null) {
+ return;
+ }
+ if (consumer.test(state, (T)o)) {
+ return;
+ }
+ }
+ a = (Object[])a[c];
+ }
+ }
+}
diff --git a/src/main/java/io/reactivesocket/internal/BackpressureHelper.java b/src/main/java/io/reactivesocket/internal/rx/BackpressureHelper.java
similarity index 98%
rename from src/main/java/io/reactivesocket/internal/BackpressureHelper.java
rename to src/main/java/io/reactivesocket/internal/rx/BackpressureHelper.java
index bee59b440..cd51ac01b 100644
--- a/src/main/java/io/reactivesocket/internal/BackpressureHelper.java
+++ b/src/main/java/io/reactivesocket/internal/rx/BackpressureHelper.java
@@ -10,7 +10,7 @@
* 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 io.reactivesocket.internal;
+package io.reactivesocket.internal.rx;
import java.util.concurrent.atomic.*;
diff --git a/src/main/java/io/reactivesocket/internal/BackpressureUtils.java b/src/main/java/io/reactivesocket/internal/rx/BackpressureUtils.java
similarity index 98%
rename from src/main/java/io/reactivesocket/internal/BackpressureUtils.java
rename to src/main/java/io/reactivesocket/internal/rx/BackpressureUtils.java
index b8ce796f7..d67598d1f 100644
--- a/src/main/java/io/reactivesocket/internal/BackpressureUtils.java
+++ b/src/main/java/io/reactivesocket/internal/rx/BackpressureUtils.java
@@ -1,4 +1,4 @@
-package io.reactivesocket.internal;
+package io.reactivesocket.internal.rx;
/**
* Copyright 2015 Netflix, Inc.
diff --git a/src/main/java/io/reactivesocket/internal/rx/BaseArrayQueue.java b/src/main/java/io/reactivesocket/internal/rx/BaseArrayQueue.java
new file mode 100644
index 000000000..214aa00b2
--- /dev/null
+++ b/src/main/java/io/reactivesocket/internal/rx/BaseArrayQueue.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright 2015 Netflix, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * The code was inspired by the similarly named JCTools class:
+ * https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/atomic
+ */
+
+package io.reactivesocket.internal.rx;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+abstract class BaseArrayQueue
+ *
+ * This is an O(n) operation as we run through all the nodes and count them.
+ *
+ * @see java.util.Queue#size()
+ */
+ @Override
+ public final int size() {
+ LinkedQueueNode
+ *
+ * Queue is empty when producerNode is the same as consumerNode. An alternative implementation would be to observe
+ * the producerNode.value is null, which also means an empty queue because only the consumerNode.value is allowed to
+ * be null.
+ *
+ * @see MessagePassingQueue#isEmpty()
+ */
+ @Override
+ public final boolean isEmpty() {
+ return lvConsumerNode() == lvProducerNode();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/reactivesocket/internal/BooleanDisposable.java b/src/main/java/io/reactivesocket/internal/rx/BooleanDisposable.java
similarity index 91%
rename from src/main/java/io/reactivesocket/internal/BooleanDisposable.java
rename to src/main/java/io/reactivesocket/internal/rx/BooleanDisposable.java
index 17f75124f..6e4b70d27 100644
--- a/src/main/java/io/reactivesocket/internal/BooleanDisposable.java
+++ b/src/main/java/io/reactivesocket/internal/rx/BooleanDisposable.java
@@ -1,8 +1,8 @@
-package io.reactivesocket.internal;
+package io.reactivesocket.internal.rx;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import io.reactivesocket.observable.Disposable;
+import io.reactivesocket.rx.Disposable;
public final class BooleanDisposable implements Disposable {
volatile Runnable run;
diff --git a/src/main/java/io/reactivesocket/internal/CompositeCompletable.java b/src/main/java/io/reactivesocket/internal/rx/CompositeCompletable.java
similarity index 94%
rename from src/main/java/io/reactivesocket/internal/CompositeCompletable.java
rename to src/main/java/io/reactivesocket/internal/rx/CompositeCompletable.java
index 145853732..7d4f4a020 100644
--- a/src/main/java/io/reactivesocket/internal/CompositeCompletable.java
+++ b/src/main/java/io/reactivesocket/internal/rx/CompositeCompletable.java
@@ -1,9 +1,9 @@
-package io.reactivesocket.internal;
+package io.reactivesocket.internal.rx;
import java.util.HashSet;
import java.util.Set;
-import io.reactivesocket.Completable;
+import io.reactivesocket.rx.Completable;
/**
* A Completable container that can hold onto multiple other Completables.
diff --git a/src/main/java/io/reactivesocket/internal/CompositeDisposable.java b/src/main/java/io/reactivesocket/internal/rx/CompositeDisposable.java
similarity index 88%
rename from src/main/java/io/reactivesocket/internal/CompositeDisposable.java
rename to src/main/java/io/reactivesocket/internal/rx/CompositeDisposable.java
index 506007d3f..f8cbf5b1b 100644
--- a/src/main/java/io/reactivesocket/internal/CompositeDisposable.java
+++ b/src/main/java/io/reactivesocket/internal/rx/CompositeDisposable.java
@@ -1,10 +1,10 @@
-package io.reactivesocket.internal;
+package io.reactivesocket.internal.rx;
import java.util.HashSet;
import java.util.Set;
-import io.reactivesocket.Completable;
-import io.reactivesocket.observable.Disposable;
+import io.reactivesocket.rx.Completable;
+import io.reactivesocket.rx.Disposable;
/**
* A Disposable container that can hold onto multiple other Disposables.
diff --git a/src/main/java/io/reactivesocket/internal/EmptyDisposable.java b/src/main/java/io/reactivesocket/internal/rx/EmptyDisposable.java
similarity index 90%
rename from src/main/java/io/reactivesocket/internal/EmptyDisposable.java
rename to src/main/java/io/reactivesocket/internal/rx/EmptyDisposable.java
index e878d81a6..785fd7856 100644
--- a/src/main/java/io/reactivesocket/internal/EmptyDisposable.java
+++ b/src/main/java/io/reactivesocket/internal/rx/EmptyDisposable.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.reactivesocket.internal;
+package io.reactivesocket.internal.rx;
-import io.reactivesocket.observable.Disposable;
+import io.reactivesocket.rx.Disposable;
public class EmptyDisposable implements Disposable
{
diff --git a/src/main/java/io/reactivesocket/internal/EmptySubscription.java b/src/main/java/io/reactivesocket/internal/rx/EmptySubscription.java
similarity index 98%
rename from src/main/java/io/reactivesocket/internal/EmptySubscription.java
rename to src/main/java/io/reactivesocket/internal/rx/EmptySubscription.java
index cb2c58581..fe2c38685 100644
--- a/src/main/java/io/reactivesocket/internal/EmptySubscription.java
+++ b/src/main/java/io/reactivesocket/internal/rx/EmptySubscription.java
@@ -11,7 +11,7 @@
* the License for the specific language governing permissions and limitations under the License.
*/
-package io.reactivesocket.internal;
+package io.reactivesocket.internal.rx;
import org.reactivestreams.*;
diff --git a/src/main/java/io/reactivesocket/internal/rx/LinkedQueueNode.java b/src/main/java/io/reactivesocket/internal/rx/LinkedQueueNode.java
new file mode 100644
index 000000000..bc03d6f0c
--- /dev/null
+++ b/src/main/java/io/reactivesocket/internal/rx/LinkedQueueNode.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2015 Netflix, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * The code was inspired by the similarly named JCTools class:
+ * https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/atomic
+ */
+
+package io.reactivesocket.internal.rx;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public final class LinkedQueueNode
+ *
+ * Offer is allowed from multiple threads.
+ * Offer allocates a new node and:
+ *
+ *
+ * This works because each producer is guaranteed to 'plant' a new node and link the old node. No 2 producers can
+ * get the same producer node as part of XCHG guarantee.
+ *
+ * @see MessagePassingQueue#offer(Object)
+ * @see java.util.Queue#offer(java.lang.Object)
+ */
+ @Override
+ public final boolean offer(final T nextValue) {
+ final LinkedQueueNode
+ *
+ * Poll is allowed from a SINGLE thread.
+ * Poll reads the next node from the consumerNode and:
+ *
+ *
+ * This means the consumerNode.value is always null, which is also the starting point for the queue. Because null
+ * values are not allowed to be offered this is the only node with it's value set to null at any one time.
+ *
+ * @see MessagePassingQueue#poll()
+ * @see java.util.Queue#poll()
+ */
+ @Override
+ public final T poll() {
+ LinkedQueueNode