Collections
Package dev.versatia.util.collection.
*OrThrow helpers
MutableSet.addOrThrow, addAllOrThrow, MutableMap.putOrThrow, putAllOrThrow and
Map.getOrThrow turn silent overwrites and missing keys into exceptions.
val registry = mutableMapOf<String, Handler>()
registry.putOrThrow("shop", ShopHandler()) // throws if "shop" is already registered
addAllOrThrowandputAllOrThrowcheck the whole input before touching the receiver, so a failed call leaves the collection unchanged.- They also report duplicates inside the input, not only clashes with what is already stored.
- A stored
nullvalue counts as present (containsKey, neverget(key) != null). Iterable<Map<K, V>>.mergeOrThrowmerges several maps and, when keys are present in more than one of them, throws once with every conflict; eachMapConflict(key, existingValue, newValue)tells which.
cycle
List.cycle() is an endless iterator going round the list: its elements in order, then from the
first again, such as lines broadcast in turn.
val rotation = lines.cycle()
every(period) { VersatiaEngine.broadcast(text(rotation.next())) }
The list is copied, so later changes to it are not seen; an empty list throws
IllegalArgumentException (Cannot cycle through an empty list), since there would be nothing to
go round.
DeepMergeMap
A MutableMap<K, Any?> that merges other maps into itself recursively, useful for layering a
default configuration under a user one. For every key of the incoming map:
- Key absent in the destination: the value is deep-copied in. Nested maps become nested
DeepMergeMaps, nested collections become lists. - Both values are maps: they are merged recursively with the same rules.
- Both values are collections: the result is their concatenation.
- Anything else is a conflict, resolved by the
MergeConflictStrategygiven to the constructor:
| Strategy | Result |
|---|---|
OVERRIDE (default) | incoming value wins |
KEEP_EXISTING | existing value stays |
COMBINE_INTO_LIST | [existing, incoming]; a collection on either side is flattened into it |
THROW | IllegalStateException naming the dotted key path |
val merged = DeepMergeMap<String>(conflictStrategy = MergeConflictStrategy.KEEP_EXISTING)
merged += userConfig.getValues(true)
merged += defaults.getValues(true) // fills the gaps, keeps the user's values
null is an ordinary value, not "absent". Incoming maps are never mutated. Use merge(other) or
map += other to mutate in place and mergedWith(other) to get a copy. There is deliberately no
plus operator: defining both plus and plusAssign makes += on a var ambiguous in Kotlin.