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,6 +2,7 @@ vNEXT (in development)
2 2
 
3 3
  * Fix handling of multiple long lines sometimes dropping part of the line
4 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 7
 v0.10.1
7 8
 

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

@@ -11,14 +11,14 @@ abstract class CaseInsensitiveMap<T>(private val caseMappingProvider: () -> Case
11 11
     private val values = Collections.synchronizedSet(HashSet<T>())
12 12
 
13 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 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 22
         values.removeIf { caseMappingProvider().areEquivalent(nameOf(it), name) }
23 23
     }
24 24
 
@@ -26,11 +26,13 @@ abstract class CaseInsensitiveMap<T>(private val caseMappingProvider: () -> Case
26 26
     operator fun contains(name: String) = get(name) != null
27 27
 
28 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 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