Context.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.5.0).
003  * Copyright (c) 2007-2016 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019  */
020 package org.jenetics.util;
021 
022 import java.util.concurrent.atomic.AtomicReference;
023 import java.util.function.Function;
024 
025 /**
026  * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
027  * @version 2.0
028  * @since 3.0
029  */
030 final class Context<T> {
031 
032     private final T _default;
033     private final AtomicReference<Entry<T>> _entry;
034     private final ThreadLocal<Entry<T>> _threadLocalEntry = new ThreadLocal<>();
035 
036     Context(final T defaultValue) {
037         _default = defaultValue;
038         _entry = new AtomicReference<>(new Entry<>(defaultValue));
039     }
040 
041     void set(final T value) {
042         final Entry<T> e = _threadLocalEntry.get();
043         if (e != null) e.value = value; else _entry.set(new Entry<T>(value));
044     }
045 
046     T get() {
047         final Entry<T> e = _threadLocalEntry.get();
048         return (e != null ? e : _entry.get()).value;
049     }
050 
051     void reset() {
052         set(_default);
053     }
054 
055     <S extends T, R> R with(final S value, final Function<S, R> f) {
056         final Entry<T> e = _threadLocalEntry.get();
057         if (e != null) {
058             _threadLocalEntry.set(e.inner(value));
059         } else {
060             _threadLocalEntry.set(new Entry<T>(value, Thread.currentThread()));
061         }
062 
063         try {
064             return f.apply(value);
065         } finally {
066             _threadLocalEntry.set(_threadLocalEntry.get().parent);
067         }
068     }
069 
070     /**
071      * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
072      * @version 2.0
073      * @since 2.0
074      */
075     private static final class Entry<T> {
076         final Thread thread;
077         final Entry<T> parent;
078         T value;
079 
080         Entry(final T value, final Entry<T> parent, final Thread thread) {
081             this.value = value;
082             this.parent = parent;
083             this.thread = thread;
084         }
085 
086         Entry(final T value, final Thread thread) {
087             this(value, null, thread);
088         }
089 
090         Entry(final T value) {
091             this(value, null, null);
092         }
093 
094         Entry<T> inner(final T value) {
095             assert thread == Thread.currentThread();
096             return new Entry<>(value, this, thread);
097         }
098 
099     }
100 
101 }