Jump to content

[Java]MByte byte wrapper

- - - - -

  • Please log in to reply
No replies to this topic

#1
Sinipull

Sinipull

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 386 posts

/**
 * This class is released under GNU GENERAL PUBLIC LICENSE.
 * 
 * Wraps byte information, displays it in four different bases - binary, ASCII, decimal and hexadecimal. Preserves the four values, so no
 * recalculation occurs during displaying if value hasn't changed. Also parses the value from String form if needed. 
 * Pros: 
 *         +No additional calculations are needed when frequent converting from one base to another is needed. 
 *             It's done once after the value is changed.             
 *         +Binary String is held in its 8-bit user-friendly form. Great for displaying or bit-editing.
 *         +All the information is in one tidy class, no additional variables are needed to hold information.
 *         +Efficient and safe single bit flipping.
 * Cons:
 *         -Tests show that recalculation is a little bit slower than implementing the whole thing separately,
 *             using purely Integer's own methods. But the difference is minimal, in about 2 million value changes
 *             my computer generated about 300ms difference. (0.469 / 0.765)seconds accordingly. Most of this is thanks
 *             to the binary String concatenation (filling the '0's in front of the String to get 8 bits). 
 *             
 *  
 * Total memory usage for instanced object is 2 integers + 4 short Strings in an array
 *  
 * @author Joonas Vali, 2010 September
 *
 */
public class MByte extends Number implements Comparable<Number>{
    /**
     * 1L: 14.09.2010
     */
    private static final long serialVersionUID = 1L;
    private int value;    
    private int hash;
    private static String[] binFill = {"", "0", "00", "000", "0000", "00000", "000000", "0000000", "00000000"};
    private String[] cache;
    
    
    public static final int BINARY = 0, ASCII = 1, DECIMAL = 2, HEXADECIMAL = 3;    
    public static final int NUMBER_OF_TYPES = 4;
    
    
    
    /**
     * Create a new wrapper for a byte.  
     * @param value the decimal value of byte to be wrapped.     
     * currently existing: BINARY, ASCII, DECIMAL and HEXADECIMAL
     * * @throws IllegalArgumentException when byte is out of range(unsigned byte range)
     */
    public MByte(int value){        
        if(value < 0 || value > 255) throw new IllegalArgumentException("Byte value out of range: "+value);
        this.value = value;        
        cache = new String[NUMBER_OF_TYPES];    
        fillCache();
    }    
    
    /**
     * Calculates and fills the 'cache' with right Strings from the decimal value
     */
    private void fillCache(){        
        String str = Integer.toBinaryString(value);        
        cache[BINARY] = binFill[8- str.length()]+str;        
        cache[ASCII] = Character.toString((char)value);        
        cache[DECIMAL] = Integer.toString(value);        
        cache[HEXADECIMAL] = Integer.toString(value, 16);
        hash = ((Integer)value).hashCode();
    }
    
    
    /** 
     * @return a String based on the currently set type. Binary is always 8 digits, for bit editing purposes
     */    
    public String toString(int type){
        if(type > NUMBER_OF_TYPES || type < 0) throw new IllegalArgumentException("Type out of range");
        return cache[type];        
    }
    
    /**
     * @return the String of the decimal value
     */
    public String toString(){
        return cache[DECIMAL];        
    }
    
    /**
     * set a new value
     * @param value must be corresponding value to the type for parsing.
     * @param type must be corresponding to the value for parsing.
     * @throws IllegalArgumentException if unfit value was inserted    for a type, or type is out of range.
     */
    public void setValue(String value, int type){
        int oldValue = this.value;
        if(type > NUMBER_OF_TYPES || type < 0) throw new IllegalArgumentException("Type out of range");
        try{
            switch(type){
                case BINARY: this.value = Integer.parseInt(value,2); break;            
                case ASCII: this.value = (int)value.charAt(0); break;
                case DECIMAL: this.value = Integer.parseInt(value); break;
                case HEXADECIMAL: this.value = Integer.parseInt(value, 16);
            }
            if(oldValue != this.value)fillCache();
        } catch(Exception e){
            throw new IllegalArgumentException("Incorrect value("+value+") for specified type. Exception:\n"+e);
        }        
    }
    
    /**
     * Flip single bits. Index count starts from the end.
     * @param index the index of the bit to be switched 0-7. 0 is the rightmost bit
     * @param direction the direction of flip, true is for 1 and false is for 0.
     * if bit is already in the direction, then nothing happens.
     * @throws IllegalArgumentException if index is out of bounds
     */
    public void flipBit(int index, boolean direction){
        if(index > 7 || index < 0)throw new IllegalArgumentException("Index needs to be between 0-7");
        int oldvalue = value;
        value = direction ? value | (int)Math.pow(2, index) : value &~ (int)Math.pow(2, index);        
        if(oldvalue != value)fillCache();
    }
    
    /**
     * set a new value
     * @param value A decimal value within a range of byte
     * @throws IllegalArgumentException when value is out of range (unsigned byte range)
     */
    public void setValue(int value){
        if(value < 0 || value > 255) throw new IllegalArgumentException("Byte value out of range: "+value);
        if(this.value == value) return;
        this.value = value;
        fillCache();
    }
        
    /**
     * Checks the equality with another object. Comparison can be done with any object of the 
     * same kind or any object extending the Number Class. Only the actual value will be considered.     
     * @return true in case values are equal
     */
    @Override
    public boolean equals(Object other){        
        if(other instanceof Number && ((Number)other).intValue() == value) return true;        
        return false;
    }
    
    /**
     * Compares this object with another object. Comparison can be done with any object extending the Number Class, 
     * including this. Only the numerical value will be considered. 
     * @return the value 0 if this object is equal to the argument's numerical value; a value less than 0 if this 
     * object is numerically less than the argument's numerical value; and a value greater than 0 if this object 
     * is numerically greater than the argument's numerical value (signed comparison).
     */
    @Override
    public int compareTo(Number number) {        
        return ((Integer)this.value).compareTo(number.intValue());
    }
    
    /**
     * @return a hashcode calculated based on the numerical value
     */
    @Override
    public int hashCode(){
        return hash;
    }
    
    /**
     * Get the current value
     * @return the value in decimal and as a double
     */
    @Override
    public double doubleValue() {
        return (double)value;
    }

    /**
     * Get the current value
     * @return the value in decimal and as a float
     */
    @Override
    public float floatValue() {
        return (float)value;
    }

    /**
     * Get the current value
     * @return the value in decimal and as an integer
     */
    @Override
    public int intValue() {        
        return value;
    }
    
    /**
     * Get the current value
     * @return the value in decimal and as a long
     */
    @Override
    public long longValue() {
        return (long)value;
    }
    
    /**
     * Get the current value
     * @return the value in decimal and as a byte
     */
    public byte byteValue() {
        return (byte)value;
    }
}

Edited by Sinipull, 15 September 2010 - 02:17 PM.
Added single bit flipping possibility





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users