Calculating number bonds to value in Java - java

As part of my application, the database stores "badges" in a user's record in the database. I use the bitwise operator as (as far as I know) no two additions of them can have the same solution. Here are the values:
enum Badge {
SUPPORTER(1),
ALPHA(1 << 1),
BETA_OWNER(1 << 2),
BOOSTER(1 << 3),
ONE_MONTH(1 << 4),
THREE_MONTH(1 << 5),
SIX_MONTH(1 << 6),
ONE_YEAR(1 << 7),
TWO_YEAR(1 << 8),
;
public int value;
public int resolve() {
return value;
}
Badge(int i) {
value = i;
}
}
The method of storing them is as simple as adding up the values of each badge corresponding to the user. However, decoding this value is more tricky.
How would I go about decoding the value from the database into a list of badges that I can manipulate?

Use an EnumSet.The EnumSet can hold each item only once (it's a set). Have a look here for storing values in a database. There are solutions for decoding manually, or you can use Apache Commons for that.

Lets try something like this:
public enum BADGES {SUPPORTER, ALPHA, BETA_OWNER, BOOSTER, ONE_MONTH, THREE_MONTH, SIX_MONTH, ONE_YEAR, TWO_YEAR};
public HashMap<BADGES, Integer> badgesToIntegerMap = /* initialize map where integers are mapped to badges */
public HashMap<Integer, BADGES> integerToBadgesMap = /* initialize map where badges are mapped to their integers */
public List<BADGES> getUserBadges(int userStatus) {
List<BADGES> retVal = new ArrayList<BADGES>();
// Start from highest one, being TWO_YEAR at time of writing
int currentBadge = 1 << 8; //
while (currentBadge > 0) { // These two should be replaced by iterating the badgesToIntegerMap's values
if (userStatus && currentBadge == 1) {
retVal.add(integerToBadgesMap.get(currentBadge));
}
currentBadge = currentBadge >> 1;
}
return retVal;
}
Or you know, just pass these integers into a constructor of each individual badge, and you can avoid one lookup.

Related

2D matrix implementation

Each entity in my game has a Tag object, and there needs to be a way to Add and Remove collisions between Tag's.
This is my code:
public final class CollisionMatrix {
// TODO: Longs have at most 64 bits, so the current implementation fails
// when there are more than 64 tags.
private Map<Integer, Long> matrix = new HashMap<Integer, Long>();
public CollisionMatrix add(Tag tag1, Tag tag2) {
int id1 = tag1.id;
int id2 = tag2.id;
matrix.put(id1, matrix.getOrDefault(id1, 0L) | (1 << id2));
matrix.put(id2, matrix.getOrDefault(id2, 0L) | (1 << id1));
return this;
}
public CollisionMatrix remove(Tag tag1, Tag tag2) {
int id1 = tag1.id;
int id2 = tag2.id;
matrix.put(id1, matrix.getOrDefault(id1, 0L) & ~(1 << id2));
matrix.put(id2, matrix.getOrDefault(id2, 0L) & ~(1 << id1));
return this;
}
public boolean collidesWith(Tag tag1, Tag tag2) {
return 0 != (matrix.getOrDefault(tag1.id, 0L) & (1 << tag2.id));
}
}
This is a very ugly implementation of what I'm trying to achieve. But it working (If the number of tags are no more than 64).
I'm looking for a solution that needs to be efficient and not anti-pattern.
Tag could have a list of tags that indicate collision:
public void add(Tag tag1, Tag tag2) {
tag1.collisions.Add(tag2);
tag2.collisions.Add(tag1);
}
public void remove(Tag tag1, Tag tag2) {
if (collidesWith(tag1,tag2)) {
tag1.collisions.remove(tag2);
tag2.collisions.remove(tag1);
}
}
public boolean collidesWith(Tag tag1, Tag tag2) {
if (tag1.collisions.Contains(tag2) && tag2.collisions.Contains(tag1)) {
return true;
}
return false;
}
I wonder, is it just me or are bitwise operators very illegible? Actually I never used them and haven't really seen them either.
To the topic: What about a simple two-dimensional symmetrical array that stores booleans? array[x][y] represents whether or not x collides with y (those could be IDs of two objects assuming they are not random and start from 0).
Somehow I have a feeling that you're trying too hard to be smart there. I'd never come with an idea to represent an array of booleans as a long and I assume that's what you are trying to there.

Sorting 2 dimensional arrays in Java - skipping the first index

I have a two-dimensional array in Java that looks like this:
Each element/job has a:
Job number which is in index[0];
Job arrival time which is in index[1]; and
Job burst time in index[2]
jobs[0][0] = 1
jobs[0][1] = 0
jobs[0][2] = 5
jobs[1][0] = 2
jobs[1][1] = 2
jobs[1][2] = 19
jobs[2][0] = 3
jobs[2][1] = 4
jobs[2][2] = 10
First, I wanted to sort them according to arrival time which is according to index[1] which fortunately I did by using this code:
Arrays.sort(jobs, new Comparator<int[]>(){
public int compare(int[] a, int[] b) {
return a[1] - b[1];
}
});
Now, my problem is I want to sort it according to burst time which is according to index[2]. Here is the TWIST... How can I be able to sort it according to burst time (index[2]) skipping the first element?
I would like job[0] to remain on top of the array and sort the remaining elements by index[2] - burst time. Like this:
jobs[0][0] = 1
jobs[0][1] = 0
jobs[0][2] = 5
jobs[1][0] = 3
jobs[1][1] = 4
jobs[1][2] = 10
jobs[2][0] = 2
jobs[2][1] = 2
jobs[2][2] = 19
The jobs are being sorted by burst time with job1 remaining on top. Implementing it by the code I provided above would be much better. Thanks
First of all, you should use collections instead of arrays. And second, you should not use an array when you could use an object:
public class Job {
private int number;
private int arrival;
private int burst;
// constructor and getters omitted for brevity.
}
You could then have a List<Job>, instead of an int[][]. Just by looking at the typeof the structure, it's already clearer and more readable. Having named attributes, potentially of different types, and being able to add behavior with methods, is a part of what OO is all about. Much more readable, safe and maintainable than an int[].
The good news is that a List has much more features than an array. So you can for example, take a subList, and sort that subList:
List<Job> jobsExceptFirstOne = allJobs.subList(1);
Collections.sort(jobsExceptFirstOne, new Comparator<Job>() {
#Override
public int compare(Job left, Job right) {
return Integer.compare(left.getBurst(), right.getBurst());
}
});
VoilĂ . Problem solved.
A trivial way would be:
int firstBurst = jobs[0][2];
jobs[0][2] = Integer.MIN_VALUE;
Arrays.sort(jobs, new Comparator<int[]>(){
public int compare(int[] a, int[] b) {
// don't use subtraction, this can lead to underflows
return a[2] < b[2] ? -1 : (a[2] == b[2] ? 0 : 1);
}
});
jobs[0][2] = firstBurst;
Simply set the burst of the first item to Integer.MIN_VALUE (the integer equivalent of minus infinity). That way, it guaranteed that the first item is the smallest, so after sorting it will still be the first element. After sorting, reset the burst of the first item to its original value.
EDIT
By checking the documentation to verify that Arrays.sort is stable, I accidentally found the simplest version to solve this problem: use
Arrays.sort(T[] a,
int fromIndex,
int toIndex,
Comparator<? super T> c)
then you can do this directly:
Arrays.sort(jobs, 1, jobs.length, new Comparator<int[]>(){
public int compare(int[] a, int[] b) {
// don't use subtraction, this can lead to underflows
return a[2] < b[2] ? -1 : (a[2] == b[2] ? 0 : 1);
}
});
As stated by others, you should be using smarter collections instead of arrays, if you really want to use current code, you can use something like:
final int[][] jobs = new int[][]{{1,0,5},{2,2,19},{3,4,10}};
Arrays.sort(jobs, new Comparator<int[]>(){
public int compare(int[] a, int[] b) {
if(Arrays.equals(a, jobs[0]))
return -1;
else
return a[2] - b[2];
}
});
System.out.println(jobs[0][2]);
System.out.println(jobs[1][2]);
System.out.println(jobs[2][2]);
The only drawback is your array needs to be final.
Maybe there would be a way of using this:
final Integer job1 = Integer.valueOf(jobs[0][0]);
final Integer job2 = Integer.valueOf(jobs[0][1]);
return job1.compareTo(job2);
I dont really know if valueOf(jobs[0][0]) would be bigger then valueOf(jobs[0][1]), and I dont really know how they stand to one and another, but there must be a difference between them, and with that you should be a able to sort them according to if the returned number is bigger or smaller then the one of jobs[0][0], jobs[1][0], etc.
Use a Comparator taht remembers the job number of the first job, and regards that as the smallest prior to checking burst time.
public class MyComparator implements Comparator<int[]> {
private final int firstJob;
public MyComparator(int firstJob) {
this.firstJob = firstJob;
}
public int compare(int[] a, int[] b) {
if (a[0] == b[0]) {
return 0;
}
if (a[0] == firstJob) {
return -1;
}
if (b[0] == firstJob) {
return 1;
}
return Integer.compare(a[2], b[2]);
}
}

Java enum confusion with creating a bitmask and checking permissions

I want to port this c# permission module to java, but I am confused how I can do this when I can't save the numeric value in the database and then cast it to the enumeration representation.
In c#, I create a enum like this:
public enum ArticlePermission
{
CanRead = 1,
CanWrite = 2,
CanDelete = 4,
CanMove = 16
}
I then can create a permission set like:
ArticlePermission johnsArticlePermission = ArticlePermission.CanRead | ArticlePermission.CanMove;
I then save this into the database using:
(int)johnsArticlePermission
Now I can read it from the database as an integer/long, and cast it like:
johnsArticlePermission = (ArticlePermission) dr["articlePermissions"];
And I can check permissions like:
if(johnsArticlePermission & ArticlePermission.CanRead == ArticlePermission.CanRead)
{
}
How can I do this in java?
From what I understand, in java, you can convert the enumeration into a numeric value, and then convert it back to a java enumeration.
Ideas?
What you really need here is an EnumSet, described in the API like this:
Enum sets are represented internally as bit vectors. This
representation is extremely compact and efficient. The space and time
performance of this class should be good enough to allow its use as a
high-quality, typesafe alternative to traditional int-based "bit
flags."
An enum is a class under the hood so you can add methods to it. For example,
public enum ArticlePermission
{
CanRead(1),
CanWrite(2),
CanDelete(4),
CanMove(16); // what happened to 8?
private int _val;
ArticlePermission(int val)
{
_val = val;
}
public int getValue()
{
return _val;
}
public static List<ArticlePermission> parseArticlePermissions(int val)
{
List<ArticlePermission> apList = new ArrayList<ArticlePermission>();
for (ArticlePermission ap : values())
{
if (val & ap.getValue() != 0)
apList.add(ap);
}
return apList;
}
}
parseArticlePermissions will give you a List of ArticlePermission objects from an integer value, presumably created by ORing the value of ArticlePermission objects.
Here is a more detailed explanation of EnumSet.

Is there a Java data structure that is effectively an ArrayList with double indicies and built-in interpolation?

I am looking for a pre-built Java data structure with the following characteristics:
It should look something like an ArrayList but should allow indexing via double-precision rather than integers. Note that this means that it's likely that you'll see indicies that don't line up with the original data points (i.e., asking for the value that corresponds to key "1.5"). EDIT: For clarity, based on the comments, I'm not looking to change the ArrayList implementation. I'm looking for a similar interface and developer experience.
As a consequence, the value returned will likely be interpolated. For example, if the key is 1.5, the value returned could be the average of the value at key 1.0 and the value at key 2.0.
The keys will be sorted but the values are not ensured to be monotonically increasing. In fact, there's no assurance that the first derivative of the values will be continuous (making it a poor fit for certain types of splines).
Freely available code only, please.
For clarity, I know how to write such a thing. In fact, we already have an implementation of this and some related data structures in legacy code that I want to replace due to some performance and coding issues.
What I'm trying to avoid is spending a lot of time rolling my own solution when there might already be such a thing in the JDK, Apache Commons or another standard library. Frankly, that's exactly the approach that got this legacy code into the situation that it's in right now....
Is there such a thing out there in a freely available library?
Allowing double values as indices is a pretty large change from what ArrayList does.
The reason for this is that an array or list with double as indices would almost by definition be a sparse array, which means it has no value (or depending on your definition: a fixed, known value) for almost all possible indices and only a finite number of indices have an explicit value set.
There is no prebuilt class in Java SE that supports all that.
Personally I'd implement such a data structure as a skip-list (or similar fast-searching data structure) of (index, value) tuples with appropriate interpolation.
Edit: Actually there's a pretty good match for the back-end storage (i.e. everything except for the interpolation): Simply use a NavigableMap such as a TreeMap to store the mapping from index to value.
With that you can easily use ceilingEntry() and (if necessary) higherEntry() to get the closest value(s) to the index you need and then interpolate from those.
If your current implementation has complexity O(log N) for interpolating a value, the implementation I just made up may be for you:
package so2675929;
import java.util.Arrays;
public abstract class AbstractInterpolator {
private double[] keys;
private double[] values;
private int size;
public AbstractInterpolator(int initialCapacity) {
keys = new double[initialCapacity];
values = new double[initialCapacity];
}
public final void put(double key, double value) {
int index = indexOf(key);
if (index >= 0) {
values[index] = value;
} else {
if (size == keys.length) {
keys = Arrays.copyOf(keys, size + 32);
values = Arrays.copyOf(values, size + 32);
}
int insertionPoint = insertionPointFromIndex(index);
System.arraycopy(keys, insertionPoint, keys, insertionPoint + 1, size - insertionPoint);
System.arraycopy(values, insertionPoint, values, insertionPoint + 1, size - insertionPoint);
keys[insertionPoint] = key;
values[insertionPoint] = value;
size++;
}
}
public final boolean containsKey(double key) {
int index = indexOf(key);
return index >= 0;
}
protected final int indexOf(double key) {
return Arrays.binarySearch(keys, 0, size, key);
}
public final int size() {
return size;
}
protected void ensureValidIndex(int index) {
if (!(0 <= index && index < size))
throw new IndexOutOfBoundsException("index=" + index + ", size=" + size);
}
protected final double getKeyAt(int index) {
ensureValidIndex(index);
return keys[index];
}
protected final double getValueAt(int index) {
ensureValidIndex(index);
return values[index];
}
public abstract double get(double key);
protected static int insertionPointFromIndex(int index) {
return -(1 + index);
}
}
The concrete interpolators will only have to implement the get(double) function.
For example:
package so2675929;
public class LinearInterpolator extends AbstractInterpolator {
public LinearInterpolator(int initialCapacity) {
super(initialCapacity);
}
#Override
public double get(double key) {
final double minKey = getKeyAt(0);
final double maxKey = getKeyAt(size() - 1);
if (!(minKey <= key && key <= maxKey))
throw new IndexOutOfBoundsException("key=" + key + ", min=" + minKey + ", max=" + maxKey);
int index = indexOf(key);
if (index >= 0)
return getValueAt(index);
index = insertionPointFromIndex(index);
double lowerKey = getKeyAt(index - 1);
double lowerValue = getValueAt(index - 1);
double higherKey = getKeyAt(index);
double higherValue = getValueAt(index);
double rate = (higherValue - lowerValue) / (higherKey - lowerKey);
return lowerValue + (key - lowerKey) * rate;
}
}
And, finally, a unit test:
package so2675929;
import static org.junit.Assert.*;
import org.junit.Test;
public class LinearInterpolatorTest {
#Test
public void simple() {
LinearInterpolator interp = new LinearInterpolator(2);
interp.put(0.0, 0.0);
interp.put(1.0, 1.0);
assertEquals(0.0, interp.getValueAt(0), 0.0);
assertEquals(1.0, interp.getValueAt(1), 0.0);
assertEquals(0.0, interp.get(0.0), 0.0);
assertEquals(0.1, interp.get(0.1), 0.0);
assertEquals(0.5, interp.get(0.5), 0.0);
assertEquals(0.9, interp.get(0.9), 0.0);
assertEquals(1.0, interp.get(1.0), 0.0);
interp.put(0.5, 0.0);
assertEquals(0.0, interp.getValueAt(0), 0.0);
assertEquals(0.0, interp.getValueAt(1), 0.0);
assertEquals(1.0, interp.getValueAt(2), 0.0);
assertEquals(0.0, interp.get(0.0), 0.0);
assertEquals(0.0, interp.get(0.1), 0.0);
assertEquals(0.0, interp.get(0.5), 0.0);
assertEquals(0.75, interp.get(0.875), 0.0);
assertEquals(1.0, interp.get(1.0), 0.0);
}
#Test
public void largeKeys() {
LinearInterpolator interp = new LinearInterpolator(10);
interp.put(100.0, 30.0);
interp.put(200.0, 40.0);
assertEquals(30.0, interp.get(100.0), 0.0);
assertEquals(35.0, interp.get(150.0), 0.0);
assertEquals(40.0, interp.get(200.0), 0.0);
try {
interp.get(99.0);
fail();
} catch (IndexOutOfBoundsException e) {
assertEquals("key=99.0, min=100.0, max=200.0", e.getMessage());
}
try {
interp.get(201.0);
fail();
} catch (IndexOutOfBoundsException e) {
assertEquals("key=201.0, min=100.0, max=200.0", e.getMessage());
}
}
private static final int N = 10 * 1000 * 1000;
private double measure(int size) {
LinearInterpolator interp = new LinearInterpolator(size);
for (int i = 0; i < size; i++)
interp.put(i, i);
double max = interp.size() - 1;
double sum = 0.0;
for (int i = 0; i < N; i++)
sum += interp.get(max * i / N);
return sum;
}
#Test
public void speed10() {
assertTrue(measure(10) > 0.0);
}
#Test
public void speed10000() {
assertTrue(measure(10000) > 0.0);
}
#Test
public void speed1000000() {
assertTrue(measure(1000000) > 0.0);
}
}
So the functionality seems to work. I only measured speed in some simple cases, and these suggest that scaling will be better than linear.
Update (2010-10-17T23:45+0200): I made some stupid mistakes in checking the key argument in the LinearInterpolator, and my unit tests didn't catch them. Now I extended the tests and fixed the code accordingly.
In the Apache commons-math library, if you implement the UnivariateRealInterpolator and the return value of its interpolate method which is typed UnivariateRealFunction you'll be most of the way there.
The interpolator interface takes two arrays, x[] and y[]. The returned function has a method, value() that takes an x' and returns the interpolated y'.
Where it fails to provide an ArrayList-like experience is in the ability to add more values to the range and domain as if the List is growing.
Additionally, they look to be in need of some additional interpolation functions. There are only 4 implementations in the library for the stable release. As a commenter pointed out, it seems to be missing 'linear' or something even simpler like nearest neighbor. Maybe that's not really interpolation...
That's a huge change from ArrayList.
Same as Joachim's response above, but I'd probably implement this as a binary tree, and when I didn't find something I was looking for, average the value of the next smallest and largest values, which should be quick to traverse to.
Your description that it should be "like an ArrayList" is misleading, since what you've described is a one dimensional interpolator and has essentially nothing in common with an ArrayList. This is why you're getting suggestions for other data structures which IMO are sending you down the wrong path.
I don't know of any available in Java (and couldn't easily find one one google), but I think you should have a look at GSL - GNU Scientific Library which includes a spline interpolator. It may be a bit heavy for what you're looking for since it's a two dimensional interpolator, but it seems like you should be looking for something like this rather than something like an ArrayList.
If you'd like it to "look like an ArrayList" you can always wrap it in a Java class which has access methods similar to the List interface. You won't be able to actually implement the interface though, since the methods are declared to take integer indices.

Storing EnumSet in a database?

So in C++/C# you can create flags enums to hold multiple values, and storing a single meaningful integer in the database is, of course, trivial.
In Java you have EnumSets, which appear to be quite a nice way to pass enums around in memory, but how do you output the combined EnumSet to an integer for storage? Is there another way to approach this?
Storing the ordinal as a representation of the EnumSet is not a good idea. The ordinal numbers depend on the order of the definition in the Enum class (a related discussion is here). Your database may be easily broken by a refactoring that changes the order of Enum values or introduces new ones in the middle.
You have to introduce a stable representation of individual enum values. These can be int values again and represented in the proposed way for the EnumSet.
Your Enums can implement interfaces so the stable represenation can be directly in the enum value (adapted from Adamski):
interface Stable{
int getStableId();
}
public enum X implements Stable {
A(1), B(2);
private int stableId;
X(int id){
this.stableId = id;
}
#Override public int getStableId() {
return stableId;
}
}
adapted from Adamski's code:
public <E extends Stable> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
ret |= (1 << val.getStableId());
}
return ret;
}
Providing your enum fits into an int (i.e. there are <= 32 values) I would roll my own implementation by using each enum's ordinal value; e.g.
public <E extends Enum<E>> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
// Bitwise-OR each ordinal value together to encode as single int.
ret |= (1 << val.ordinal());
}
return ret;
}
public <E extends Enum<E>> EnumSet<E> decode(int encoded, Class<E> enumKlazz) {
// First populate a look-up map of ordinal to Enum value.
// This is fairly disgusting: Anyone know of a better approach?
Map<Integer, E> ordinalMap = new HashMap<Integer, E>();
for (E val : EnumSet.allOf(enumKlazz)) {
ordinalMap.put(val.ordinal(), val);
}
EnumSet<E> ret= EnumSet.noneOf(enumKlazz);
int ordinal = 0;
// Now loop over encoded value by analysing each bit independently.
// If the bit is set, determine which ordinal that corresponds to
// (by also maintaining an ordinal counter) and use this to retrieve
// the correct value from the look-up map.
for (int i=1; i!=0; i <<= 1) {
if ((i & encoded) != 0) {
ret.add(ordinalMap.get(ordinal));
}
++ordinal;
}
return ret;
}
Disclaimer: I haven't tested this!
EDIT
As Thomas mentions in the comments the ordinal numbers are unstable in that any change to your enum definition within your code will render the encodings in your database corrupt (e.g. if you insert a new enum value in the middle of your existing definition). My approach to solving this problem is to define an "Enum" table per enumeration, containing a numerical ID (not the ordinal) and the String enum value. When my Java application starts, the first thing the DAO layer does is to read each Enum table into memory and:
Verify that all String enum values in the database match the Java definition.
Initialise a Bi-directional map of ID to enum and vice-versa, which I then use whenever I persist an enum (In other words, all "data" tables reference the database-specific Enum ID, rather than store the String value explicitly).
This is much cleaner / more robust IMHO than the ordinal approach I describe above.
It struck me as a surprise that nobody was suggesting a well-maintained library instead of writing your own. The above answer is spot on and educational but it just encourages people to copy and paste code around (then mostly forget the credits).
Here's my 2 cents:
EnumSet<YourEnum> mySet = EnumSet.of(YourEnum.FIRST);
long vector = EnumUtils.generateBitVector(YourEnum.class, mySet);
EnumSet<YourEnum> sameSet = EnumUtils.processBitVector(YourEnum.class, vector);
See https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/EnumUtils.html
// From Adamski's answer
public static <E extends Enum<E>> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
ret |= 1 << val.ordinal();
}
return ret;
}
#SuppressWarnings("unchecked")
private static <E extends Enum<E>> EnumSet<E> decode(int code,
Class<E> enumType) {
try {
E[] values = (E[]) enumType.getMethod("values").invoke(null);
EnumSet<E> result = EnumSet.noneOf(enumType);
while (code != 0) {
int ordinal = Integer.numberOfTrailingZeros(code);
code ^= Integer.lowestOneBit(code);
result.add(values[ordinal]);
}
return result;
} catch (IllegalAccessException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
// Probably a NullPointerException, caused by calling this method
// from within E's initializer.
throw (RuntimeException) ex.getCause();
} catch (NoSuchMethodException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
}
}
If you look in the source for RegularEnumSet, which is the implementation for Enum's <= 64 members, you will see that it contains:
/**
* Bit vector representation of this set. The 2^k bit indicates the
* presence of universe[k] in this set.
*/
private long elements = 0L;
elements is a bit-mask where the bit positions equal the enum ordinals, which is exactly what you need. However this attribute is not made availlable through a getter or setter as that would not match the equivalent accessors for the JumboEnumSet.
It is not one of the nicest solutions, but if simplicity and speed is what you are after, you could create 2 static utility methods that retrieve and set the elements attribute using reflection.
For me, I would probably just setup a constants class holding the enum values as integer constants where I can be sure which enum gets assigned what bit.
EnumSet implements Serializable, but there's a lot of overhead if you use that (it is written as an array of IDs, not a BitSet as you might expect, plus the object stream header.)
This is an old post that I found helpful, but with Java 8 or newer I've adapted the solution posted by #finnw into this interface:
public interface BitMaskable {
int getBitMaskOrdinal();
static int bitMaskValue(Set<? extends BitMaskable> set) {
int mask = 0;
for (BitMaskable val : set) {
mask |= (1 << val.getBitMaskOrdinal());
}
return mask;
}
static <E extends Enum<E> & BitMaskable> Set<E> valueOfBitMask(int mask, Class<E> enumType) {
E[] values = enumType.getEnumConstants();
EnumSet<E> result = EnumSet.noneOf(enumType);
Map<Integer, E> ordinalCache = null;
while (mask != 0) {
int ordinal = Integer.numberOfTrailingZeros(mask);
mask ^= Integer.lowestOneBit(mask);
E value = null;
if (ordinalCache != null) {
value = ordinalCache.get(ordinal);
}
if (value == null) {
for (E e : values) {
if (e.getBitMaskOrdinal() == ordinal) {
value = e;
break;
}
// if there are more values to decode and e has a higher
// ordinal than what we've seen, cache that for later
if (mask != 0 && e.getBitMaskOrdinal() > ordinal) {
if (ordinalCache == null) {
ordinalCache = new HashMap<>(values.length);
}
ordinalCache.put(e.getBitMaskOrdinal(), e);
}
}
}
if (value != null) {
result.add(value);
}
}
return result;
}
}
Usage for an enum like this (note the bmOrdinal values are out-of-order from the built-in enum ordinal values):
public enum BitMaskEnum implements BitMaskable {
A(0),
B(2),
C(1),
D(3);
private int bmOrdinal;
private BitMaskEnum(int bmOrdinal) {
this.bmOrdinal = bmOrdinal;
}
#Override
public int getBitMaskOrdinal() {
return bmOrdinal;
}
}
is then along these lines:
// encode as bit mask; result == 5
int result = BitMaskable.bitMaskValue(EnumSet.of(BitMaskEnum.A, BitMaskEnum.B));
// decode into set; result contains A & B
Set<BitMaskEnum> result = BitMaskable.valueOfBitMask(5, BitMaskEnum.class);
With the methods given in the answers it is possible to convert a integer to an EnumSet and vice versa. But I found that this is often error prone. Especially when you get negative values as java only has signed int and long. So if you plan to do such conversions on all sets of enums you might want to use a data structure that already supports this. I have created such a data structure, that can be used just like a BitSet or an EnumSet, but it also has methods such as toLong() and toBitSet(). Note that this requires Java 8 or newer.
Here's the link: http://claude-martin.ch/enumbitset/
Without going into the debate about pros and cons of ordinal values in the database - I posted a possible answer to the given question here:
JPA map collection of Enums
The idea is to create a new PersistentEnumSet which uses the implementation of java.util.RegularEnumSet, but offers the elements bitmask to JPA.
That one can than be used in an embeddable:
#Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
public InterestsSet() {
super(InterestsEnum.class);
}
}
And that set is used in the entity:
#Entity
public class MyEntity {
// ...
#Embedded
private InterestsSet interests = new InterestsSet();
}
For further comments see my answer over there.
I have done some changes on finnw's code, so it works with enumerations having up to 64 items.
// From Adamski's answer
public static <E extends Enum<E>> long encode(EnumSet<E> set) {
long ret = 0;
for (E val : set) {
ret |= 1L << val.ordinal();
}
return ret;
}
#SuppressWarnings("unchecked")
public static <E extends Enum<E>> EnumSet<E> decode(long code,
Class<E> enumType) {
try {
E[] values = (E[]) enumType.getMethod("values").invoke(null);
EnumSet<E> result = EnumSet.noneOf(enumType);
while (code != 0) {
int ordinal = Long.numberOfTrailingZeros(code);
code ^= Long.lowestOneBit(code);
result.add(values[ordinal]);
}
return result;
} catch (IllegalAccessException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
// Probably a NullPointerException, caused by calling this method
// from within E's initializer.
throw (RuntimeException) ex.getCause();
} catch (NoSuchMethodException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
}
}

Categories