]> git.basschouten.com Git - openhab-addons.git/blob
6157804e7cdd03a3c2e74cd025e271f8e90acaf3
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.automation.jrubyscripting.internal.watch;
14
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.concurrent.locks.ReentrantReadWriteLock;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23
24 // Copy of org.openhab.core.automation.module.script.rulesupport.internal.loader.collection.BidiSetBag
25
26 /**
27  * Bidirectional bag of unique elements. A map allowing multiple, unique values to be stored against a single key.
28  * Provides optimized lookup of values for a key, as well as keys referencing a value.
29  *
30  * @author Jonathan Gilbert - Initial contribution
31  * @author Jan N. Klug - Make implementation thread-safe
32  * @param <K> Type of Key
33  * @param <V> Type of Value
34  */
35 @NonNullByDefault
36 public class BidiSetBag<K, V> {
37
38     private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
39     private final Map<K, Set<V>> keyToValues = new HashMap<>();
40     private final Map<V, Set<K>> valueToKeys = new HashMap<>();
41
42     public void put(K key, V value) {
43         lock.writeLock().lock();
44         try {
45             keyToValues.computeIfAbsent(key, k -> new HashSet<>()).add(value);
46             valueToKeys.computeIfAbsent(value, v -> new HashSet<>()).add(key);
47         } finally {
48             lock.writeLock().unlock();
49         }
50     }
51
52     public Set<V> getValues(K key) {
53         lock.readLock().lock();
54         try {
55             Set<V> values = keyToValues.getOrDefault(key, Set.of());
56             return Collections.unmodifiableSet(values);
57         } finally {
58             lock.readLock().unlock();
59         }
60     }
61
62     public Set<K> getKeys(V value) {
63         lock.readLock().lock();
64         try {
65             Set<K> keys = valueToKeys.getOrDefault(value, Set.of());
66             return Collections.unmodifiableSet(keys);
67         } finally {
68             lock.readLock().unlock();
69         }
70     }
71
72     public Set<V> removeKey(K key) {
73         lock.writeLock().lock();
74         try {
75             Set<V> values = keyToValues.remove(key);
76             if (values != null) {
77                 for (V value : values) {
78                     valueToKeys.computeIfPresent(value, (k, v) -> {
79                         v.remove(key);
80                         return v;
81                     });
82                 }
83                 return values;
84             } else {
85                 return Set.of();
86             }
87         } finally {
88             lock.writeLock().unlock();
89         }
90     }
91
92     public Set<K> removeValue(V value) {
93         lock.writeLock().lock();
94         try {
95             Set<K> keys = valueToKeys.remove(value);
96             if (keys != null) {
97                 for (K key : keys) {
98                     keyToValues.computeIfPresent(key, (k, v) -> {
99                         v.remove(value);
100                         return v;
101                     });
102                 }
103                 return keys;
104             } else {
105                 return Set.of();
106             }
107         } finally {
108             lock.writeLock().unlock();
109         }
110     }
111 }