001 /*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005 package com.nativelibs4java.util;
006
007 import java.util.*;
008
009 /**
010 * Methods to ease conversion between EnumValue-annotated enums and their integer value.
011 * @author ochafik
012 */
013 public class EnumValues {
014
015 private static class Cache<E extends Enum<?>> {
016
017 final Map<Long, E> enumsByValue = new LinkedHashMap<Long, E>();
018 final Map<E, Long> valuesByEnum = new LinkedHashMap<E, Long>();
019
020 public Cache(Class<E> enumClass) {
021
022 if (ValuedEnum.class.isAssignableFrom(enumClass)) {
023 for (E e : enumClass.getEnumConstants()) {
024 long value = ((ValuedEnum)e).value();
025 enumsByValue.put(value, e);
026 valuesByEnum.put(e, value);
027 }
028 } else {
029 for (E e : enumClass.getEnumConstants()) {
030 EnumValue ev = null;
031 try {
032 ev = enumClass.getField(e.name()).getAnnotation(EnumValue.class);
033 } catch (Exception ex) {
034 throw new RuntimeException(ex);
035 }
036 if (ev == null) {
037 throw new IllegalArgumentException("Enum value is not annotated with the " + EnumValue.class.getName() + " annotation : " + e);
038 }
039 long value = ev.value();
040 enumsByValue.put(value, e);
041 valuesByEnum.put(e, value);
042 }
043 }
044 }
045 }
046 private static final Map<Class<? extends Enum<?>>, Cache<?>> caches = new HashMap<Class<? extends Enum<?>>, Cache<?>>();
047
048 @SuppressWarnings("unchecked")
049 private static synchronized <E extends Enum<?>> Cache<E> getCache(Class<E> enumClass) {
050 Cache<E> cache = (Cache<E>) caches.get(enumClass);
051 if (cache == null) {
052 caches.put(enumClass, cache = new Cache(enumClass));
053 }
054 return cache;
055 }
056
057 /**
058 * Get the first enum item in enum class E which EnumValue value is equal to value
059 * @param <E> type of the enum
060 * @param value
061 * @param enumClass
062 * @return first enum item with matching value, null if there is no matching enum item
063 */
064 public static <E extends Enum<E>> E getEnum(long value, Class<E> enumClass) {
065 return getCache(enumClass).enumsByValue.get(value);
066 }
067
068 /**
069 * Get the set of all the enum item in enum class E which EnumValue value flags are all present in value
070 * @param <E> type of the enum
071 * @param value
072 * @param enumClass
073 * @return enum items with matching value flags
074 */
075 public static <E extends Enum<E>> EnumSet<E> getEnumSet(long value, Class<E> enumClass) {
076 EnumSet<E> set = EnumSet.noneOf(enumClass);
077 for (Map.Entry<Long, E> pair : getCache(enumClass).enumsByValue.entrySet()) {
078 long ev = pair.getKey();
079 if ((ev & value) == ev) {
080 set.add(pair.getValue());
081 }
082 }
083 return set;
084 }
085
086 /**
087 * Get the integer value associated with an enum item
088 * @see EnumValue
089 * @param enumItem
090 * @return the numeric value of the enum
091 */
092 @SuppressWarnings("unchecked")
093 public static <E extends Enum<?>> long getValue(E enumItem) {
094 return getCache((Class<E>) enumItem.getDeclaringClass()).valuesByEnum.get(enumItem);
095 }
096
097 /**
098 * Get the integer value resulting from ORing all the values of all the enum items present in the enum set.
099 * @see EnumValues#getValue(java.lang.Enum)
100 * @see EnumValue
101 * @param set the EnumSet to process
102 * @return the OR of all the values of the enums in the set
103 */
104 public static <E extends Enum<E>> long getValue(EnumSet<E> set) {
105 long v = 0;
106 for (E e : set) {
107 v |= getValue(e);
108 }
109 return v;
110 }
111 }