Merge remote-tracking branch 'origin/development' into development
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / util / ObservableAtomicReference.java
1 package net.mograsim.logic.model.util;
2
3 import java.lang.invoke.VarHandle;
4 import java.util.ArrayList;
5 import java.util.List;
6 import java.util.concurrent.atomic.AtomicReference;
7 import java.util.function.Consumer;
8 import java.util.function.UnaryOperator;
9
10 public class ObservableAtomicReference<V>
11 {
12         private final AtomicReference<V> ref;
13
14         private final List<Consumer<ObservableAtomicReference<V>>> observers;
15
16         public ObservableAtomicReference()
17         {
18                 ref = new AtomicReference<>();
19                 observers = new ArrayList<>();
20         }
21
22         public ObservableAtomicReference(V initialValue)
23         {
24                 ref = new AtomicReference<>(initialValue);
25                 observers = new ArrayList<>();
26         }
27
28         /**
29          * Returns the current value, with memory effects as specified by {@link VarHandle#getVolatile}.
30          *
31          * @return the current value
32          */
33         public V get()
34         {
35                 return ref.get();
36         }
37
38         /**
39          * Sets the value to {@code newValue}, with memory effects as specified by {@link VarHandle#setVolatile}.
40          *
41          * @param newValue the new value
42          */
43         public void set(V newValue)
44         {
45                 ref.set(newValue);
46                 callObservers();
47         }
48
49         /**
50          * Atomically sets the value to {@code newValue} and returns the old value, with memory effects as specified by
51          * {@link VarHandle#getAndSet}.
52          *
53          * @param newValue the new value
54          * @return the previous value
55          */
56         public V getAndSet(V newValue)
57         {
58                 V oldValue = ref.getAndSet(newValue);
59                 callObservers();
60                 return oldValue;
61         }
62
63         /**
64          * Atomically updates (with memory effects as specified by {@link VarHandle#compareAndSet}) the current value with the results of
65          * applying the given function, returning the updated value. The function should be side-effect-free, since it may be re-applied when
66          * attempted updates fail due to contention among threads.
67          *
68          * @param updateFunction a side-effect-free function
69          * @return the updated value
70          */
71         public V updateAndGet(UnaryOperator<V> updateFunction)
72         {
73                 V updatedValue = ref.updateAndGet(updateFunction);
74                 callObservers();
75                 return updatedValue;
76         }
77
78         public void addObserver(Consumer<ObservableAtomicReference<V>> obs)
79         {
80                 observers.add(obs);
81         }
82
83         public void removeObserver(Consumer<ObservableAtomicReference<V>> obs)
84         {
85                 observers.add(obs);
86         }
87
88         private void callObservers()
89         {
90                 observers.forEach(o -> o.accept(this));
91         }
92 }