| package li.cil.oc.util |
| |
| import scala.annotation.tailrec |
| |
| /** |
| * https://gist.github.com/viktorklang/1057513 |
| */ |
| trait ScalaEnum { |
| import java.util.concurrent.atomic.AtomicReference //Concurrency paranoia |
| |
| type EnumVal <: Value //This is a type that needs to be found in the implementing class |
| |
| private val _values = new AtomicReference(Vector[EnumVal]()) //Stores our enum values |
| |
| //Adds an EnumVal to our storage, uses CCAS to make sure it's thread safe, returns the ordinal |
| @tailrec private final def addEnumVal(newVal: EnumVal): Int = { |
| import _values.{get, compareAndSet => CAS} |
| val oldVec = get |
| val newVec = oldVec :+ newVal |
| if ((get eq oldVec) && CAS(oldVec, newVec)) |
| newVec.indexWhere(_ eq newVal) |
| else |
| addEnumVal(newVal) |
| } |
| |
| def values: Vector[EnumVal] = _values.get //Here you can get all the enums that exist for this type |
| |
| //This is the trait that we need to extend our EnumVal type with, it does the book-keeping for us |
| protected trait Value { self: EnumVal => //Enforce that no one mixes in Value in a non-EnumVal type |
| final val ordinal = addEnumVal(this) //Adds the EnumVal and returns the ordinal |
| |
| def name: String //All enum values should have a name |
| |
| override def toString = name //And that name is used for the toString operation |
| |
| override def equals(other: Any) = this eq other.asInstanceOf[AnyRef] |
| |
| override def hashCode = 31 * (this.getClass.## + name.## + ordinal) |
| } |
| |
| } |