Browse Source

Synchronise maps properly.

SynchronizedSet() requires manual synchronisation when iterating
over it. When returning an iterator make a copy of the set first
to avoid issues with users iterating.
tags/v0.10.2
Chris Smith 5 years ago
parent
commit
5f5aea0652
2 changed files with 9 additions and 6 deletions
  1. 1
    0
      CHANGELOG
  2. 8
    6
      src/main/kotlin/com/dmdirc/ktirc/model/Maps.kt

+ 1
- 0
CHANGELOG View File

2
 
2
 
3
  * Fix handling of multiple long lines sometimes dropping part of the line
3
  * Fix handling of multiple long lines sometimes dropping part of the line
4
  * Support lines with 8191 bytes of tags, as allowed by the message-tags spec
4
  * Support lines with 8191 bytes of tags, as allowed by the message-tags spec
5
+ * Fix a few more instances of occasional ConcurrentModificationExceptions
5
 
6
 
6
 v0.10.1
7
 v0.10.1
7
 
8
 

+ 8
- 6
src/main/kotlin/com/dmdirc/ktirc/model/Maps.kt View File

11
     private val values = Collections.synchronizedSet(HashSet<T>())
11
     private val values = Collections.synchronizedSet(HashSet<T>())
12
 
12
 
13
     /** Gets the value of the given key, if present. */
13
     /** Gets the value of the given key, if present. */
14
-    operator fun get(name: String) = values.find { caseMappingProvider().areEquivalent(nameOf(it), name) }
14
+    operator fun get(name: String) = synchronized(values) { values.find { caseMappingProvider().areEquivalent(nameOf(it), name) } }
15
 
15
 
16
-    internal operator fun plusAssign(value: T) {
17
-        require(get(nameOf(value)) == null) { "Value already registered: ${nameOf(value)}"}
16
+    internal operator fun plusAssign(value: T): Unit = synchronized(values) {
17
+        require(get(nameOf(value)) == null) { "Value already registered: ${nameOf(value)}" }
18
         values.add(value)
18
         values.add(value)
19
     }
19
     }
20
 
20
 
21
-    internal operator fun minusAssign(name: String) {
21
+    internal operator fun minusAssign(name: String): Unit = synchronized(values) {
22
         values.removeIf { caseMappingProvider().areEquivalent(nameOf(it), name) }
22
         values.removeIf { caseMappingProvider().areEquivalent(nameOf(it), name) }
23
     }
23
     }
24
 
24
 
26
     operator fun contains(name: String) = get(name) != null
26
     operator fun contains(name: String) = get(name) != null
27
 
27
 
28
     /** Provides a read-only iterator over the values in this map. */
28
     /** Provides a read-only iterator over the values in this map. */
29
-    override fun iterator() = values.iterator().iterator()
29
+    override fun iterator() = HashSet(values).iterator().iterator()
30
 
30
 
31
     internal fun clear() = values.clear()
31
     internal fun clear() = values.clear()
32
 
32
 
33
-    internal fun removeIf(predicate: (T) -> Boolean) = values.removeIf(predicate)
33
+    internal fun removeIf(predicate: (T) -> Boolean): Unit = synchronized(values) {
34
+        values.removeIf(predicate)
35
+    }
34
 
36
 
35
 }
37
 }
36
 
38
 

Loading…
Cancel
Save