/*
* Copyright 2016 higherfrequencytrading.com
*
* 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 net.openhft.lang.threadlocal;
public abstract class Provider<T> {
public static <T> Provider<T> of(Class<T> tClass) {
if (StatefulCopyable.class.isAssignableFrom(tClass)) {
return StatefulProvider.INSTANCE;
}
return StatelessProvider.INSTANCE;
}
public abstract T get(ThreadLocalCopies copies, T original);
public abstract ThreadLocalCopies getCopies(ThreadLocalCopies copies);
private static final class StatefulProvider<T extends StatefulCopyable<T>> extends Provider<T> {
private static final Provider INSTANCE = new StatefulProvider();
@Override
public ThreadLocalCopies getCopies(ThreadLocalCopies copies) {
if (copies != null)
return copies;
return ThreadLocalCopies.get();
}
@Override
public T get(ThreadLocalCopies copies, T original) {
return get(copies, original, true);
}
private T get(ThreadLocalCopies copies, T original, boolean syncPut) {
Object id = original.stateIdentity();
int m = copies.mask;
Object[] tab = copies.table;
int i = System.identityHashCode(id) & m;
while (true) {
Object idInTable = tab[i];
if (idInTable == id) {
return (T) tab[i + 1];
} else if (idInTable == null) {
if (syncPut) {
if (copies.currentlyAccessed.compareAndSet(false, true)) {
try {
return get(copies, original, false);
} finally {
copies.currentlyAccessed.set(false);
}
} else {
throw new IllegalStateException("Concurrent or recursive access " +
"to ThreadLocalCopies is not allowed");
}
} else {
// actual put
tab[i] = id;
T copy;
tab[i + 1] = copy = original.copy();
copies.postInsert();
return copy;
}
}
i = (i + 2) & m;
}
}
}
private static final class StatelessProvider<M> extends Provider<M> {
private static final Provider INSTANCE = new StatelessProvider();
@Override
public M get(ThreadLocalCopies copies, M original) {
return original;
}
@Override
public ThreadLocalCopies getCopies(ThreadLocalCopies copies) {
return copies;
}
}
}