changeset 95:df9dedc80485

Atomic add-observer.
author Mikhail Kryshen <mikhail@kryshen.net>
date Thu, 03 Mar 2011 03:20:23 +0300
parents 649d12b6c9ec
children fbedad9bd6de
files src/net/kryshen/indyvon/core.clj
diffstat 1 files changed, 24 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/net/kryshen/indyvon/core.clj	Thu Mar 03 03:13:14 2011 +0300
+++ b/src/net/kryshen/indyvon/core.clj	Thu Mar 03 03:20:23 2011 +0300
@@ -1,5 +1,5 @@
 ;;
-;; Copyright 2010 Mikhail Kryshen <mikhail@kryshen.net>
+;; Copyright 2010, 2011 Mikhail Kryshen <mikhail@kryshen.net>
 ;;
 ;; This file is part of Indyvon.
 ;;
@@ -23,7 +23,8 @@
    (java.awt.geom AffineTransform Point2D$Double Rectangle2D$Double Area)
    (java.awt.event MouseListener MouseMotionListener)
    (java.awt.font FontRenderContext)
-   (com.google.common.collect MapMaker)))
+   java.util.concurrent.ConcurrentMap
+   com.google.common.collect.MapMaker))
 
 ;;
 ;; Layer context
@@ -141,9 +142,28 @@
 ;; The mechanism used by layers to request repaints
 ;;
 
-(def ^java.util.Map observers
+(def ^ConcurrentMap observers
      (-> (MapMaker.) (.weakKeys) (.makeMap)))
 
+(defn- cm-replace!
+  "Wrap ConcurrentMap replace method to treat nil value as absent
+   mapping. Use with maps that does not support nil values."
+  [^ConcurrentMap cmap key old new]
+  (if (nil? old)
+    (nil? (.putIfAbsent cmap key new))
+    (.replace cmap key old new)))
+
+(defn- cm-swap!
+  "Atomically swaps the value associated with key in ConcurrentMap
+   to be (apply f current-value args). Returns the new value."
+  [cmap key f & args]
+  (loop []
+    (let [old (.get cmap key)
+          new (apply f old args)]
+      (if (cm-replace! cmap key old new)
+        new
+        (recur)))))
+
 (defn add-observer
   "Add observer fn for the target. Watcher identifies the group of
   observers and could be used to remove the group. Watcher is weakly
@@ -152,7 +172,7 @@
   watcher and target arguments and any additional arguments specified
   in update call."
   [watcher target f]
-  (.put observers watcher (assoc-cons (.get observers watcher) target f))
+  (cm-swap! observers watcher assoc-cons target f)
   nil)
 
 (defn remove-observers