Using classical java.util classes minimizes the chance I will do mistake when coding linked list myself
1.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Proto.java Fri Aug 01 17:13:23 2014 +0200
1.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Proto.java Sat Aug 02 06:25:53 2014 +0200
1.3 @@ -47,6 +47,8 @@
1.4 import net.java.html.BrwsrCtx;
1.5 import net.java.html.json.ComputedProperty;
1.6 import net.java.html.json.Model;
1.7 +import org.apidesign.html.json.spi.Watcher.Observers;
1.8 +import org.apidesign.html.json.spi.Watcher.Watchers;
1.9 import org.netbeans.html.json.impl.Bindings;
1.10 import org.netbeans.html.json.impl.JSON;
1.11 import org.netbeans.html.json.impl.JSONList;
1.12 @@ -69,8 +71,8 @@
1.13 private final Type type;
1.14 private final net.java.html.BrwsrCtx context;
1.15 private org.netbeans.html.json.impl.Bindings ko;
1.16 - private Watcher mine;
1.17 - private Watcher.Ref observers;
1.18 + private Watchers mine;
1.19 + private Observers observers;
1.20
1.21 Proto(Object obj, Type type, BrwsrCtx context) {
1.22 this.obj = obj;
1.23 @@ -132,7 +134,7 @@
1.24 ko.valueHasMutated(propName, null, null);
1.25 }
1.26 if (observers != null) {
1.27 - observers = Watcher.Ref.valueHasMutated(observers, propName);
1.28 + observers.valueHasMutated(propName);
1.29 }
1.30 }
1.31 });
1.32 @@ -162,7 +164,7 @@
1.33 ko.valueHasMutated(propName, oldValue, newValue);
1.34 }
1.35 if (observers != null) {
1.36 - observers = Watcher.Ref.valueHasMutated(observers, propName);
1.37 + observers.valueHasMutated(propName);
1.38 }
1.39 }
1.40 });
1.41 @@ -456,7 +458,7 @@
1.42 }
1.43
1.44 final Watcher watcher(String prop) {
1.45 - return Watcher.find(mine, null, prop);
1.46 + return mine == null ? null : mine.find(prop);
1.47 }
1.48
1.49 /** Functionality used by the code generated by annotation
2.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Watcher.java Fri Aug 01 17:13:23 2014 +0200
2.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Watcher.java Sat Aug 02 06:25:53 2014 +0200
2.3 @@ -43,18 +43,20 @@
2.4 package org.apidesign.html.json.spi;
2.5
2.6 import java.lang.ref.WeakReference;
2.7 +import java.util.ArrayList;
2.8 +import java.util.Iterator;
2.9 +import java.util.LinkedList;
2.10 +import java.util.List;
2.11
2.12 /**
2.13 *
2.14 * @author Jaroslav Tulach
2.15 */
2.16 final class Watcher {
2.17 - private static final Object LOCK = new Object();
2.18 - private static Watcher global;
2.19 + private static final LinkedList<Watcher> GLOBAL = new LinkedList<Watcher>();
2.20
2.21 private final Proto proto;
2.22 private final String prop;
2.23 - private Watcher next;
2.24
2.25 private Watcher(Proto proto, String prop) {
2.26 this.proto = proto;
2.27 @@ -62,97 +64,48 @@
2.28 }
2.29
2.30 static void beginComputing(Proto p, String name) {
2.31 - synchronized (LOCK) {
2.32 - Watcher alreadyThere = find(global, p, null);
2.33 - if (alreadyThere != null) {
2.34 - throw new IllegalStateException("Re-entrant attempt to access " + p);
2.35 - }
2.36 + synchronized (GLOBAL) {
2.37 + verifyUnlocked(p);
2.38 final Watcher nw = new Watcher(p, name);
2.39 - nw.next = global;
2.40 - global = nw;
2.41 + GLOBAL.push(nw);
2.42 }
2.43 }
2.44
2.45 static void verifyUnlocked(Proto p) {
2.46 - synchronized (LOCK) {
2.47 - Watcher alreadyThere = find(global, p, null);
2.48 - if (alreadyThere != null) {
2.49 - throw new IllegalStateException("Re-entrant attempt to access " + p);
2.50 + synchronized (GLOBAL) {
2.51 + for (Watcher w : GLOBAL) {
2.52 + if (w.proto == p) {
2.53 + throw new IllegalStateException("Re-entrant attempt to access " + p);
2.54 + }
2.55 }
2.56 }
2.57 }
2.58
2.59 - static Ref accessingValue(Proto p, Ref observers, String propName) {
2.60 - synchronized (LOCK) {
2.61 - Watcher alreadyThere = find(global, p, null);
2.62 - if (alreadyThere != null) {
2.63 - throw new IllegalStateException("Re-entrant attempt to access " + p);
2.64 + static Observers accessingValue(Proto p, Observers observers, String propName) {
2.65 + synchronized (GLOBAL) {
2.66 + verifyUnlocked(p);
2.67 + for (Watcher w : GLOBAL) {
2.68 + if (observers == null) {
2.69 + observers = new Observers();
2.70 + }
2.71 + observers.add(w, new Ref(w, propName));
2.72 }
2.73 - Watcher w = global;
2.74 - for (;;) {
2.75 - if (w == null) {
2.76 - return observers;
2.77 - }
2.78 - observers = w.observe(observers, propName);
2.79 - w = w.next;
2.80 - }
2.81 + return observers;
2.82 }
2.83 }
2.84
2.85 - static Watcher finishComputing(Proto p, Watcher mine) {
2.86 - synchronized (LOCK) {
2.87 - Watcher w = global;
2.88 - global = w.next;
2.89 - w.next = null;
2.90 + static Watchers finishComputing(Proto p, Watchers mine) {
2.91 + synchronized (GLOBAL) {
2.92 + Watcher w = GLOBAL.pop();
2.93 if (w.proto != p) {
2.94 throw new IllegalStateException("Inconsistency: " + w.proto + " != " + p);
2.95 }
2.96 - return register(mine, w);
2.97 - }
2.98 - }
2.99 -
2.100 - static Watcher find(Watcher first, Proto proto, String prop) {
2.101 - // assert Thread.holdsLock(LOCK);
2.102 - for (;;) {
2.103 - if (first == null) {
2.104 - return null;
2.105 + if (mine == null) {
2.106 + mine = new Watchers();
2.107 }
2.108 - if (prop != null && prop.equals(first.prop)) {
2.109 - return first;
2.110 - }
2.111 - if (proto != null && proto == first.proto) {
2.112 - return first;
2.113 - }
2.114 - first = first.next;
2.115 - }
2.116 - }
2.117 -
2.118 - private static Watcher register(Watcher mine, Watcher locked) {
2.119 - assert Thread.holdsLock(LOCK);
2.120 - if (locked.prop == null) {
2.121 + mine.add(w);
2.122 return mine;
2.123 }
2.124 - if (mine == null) {
2.125 - return locked;
2.126 - }
2.127 - if (locked.prop.equals(mine.prop)) {
2.128 - locked.next = mine.next;
2.129 - return locked;
2.130 - }
2.131 - Watcher current = mine;
2.132 - for (;;) {
2.133 - Watcher next = current.next;
2.134 - if (next == null) {
2.135 - current.next = locked;
2.136 - return mine;
2.137 - }
2.138 - if (locked.prop.equals(next.prop)) {
2.139 - locked.next = next.next;
2.140 - current.next = locked;
2.141 - return mine;
2.142 - }
2.143 - current = next;
2.144 - }
2.145 }
2.146
2.147 static Watcher computing(Proto proto, String prop) {
2.148 @@ -161,71 +114,107 @@
2.149 return new Watcher(proto, prop);
2.150 }
2.151
2.152 - Ref observe(Ref prev, String prop) {
2.153 - if (prop == null) {
2.154 - return prev;
2.155 - }
2.156 - return new Ref(this, prop).chain(prev);
2.157 + @Override
2.158 + public String toString() {
2.159 + return "Watcher: " + proto + ", " + prop;
2.160 }
2.161
2.162 - @Override
2.163 - public String toString() {
2.164 - return "Watcher: " + proto + ", " + prop + "\n -> " + next;
2.165 - }
2.166 -
2.167 - static final class Ref extends WeakReference<Watcher> {
2.168 + private static final class Ref extends WeakReference<Watcher> {
2.169 private final String prop;
2.170 - private Ref next;
2.171
2.172 public Ref(Watcher ref, String prop) {
2.173 super(ref);
2.174 this.prop = prop;
2.175 }
2.176
2.177 - Ref chain(Ref prev) {
2.178 - this.next = dropDead(prev, null);
2.179 - return this;
2.180 - }
2.181 -
2.182 - private Watcher watcher() {
2.183 + final Watcher watcher() {
2.184 Watcher w = get();
2.185 if (w != null && w.proto.watcher(w.prop) == w) {
2.186 return w;
2.187 }
2.188 return null;
2.189 }
2.190 -
2.191 - private static Ref dropDead(Ref self, String fireProp) {
2.192 - while (self != null && self.watcher() == null) {
2.193 - self = self.next;
2.194 - }
2.195 - if (self == null) {
2.196 + }
2.197 +
2.198 + static final class Watchers {
2.199 + private final List<Watcher> watchers = new ArrayList<Watcher>();
2.200 +
2.201 + Watcher find(String prop) {
2.202 + if (prop == null) {
2.203 return null;
2.204 }
2.205 - Ref current = self;
2.206 - for (;;) {
2.207 - Watcher w = current.watcher();
2.208 - if (w != null && fireProp != null && fireProp.equals(current.prop)) {
2.209 - w.proto.valueHasMutated(w.prop);
2.210 + for (Watcher w : watchers) {
2.211 + if (prop.equals(w.prop)) {
2.212 + return w;
2.213 }
2.214 - for (;;) {
2.215 - Ref next = current.next;
2.216 - if (next == null) {
2.217 - return self;
2.218 + }
2.219 + return null;
2.220 + }
2.221 +
2.222 + final void add(Watcher w) {
2.223 + for (int i = 0; i < watchers.size(); i++) {
2.224 + Watcher ith = watchers.get(i);
2.225 + if (w.prop == null) {
2.226 + if (ith.prop == null) {
2.227 + watchers.set(i, w);
2.228 + return;
2.229 }
2.230 - if (next.watcher() != null) {
2.231 - current = next;
2.232 - break;
2.233 - } else {
2.234 - current.next = next.next;
2.235 + } else if (w.prop.equals(ith.prop)) {
2.236 + watchers.set(i, w);
2.237 + return;
2.238 + }
2.239 + }
2.240 + watchers.add(w);
2.241 + }
2.242 + }
2.243 +
2.244 + static final class Observers {
2.245 + private final List<Ref> observers = new ArrayList<Ref>();
2.246 +
2.247 + void valueHasMutated(String propName) {
2.248 + List<Watcher> mutated = new LinkedList<Watcher>();
2.249 + synchronized (GLOBAL) {
2.250 + Iterator<Ref> it = observers.iterator();
2.251 + while (it.hasNext()) {
2.252 + Ref ref = it.next();
2.253 + if (ref.get() == null) {
2.254 + it.remove();
2.255 + continue;
2.256 + }
2.257 + if (ref.prop.equals(propName)) {
2.258 + Watcher w = ref.watcher();
2.259 + if (w != null) {
2.260 + mutated.add(w);
2.261 + }
2.262 }
2.263 }
2.264 }
2.265 -
2.266 + for (Watcher w : mutated) {
2.267 + w.proto.valueHasMutated(w.prop);
2.268 + }
2.269 }
2.270
2.271 - static Ref valueHasMutated(Ref self, String propName) {
2.272 - return dropDead(self, propName);
2.273 + void add(Watcher w, Ref r) {
2.274 + Thread.holdsLock(GLOBAL);
2.275 + if (w == null) {
2.276 + return;
2.277 + }
2.278 + Iterator<Ref> it = observers.iterator();
2.279 + while (it.hasNext()) {
2.280 + Ref ref = it.next();
2.281 + if (r == ref) {
2.282 + return;
2.283 + }
2.284 + final Watcher rw = ref.get();
2.285 + if (rw == null) {
2.286 + it.remove();
2.287 + continue;
2.288 + }
2.289 + if (rw == w && r.prop.equals(r.prop)) {
2.290 + return;
2.291 + }
2.292 + }
2.293 + observers.add(r);
2.294 }
2.295 }
2.296 }