Skip to content

Instantly share code, notes, and snippets.

@Miha-x64
Last active February 9, 2022 10:00
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Miha-x64/5f626228b34175f827734596d6701008 to your computer and use it in GitHub Desktop.
Save Miha-x64/5f626228b34175f827734596d6701008 to your computer and use it in GitHub Desktop.
Enum extensions for Kotlin, superseded by https://github.com/Miha-x64/Kotlin-MPP_Collection_utils
package net.aquadc.common
// Gist: https://gist.github.com/Miha-x64/5f626228b34175f827734596d6701008
import java.util.*
// maps
inline fun <reified K : Enum<K>, V> enumMapOf(): MutableMap<K, V> {
return EnumMap<K, V>(K::class.java)
}
inline fun <reified K : Enum<K>, V> enumMapOf(k: K, v: V): MutableMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
map.put(k, v)
return map
}
inline fun <reified K : Enum<K>, V> enumMapOf(k0: K, v0: V, k1: K, v1: V): MutableMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
map.put(k0, v0)
map.put(k1, v1)
return map
}
inline fun <reified K : Enum<K>, V> enumMapOf(k0: K, v0: V, k1: K, v1: V, k2: K, v2: V): MutableMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
map.put(k0, v0)
map.put(k1, v1)
map.put(k2, v2)
return map
}
inline fun <reified K : Enum<K>, V> enumMapOf(k0: K, v0: V, k1: K, v1: V, k2: K, v2: V, k3: K, v3: V): MutableMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
map.put(k0, v0)
map.put(k1, v1)
map.put(k2, v2)
map.put(k3, v3)
return map
}
inline fun <reified K : Enum<K>, V> enumMapOf(k0: K, v0: V, k1: K, v1: V, k2: K, v2: V, k3: K, v3: V, k4: K, v4: V): MutableMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
map.put(k0, v0)
map.put(k1, v1)
map.put(k2, v2)
map.put(k3, v3)
map.put(k4, v4)
return map
}
inline fun <reified K : Enum<K>, V> enumMapOf(k0: K, v0: V, k1: K, v1: V, k2: K, v2: V, k3: K, v3: V, k4: K, v4: V, k5: K, v5: V): MutableMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
map.put(k0, v0)
map.put(k1, v1)
map.put(k2, v2)
map.put(k3, v3)
map.put(k4, v4)
map.put(k5, v5)
return map
}
inline fun <reified K : Enum<K>, V> enumMapOf(k0: K, v0: V, k1: K, v1: V, k2: K, v2: V, k3: K, v3: V, k4: K, v4: V, k5: K, v5: V, k6: K, v6: V): MutableMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
map.put(k0, v0)
map.put(k1, v1)
map.put(k2, v2)
map.put(k3, v3)
map.put(k4, v4)
map.put(k5, v5)
map.put(k6, v6)
return map
}
// sets
inline fun <reified E : Enum<E>> enumSetOf(): MutableSet<E> = EnumSet.noneOf(E::class.java)
inline fun <E : Enum<E>> enumSetOf(single: E): MutableSet<E> = EnumSet.of(single)
inline fun <E : Enum<E>> enumSetOf(e0: E, e1: E): MutableSet<E> = EnumSet.of(e0, e1)
inline fun <E : Enum<E>> enumSetOf(e0: E, e1: E, e2: E): MutableSet<E> = EnumSet.of(e0, e1, e2)
// transforms
/**
* Variation of groupBy optimized for enum keys; however, this map has is not linked, it has its own order.
*/
@JvmName("groupByEnum")
inline fun <T, reified K : Enum<K>> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> {
return groupByTo(EnumMap<K, MutableList<T>>(K::class.java), keySelector)
}
@JvmName("associateByEnum")
inline fun <T, reified K : Enum<K>> Iterable<T>.associateBy(keySelector: (T) -> K): MutableMap<K, T> {
return associateByTo(EnumMap(K::class.java), keySelector)
}
@file:Suppress("NOTHING_TO_INLINE")
package net.aquadc.common.android
// Gist: https://gist.github.com/Miha-x64/5f626228b34175f827734596d6701008
import android.content.Intent
import android.os.Bundle
import android.os.Parcel
import java.util.*
// enum
inline fun Parcel.writeEnum(e: Enum<*>) {
writeString(e.name)
}
inline fun <reified E : Enum<E>> Parcel.readEnum(): E =
java.lang.Enum.valueOf(E::class.java, readString())
inline fun <E : Enum<E>> Parcel.readEnum(eClass: Class<E>): E =
java.lang.Enum.valueOf(eClass, readString())
inline fun Bundle.putEnum(name: String, value: Enum<*>) {
putString(name, value.name)
}
inline fun <reified E : Enum<E>> Bundle.getEnum(name: String): E =
java.lang.Enum.valueOf(E::class.java, getString(name))
inline fun <E : Enum<E>> Bundle.getEnum(name: String, eClass: Class<E>): E =
java.lang.Enum.valueOf(eClass, getString(name))
inline fun Intent.putEnumExtra(name: String, value: Enum<*>): Intent =
putExtra(name, value.name)
inline fun <reified E : Enum<E>> Intent.getEnumExtra(name: String): E =
java.lang.Enum.valueOf(E::class.java, getStringExtra(name))
inline fun <E : Enum<E>> Intent.getEnumExtra(name: String, eClass: Class<E>): E =
java.lang.Enum.valueOf(eClass, getStringExtra(name))
// enumSet
fun <E : Enum<E>> Parcel.writeEnumSet(set: Set<E>) {
writeStringArray(set.mapToArray { it.name })
}
inline fun <reified E : Enum<E>> Parcel.readEnumSet(): Set<E> =
readEnumSet(E::class.java)
fun <E : Enum<E>> Parcel.readEnumSet(eClass: Class<E>): Set<E> =
createStringArray().mapTo(EnumSet.noneOf(eClass)) { java.lang.Enum.valueOf(eClass, it) }
fun <E : Enum<E>> Bundle.putEnumSet(name: String, set: Set<E>) {
putStringArray(name, set.mapToArray { it.name })
}
inline fun <reified E : Enum<E>> Bundle.getEnumSet(name: String): Set<E> =
getEnumSet(name, E::class.java)
fun <E : Enum<E>> Bundle.getEnumSet(name: String, eClass: Class<E>): Set<E> =
getStringArray(name).mapTo(EnumSet.noneOf(eClass)) { java.lang.Enum.valueOf(eClass, it) }
fun <E : Enum<E>> Intent.putEnumSetExtra(name: String, set: Set<E>) {
putExtra(name, set.mapToArray { it.name })
}
inline fun <reified E : Enum<E>> Intent.getEnumSetExtra(name: String): Set<E> =
getEnumSetExtra(name, E::class.java)
fun <E : Enum<E>> Intent.getEnumSetExtra(name: String, eClass: Class<E>): Set<E> =
getStringArrayExtra(name).mapTo(EnumSet.noneOf(eClass)) { java.lang.Enum.valueOf(eClass, it) }
// internal
private inline fun <T, reified R> Collection<T>.mapToArray(transform: (T) -> R): Array<R> {
val itr = iterator()
val array = Array(size) { transform(itr.next()) }
check(!itr.hasNext())
return array
}
@ChristianIvicevic
Copy link

It's never a good idea to have function with too many arguments. SonarLint for example will complain. Furthermore there is a more idiomatic way with a single function to create the EnumMap as follows:

inline fun <reified K : Enum<K>, V> enumMapOf(vararg pairs: Pair<K, V>) = EnumMap<K, V>(K::class.java).also {
    it.putAll(pairs.toMap())
}

@Miha-x64
Copy link
Author

Miha-x64 commented Sep 7, 2019

It's never a good idea to allocate an Array of Pairs and also call toMap which allocates a LinkedHashMap (with another Array with Nodes inside) just to pass arguments in 'idiomatic' way or to make static analyzer shut up.
Escape analysis and scalarization may not work for such a complicated case with intermediate map, and no one should ever rely on such a subtle VM optimization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment