Adding Nelson Carpentier's patch adding an EnumSet to bit vector (and back again) to EnumUtils. LANG-730

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1149058 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Henri Yandell 2011-07-21 08:00:28 +00:00
parent 0154a74354
commit 4574329913
3 changed files with 129 additions and 0 deletions

View File

@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.EnumSet;
/**
* <p>Utility library to provide helper methods for Java enums.</p>
@ -114,4 +115,66 @@ public class EnumUtils {
}
}
/**
* <p>Creates a long bit vector representation of the given subset of an Enum.</p>
*
* <p>This generates a value that is usable by {@link EnumUtils#processBitVector}.</p>
*
* <p>Do not use this method if you have more than 64 values in your Enum, as this
* would create a value greater than a long can hold.</p>
*
* @param enumClass the class of the enum we are working with, not null
* @param set the set of enum values we want to convert
* @param <E> the type of the enumeration
* @return a long whose binary value represents the given set of enum values.
*/
public static <E extends Enum<E>> long generateBitVector(Class<E> enumClass, EnumSet<E> set) {
if (enumClass == null) {
throw new IllegalArgumentException("EnumClass must be defined.");
}
final E[] constants = enumClass.getEnumConstants();
if (constants != null && constants.length > 64) {
throw new IllegalArgumentException("EnumClass is too big to be stored in a 64-bit value.");
}
long total = 0;
if (set != null) {
if (constants != null && constants.length > 0) {
for (E constant : constants) {
if (set.contains(constant)) {
total += Math.pow(2, constant.ordinal());
}
}
}
}
return total;
}
/**
* <p>Convert a long value created by {@link EnumUtils#generateBitVector} into the set of
* enum values that it represents.</p>
*
* <p>If you store this value, beware any changes to the enum that would affect ordinal values.</p>
* @param enumClass the class of the enum we are working with, not null
* @param value the long value representation of a set of enum values
* @param <E> the type of the enumeration
* @return a set of enum values
*/
public static <E extends Enum<E>> EnumSet<E> processBitVector(Class<E> enumClass, long value) {
if (enumClass == null) {
throw new IllegalArgumentException("EnumClass must be defined.");
}
final E[] constants = enumClass.getEnumConstants();
if (constants != null && constants.length > 64) {
throw new IllegalArgumentException("EnumClass is too big to be stored in a 64-bit value.");
}
final EnumSet results = EnumSet.noneOf(enumClass);
if (constants != null && constants.length > 0) {
for (E constant : constants) {
if ((value & (1 << constant.ordinal())) != 0) {
results.add(constant);
}
}
}
return results;
}
}

View File

@ -21,6 +21,10 @@
</properties>
<body>
<release version="3.0.1" date="Unreleased" description="Next 3.x release">
<action type="add" issue="LANG-730">EnumSet -> bit vector</action>
</release>
<release version="3.0" date="2011-07-18" description="Backwards incompatible update of Commons Lang to Java 5">
<action type="fix" issue="LANG-720">StringEscapeUtils.escapeXml(input) outputs wrong results when an input contains characters in Supplementary Planes.</action>
<action type="update" issue="LANG-718">build.xml Java 1.5+ updates.</action>

View File

@ -18,6 +18,7 @@
*/
package org.apache.commons.lang3;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
@ -89,8 +90,69 @@ public class EnumUtilsTest extends TestCase {
}
}
public void test_generateBitVector_nullClass() {
try {
EnumUtils.generateBitVector(null, EnumSet.of(Traffic.RED));
} catch (IllegalArgumentException ex) {
// ok
}
}
public void test_generateBitVector_longClass() {
try {
EnumUtils.generateBitVector(TooMany.class, EnumSet.of(TooMany.A1));
} catch (IllegalArgumentException ex) {
// ok
}
}
public void test_generateBitVector() {
assertEquals(0L, EnumUtils.generateBitVector(Traffic.class, null));
assertEquals(0L, EnumUtils.generateBitVector(Traffic.class, EnumSet.noneOf(Traffic.class)));
assertEquals(1L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED)));
assertEquals(2L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.AMBER)));
assertEquals(4L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.GREEN)));
assertEquals(3L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED, Traffic.AMBER)));
assertEquals(5L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED, Traffic.GREEN)));
assertEquals(6L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.AMBER, Traffic.GREEN)));
assertEquals(7L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED, Traffic.AMBER, Traffic.GREEN)));
}
public void test_processBitVector_nullClass() {
final Class<Traffic> empty = null;
try {
EnumUtils.processBitVector(empty, 0L);
} catch (IllegalArgumentException ex) {
// ok
}
}
public void test_processBitVector_longClass() {
try {
EnumUtils.processBitVector(TooMany.class, 0L);
} catch (IllegalArgumentException ex) {
// ok
}
}
public void test_processBitVector() {
assertEquals(EnumSet.noneOf(Traffic.class), EnumUtils.processBitVector(Traffic.class, 0L));
assertEquals(EnumSet.of(Traffic.RED), EnumUtils.processBitVector(Traffic.class, 1L));
assertEquals(EnumSet.of(Traffic.AMBER), EnumUtils.processBitVector(Traffic.class, 2L));
assertEquals(EnumSet.of(Traffic.RED, Traffic.AMBER), EnumUtils.processBitVector(Traffic.class, 3L));
assertEquals(EnumSet.of(Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 4L));
assertEquals(EnumSet.of(Traffic.RED, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 5L));
assertEquals(EnumSet.of(Traffic.AMBER, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 6L));
assertEquals(EnumSet.of(Traffic.RED, Traffic.AMBER, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 7L));
}
}
enum Traffic {
RED, AMBER, GREEN
}
enum TooMany{
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1;
}