Advertisement
DulcetAirman

EnumBitOperations

Dec 31st, 2013
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 13.15 KB | None | 0 0
  1. !!!!! There is now a project with much better code than this !!!!!
  2. http://claude-martin.ch/enumbitset/
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21. I made this because enums can not easily be stored to bit fields. Set and bitwise operations are equally difficult.
  22. I put this on pastebin because it's just one single interface. I will edit this paste if I change anything. Maybe I'll put in on a repository later.
  23. Note that I didn't really test this!
  24. You can use it for whatever you want. There is no copyright. But it would be nice if you would keep my name in the file.
  25. -----------------
  26. package ch.claude_martin.java8;
  27.  
  28. import java.math.BigInteger;
  29. import java.util.Arrays;
  30. import java.util.BitSet;
  31. import java.util.EnumSet;
  32. import java.util.Set;
  33.  
  34. /**
  35. * This adds support to use bit fields and bit masks for the enym type. The set
  36. * of enum values is interpreted as a bit set, which can be stored to a bit
  37. * field.
  38. *
  39. * <p>
  40. * Since this is an interface it does not change the state of the element it is
  41. * used on or any parameters. Instead it always returns a newly created object.
  42. * I.e. all methods that take a Set return a new Set. If you wish to alter the
  43. * set you can simply use the methods of that set.
  44. *
  45. * <p>
  46. * Bit fields are by default of type {@link BigInteger}, but {@link BitSet} and
  47. * {@link Long long} can be used as well. Bit masks should not be stored into a
  48. * database unless you can guarantee that no changes are made in the future. The
  49. * only change that would not break your code is to add new enums at the end of
  50. * the list of existing enums. Note that {@link EnumSet} and {@link BigInteger}
  51. * already has many methods to help using sets of enums and large integers.
  52. *
  53. * <p>
  54. * A bit field is always used to store a set of bits. Each bit can represent one
  55. * enum value. each enum has a distinct {@link #bitmask() bit mask}.
  56. *
  57. * <p>
  58. * Java 8 Beta has still a bug that does not allow assert statements in
  59. * interfaces: <a
  60. * href="https://bugs.openjdk.java.net/browse/JDK-8025141">https:/
  61. * /bugs.openjdk.java.net/browse/JDK-8025141</a>
  62. *
  63. * <p>
  64. * Nomenclature:
  65. * <dl>
  66. * <dt>enum type</dt>
  67. * <dd>Any type that is an enum. I.e. it uses "enum" insteaf of "class" in its
  68. * declaration. <br/>
  69. * Example: <code>Planet.class</code></dd>
  70. * <dt>enum</dt>
  71. * <dd>A field of an enumy type. This is one single value of any enum type.<br/>
  72. * Example: Planet.VENUS</dd>
  73. * </dl>
  74. * Example:
  75. *
  76. * <pre><blockquote>
  77. * public enum Planet {
  78. *   MERCURY, VENUS, EARTH, ...
  79. * }
  80. * </blockquote></pre>
  81. * <p>
  82. * The goal of this interface is to use only existing types. Since all primitive
  83. * types are limited this uses {@link BigInteger} instead.
  84. *
  85. * @author Claude Martin
  86. *
  87. * @param <E>
  88. *          The Enum-Type.
  89. */
  90. public interface EnumBitOperations<E extends Enum<E>> {
  91.     /**
  92.      * Returns whether this enum can be found in the list of enums of the same
  93.      * type.
  94.      *
  95.      * @returns <code>true</code>, if <code>this</code> can be found.
  96.      */
  97.     public default boolean elementOf(final Enum<?>... set) {
  98.         for (final Enum<?> e : set)
  99.             if (e == this)
  100.                 return true;
  101.         return false;
  102.     }
  103.  
  104.     /**
  105.      * Returns whether this enum can be found in the set of enums of the same
  106.      * type.
  107.      * <p>
  108.      * This is equivalent to: <code>
  109.      * set.contains(this);
  110.      * </code>
  111.      *
  112.      * @returns <code>true</code>, if <code>this</code> can be found.
  113.      */
  114.     public default boolean elementOf(final Set<Enum<?>> set) {
  115.         return set.contains(this);
  116.     }
  117.  
  118.     /**
  119.      * Creates a new EnumSet with <code>this</code> added.
  120.      *
  121.      * @returns A new {@link EnumSet} including all given elements and also
  122.      *          <code>this</code>.
  123.      */
  124.     @SuppressWarnings("unchecked")
  125.     public default EnumSet<E> addTo(final E... set) {
  126.         final EnumSet<E> result = EnumSet.copyOf(Arrays.asList(set));
  127.         result.add((E) this);
  128.         return result;
  129.     }
  130.  
  131.     /**
  132.      * Creates a new EnumSet with <code>this</code> added.
  133.      *
  134.      * @returns A new {@link EnumSet} including all elements of the set and also
  135.      *          <code>this</code>.
  136.      */
  137.     @SuppressWarnings("unchecked")
  138.     public default EnumSet<E> addedTo(final EnumSet<E> set) {
  139.         final EnumSet<E> result = EnumSet.copyOf(set);
  140.         result.add((E) this);
  141.         return result;
  142.     }
  143.  
  144.     /**
  145.      * Creates a new EnumSet with <code>this</code> removed.
  146.      *
  147.      * @returns A new {@link EnumSet} with all given enums, except
  148.      *          <code>this</code>. A copy of the set is returned if
  149.      *          <code>this</code> is not present.
  150.      */
  151.     @SuppressWarnings("unchecked")
  152.     public default EnumSet<E> removedFrom(final E... set) {
  153.         final EnumSet<E> result = EnumSet.copyOf(Arrays.asList(set));
  154.         result.remove(this);
  155.         return result;
  156.     }
  157.  
  158.     /**
  159.      * Creates a new EnumSet with <code>this</code> removed.
  160.      *
  161.      * @returns A new {@link EnumSet} with all elements of the set, except
  162.      *          <code>this</code>. A copy of the set is returned if
  163.      *          <code>this</code> is not present.
  164.      */
  165.     public default EnumSet<E> removedFrom(final EnumSet<E> set) {
  166.         final EnumSet<E> result = EnumSet.copyOf(set);
  167.         result.remove(this);
  168.         return result;
  169.     }
  170.  
  171.     /**
  172.      * Returns a set of all enums except <code>this</code>.
  173.      *
  174.      * <p>
  175.      * This is equivalent to: <code>EnumSet.complementOf(this.asSet())</code>
  176.      *
  177.      * @returns A new {@link EnumSet} with all elements except <code>this</code>.
  178.      */
  179.     @SuppressWarnings("unchecked")
  180.     public default EnumSet<E> others() {
  181.         final E e = (E) this;
  182.         final EnumSet<E> result = EnumSet.allOf(e.getClass());
  183.         result.remove(e);
  184.         return result;
  185.     }
  186.  
  187.     /**
  188.      * Returns a set containing nothing but <code>this</code>.
  189.      *
  190.      * @returns A new {@link EnumSet} containing <code>this</code>.
  191.      */
  192.     @SuppressWarnings("unchecked")
  193.     public default EnumSet<E> asEnumSet() {
  194.         final E e = (E) this;
  195.         final EnumSet<E> result = EnumSet.noneOf(e.getClass());
  196.         result.add(e);
  197.         return result;
  198.     }
  199.  
  200.     /**
  201.      * Returns a BitSet with all bits set to 0, except the bit representing
  202.      * <code>this</code>.
  203.      *
  204.      * @returns A new {@link EnumSet} containing <code>this</code>.
  205.      */
  206.     @SuppressWarnings("unchecked")
  207.     public default BitSet asBitSet() {
  208.         final E e = (E) this;
  209.         final BitSet result = new BitSet();
  210.         result.set(e.ordinal());
  211.         return result;
  212.     }
  213.  
  214.     /**
  215.      * Bitmask for <code>this</code>. The value is based on the ordinal.
  216.      *
  217.      * @return <code>1&lt;&lt;this.ordinal()</code>
  218.      * @deprecated This is actually the same as {@link #bitmask()}. This is here
  219.      *             so that programmers will find and use {@link #bitmask()}.
  220.      */
  221.     @Deprecated
  222.     public default BigInteger asBigInteger() {
  223.         return this.bitmask();
  224.     }
  225.  
  226.     /**
  227.      * 64 bit bitmask for <code>this</code>. The value is based on the ordinal.
  228.      *
  229.      * @return <code>1&lt;&lt;this.ordinal()</code>
  230.      */
  231.     @SuppressWarnings("unchecked")
  232.     public default long bitmask64() {
  233.         final E e = (E) this;
  234.         // assert EnumSet.allOf(e.getClass()).size() <= 64;
  235.         return 1 << e.ordinal();
  236.     }
  237.  
  238.     /**
  239.      * Bitmask for <code>this</code>. The value is based on the ordinal.
  240.      *
  241.      * @return <code>1&lt;&lt;this.ordinal()</code>
  242.      */
  243.     @SuppressWarnings("unchecked")
  244.     public default BigInteger bitmask() {
  245.         final E e = (E) this;
  246.         return BigInteger.ONE.shiftLeft(e.ordinal());
  247.     }
  248.  
  249.     /**
  250.      * Returns whether this value is set in the given bitmask.
  251.      *
  252.      * @param bitmask64
  253.      *          A bitmask.
  254.      * @return (this.bitmask64() & bitmask8) != 0;
  255.      */
  256.     public default boolean elementOf(final long bitmask64) {
  257.         return (this.bitmask64() & bitmask64) != 0;
  258.     }
  259.  
  260.     /**
  261.      * Returns whether this value is set in the given bitmask.
  262.      *
  263.      * @param bitmask
  264.      *          A bitmask.
  265.      * @return (this.bitmask() & bitmask) != 0
  266.      */
  267.     public default boolean elementOf(final BigInteger bitmask) {
  268.         return !this.bitmask().and(bitmask).equals(BigInteger.ZERO);
  269.     }
  270.  
  271.     /**
  272.      * Returns whether this value is set in the given bitset.
  273.      *
  274.      * @param bitset
  275.      * @return bitset.get(this.ordinal());
  276.      */
  277.     @SuppressWarnings("unchecked")
  278.     public default boolean elementOf(final BitSet bitset) {
  279.         return bitset.get(((E) this).ordinal());
  280.     }
  281.  
  282.     /** Creates a 64 bit bitmask of a given set of enums. */
  283.     public static <X extends Enum<X> & EnumBitOperations<X>> long toBitmask64(final EnumSet<X> set) {
  284.         long result = 0;
  285.         for (final X e : set)
  286.             result |= e.bitmask64();
  287.         return result;
  288.     }
  289.  
  290.     /** Creates a 64 bit bitmask of a given set of enums. */
  291.     @SafeVarargs
  292.     public static <X extends Enum<X> & EnumBitOperations<X>> long toBitmask64(final X... set) {
  293.         long result = 0;
  294.         for (final X e : set)
  295.             result |= e.bitmask64();
  296.         return result;
  297.     }
  298.  
  299.     /** Creates a bitmask of a given set of enums. */
  300.     public static <X extends Enum<X> & EnumBitOperations<X>> BigInteger toBitmask(final EnumSet<X> set) {
  301.         BigInteger result = BigInteger.ZERO;
  302.         for (final X e : set)
  303.             result = result.or(e.bitmask());
  304.         return result;
  305.     }
  306.  
  307.     /** Creates a bitmask of a given set of enums. */
  308.     @SafeVarargs
  309.     public static <X extends Enum<X> & EnumBitOperations<X>> BigInteger toBitmask(final X... set) {
  310.         BigInteger result = BigInteger.ZERO;
  311.         for (final X e : set)
  312.             result = result.or(e.bitmask());
  313.         return result;
  314.     }
  315.  
  316.     /**
  317.      * Creates a BitSet of a given set of enums.
  318.      * */
  319.     @SafeVarargs
  320.     public static <X extends Enum<X> & EnumBitOperations<X>> BitSet toBitSet(final X... set) {
  321.         final BitSet result = new BitSet();
  322.         for (final X e : set)
  323.             result.set(e.ordinal());
  324.         return result;
  325.     }
  326.  
  327.     /**
  328.      * Creates a BitSet of a given set of enums.
  329.      */
  330.     public static <X extends Enum<X> & EnumBitOperations<X>> BitSet toBitSet(final EnumSet<X> set) {
  331.         final BitSet result = new BitSet();
  332.         for (final X e : set)
  333.             result.set(e.ordinal());
  334.         return result;
  335.     }
  336.  
  337.     /** Creates a BitSet of a given mask. */
  338.     public static BitSet toBitSet(final BigInteger mask) {
  339.         return BitSet.valueOf(mask.toByteArray());
  340.     }
  341.  
  342.     /** Creates a BigInteger of a given mask. */
  343.     public static BigInteger toBigInteger(final BitSet bitset) {
  344.         return new BigInteger(bitset.toByteArray());
  345.     }
  346.  
  347.     /** Creates set of enums from a 64 bit bitset. */
  348.     public static <X extends Enum<X> & EnumBitOperations<X>> EnumSet<X> toEnumSet(final long mask, final Class<X> type) {
  349.         final EnumSet<X> result = EnumSet.noneOf(type);
  350.         for (final X e : EnumSet.allOf(type))
  351.             if ((e.bitmask64() & mask) != 0)
  352.                 result.add(e);
  353.         return result;
  354.     }
  355.  
  356.     /** Creates set of enums from a BitSet. */
  357.     public static <X extends Enum<X> & EnumBitOperations<X>> EnumSet<X> toEnumSet(final BitSet bitset, final Class<X> type) {
  358.         long mask = 0L;
  359.         for (int i = 0; i < bitset.length(); ++i)
  360.             mask += bitset.get(i) ? 1L << i : 0L;
  361.         return EnumBitOperations.toEnumSet(mask, type);
  362.     }
  363.  
  364.     /**
  365.      * Takes the bitmasks of <code>this</code> and all arguments, then applies
  366.      * logical OR to all. This results in a bitmask for all given enums (including
  367.      * <code>this</code>).
  368.      *
  369.      * @see #or(Enum...)
  370.      * @see EnumSet#of(Enum)
  371.      * @return <code>this.bitmask64() | arg0.bitmask64() | ... | argN.bitmask64()</code>
  372.      */
  373.     @SuppressWarnings("unchecked")
  374.     public default <X extends Enum<X> & EnumBitOperations<X>> long or64(final X... set) {
  375.         long result = this.bitmask64();
  376.         for (final X e : set)
  377.             result |= 1 << e.ordinal();
  378.         return result;
  379.     }
  380.  
  381.     /**
  382.      *
  383.      * Note that there is a much simpler way using {@link EnumSet#of(Enum)
  384.      * of(...)}. The following expressions define the same set: <br>
  385.      * <code>Planet.<b>EARTH</b>.or(Planet.<b>MARS</b>, Planet.<b>JUPITER</b>)<br/>
  386.      * Planet.of(Planet.<b>EARTH</b>, Planet.<b>MARS</b>, Planet.<b>JUPITER</b>)</code>
  387.      * <br/>
  388.      * However, this method returns a bitmask of type BigInteger.
  389.      *
  390.      * @see EnumSet#of(Enum)
  391.      * @see #or(BigInteger)
  392.      * @return <code>this.bitmask() | arg<sub>0</sub>.bitmask() | ... | arg<sub>N</sub>.bitmask()</code>
  393.      */
  394.     @SuppressWarnings("unchecked")
  395.     public default <X extends Enum<X> & EnumBitOperations<X>> BigInteger addedTo(final X... set) {
  396.         BigInteger result = this.bitmask();
  397.         for (final X e : set)
  398.             result = result.or(e.bitmask());
  399.         return result;
  400.     }
  401.  
  402.     /**
  403.      * Takes the bitmasks of <code>this</code> and <code>mask</code>, then applies
  404.      * logical OR. This results in a new bitmask that also includes
  405.      * <code>this</code>.
  406.      *
  407.      * @see #addedTo(BigInteger)
  408.      * @see #addedTo(EnumSet)
  409.      * @see #addedTo(Enum...)
  410.      * @return <code>mask.or(this.bitmask())</code>
  411.      */
  412.     public default <X extends Enum<X> & EnumBitOperations<X>> BigInteger or(final BigInteger mask) {
  413.         return mask.or(this.bitmask());
  414.     }
  415.  
  416.     /**
  417.      * @return <code>mask.and(this.bitmask())</code>
  418.      */
  419.     public default <X extends Enum<X> & EnumBitOperations<X>> BigInteger and(final BigInteger mask) {
  420.         return mask.and(this.bitmask());
  421.     }
  422.  
  423.     /**
  424.      * @return <code>mask.xor(this.bitmask())</code>
  425.      */
  426.     public default <X extends Enum<X> & EnumBitOperations<X>> BigInteger xor(final BigInteger mask) {
  427.         return mask.xor(this.bitmask());
  428.     }
  429.  
  430.     /**
  431.      * Removes this from mask, but only if its bit is set in the mask.
  432.      *
  433.      * @return <code>mask.andNot(this.bitmask())</code>
  434.      */
  435.     public default <X extends Enum<X> & EnumBitOperations<X>> BigInteger removedFrom(final BigInteger mask) {
  436.         return mask.andNot(this.bitmask());
  437.     }
  438.  
  439. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement