Refactor MetaAccumulator to be a little more sane

This commit is contained in:
Luck 2018-09-04 20:33:08 +01:00
parent 274286032a
commit f0c0328919
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
6 changed files with 83 additions and 53 deletions

View File

@ -262,8 +262,8 @@ public class VaultChatHook extends AbstractVaultChat {
// find the max inherited priority & add 10
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, createContextForWorldSet(world));
int priority = (type == ChatMetaType.PREFIX ? metaAccumulator.getPrefixes() : metaAccumulator.getSuffixes()).keySet().stream()
.mapToInt(e -> e).max().orElse(0) + 10;
metaAccumulator.complete();
int priority = metaAccumulator.getChatMeta(type).keySet().stream().mapToInt(e -> e).max().orElse(0) + 10;
Node.Builder chatMetaNode = NodeFactory.buildChatMetaNode(type, priority, value);
chatMetaNode.setServer(this.permissionHook.getVaultServer());

View File

@ -44,12 +44,14 @@ import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicReference;
/**
* Holds temporary mutable meta whilst this object is passed up the
* inheritance tree to accumulate meta from parents
*/
public class MetaAccumulator {
public static MetaAccumulator makeFromConfig(LuckPermsPlugin plugin) {
return new MetaAccumulator(
new SimpleMetaStack(plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), ChatMetaType.PREFIX),
@ -57,6 +59,18 @@ public class MetaAccumulator {
);
}
/**
* Represents the current state of a {@link MetaAccumulator}.
*/
private enum State {
/** Marks that the accumulator is still gaining (accumulating) new data. */
ACCUMULATING,
/** Marks that the process of gaining (accumulating) new data is complete. */
COMPLETE
}
private final AtomicReference<State> state = new AtomicReference<>(State.ACCUMULATING);
private final ListMultimap<String, String> meta;
private final SortedMap<Integer, String> prefixes;
private final SortedMap<Integer, String> suffixes;
@ -75,7 +89,34 @@ public class MetaAccumulator {
this.suffixStack = suffixStack;
}
private void ensureState(State state) {
if (this.state.get() != state) {
throw new IllegalStateException("State must be " + state + ", but is actually " + this.state.get());
}
}
/**
* "Completes" the accumulator, preventing any further changes.
*
* Also performs some final processing on the accumulators state, before
* data is read.
*/
public void complete() {
if (!this.state.compareAndSet(State.ACCUMULATING, State.COMPLETE)) {
return;
}
// perform final changes
if (!this.meta.containsKey(NodeTypes.WEIGHT_KEY) && this.weight != 0) {
this.meta.put(NodeTypes.WEIGHT_KEY, String.valueOf(this.weight));
}
}
// accumulate methods
public void accumulateNode(LocalizedNode n) {
ensureState(State.ACCUMULATING);
n.getTypeData(MetaType.KEY).ifPresent(metaType ->
this.meta.put(metaType.getKey(), metaType.getValue())
);
@ -92,60 +133,60 @@ public class MetaAccumulator {
}
public void accumulateMeta(String key, String value) {
ensureState(State.ACCUMULATING);
this.meta.put(key, value);
}
public void accumulateWeight(int weight) {
ensureState(State.ACCUMULATING);
this.weight = Math.max(this.weight, weight);
}
// We can assume that if this method is being called, this holder is effectively finalized.
// (it's not going to accumulate more nodes)
// Therefore, it should be ok to set the weight meta key, if not already present.
public ListMultimap<String, String> getMeta() {
if (!this.meta.containsKey(NodeTypes.WEIGHT_KEY) && this.weight != 0) {
this.meta.put(NodeTypes.WEIGHT_KEY, String.valueOf(this.weight));
}
// read methods
public ListMultimap<String, String> getMeta() {
ensureState(State.COMPLETE);
return this.meta;
}
public Map<Integer, String> getChatMeta(ChatMetaType type) {
ensureState(State.COMPLETE);
return type == ChatMetaType.PREFIX ? this.prefixes : this.suffixes;
}
public MetaStack getStack(ChatMetaType type) {
return type == ChatMetaType.PREFIX ? this.prefixStack : this.suffixStack;
}
public SortedMap<Integer, String> getPrefixes() {
ensureState(State.COMPLETE);
return this.prefixes;
}
public SortedMap<Integer, String> getSuffixes() {
ensureState(State.COMPLETE);
return this.suffixes;
}
public int getWeight() {
ensureState(State.COMPLETE);
return this.weight;
}
public MetaStack getPrefixStack() {
ensureState(State.COMPLETE);
return this.prefixStack;
}
public MetaStack getSuffixStack() {
ensureState(State.COMPLETE);
return this.suffixStack;
}
@Override
public String toString() {
return "MetaAccumulator(" +
"meta=" + this.getMeta() + ", " +
"prefixes=" + this.getPrefixes() + ", " +
"suffixes=" + this.getSuffixes() + ", " +
"weight=" + this.getWeight() + ", " +
"prefixStack=" + this.getPrefixStack() + ", " +
"suffixStack=" + this.getSuffixStack() + ")";
"meta=" + this.meta + ", " +
"prefixes=" + this.prefixes + ", " +
"suffixes=" + this.suffixes + ", " +
"weight=" + this.weight + ", " +
"prefixStack=" + this.prefixStack + ", " +
"suffixStack=" + this.suffixStack + ")";
}
}

View File

@ -39,8 +39,6 @@ import me.lucko.luckperms.common.metastacking.MetaStack;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.annotation.Nonnull;
@ -48,7 +46,6 @@ import javax.annotation.Nonnull;
* Holds cached meta for a given context
*/
public class MetaCache implements MetaData {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
/**
* The contexts this container is holding data for
@ -67,51 +64,40 @@ public class MetaCache implements MetaData {
}
public void loadMeta(MetaAccumulator meta) {
this.lock.writeLock().lock();
try {
this.metaMultimap = ImmutableListMultimap.copyOf(meta.getMeta());
meta.complete();
//noinspection unchecked
Map<String, List<String>> metaMap = (Map) this.metaMultimap.asMap();
ImmutableMap.Builder<String, String> metaMapBuilder = ImmutableMap.builder();
this.metaMultimap = ImmutableListMultimap.copyOf(meta.getMeta());
for (Map.Entry<String, List<String>> e : metaMap.entrySet()) {
if (e.getValue().isEmpty()) {
continue;
}
//noinspection unchecked
Map<String, List<String>> metaMap = (Map) this.metaMultimap.asMap();
ImmutableMap.Builder<String, String> metaMapBuilder = ImmutableMap.builder();
// take the value which was accumulated first
metaMapBuilder.put(e.getKey(), e.getValue().get(0));
for (Map.Entry<String, List<String>> e : metaMap.entrySet()) {
if (e.getValue().isEmpty()) {
continue;
}
this.meta = metaMapBuilder.build();
this.prefixes = ImmutableSortedMap.copyOfSorted(meta.getPrefixes());
this.suffixes = ImmutableSortedMap.copyOfSorted(meta.getSuffixes());
this.prefixStack = meta.getPrefixStack();
this.suffixStack = meta.getSuffixStack();
} finally {
this.lock.writeLock().unlock();
// take the value which was accumulated first
metaMapBuilder.put(e.getKey(), e.getValue().get(0));
}
this.meta = metaMapBuilder.build();
this.prefixes = ImmutableSortedMap.copyOfSorted(meta.getPrefixes());
this.suffixes = ImmutableSortedMap.copyOfSorted(meta.getSuffixes());
this.prefixStack = meta.getPrefixStack();
this.suffixStack = meta.getSuffixStack();
}
@Override
public String getPrefix() {
this.lock.readLock().lock();
try {
return this.prefixStack == null ? null : this.prefixStack.toFormattedString();
} finally {
this.lock.readLock().unlock();
}
MetaStack prefixStack = this.prefixStack;
return prefixStack == null ? null : prefixStack.toFormattedString();
}
@Override
public String getSuffix() {
this.lock.readLock().lock();
try {
return this.suffixStack == null ? null : this.suffixStack.toFormattedString();
} finally {
this.lock.readLock().unlock();
}
MetaStack suffixStack = this.suffixStack;
return suffixStack == null ? null : suffixStack.toFormattedString();
}
@Nonnull

View File

@ -107,6 +107,7 @@ public class MetaSetChatMeta extends SharedSubCommand {
// determine the priority to set at
if (priority == Integer.MIN_VALUE) {
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, Contexts.of(context, Contexts.global().getSettings()));
metaAccumulator.complete();
priority = metaAccumulator.getChatMeta(this.type).keySet().stream().mapToInt(e -> e).max().orElse(0) + 1;
if (holder instanceof Group) {

View File

@ -118,6 +118,7 @@ public class MetaSetTempChatMeta extends SharedSubCommand {
// determine the priority to set at
if (priority == Integer.MIN_VALUE) {
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, Contexts.of(context, Contexts.global().getSettings()));
metaAccumulator.complete();
priority = metaAccumulator.getChatMeta(this.type).keySet().stream().mapToInt(e -> e).max().orElse(0) + 1;
if (holder instanceof Group) {

View File

@ -362,6 +362,7 @@ public class HolderSubjectData implements LPSubjectData {
));
MetaAccumulator metaAccumulator = this.holder.accumulateMeta(null, Contexts.of(contexts, Contexts.global().getSettings()));
metaAccumulator.complete();
int priority = metaAccumulator.getChatMeta(type).keySet().stream().mapToInt(e -> e).max().orElse(0);
priority += 10;