Sunday, May 4, 2014

store multiple boolean variables without additional memory usage

Java doesn't specify the storage usage of boolean variables, here, but most popular JVM store boolean as an integer. If you have a class with multiple boolean variables, the memory usage will be linear to the number of instances of the collection. For large collections, this can be significant.

We can also solve this problem by using a multiple flag enum, SixFlags, which doesn't require additional memory usage so definitely is a huge advantage in Big Data age.

How can we find the correspondent enum instance when one flag changed? we can use the resolve(int index, boolean flag) method. Even it is quick to encode the boolean flags into an integer and then look up the enum instance in a lookup map, this approach still requires some computing. The most efficient approach is to calculate all the correspondent enum instances by flipping one flag each time and store the flipped instances in an array variable. The SixFlags class implemented this approach,
    /**
     * @param index
     * @param flag
     * @return itself or the flipped instance which has the same value as the given value
     * on the given index.
     */
    public SixFlags resolve(int index, boolean flag) {
        return flag == flags[index] ? this : flippedFlags[index];
    }

    ...

    static class Helper {

        static void flipFlags() {
            lookup.keySet().forEach(key -> {
                int mask = 1;
                SixFlags original = lookup.get(key);
                for (int i = 0; i < original.flags.length; i++) {
                    int flippedKey = original.flags[i] ? key ^ mask : key | mask;
                    SixFlags flipped = lookup.get(flippedKey);
                    original.flippedFlags[i] = flipped;
                    flipped.flippedFlags[i] = original;
                    mask <<= 1;
                }
            });
            lookup.clear();
            lookup = null;
        }


        private static void flip(SixFlags original, int i, SixFlags flipped) {
            original.flippedFlags[i] = flipped;
            flipped.flippedFlags[i] = original;
        }

        ...

        static Map<Integer, SixFlags> lookup = new HashMap<>();
    }


The array doesn't require more storage space since the values are all enum constants. Please go over the test to find out how to use it. It can be used for store 1 to 6 boolean variables.
package algocraft.function;

import org.junit.Test;

import static algocraft.function.SixFlags.*;
import static org.junit.Assert.*;

public class SixFlagsTest {

    @Test
    public void testToString() throws Exception {
        assertEquals("[flag0,flag1,flag2,flag3,flag4,flag5]", YYYYYY.toString());
        assertEquals("[!flag0,!flag1,!flag2,!flag3,!flag4,!flag5]", SixFlags.______.toString());
    }

    @Test
    public void testSet() {
        assertEquals(YYYYYY, YY_YYY.resolve(2, true));
        assertEquals(YYYYYY, YYYYYY.resolve(2, true));
        assertEquals(YY_YYY, YY_YYY.resolve(2, false));
        assertEquals(YY_YYY, YYYYYY.resolve(2, false));
    }

    @Test
    public void testIs() {
        assertTrue(YYYYYY.valueAt(0));
        assertFalse(YY_YYY.valueAt(2));
    }


    @Test
    public void testApplicationUsing2Flags() {
        Person john = new Person();
        john.setMarried(false);
        john.setHasChildren(true);

        assertTrue(john.hasChildren());
        assertFalse(john.isMarried());
        assertEquals("[!Married,HasChilren]", john.toString());
    }

    @Test
    public void testApplicationUsing3Flags() {
        Product product = new Product();
        product.setImported(true);
        product.setPackaged(false);
        product.setTaxfree(true);

        assertTrue(product.isImported());
        assertFalse(product.isPackaged());
        assertTrue(product.isTaxfree());
        assertEquals("[Imported,!Packaged,Taxfree]", product.toString());
    }

    @Test
    public void testDisplay() {
        out.println(SixFlags.display());
    }

}



package algocraft.function;


import static algocraft.function.Product.FlagDef2.*;
import static algocraft.function.SixFlags.______;

class Product {

    static enum FlagDef2 {Imported, Packaged, Taxfree}

    private SixFlags flags = ______;

    public boolean isImported() {
        return flags.valueOf(Imported);
    }

    public boolean isPackaged() {
        return flags.valueOf(Packaged);
    }

    public boolean isTaxfree() {
        return flags.valueOf(Taxfree);
    }

    public void setImported(boolean flag) {
        flags = flags.resolve(Imported, flag);
    }

    public void setPackaged(boolean flag) {
        flags = flags.resolve(Packaged, flag);
    }

    public void setTaxfree(boolean flag) {
        flags = flags.resolve(Taxfree, flag);
    }

    @Override
    public String toString() {
        return flags.toString(FlagDef2.values());
    }

}


package algocraft.function;

import static algocraft.function.Person.FlagDef.HasChilren;
import static algocraft.function.Person.FlagDef.Married;
import static algocraft.function.SixFlags.______;

public class Person {

    static enum FlagDef {Married, HasChilren}

    private SixFlags flags = ______;

    public boolean isMarried() {
        return flags.valueOf(Married);
    }

    public boolean hasChildren() {
        return flags.valueOf(HasChilren);
    }

    public void setMarried(boolean flag) {
        flags = flags.resolve(Married, flag);
    }

    public void setHasChildren(boolean flag) {
        flags = flags.resolve(HasChilren, flag);
    }

    @Override
    public String toString() {
        return flags.toString(FlagDef.values());
    }
}


+------+-----------+-----------+-----------------------------------------------+
|                  |   flags   |                flippedFlags                   |
+------+-----------+-----------+-----------------------------------------------+
|flag  |key        |0|1|2|3|4|5|0      |1      |2      |3      |4      |5      |
+------+-----------+-----------+-----------------------------------------------+
|YYYYYY|0b111111=63|Y|Y|Y|Y|Y|Y|_YYYYY |Y_YYYY |YY_YYY |YYY_YY |YYYY_Y |YYYYY_ |
+------+-----------+-----------+-----------------------------------------------+

For example, enum instance YYYYYY, all its flags are true, and it will be encoded as 63 if true is 1 for each flag. When flipping the first flag, we can get the correspondent flippedFlag from the first element of the flippedFlag array which is _YYYYY, and second flipped flag is Y_YYYY, and so on.
package algocraft.function;

import java.util.HashMap;
import java.util.Map;

import static algocraft.function.SixFlags.Helper.*;
import static com.google.common.base.Joiner.on;
import static java.lang.Math.pow;

public enum SixFlags {

    YYYYYY,
    _YYYYY,
    Y_YYYY,
    __YYYY,
    YY_YYY,
    _Y_YYY,
    Y__YYY,
    ___YYY,
    YYY_YY,
    _YY_YY,
    Y_Y_YY,
    __Y_YY,
    YY__YY,
    _Y__YY,
    Y___YY,
    ____YY,
    YYYY_Y,
    _YYY_Y,
    Y_YY_Y,
    __YY_Y,
    YY_Y_Y,
    _Y_Y_Y,
    Y__Y_Y,
    ___Y_Y,
    YYY__Y,
    _YY__Y,
    Y_Y__Y,
    __Y__Y,
    YY___Y,
    _Y___Y,
    Y____Y,
    _____Y,
    YYYYY_,
    _YYYY_,
    Y_YYY_,
    __YYY_,
    YY_YY_,
    _Y_YY_,
    Y__YY_,
    ___YY_,
    YYY_Y_,
    _YY_Y_,
    Y_Y_Y_,
    __Y_Y_,
    YY__Y_,
    _Y__Y_,
    Y___Y_,
    ____Y_,
    YYYY__,
    _YYY__,
    Y_YY__,
    __YY__,
    YY_Y__,
    _Y_Y__,
    Y__Y__,
    ___Y__,
    YYY___,
    _YY___,
    Y_Y___,
    __Y___,
    YY____,
    _Y____,
    Y_____,
    ______;


    public static String display() {
        return concatenate(header(), header2(), line(), displayAll(), line(), header2(), header());
    }

    private final boolean[] flags = init(this);
    private final SixFlags[] flippedFlags = new SixFlags[flags.length];
    private final String description = concatenate("[", describe("flag", flags), "]");

    private SixFlags() {
        lookup.put(encodeAll(flags), this);
        if (lookup.size() == pow(2, flags.length)) {
            flipFlags();
        }
    }

    /**
     * @param description
     * @return the value of the boolean on the ordinal of the given description enum.
     */
    public boolean valueOf(Enum description) {
        return flags[description.ordinal()];
    }

    /**
     * @param index
     * @return the value of the boolean on the given index.
     */
    public boolean valueAt(int index) {
        return flags[index];
    }

    /**
     * @param description
     * @param flag
     * @return itself or the flipped instance which has the same value as the given value
     * on the ordinal of the given description enum.
     */
    public SixFlags resolve(Enum description, boolean flag) {
        int ordinal = description.ordinal();
        return flag == flags[ordinal] ? this : flippedFlags[ordinal];
    }

    /**
     * @param index
     * @param flag
     * @return itself or the flipped instance which has the same value as the given value
     * on the given index.
     */
    public SixFlags resolve(int index, boolean flag) {
        return flag == flags[index] ? this : flippedFlags[index];
    }

    /**
     * Build the following line according to its value,
     * |YYYYYY|0b111111=63|Y|Y|Y|Y|Y|Y|_YYYYY |Y_YYYY |YY_YYY |YYY_YY |YYYY_Y |YYYYY_ |
     *
     * @return
     */
    private String describeThis() {
        return concatenate("|", name(), "|0b", encodeAll(this), "=", key(this), value(this), flippedFlags(this), "\n");
    }

    /**
     * Description of this instance using default format.
     *
     * @return
     */
    @Override
    public String toString() {
        return description;
    }

    /**
     * Description this instance according to the give description enum instances.
     *
     * @param descriptions
     * @return
     */
    public String toString(Enum... descriptions) {
        return concatenate("[", describe(this.flags, descriptions), "]");
    }

    static class Helper {

        static void flipFlags() {
            for (int key : lookup.keySet()) {
                SixFlags original = lookup.get(key);
                for (int i = 0; i < original.flags.length; i++) {
                    int flippedKey = original.flags[i] ? key ^ 1 << i : key | 1 << i;
                    SixFlags flipped = lookup.get(flippedKey);
                    original.flippedFlags[i] = flipped;
                    flipped.flippedFlags[i] = original;
                }
            }
            lookup.clear();
            lookup = null;
        }

        static boolean[] init(SixFlags flag) {
            int length = flag.name().length();
            boolean[] flags = new boolean[length];
            for (int i = 0; i < length; i++) {
                flags[i] = flag.name().charAt(i) == 'Y';
            }
            return flags;
        }

        static int encodeAll(boolean... flags) {
            int code = 0;
            int mask = 1;
            for (boolean flag : flags) {
                if (flag) {
                    code |= mask;
                }
                mask <<= 1;
            }
            return code;
        }

        static CharSequence displayAll() {
            StringBuilder sb = new StringBuilder();
            for (SixFlags flag : SixFlags.values()) {
                sb.append(flag.describeThis());
            }
            return sb;
        }

        static CharSequence flippedFlags(SixFlags flag) {
            StringBuilder sb = new StringBuilder();
            for (SixFlags flippedFlag : flag.flippedFlags) {
                sb.append(flippedFlag.name() + " |");
            }
            return sb;
        }

        static CharSequence value(SixFlags flag) {
            StringBuilder sb = new StringBuilder();
            for (boolean value : flag.flags) {
                sb.append(value ? "Y|" : "_|");
            }
            return sb;
        }

        static CharSequence key(SixFlags flag) {
            int key = encodeAll(flag.flags);
            return concatenate((key < 10 ? " " : ""), key, "|");
        }

        static CharSequence encodeAll(SixFlags flag) {
            StringBuilder sb = new StringBuilder();
            for (int i = flag.flags.length - 1; i >= 0; i--) {
                sb.append(flag.flags[i] ? "1" : "0");
            }
            return sb;
        }

        static CharSequence line() {
            return "+------+-----------+-----------+-----------------------------------------------+\n";
        }

        static CharSequence header2() {
            return concatenate("|flag  |key        |", header("|"), header("      |"), "\n");
        }

        static CharSequence header(String filler) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < YYYYYY.flippedFlags.length; i++) {
                sb.append(i + filler);
            }
            return sb;
        }

        static CharSequence header() {
            return concatenate(line(), "|                  |   flags   |                flippedFlags                   |\n", line());
        }

        static CharSequence describe(boolean flags[], Enum... indexes) {
            StringBuilder sb = new StringBuilder();
            for (Enum index : indexes) {
                sb.append(concatenate(flags[index.ordinal()] ? "" : "!", index.name(), ","));
            }
            return removeLastChar(sb);
        }

        static CharSequence describe(String desc, boolean[] flags) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < flags.length; i++) {
                sb.append(concatenate(flags[i] ? "" : "!", desc + i, ","));
            }
            return removeLastChar(sb);
        }

        static String concatenate(Object... desc) {
            return on("").join(desc);
        }

        static CharSequence removeLastChar(StringBuilder sb) {
            return sb.deleteCharAt(sb.length() - 1).toString();
        }

        static Map<Integer, SixFlags> lookup = new HashMap<Integer, SixFlags>();

    }
}


This is what it prints,
+------+-----------+-----------+-----------------------------------------------+
|                  |   flags   |                flippedFlags                   |
+------+-----------+-----------+-----------------------------------------------+
|flag  |key        |0|1|2|3|4|5|0      |1      |2      |3      |4      |5      |
+------+-----------+-----------+-----------------------------------------------+
|YYYYYY|0b111111=63|Y|Y|Y|Y|Y|Y|_YYYYY |Y_YYYY |YY_YYY |YYY_YY |YYYY_Y |YYYYY_ |
|_YYYYY|0b111110=62|_|Y|Y|Y|Y|Y|YYYYYY |__YYYY |_Y_YYY |_YY_YY |_YYY_Y |_YYYY_ |
|Y_YYYY|0b111101=61|Y|_|Y|Y|Y|Y|__YYYY |YYYYYY |Y__YYY |Y_Y_YY |Y_YY_Y |Y_YYY_ |
|__YYYY|0b111100=60|_|_|Y|Y|Y|Y|Y_YYYY |_YYYYY |___YYY |__Y_YY |__YY_Y |__YYY_ |
|YY_YYY|0b111011=59|Y|Y|_|Y|Y|Y|_Y_YYY |Y__YYY |YYYYYY |YY__YY |YY_Y_Y |YY_YY_ |
|_Y_YYY|0b111010=58|_|Y|_|Y|Y|Y|YY_YYY |___YYY |_YYYYY |_Y__YY |_Y_Y_Y |_Y_YY_ |
|Y__YYY|0b111001=57|Y|_|_|Y|Y|Y|___YYY |YY_YYY |Y_YYYY |Y___YY |Y__Y_Y |Y__YY_ |
|___YYY|0b111000=56|_|_|_|Y|Y|Y|Y__YYY |_Y_YYY |__YYYY |____YY |___Y_Y |___YY_ |
|YYY_YY|0b110111=55|Y|Y|Y|_|Y|Y|_YY_YY |Y_Y_YY |YY__YY |YYYYYY |YYY__Y |YYY_Y_ |
|_YY_YY|0b110110=54|_|Y|Y|_|Y|Y|YYY_YY |__Y_YY |_Y__YY |_YYYYY |_YY__Y |_YY_Y_ |
|Y_Y_YY|0b110101=53|Y|_|Y|_|Y|Y|__Y_YY |YYY_YY |Y___YY |Y_YYYY |Y_Y__Y |Y_Y_Y_ |
|__Y_YY|0b110100=52|_|_|Y|_|Y|Y|Y_Y_YY |_YY_YY |____YY |__YYYY |__Y__Y |__Y_Y_ |
|YY__YY|0b110011=51|Y|Y|_|_|Y|Y|_Y__YY |Y___YY |YYY_YY |YY_YYY |YY___Y |YY__Y_ |
|_Y__YY|0b110010=50|_|Y|_|_|Y|Y|YY__YY |____YY |_YY_YY |_Y_YYY |_Y___Y |_Y__Y_ |
|Y___YY|0b110001=49|Y|_|_|_|Y|Y|____YY |YY__YY |Y_Y_YY |Y__YYY |Y____Y |Y___Y_ |
|____YY|0b110000=48|_|_|_|_|Y|Y|Y___YY |_Y__YY |__Y_YY |___YYY |_____Y |____Y_ |
|YYYY_Y|0b101111=47|Y|Y|Y|Y|_|Y|_YYY_Y |Y_YY_Y |YY_Y_Y |YYY__Y |YYYYYY |YYYY__ |
|_YYY_Y|0b101110=46|_|Y|Y|Y|_|Y|YYYY_Y |__YY_Y |_Y_Y_Y |_YY__Y |_YYYYY |_YYY__ |
|Y_YY_Y|0b101101=45|Y|_|Y|Y|_|Y|__YY_Y |YYYY_Y |Y__Y_Y |Y_Y__Y |Y_YYYY |Y_YY__ |
|__YY_Y|0b101100=44|_|_|Y|Y|_|Y|Y_YY_Y |_YYY_Y |___Y_Y |__Y__Y |__YYYY |__YY__ |
|YY_Y_Y|0b101011=43|Y|Y|_|Y|_|Y|_Y_Y_Y |Y__Y_Y |YYYY_Y |YY___Y |YY_YYY |YY_Y__ |
|_Y_Y_Y|0b101010=42|_|Y|_|Y|_|Y|YY_Y_Y |___Y_Y |_YYY_Y |_Y___Y |_Y_YYY |_Y_Y__ |
|Y__Y_Y|0b101001=41|Y|_|_|Y|_|Y|___Y_Y |YY_Y_Y |Y_YY_Y |Y____Y |Y__YYY |Y__Y__ |
|___Y_Y|0b101000=40|_|_|_|Y|_|Y|Y__Y_Y |_Y_Y_Y |__YY_Y |_____Y |___YYY |___Y__ |
|YYY__Y|0b100111=39|Y|Y|Y|_|_|Y|_YY__Y |Y_Y__Y |YY___Y |YYYY_Y |YYY_YY |YYY___ |
|_YY__Y|0b100110=38|_|Y|Y|_|_|Y|YYY__Y |__Y__Y |_Y___Y |_YYY_Y |_YY_YY |_YY___ |
|Y_Y__Y|0b100101=37|Y|_|Y|_|_|Y|__Y__Y |YYY__Y |Y____Y |Y_YY_Y |Y_Y_YY |Y_Y___ |
|__Y__Y|0b100100=36|_|_|Y|_|_|Y|Y_Y__Y |_YY__Y |_____Y |__YY_Y |__Y_YY |__Y___ |
|YY___Y|0b100011=35|Y|Y|_|_|_|Y|_Y___Y |Y____Y |YYY__Y |YY_Y_Y |YY__YY |YY____ |
|_Y___Y|0b100010=34|_|Y|_|_|_|Y|YY___Y |_____Y |_YY__Y |_Y_Y_Y |_Y__YY |_Y____ |
|Y____Y|0b100001=33|Y|_|_|_|_|Y|_____Y |YY___Y |Y_Y__Y |Y__Y_Y |Y___YY |Y_____ |
|_____Y|0b100000=32|_|_|_|_|_|Y|Y____Y |_Y___Y |__Y__Y |___Y_Y |____YY |______ |
|YYYYY_|0b011111=31|Y|Y|Y|Y|Y|_|_YYYY_ |Y_YYY_ |YY_YY_ |YYY_Y_ |YYYY__ |YYYYYY |
|_YYYY_|0b011110=30|_|Y|Y|Y|Y|_|YYYYY_ |__YYY_ |_Y_YY_ |_YY_Y_ |_YYY__ |_YYYYY |
|Y_YYY_|0b011101=29|Y|_|Y|Y|Y|_|__YYY_ |YYYYY_ |Y__YY_ |Y_Y_Y_ |Y_YY__ |Y_YYYY |
|__YYY_|0b011100=28|_|_|Y|Y|Y|_|Y_YYY_ |_YYYY_ |___YY_ |__Y_Y_ |__YY__ |__YYYY |
|YY_YY_|0b011011=27|Y|Y|_|Y|Y|_|_Y_YY_ |Y__YY_ |YYYYY_ |YY__Y_ |YY_Y__ |YY_YYY |
|_Y_YY_|0b011010=26|_|Y|_|Y|Y|_|YY_YY_ |___YY_ |_YYYY_ |_Y__Y_ |_Y_Y__ |_Y_YYY |
|Y__YY_|0b011001=25|Y|_|_|Y|Y|_|___YY_ |YY_YY_ |Y_YYY_ |Y___Y_ |Y__Y__ |Y__YYY |
|___YY_|0b011000=24|_|_|_|Y|Y|_|Y__YY_ |_Y_YY_ |__YYY_ |____Y_ |___Y__ |___YYY |
|YYY_Y_|0b010111=23|Y|Y|Y|_|Y|_|_YY_Y_ |Y_Y_Y_ |YY__Y_ |YYYYY_ |YYY___ |YYY_YY |
|_YY_Y_|0b010110=22|_|Y|Y|_|Y|_|YYY_Y_ |__Y_Y_ |_Y__Y_ |_YYYY_ |_YY___ |_YY_YY |
|Y_Y_Y_|0b010101=21|Y|_|Y|_|Y|_|__Y_Y_ |YYY_Y_ |Y___Y_ |Y_YYY_ |Y_Y___ |Y_Y_YY |
|__Y_Y_|0b010100=20|_|_|Y|_|Y|_|Y_Y_Y_ |_YY_Y_ |____Y_ |__YYY_ |__Y___ |__Y_YY |
|YY__Y_|0b010011=19|Y|Y|_|_|Y|_|_Y__Y_ |Y___Y_ |YYY_Y_ |YY_YY_ |YY____ |YY__YY |
|_Y__Y_|0b010010=18|_|Y|_|_|Y|_|YY__Y_ |____Y_ |_YY_Y_ |_Y_YY_ |_Y____ |_Y__YY |
|Y___Y_|0b010001=17|Y|_|_|_|Y|_|____Y_ |YY__Y_ |Y_Y_Y_ |Y__YY_ |Y_____ |Y___YY |
|____Y_|0b010000=16|_|_|_|_|Y|_|Y___Y_ |_Y__Y_ |__Y_Y_ |___YY_ |______ |____YY |
|YYYY__|0b001111=15|Y|Y|Y|Y|_|_|_YYY__ |Y_YY__ |YY_Y__ |YYY___ |YYYYY_ |YYYY_Y |
|_YYY__|0b001110=14|_|Y|Y|Y|_|_|YYYY__ |__YY__ |_Y_Y__ |_YY___ |_YYYY_ |_YYY_Y |
|Y_YY__|0b001101=13|Y|_|Y|Y|_|_|__YY__ |YYYY__ |Y__Y__ |Y_Y___ |Y_YYY_ |Y_YY_Y |
|__YY__|0b001100=12|_|_|Y|Y|_|_|Y_YY__ |_YYY__ |___Y__ |__Y___ |__YYY_ |__YY_Y |
|YY_Y__|0b001011=11|Y|Y|_|Y|_|_|_Y_Y__ |Y__Y__ |YYYY__ |YY____ |YY_YY_ |YY_Y_Y |
|_Y_Y__|0b001010=10|_|Y|_|Y|_|_|YY_Y__ |___Y__ |_YYY__ |_Y____ |_Y_YY_ |_Y_Y_Y |
|Y__Y__|0b001001= 9|Y|_|_|Y|_|_|___Y__ |YY_Y__ |Y_YY__ |Y_____ |Y__YY_ |Y__Y_Y |
|___Y__|0b001000= 8|_|_|_|Y|_|_|Y__Y__ |_Y_Y__ |__YY__ |______ |___YY_ |___Y_Y |
|YYY___|0b000111= 7|Y|Y|Y|_|_|_|_YY___ |Y_Y___ |YY____ |YYYY__ |YYY_Y_ |YYY__Y |
|_YY___|0b000110= 6|_|Y|Y|_|_|_|YYY___ |__Y___ |_Y____ |_YYY__ |_YY_Y_ |_YY__Y |
|Y_Y___|0b000101= 5|Y|_|Y|_|_|_|__Y___ |YYY___ |Y_____ |Y_YY__ |Y_Y_Y_ |Y_Y__Y |
|__Y___|0b000100= 4|_|_|Y|_|_|_|Y_Y___ |_YY___ |______ |__YY__ |__Y_Y_ |__Y__Y |
|YY____|0b000011= 3|Y|Y|_|_|_|_|_Y____ |Y_____ |YYY___ |YY_Y__ |YY__Y_ |YY___Y |
|_Y____|0b000010= 2|_|Y|_|_|_|_|YY____ |______ |_YY___ |_Y_Y__ |_Y__Y_ |_Y___Y |
|Y_____|0b000001= 1|Y|_|_|_|_|_|______ |YY____ |Y_Y___ |Y__Y__ |Y___Y_ |Y____Y |
|______|0b000000= 0|_|_|_|_|_|_|Y_____ |_Y____ |__Y___ |___Y__ |____Y_ |_____Y |
+------+-----------+-----------+-----------------------------------------------+
|flag  |key        |0|1|2|3|4|5|0      |1      |2      |3      |4      |5      |
+------+-----------+-----------+-----------------------------------------------+
|                  |   flags   |                flippedFlags                   |
+------+-----------+-----------+-----------------------------------------------+


Why do I call it SixFlags? :)

No comments:

Post a Comment