订阅所有JSP/Servlet的日志 订阅 | 这是最新一篇日志 上一篇 | 下一篇日志 下一篇 ]
JAVA技术

Bitwise Operators and Bit Masks

Bitwise Operators and Bit Masks






Bitwise Operators





  • Although the examples here use 8-bit integers, Java integers are 32 bits. The highest bit is reserved for plus or minus sign. So you can set/unset 31 one-bit flags and a whole bunch of combination masks derived from the one-bit flag masks.

  • It is not recommended to use bitwise operations in routine application programming because the resulting code is not very easy to understand. The flow of logic is not obvious. Save bitwise operations for systems programming or where memory savings may be desired such as in a JavaCards.

  • One hexadecimal digit represents four binary digits. Some math:

    Binary Math

     
    0 + 0 = 0
    0 + 1 = 1
    1 + 1 = 10


    Binary to Decimal Conversion

     
    00010011 = 0*2**7 + 0*2**6 + 0*2**5 + 1*2**4 +
    0*2**3 + 0*2**2 + 1*2**1 + 1*2**0
    = 0 + 0 + 0 + 16 + 0 + 0 + 2 + 1
    = 19



    Hexadecimal to Decimal Conversion

     
    3F = 3*16**1 + 15*16**0
    = 63 (01111111 in binary)







































    Logical Bitwise Operations
    bit 1 bit 2 OR (|) AND (&) XOR (^)
    0 0 0 0 0
    1 0 1 0 1
    0 1 1 0 1
    1 1 1 1 0













  • | (Bitwise OR) sets a bit to 1 if one or both of the corresponding bits in its operands are 1, and to 0 if both of the corresponding bits are 0. In other words, | returns one in all cases except where the corresponding bits of both operands are zero. The resulting bit pattern is the "set" (1 or true) bits of any of the two operands. This property is used to "set" or "turn on" a "flag" (bit set to one) in your flags or options variable regardless of whether that flag was set previously or not. Multiple flag bits can be set if a combo MASK is defined.
     
    // To set or turn on a flag bit(s)
    flags = flags | MASK;
    // or, more succintly
    flags |= MASK;


  • & (Bitwise AND) sets a bit to 1 if and only if both of the corresponding bits in its operands are 1, and to 0 if the bits differ or both are 0. In other words, a one ANDed with any bit is that bit and a zero ANDed with any bit is zero. This operator is used to check the state of a flag in your flags variable. When you AND your flags variable with the MASK, all zeroes in the MASK will return zero for the corresponding position in flags and all ones in the MASK will return whatever the corresponding bit is set to in your flags variable. Therefore, the bitwise AND operator's evaluates to the MASK itself only if the MASK flags are also set in the flags variable.
     
    // To check the state of a flag bit(s)
    if (flags & MASK) == MASK)
    {
    // flag is set or turned on
    ...
    }
    else {
    //flag is not set or is turned off
    ...
    }



<script type="text/javascript"><!--
google_ad_client = "pub-4447351096301747";
google_ad_width = 300;
google_ad_height = 250;
google_ad_format = "300x250_as";
google_color_border = "DDB7BA";
google_color_bg = "FFF5F6";
google_color_link = "0000CC";
google_color_url = "008000";
google_color_text = "6F6F6F";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>








  • ^ (Bitwise XOR or exclusive OR) sets the bit to 1 where the corresponding bits in its operands are different, and to 0 if they are the same. Even 1 ^ 1 evaluates to 0 unlike the regular Bitwise OR. A bit pattern XORed with itself returns zero (because same bit values return zero). The Bitwise XOR is used to toggle the flag bits of a MASK in your flags variable. It means that, if a flag bit was set in flags, XORing with its MASK will unset it. If it was not set, XORing will set it. This is different from turning a flag bit on or off, regardless of its prior state (which is accomplished using | and & ~).
     
    // To toggle a flag bit(s) (on if it was off, off if it was on)
    flags = flags ^ MASK;
    // or, more succintly
    flags ^= MASK;





  • ~ (Bitwise NOT) takes only one parameter and inverts each bit in the operand, changing all the ones to zeros and zeros to ones. This is useful when "unsetting" or "turning off" a flag.
     
    // To unset or turn off a flag bit(s)
    flags = flags & ~MASK;
    // or, more succintly
    flags &= ~MASK;



    Here, ~MASK turns all zeros to ones and all ones to zeros in MASK. flags & ~MASK leaves all the bits of flags as they are (one bit in the now-inverted MASK ANDed with any flags bit is that flags bit) except for the now-zeroed MASK bits. Zeroed MASK bits ANDed with any flags bit return zero, thereby unsetting the flag, regardless of its original value.


























    Typical Bit Mask Operations
    Operation Code
    Set a flag or overlay multiple values flags | flagbitN
    Unset a flag (zero-out a bit or set a bit to zero) flags & ~flagbitN
    Check if a bit is set (flags & flagbitN) == flagbitN
    Invert a pattern of bits ~flags











  • Bit flags and bit masks use bitwise operators. A Java integer has 32 bits out of which 31 bits can be turned off or on to act as flag bits. (The highest order bit is reserved for plus or minus sign). A bit mask is simply a integer with one or more bits sets to 1. If you assign the integer any power of 2, it will set only one bit as 1 in the integer. Therefore, you initialize one-bit masks to powers of 2. Java integers can go from 2^^0 through 2^^30.
     
    // Constants to hold bit masks for desired flags
    static final int flagAllOff = 0; // 000...00000000 (empty mask)
    static final int flagbit1 = 1; // 2^^0 000...00000001
    static final int flagbit2 = 2; // 2^^1 000...00000010
    static final int flagbit3 = 4; // 2^^2 000...00000100
    static final int flagbit4 = 8; // 2^^3 000...00001000
    static final int flagbit5 = 16; // 2^^4 000...00010000
    static final int flagbit6 = 32; // 2^^5 000...00100000
    static final int flagbit7 = 64; // 2^^6 000...01000000
    static final int flagbit8 = 128; // 2^^7 000...10000000
    //...
    static final int flagbit31 = (int) Math.pow(2, 30); // 2^^30
    //...

    // Variable to hold the status of all flags
    int flags = 0;





  • Traditionally, you will use boolean-type variables to act as a flag:
     
    boolean VISIBLE = true;


    If you want to use a bit mask as a flag:

     
    int VISIBLE = 4; // 0000 0100 in binary


    which sets the third bit from the right as the flag for VISIBLE, thus becoming a bit mask for the VISIBLE flag. Then you do bitwise operations to apply this mask on some flags (or options or status) variable to set, unset, check or toggle the VISIBLE flag bit in your flags variable.

  • You can combine individual masks to obtain combo masks:
     
    int maskReadAllowed = 4; // 00001000
    int maskWriteAllowed = 16; // 00010000
    // 00001000 | 00010000 = 00011000 represents both read and write permissions
    int maskReadAndWriteAllowed = maskReadAllowed | maskWriteAllowed;

    // Start out with no permissions
    int user1Permissions = 0; // 00000000
    int user2Permissions = 0; // 00000000

    // Allow user 1 to read
    // 00000000 | 00001000 = 00001000
    user1Permissions |= maskReadAllowed;

    // Allow user 2 to read as well as write in one shot
    // 00000000 | 00011000 = 00011000
    user2Permissions |= maskReadAndWriteAllowed;

    // Later, allow user 1 to write also
    // 00001000 | 00010000 = 00011000
    user1Permissions |= maskWriteAllowed;

    // Or, to make sure that user 1 has read permission as well, just in case
    // 00001000 | 00011000 = 00011000 (same as before)
    user1Permissions |= maskReadAndWriteAllowed;












Why the name Bit Mask?





  • When a bitwise AND is performed, the zeros in the MASK constant hide the corresponding bits in the your flags variable (because the result contains only the bits that are ones in both operands). You can think of the zeros in the MASK constant as being opaque and the ones as being transparent. Thus the expression flags & MASK is like covering the bit pattern of flags with the bit pattern of MASK so that only the bits under the ones of MASK are visible.
     
    0 0 0 0 0 0 1 0 (MASK constant)
    AND 1 0 0 1 0 1 1 0 (your flags variable)
    ---------------
    0 0 0 0 0 0 1 0 (result of operation)















Uses of Bit Masks






  • ^ can swap two variables without using an intermediate, temporary variable which is useful if you are short on available RAM or want that sliver of extra speed.

    Usually, when not using ^, you will do:

     
    temp = a;
    a = b;
    b = temp;


    Using ^, no "temp" is needed:

     
    a ^= b;
    b ^= a;
    a ^= b;


    This will swap "a" and "b" integers. Both must be integers.


  • A common C language usage of masks is:
     
    ch &= 0377
    where octal value 0377 is:
    11111111 in binary
    FF in Hexadecimal
    255 in Decimal


    This mask leaves the final (low or right end) eight bits of the variable ch alone and sets the rest to zero. Thus, regardless of whether the original ch is 8, 16, 32 or more bits, the final value is trimmed down to fit into a single byte. This is useful:


    • For cross-platform development where the sizes of the primitive data types may vary between platforms.
    • When the operands to the binary bitwise operators are of different-sized data types.


  • The most common application of the bitwise operators is to set, clear, test and toggle individual bit flags using bit masks. One 32 bit Java integer can hold 31 individual flags (about 2**31 - 1 total combinations). The last bit on the left (the highest or most significant bit) is reserved for the + or - sign of the integer.


  • Bit masks can be used to store all the permissions granted to a database user as an integer in the permissions table.

    Let's say that a user can be granted four types of permissions (in practice, there can be numerous types of permissions) - View, Add, Edit and Delete.































    Desired User Permissions
    User ID View Add Edit Delete
    tom Yes No No No
    dick Yes Yes Yes No
    harry Yes Yes Yes Yes



    It doesn't make sense to allow a user to add, edit or delete tables or rows if the user cannot view them. What we need are sets of valid permissions that a user may be granted.


    • No permission to do anything
    • View Only
    • View and Add
    • View and Edit
    • View, Add and Edit
    • All permissions (View, Add, Edit and Delete)



    Using bit flags and masks, Each user's permission set can be stored as an integer in a simple key-value file or database. For very large systems or very small systems, this can significantly reduce the disk space needed.

     
    User ID Permission Set
    ------- --------------
    User1 1
    User2 9
    User3 15





    How do we make sure that a user can only be assigned one of these permission sets? And how can we store permissions for numerous users for later access. We will investigate two ways of doing it - the application programming way and the system programming way.













Code Examples Using Bitwise Operators





  • There are two main Java code files below - BitwisePermissions.java and BooleanPermissions.java. The first one shows how to use bitwise Operators to set and unset various permission flags for database users. BooleanPermissions.java accomplishes exactly the same thing except that it uses Java booleans to represent flags.

  • On an average over 100's of tests, boolean version took about 50 percent longer to achieve same results.

    Memory used by the boolean version was about 150 percent more than the memory used by the bitwise version.

     
    Average time taken for testBitwiseOperations() = 1.62 millisecs
    Free memory change for testBitwiseOperations() = -13656 bytes
    Average time taken for testBooleanOperations() = 2.44 millisecs
    Free memory change for testBooleanOperations() = -34024 bytes



  • Instead of using Java's System.out.println() method, the examples on this page use Apache Log4j's cat.info() methods to display output. To run the example code, you will need to put log4j.jar in Java's classpath. Alternatively, you may want to download the latest Log4j software (about 2.3MB as of log4j 1.1.3) and extract log4j.jar (about 156KB) out of it.

    You will also need to save the following statements in a file named log4j.properties and place that file in a directory which is in Java's classpath so that Log4j can find this file and configure itself.

     
    #### ROOT category will log INFO and higher
    log4j.rootCategory=info, dest1
    #log4j.rootCategory=error, dest1

    #### Individual categories, if different from root. Usually unnecessary.
    #log4j.category.assign_permissions=DEBUG
    #log4j.category.assign_permissions=DEBUG, dest1

    #### Write logs to console stdout
    log4j.appender.dest1=org.apache.log4j.ConsoleAppender

    #### Layout for writing each log message
    log4j.appender.dest1.layout=org.apache.log4j.PatternLayout
    #log4j.appender.dest1.layout.ConversionPattern=%-5p %m%n
    #log4j.appender.dest1.layout.ConversionPattern=%C.%M(): %m%n
    #log4j.appender.dest1.layout.ConversionPattern=%5.5r %-25.25c.%-25.25M(): %m%n


    To measure performance of the code examples below, you will need to disable logging for every statement below the error as shown in the commented-out line above. Otherwise, the logging action itself takes too much time.

    To not use Log4j, replace cat.info( with System.out.println( and delete import org.apache.log4j.*;



  • First of all, we will need DBSecurityException.java class to throw custom exceptions when the requested permissions do not make sense.
     
    public class DBSecurityException extends Exception {
    DBSecurityException() { super(); }
    DBSecurityException(String s) { super(s); }
    }


  • BitwisePermissions.java is the primary file which exercises bitwise operators. What we are doing here is trying to represent valid sets of database permissions as bit masks. This coding practice is used in systems level programming where speed and memory usage matters. A user can then be granted one of these valid permission sets. It needs Java 2 or higher because it uses the Arrays.
     
    import org.apache.log4j.*;
    import java.util.Arrays;

    class BitwisePermissions {

    // Log4j logging category
    static Category cat =
    Category.getInstance(BitwisePermissions.class.getName());

    // Define masks for lowest level permissions as constants which
    // are powers of 2. This ensures that only one bit in an integer
    // is set to 1. Make these private because combinations will be
    // used to publically access valid permission sets.
    public static final int VIEW = 4;
    public static final int ADD = 16;
    public static final int EDIT = 32;
    public static final int DELETE = 256;


    /* Valid permission sets
    - No permission to do anything
    - View Only
    - View and Add
    - View and Edit
    - View, Add and Edit
    - All permissions (View, Add, Edit and Delete)
    */

    // Obtain valid permission sets by Bitwise ORing lower level permissions
    public static final int NOTHING_ALLOWED = 0;
    public static final int VIEW_ALLOWED = VIEW;
    public static final int VIEW_ADD_ALLOWED = VIEW | ADD;
    public static final int VIEW_EDIT_ALLOWED = VIEW | EDIT;
    public static final int VIEW_ADD_EDIT_ALLOWED = VIEW | ADD | EDIT;
    public static final int ALL_ALLOWED = VIEW | ADD | EDIT | DELETE;
    // Or, alternately
    //public static final int ALL_ALLOWED = VIEW_ADD_EDIT_ALLOWED | DELETE;


    public static final int [] validPermissions = {
    NOTHING_ALLOWED,
    VIEW_ALLOWED,
    VIEW_ADD_ALLOWED,
    VIEW_EDIT_ALLOWED,
    VIEW_ADD_EDIT_ALLOWED,
    ALL_ALLOWED,
    };

    static {
    // Sort needed to later use binarySearch() method
    Arrays.sort(validPermissions);
    for (int i = 0; i &lt; validPermissions.length; i++) {
    if(cat.isInfoEnabled()) {
    cat.info("Valid permission:" +
    printAsBinary(validPermissions[i]) );
    }
    }
    }

    // Check permission(s)
    public static boolean isPermitted(
    int myPermissions,
    int permissionToCheck
    ) {
    return ((myPermissions &amp; permissionToCheck) == permissionToCheck);
    }





    /* Public setter methods to make sure that only valid
    * permission sets can be assigned */

    public static int addPermission(int myPermissions, int permissionToAdd)
    throws DBSecurityException {

    return addPermissions(myPermissions,
    new int[] { permissionToAdd } );

    }


    public static int addPermissions(int myPermissions, int[] permissionsToAdd)
    throws DBSecurityException {

    if(cat.isInfoEnabled()) {
    cat.info("BEFORE Permissions:" + printAsBinary(myPermissions) );
    }
    for (int i = 0; i &lt; permissionsToAdd.length; i++) {
    if(cat.isInfoEnabled()) {
    cat.info("Add permission:" +
    printAsBinary(permissionsToAdd[i]));
    }
    myPermissions |= permissionsToAdd[i];
    }

    if (Arrays.binarySearch(validPermissions, myPermissions) &lt; 0) {
    throw new DBSecurityException(
    "Resulting permission set will be invalid. Aborted.");
    }
    else {
    if(cat.isInfoEnabled()) {
    cat.info("AFTER Permissions:" +
    printAsBinary(myPermissions) + "\n");
    }
    return myPermissions;
    }

    }


    public static int deletePermission(
    int myPermissions,
    int permissionToDelete
    ) throws DBSecurityException {
    return deletePermissions(myPermissions,
    new int[] { permissionToDelete } );
    }



    public static int deletePermissions(
    int myPermissions,
    int[] permissionsToDelete
    ) throws DBSecurityException {

    if(cat.isInfoEnabled()) {
    cat.info("BEFORE Permissions:" + printAsBinary(myPermissions));
    }
    for (int i = 0; i &lt; permissionsToDelete.length; i++) {
    if(cat.isInfoEnabled()) {
    cat.info("Delete permission:" +
    printAsBinary(permissionsToDelete[i]));
    }
    myPermissions &amp;= ~permissionsToDelete[i];
    }

    if (Arrays.binarySearch(validPermissions, myPermissions) &lt; 0) {
    throw new DBSecurityException(
    "Resulting permission set will be invalid. Aborted.");
    }
    else {
    if(cat.isInfoEnabled()) {
    cat.info("AFTER Permissions:" +
    printAsBinary(myPermissions) + "\n");
    }
    return myPermissions;
    }

    }


    // Toggle permission(s) - off if on, on if off - RARELY USED
    public static int togglePermission(
    int myPermissions,
    int permissionToToggle
    ) throws DBSecurityException {

    myPermissions ^= permissionToToggle;

    if (Arrays.binarySearch(validPermissions, myPermissions) &lt; 0) {
    throw new DBSecurityException(
    "Resulting permission set will be invalid. Aborted.");
    }
    else {
    return myPermissions;
    }

    }


    // Convert an int to a string displaying int as binary
    private static String printAsBinary(int i) {

    if(cat.isDebugEnabled()) cat.debug("incoming = " + i);

    StringBuffer sb = new StringBuffer();
    if ( isPermitted(i, VIEW) ) sb.append('V');
    else sb.append(' ');
    if ( isPermitted(i, ADD) ) sb.append('A');
    else sb.append(' ');
    if ( isPermitted(i, EDIT) ) sb.append('E');
    else sb.append(' ');
    if ( isPermitted(i, DELETE) ) sb.append('D');
    else sb.append(' ');

    String s = Integer.toString(i, 2);

    String pattern = "................................";

    if(cat.isDebugEnabled()) cat.debug("pattern = " + pattern);

    String temp1 = pattern.substring(0, pattern.length() - s.length());

    String temp2 = temp1 + s;

    if(cat.isDebugEnabled()) cat.debug("converted = " + temp2);

    temp2 = temp2.replace('0', '.');

    sb.append("=" + temp2);

    if(cat.isDebugEnabled()) cat.debug("returned = " + sb.toString());
    return sb.toString();
    }



    } // End of class



  • BooleanPermissions.java is a replica of the bitwise class above, except that it uses booleans as flags instead of bitmasks as flags. This coding practice is used in application level programming.
     
    import org.apache.log4j.*;
    import java.util.Arrays;

    class BooleanPermissions implements Cloneable, Comparable {

    // Log4j logging category
    static Category cat =
    Category.getInstance(BooleanPermissions.class.getName());


    /* Public constants */
    public static final int VIEW = 1;
    public static final int ADD = 2;
    public static final int EDIT = 3;
    public static final int DELETE = 4;


    /* Private permission variables */

    // Nothing is allowed by default
    private boolean bViewAllowed = false;
    private boolean bAddAllowed = false;
    private boolean bEditAllowed = false;
    private boolean bDeleteAllowed = false;



    /* Valid permission sets
    - No permission to do anything
    - View Only
    - View and Add
    - View and Edit
    - View, Add and Edit
    - All permissions (View, Add, Edit and Delete)
    */

    public static final BooleanPermissions
    NOTHING_ALLOWED = new BooleanPermissions();

    public static final BooleanPermissions
    VIEW_ALLOWED = new BooleanPermissions();

    public static final BooleanPermissions
    VIEW_ADD_ALLOWED = new BooleanPermissions();

    public static final BooleanPermissions
    VIEW_EDIT_ALLOWED = new BooleanPermissions();

    public static final BooleanPermissions
    VIEW_ADD_EDIT_ALLOWED = new BooleanPermissions();

    public static final BooleanPermissions
    ALL_ALLOWED = new BooleanPermissions();


    public static final BooleanPermissions [] validPermissions = {
    NOTHING_ALLOWED,
    VIEW_ALLOWED,
    VIEW_ADD_ALLOWED,
    VIEW_EDIT_ALLOWED,
    VIEW_ADD_EDIT_ALLOWED,
    ALL_ALLOWED,
    };



    static {

    VIEW_ALLOWED.bViewAllowed = true;

    VIEW_ADD_ALLOWED.bViewAllowed = true;
    VIEW_ADD_ALLOWED.bAddAllowed = true;

    VIEW_EDIT_ALLOWED.bViewAllowed = true;
    VIEW_EDIT_ALLOWED.bEditAllowed = true;

    VIEW_ADD_EDIT_ALLOWED.bViewAllowed = true;
    VIEW_ADD_EDIT_ALLOWED.bAddAllowed = true;
    VIEW_ADD_EDIT_ALLOWED.bEditAllowed = true;

    ALL_ALLOWED.bViewAllowed = true;
    ALL_ALLOWED.bAddAllowed = true;
    ALL_ALLOWED.bEditAllowed = true;
    ALL_ALLOWED.bDeleteAllowed = true;


    Arrays.sort(validPermissions);

    for (int i = 0; i &lt; validPermissions.length; i++) {
    if(cat.isInfoEnabled()) {
    cat.info("Valid permission:" + validPermissions[i]);
    }
    }
    }



    public String toString() {
    StringBuffer sb = new StringBuffer();
    if (bViewAllowed) sb.append('V');
    else sb.append(' ');
    if (bAddAllowed) sb.append('A');
    else sb.append(' ');
    if (bEditAllowed) sb.append('E');
    else sb.append(' ');
    if (bDeleteAllowed) sb.append('D');
    else sb.append(' ');
    sb.append("=" + hashCode());
    return sb.toString();
    }



    public boolean equals(Object o) {

    if ((o instanceof BooleanPermissions) &amp;&amp;
    (o.hashCode() != this.hashCode())
    ) {
    return true;
    }
    else {
    return false;
    }
    }



    public int hashCode() {
    StringBuffer sb = new StringBuffer();
    if (bViewAllowed) sb.append('1');
    else sb.append('0');
    if (bAddAllowed) sb.append('1');
    else sb.append('0');
    if (bEditAllowed) sb.append('1');
    else sb.append('0');
    if (bDeleteAllowed) sb.append('1');
    else sb.append('0');
    return Integer.parseInt(sb.toString());
    }



    public int compareTo(Object o) {
    return this.hashCode() - o.hashCode();
    }



    private void copyFields(BooleanPermissions bp) {
    if (bp != null) {
    this.bViewAllowed = bp.bViewAllowed;
    this.bAddAllowed = bp.bAddAllowed;
    this.bEditAllowed = bp.bEditAllowed;
    this.bDeleteAllowed = bp.bDeleteAllowed;
    }
    }



    private void setPermission(int permission, boolean value)
    throws DBSecurityException {
    switch(permission) {
    case VIEW:
    if(cat.isInfoEnabled()) cat.info("Set VIEW = " + value);
    bViewAllowed = value;
    break;
    case ADD:
    if(cat.isInfoEnabled()) cat.info("Set ADD = " + value);
    bAddAllowed = value;
    break;
    case EDIT:
    if(cat.isInfoEnabled()) cat.info("Set EDIT = " + value);
    bEditAllowed = value;
    break;
    case DELETE:
    if(cat.isInfoEnabled()) cat.info("Set DELETE = " + value);
    bDeleteAllowed = value;
    break;
    default:
    throw new DBSecurityException("Invalid permission");
    }
    }



    public boolean isPermitted(int permission) {
    switch(permission) {
    case VIEW:
    if(cat.isInfoEnabled()) {
    cat.info("Checking permission " + permission +
    " VIEW = " + bViewAllowed);
    }
    return bViewAllowed;
    case ADD:
    if(cat.isInfoEnabled()) {
    cat.info("Checking permission " + permission +
    " ADD = " + bAddAllowed);
    }
    return bAddAllowed;
    case EDIT:
    if(cat.isInfoEnabled()) {
    cat.info("Checking permission " + permission +
    " EDIT = " + bEditAllowed);
    }
    return bEditAllowed;
    case DELETE:
    if(cat.isInfoEnabled()) {
    cat.info("Checking permission " + permission +
    " DELETE = " + bDeleteAllowed);
    }
    return bDeleteAllowed;
    default:
    if(cat.isInfoEnabled()) {
    cat.info("Checking permission " + permission +
    " NOT FOUND. Returning false");
    }
    return false;
    }

    }



    public void addPermission(int permissionToAdd) throws DBSecurityException {
    addPermissions(new int[] { permissionToAdd } );
    }



    public void addPermissions(int[] permissionsToAdd)
    throws DBSecurityException {

    if(cat.isInfoEnabled()) cat.info("BEFORE Permissions:" + this);

    BooleanPermissions temp = null;
    try {
    temp = (BooleanPermissions) this.clone();
    }
    catch (CloneNotSupportedException cns) {
    // Should not happen. Ignore.
    if(cat.isDebugEnabled()) cat.debug( cns, cns);
    }

    for (int i = 0; i &lt; permissionsToAdd.length; i++) {
    setPermission(permissionsToAdd[i], true);
    }

    if (Arrays.binarySearch(validPermissions, this) &lt; 0) {
    copyFields(temp);
    throw new DBSecurityException(
    "Resulting permission set will be invalid. Aborted.");
    }
    if(cat.isInfoEnabled()) cat.info("AFTER Permissions:" + this + "\n");

    }



    public void deletePermission(int permissionToDelete)
    throws DBSecurityException {
    deletePermissions(new int[] { permissionToDelete } );
    }



    public void deletePermissions(int[] permissionsToDelete)
    throws DBSecurityException {

    if(cat.isInfoEnabled()) cat.info("BEFORE Permissions:" + this);

    BooleanPermissions temp = null;
    try {
    temp = (BooleanPermissions) this.clone();
    }
    catch (CloneNotSupportedException cns) {
    // Should not happen. Ignore.
    if(cat.isDebugEnabled()) cat.debug( cns, cns);
    }

    for (int i = 0; i &lt; permissionsToDelete.length; i++) {
    setPermission(permissionsToDelete[i], false);
    }

    if (Arrays.binarySearch(validPermissions, this) &lt; 0) {
    copyFields(temp);
    throw new DBSecurityException(
    "Resulting permission set will be invalid. Aborted.");
    }
    if(cat.isInfoEnabled()) cat.info("AFTER Permissions:" + this + "\n");

    }


    } // End of class




  • Okay, this one is a bit tricky. assign_permissions.java uses JUnit package to implement a testing class which exercises the two classes above. Basically, it extends JUnit's TestCase class, defines two methods - testBitwiseOperations() and testBooleanOperations() and runs these two methods repeatedly n2 number of times. You can change n2 value, recompile and run it. You may want to run with n2 = 1 and Log4j root category set to info. Then, you may want to run at n2 = 100 or something like that, but make sure that you set the Log4j root category to error, otherwise the tests will generate heaps of output and take forever to run. You, of course, need junit.jar in Java's classpath.
     
    import org.apache.log4j.*;
    import junit.framework.*;
    import junit.extensions.*;
    import java.util.*;

    public class assign_permissions extends TestCase {

    // Log4j logging category
    static Category cat =
    Category.getInstance(assign_permissions.class.getName());

    // Fixtures - Class fields to allow access from anywhere in class
    HashMap bitwiseUsers;
    HashMap booleanUsers;

    // Some free memory info
    Runtime rt = Runtime.getRuntime();

    long tm, tm2;
    long free4, free5;

    // Test statistics
    static int n2 = 0;
    static long timetaken1 = 0;
    static long timetaken2 = 0;
    static long freechange1 = 0;
    static long freechange2 = 0;


    // Required constructor - takes method name to test as parameter
    public assign_permissions(String name) {
    super(name);
    }


    // Add tests to run in order of running into the suite
    public static Test suite() {

    // Shortcut to automatically add all testXXX methods
    //return new TestSuite(assign_permissions.class);

    // Number of repetitions per test
    n2 = 1;

    TestSuite suite1 = new TestSuite();
    suite1.addTest(
    new RepeatedTest(
    new assign_permissions("testBitwiseOperations"), n2));

    TestSuite suite2 = new TestSuite();
    suite2.addTest(
    new RepeatedTest(
    new assign_permissions("testBooleanOperations"), n2));

    TestSuite suite = new TestSuite();
    //suite.addTest(new assign_permissions("testBitwiseOperations"));
    //suite.addTest(new assign_permissions("testBooleanOperations"));
    suite.addTest(suite1);
    suite.addTest(suite2);
    //TestResult result = suite.run();

    return suite;
    }




    public static void main (String[] args) {

    // Initialize static fields
    timetaken1 = 0;
    timetaken2 = 0;
    freechange1 = 0;
    freechange2 = 0;

    // Run the tests
    junit.textui.TestRunner.run( suite() );

    // Print the results
    // No sense in averaging less than 10 tests
    if (n2 &gt; 9) {
    cat.error(
    "Average time taken for testBitwiseOperations() = " +
    ((0.0 + (timetaken1*100.0/n2))/100.0) + " millisecs" );
    cat.error(
    "Average time taken for testBooleanOperations() = " +
    ((0.0 + (timetaken2*100.0/n2))/100.0) + " millisecs" );

    if (timetaken1 != 0) {
    cat.error(
    "testBooleanOperations() takes " +
    ((timetaken2-timetaken1)*100/timetaken1) +
    "% more time than testBitwiseOperations()");
    }

    }


    // Because of automatic garbage collection, no sense in measuring
    // memory usage for more than 1 tests

    if (n2 == 1) {
    cat.error(
    "Memory used for testBitwiseOperations() = " +
    freechange1 + " bytes" );
    cat.error(
    "Memory used for testBooleanOperations() = " +
    freechange2 + " bytes" );
    if (freechange1 != 0) {
    cat.error("testBooleanOperations() uses " +
    ((freechange2-freechange1)*100/freechange1) +
    "% more memory than testBitwiseOperations()");
    }
    }


    }



    // This method is called before running each test
    protected void setUp() {
    if(cat.isInfoEnabled()) cat.info("setUp(): Started\n");
    //System.gc();
    }



    // Test method
    public void testBitwiseOperations() {
    if(cat.isInfoEnabled()) cat.info("testBitwiseOperations(): Started\n");


    tm = System.currentTimeMillis();
    free4 = rt.freeMemory();


    bitwiseUsers = new HashMap();
    bitwiseUsers.put("user1",
    new Integer(BitwisePermissions.NOTHING_ALLOWED)
    );
    bitwiseUsers.put("user2",
    new Integer(BitwisePermissions.VIEW_ALLOWED));
    bitwiseUsers.put("user3",
    new Integer(BitwisePermissions.VIEW_ADD_ALLOWED));
    bitwiseUsers.put("user4",
    new Integer(BitwisePermissions.VIEW_EDIT_ALLOWED));
    bitwiseUsers.put("user5",
    new Integer(BitwisePermissions.VIEW_ADD_EDIT_ALLOWED));
    bitwiseUsers.put("user6",
    new Integer(BitwisePermissions.ALL_ALLOWED));

    Set keys = bitwiseUsers.keySet();
    Iterator i = keys.iterator();

    while (i.hasNext()) {
    Object o = i.next();
    if(cat.isInfoEnabled()) cat.info("User ID = " + o + "\n");
    int currentPermissions =
    ((Integer) bitwiseUsers.get(o)).intValue();

    try {
    currentPermissions =
    BitwisePermissions.addPermissions(
    currentPermissions,
    new int[] {
    BitwisePermissions.DELETE,
    BitwisePermissions.ADD,
    BitwisePermissions.EDIT,
    BitwisePermissions.VIEW,

    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }

    try {
    currentPermissions =
    BitwisePermissions.deletePermissions(
    currentPermissions,
    new int[] {
    BitwisePermissions.ADD,
    BitwisePermissions.EDIT,
    BitwisePermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }

    try {
    currentPermissions =
    BitwisePermissions.addPermissions(
    currentPermissions,
    new int[] {
    BitwisePermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }

    try {
    currentPermissions =
    BitwisePermissions.addPermissions(
    currentPermissions,
    new int[] {
    BitwisePermissions.DELETE,
    BitwisePermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }


    try {
    currentPermissions =
    BitwisePermissions.deletePermissions(
    currentPermissions,
    new int[] {
    BitwisePermissions.DELETE,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }


    try {
    currentPermissions =
    BitwisePermissions.addPermissions(
    currentPermissions,
    new int[] {
    BitwisePermissions.DELETE,
    BitwisePermissions.EDIT,
    BitwisePermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }

    try {
    currentPermissions =
    BitwisePermissions.deletePermissions(
    currentPermissions,
    new int[] {
    BitwisePermissions.DELETE,
    BitwisePermissions.ADD,
    BitwisePermissions.EDIT,
    BitwisePermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }
    }

    tm2 = System.currentTimeMillis();
    free5 = rt.freeMemory();

    timetaken1 += (tm2-tm);
    freechange1 += (free5-free4);


    assertTrue(true);
    }



    // Test method
    public void testBooleanOperations() {

    if(cat.isInfoEnabled()) cat.info("testBooleanOperations(): Started\n");

    tm = System.currentTimeMillis();
    free4 = rt.freeMemory();

    booleanUsers = new HashMap();
    booleanUsers.put("user1", BooleanPermissions.NOTHING_ALLOWED);
    booleanUsers.put("user2", BooleanPermissions.VIEW_ALLOWED);
    booleanUsers.put("user3", BooleanPermissions.VIEW_ADD_ALLOWED);
    booleanUsers.put("user4", BooleanPermissions.VIEW_EDIT_ALLOWED);
    booleanUsers.put("user5", BooleanPermissions.VIEW_ADD_EDIT_ALLOWED);
    booleanUsers.put("user6", BooleanPermissions.ALL_ALLOWED);

    Set keys = booleanUsers.keySet();
    Iterator i = keys.iterator();

    while (i.hasNext()) {
    Object o = i.next();
    if(cat.isInfoEnabled()) cat.info("User ID = " + o + "\n");
    BooleanPermissions currentPermissions =
    (BooleanPermissions) booleanUsers.get(o);

    try {
    currentPermissions.addPermissions(
    new int[] {
    BooleanPermissions.DELETE,
    BooleanPermissions.ADD,
    BooleanPermissions.EDIT,
    BooleanPermissions.VIEW,

    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }

    try {
    currentPermissions.deletePermissions(
    new int[] {
    BooleanPermissions.ADD,
    BooleanPermissions.EDIT,
    BooleanPermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }

    try {
    currentPermissions.addPermissions(
    new int[] {
    BooleanPermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }

    try {
    currentPermissions.addPermissions(
    new int[] {
    BooleanPermissions.DELETE,
    BooleanPermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }


    try {
    currentPermissions.deletePermissions(
    new int[] {
    BooleanPermissions.DELETE,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }


    try {
    currentPermissions.addPermissions(
    new int[] {
    BooleanPermissions.DELETE,
    BooleanPermissions.EDIT,
    BooleanPermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }

    try {
    currentPermissions.addPermissions(
    new int[] {
    BooleanPermissions.DELETE,
    BooleanPermissions.ADD,
    BooleanPermissions.EDIT,
    BooleanPermissions.VIEW,
    }
    );
    }
    catch (DBSecurityException dbse) {
    if(cat.isEnabledFor(Priority.WARN)) cat.warn(dbse, dbse);
    }
    }

    tm2 = System.currentTimeMillis();
    free5 = rt.freeMemory();

    timetaken2 += (tm2-tm);
    freechange2 += (free5-free4);

    assertTrue(true);
    }



    } // End of class






    References





    平均得分
    (0 次评分)





文章来自: 本站原创
标签: bit mask 
评论: 9 | 查看次数: 2056
  • 共有 9 条评论
游客 [2008-11-01 14:42:57]
游客 [2008-10-27 17:17:32]
Air Jordan Shoes
Warhammer Gold
Warhammer Online Gold
Warhammer Accounts
Warhammer Power Leveling
Warhammer Online Key
Warhammer Gold
Warhammer Online Gold
Warhammer Time Card
Warhammer CD Key
WAR gold
warhammer online gold
Buy WAR gold
Buy warhammer gold
Buy warhammer online gold
warhammer gold
WAR Accounts
warhammer Accounts
warhammer online Accounts
Buy WAR Accounts
warhammer Accounts for sale
Warhammer Power Leveling
Warhammer Online Power Leveling
War Power Leveling
Buy Warhammer Power Leveling
Warhammer PowerLeveling
Cheap Warhammer Power Leveling
Cheap Warhammer Online Power Leveling
Buy War Power Leveling
Warhammer EU Power Leveling
Cheap Warhammer Gold
Cheap Warhammer online gold
Buy Cheap Warhammer Gold
Buy WAR Gold
Warhammer EU Gold
Warhammer EU Power Leveling
Warhammer EU CD Key
Warhammer EU Accounts
Warhammer CD Key
Warhammer online CD Key
Warhammer Timecard
Buy Warhammer Time Card
Warhammer 60 days Time Card
Cheap WAR Accounts
Cheap warhammer Accounts
Cheap warhammer online Accounts
Buy Cheap WAR Accounts
buy Warhammer CD Key
buy Warhammer online CD Key
cheap Warhammer CD key
warhammer time card
Warhammer prepaid time card
Lord of the Rings Online Gold
Buy Lotro Gold
Sell LoTRO Gold
LoTRO CD Key
LoTRO Europe Gold
Cheap LoTRO Accounts
Lord of the Rings Online Power Leveling
Lord of the Rings online CD Key
Cheap Lotro Gold
Buy Lotro Gold | Lord Of The Rings Online Gold
Lotro Accounts
| Buy Lotro Accounts
Lord Of The Rings Online Power Leveling | Lord Of The Rings Online PowerLeveling
Lotro Cd Key | Lord Time Card
Lotro Gold | Lotro Gold Instant Delivery
lord of the rings online accounts | lord of the rings online accounts for sale
Lotro Power Leveling | Lotro Powerleveling
Lord Of The Rings Online Cd Key | Lord Of The Rings Online Time Card
游客 [2008-10-19 11:54:39]
游客 [2008-09-25 16:24:48]
Warhammer Gold
Warhammer Online Gold
Warhammer gold
cheap Warhammer gold
Warhammer Online gold
Warhammer gold
Buy WAR gold
Cheap Warhammer Gold
Buy warhammer online gold
cheap warhammer online gold
Buy warhammer gold
buy warhammer online gold
buy cheap warhammer gold
War Gold
Buy Warhammer Gold
Warhammer Online Gold
Warhammer Gold for sale
Cheap Warhammer Gold
Warhammer Accounts
Buy Warhammer Accounts
Cheap Warhammer Accounts
Warhammer Power leveling
War Power leveling
Warhammer Online Power Leveling
heap Warhammer Power Leveling
Warhammer CD Key
War CD Key
Warhammer Online CD Key
Warhammer Game Time Card
Warhammer Game Card
Buy Warhammer Online CD Key
Buy War Gold
Sell Warhammer Gold
Warhammer EU Gold
Warhammer Online EU Gold
Sell Warhammer Gold
Warhammer EU Gold
Buy War Gold
Warhammer Online EU Gold
Buy Cheap Warhammer Gold
Cheap warhammer EU gold
Cheap War Gold
Cheapest Warhammer Gold
Buy Cheap Warhammer Gold
Buy Warhammer Online Accounts
Buy WAR Accounts
Buy Warhammer Power Leveling
Warhammer Powerleveling
Buy WAR Power Leveling
Buy Cheap Warhammer Power Leveling
Buy Warhammer CD Key
Warhammer EU CD key
Buy Warhammer Online key
Warhammer Time Card
Buy Warhammer Time Card

LoTRO Gold
Lord of the Rings Online Gold
Buy Lotro Gold
Sell LoTRO Gold
LoTRO CD Key
LoTRO Europe Gold
Cheap LoTRO Accounts
Lord of the Rings Online Power Leveling
Lord of the Rings online CD Key
Cheap Lotro Gold
Buy Lotro Gold | Lord Of The Rings Online Gold
Lotro Accounts
| Buy Lotro Accounts
Lord Of The Rings Online Power Leveling | Lord Of The Rings Online PowerLeveling
Lotro Cd Key | Lord Time Card
Lotro Gold | Lotro Gold Instant Delivery
lord of the rings online accounts | lord of the rings online accounts for sale
Lotro Power Leveling | Lotro Powerleveling
Lord Of The Rings Online Cd Key | Lord Of The Rings Online Time Card
游客 [2008-09-24 17:57:43]
Buy Lotro Gold | Lord Of The Rings Online Gold
Lotro Accounts
| Buy Lotro Accounts
Lord Of The Rings Online Power Leveling | Lord Of The Rings Online PowerLeveling
Lotro Cd Key | Lord Time Card
Lotro Gold | Lotro Gold Instant Delivery
lord of the rings online accounts | lord of the rings online accounts for sale
Lotro Power Leveling | Lotro Powerleveling
Lord Of The Rings Online Cd Key | Lord Of The Rings Online Time Card
LoTRO Gold
Lord of the Rings Online Gold
Buy Lotro Gold
Sell LoTRO Gold
LoTRO CD Key
LoTRO Europe Gold
Cheap LoTRO Accounts
Lord of the Rings Online Power Leveling
Lord of the Rings online CD Key
Cheap Lotro Gold
Warhammer gold
Warhammer Online Gold
Warhammer Accounts
Warhammer Power Leveling
Warhammer CD Key

WAR gold
warhammer gold
warhammer online gold
Buy WAR gold
Buy warhammer gold
Buy warhammer online gold

WAR Accounts
warhammer Accounts
warhammer online Accounts
Buy WAR Accounts
warhammer Accounts for sale

WAR Power leveling
WAR Powerleveling
warhammer Power leveling
warhammer online Power leveling
Buy WAR Powerleveling
Buy warhammer Powerleveling
Buy warhammer online Powerleveling

warhammer game card
warhammer cd key
warhammer online game card
warhammer online cd key
warhammer cdkey
warhammer online cdkey

Warhammer Gold
Warhammer Online Gold
Warhammer Accounts
Warhammer Power Leveling
Warhammer CD Key

Cheap Warhammer Gold
Cheap Warhammer online gold
Buy Cheap Warhammer Gold
Buy WAR Gold

Cheap WAR Accounts
Cheap warhammer Accounts
Cheap warhammer online Accounts
Buy Cheap WAR Accounts

Cheap Warhammer Power Leveling
Cheap Warhammer Online Power Leveling
Cheap WAR Power Leveling

buy warhammer cd key
buy warhammer online cd key
cheap warhammer online cd key
warhammer time card
游客 [2008-09-22 16:25:20]
游客 [2008-09-10 15:22:41]
游客 [2008-09-02 16:08:40]
游客 [2008-08-06 14:49:08]
  • 共有 9 条评论
发表评论
昵 称:  登录
内 容: