31 32 /** 33 * A context for obtaining values for {@link OptionKey}s that allows for key/value pairs to be 34 * updated. Updates have atomic copy-on-write semantics which means a thread may see an old value 35 * when reading but writers will never loose updates. 36 */ 37 public class ModifiableOptionValues extends OptionValues { 38 39 private final AtomicReference<UnmodifiableEconomicMap<OptionKey<?>, Object>> v = new AtomicReference<>(); 40 41 private static final EconomicMap<OptionKey<?>, Object> EMPTY_MAP = newOptionMap(); 42 43 public ModifiableOptionValues(UnmodifiableEconomicMap<OptionKey<?>, Object> values) { 44 super(EMPTY_MAP); 45 EconomicMap<OptionKey<?>, Object> map = newOptionMap(); 46 initMap(map, values); 47 v.set(map); 48 } 49 50 /** 51 * Updates this object with the given key/value pair. 52 */ 53 public void update(OptionKey<?> key, Object value) { 54 UnmodifiableEconomicMap<OptionKey<?>, Object> expect; 55 EconomicMap<OptionKey<?>, Object> newMap; 56 do { 57 expect = v.get(); 58 newMap = EconomicMap.create(Equivalence.IDENTITY, expect); 59 key.update(newMap, value); 60 // Need to do the null encoding here as `key.update()` doesn't do it 61 newMap.put(key, encodeNull(value)); 62 } while (!v.compareAndSet(expect, newMap)); 63 } 64 65 /** 66 * Updates this object with the key/value pairs in {@code values}. 67 */ 68 public void update(UnmodifiableEconomicMap<OptionKey<?>, Object> values) { 69 if (values.isEmpty()) { 70 return; 71 } 72 UnmodifiableEconomicMap<OptionKey<?>, Object> expect; 73 EconomicMap<OptionKey<?>, Object> newMap; 74 do { 75 expect = v.get(); 76 newMap = EconomicMap.create(Equivalence.IDENTITY, expect); 77 UnmodifiableMapCursor<OptionKey<?>, Object> cursor = values.getEntries(); 78 while (cursor.advance()) { 79 OptionKey<?> key = cursor.getKey(); 80 Object value = cursor.getValue(); 81 key.update(newMap, value); 82 // Need to do the null encoding here as `key.update()` doesn't do it 83 newMap.put(key, encodeNull(value)); 84 } 85 } while (!v.compareAndSet(expect, newMap)); 86 } 87 88 @Override 89 protected <T> T get(OptionKey<T> key) { 90 return OptionValues.get(v.get(), key); 91 } 92 93 @Override 94 protected boolean containsKey(OptionKey<?> key) { 95 return v.get().containsKey(key); 96 } 97 98 @Override 99 public UnmodifiableEconomicMap<OptionKey<?>, Object> getMap() { 100 return v.get(); 101 } 102 } | 31 32 /** 33 * A context for obtaining values for {@link OptionKey}s that allows for key/value pairs to be 34 * updated. Updates have atomic copy-on-write semantics which means a thread may see an old value 35 * when reading but writers will never loose updates. 36 */ 37 public class ModifiableOptionValues extends OptionValues { 38 39 private final AtomicReference<UnmodifiableEconomicMap<OptionKey<?>, Object>> v = new AtomicReference<>(); 40 41 private static final EconomicMap<OptionKey<?>, Object> EMPTY_MAP = newOptionMap(); 42 43 public ModifiableOptionValues(UnmodifiableEconomicMap<OptionKey<?>, Object> values) { 44 super(EMPTY_MAP); 45 EconomicMap<OptionKey<?>, Object> map = newOptionMap(); 46 initMap(map, values); 47 v.set(map); 48 } 49 50 /** 51 * Value that can be used in {@link #update(UnmodifiableEconomicMap)} and 52 * {@link #update(OptionKey, Object)} to remove an explicitly set value for a key such that 53 * {@link OptionKey#hasBeenSet(OptionValues)} will return {@code false} for the key. 54 */ 55 public static final Object UNSET_KEY = new Object(); 56 57 /** 58 * Updates this object with the given key/value pair. 59 * 60 * @see #UNSET_KEY 61 */ 62 public void update(OptionKey<?> key, Object value) { 63 UnmodifiableEconomicMap<OptionKey<?>, Object> expect; 64 EconomicMap<OptionKey<?>, Object> newMap; 65 do { 66 expect = v.get(); 67 newMap = EconomicMap.create(Equivalence.IDENTITY, expect); 68 if (value == UNSET_KEY) { 69 newMap.removeKey(key); 70 } else { 71 key.update(newMap, value); 72 // Need to do the null encoding here as `key.update()` doesn't do it 73 newMap.put(key, encodeNull(value)); 74 } 75 } while (!v.compareAndSet(expect, newMap)); 76 } 77 78 /** 79 * Updates this object with the key/value pairs in {@code values}. 80 * 81 * @see #UNSET_KEY 82 */ 83 public void update(UnmodifiableEconomicMap<OptionKey<?>, Object> values) { 84 if (values.isEmpty()) { 85 return; 86 } 87 UnmodifiableEconomicMap<OptionKey<?>, Object> expect; 88 EconomicMap<OptionKey<?>, Object> newMap; 89 do { 90 expect = v.get(); 91 newMap = EconomicMap.create(Equivalence.IDENTITY, expect); 92 UnmodifiableMapCursor<OptionKey<?>, Object> cursor = values.getEntries(); 93 while (cursor.advance()) { 94 OptionKey<?> key = cursor.getKey(); 95 Object value = cursor.getValue(); 96 if (value == UNSET_KEY) { 97 newMap.removeKey(key); 98 } else { 99 key.update(newMap, value); 100 // Need to do the null encoding here as `key.update()` doesn't do it 101 newMap.put(key, encodeNull(value)); 102 } 103 } 104 } while (!v.compareAndSet(expect, newMap)); 105 } 106 107 @Override 108 protected <T> T get(OptionKey<T> key) { 109 return OptionValues.get(v.get(), key); 110 } 111 112 @Override 113 protected boolean containsKey(OptionKey<?> key) { 114 return v.get().containsKey(key); 115 } 116 117 @Override 118 public UnmodifiableEconomicMap<OptionKey<?>, Object> getMap() { 119 return v.get(); 120 } 121 } |