org.refcodes.codec.BaseMetricsImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refcodes-codec Show documentation
Show all versions of refcodes-codec Show documentation
Artifact with encoding and decoding (not in terms of encryption/decryption)
implementations (codecs) such as BASE64 encoding / decoding.
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////
package org.refcodes.codec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.refcodes.data.CharSet;
import org.refcodes.data.PaddingChar;
import org.refcodes.exception.BugException;
import org.refcodes.textual.VerboseTextBuilder;
/**
* {@link BaseMetrics} implementation for playing around with your own
* configuration. You may use a template as one provided by
* {@link BaseMetricsConfig} and tweak some attributes as you wish.
*/
public class BaseMetricsImpl implements BaseMetrics {
// /////////////////////////////////////////////////////////////////////////
// CONSTANTS:
// /////////////////////////////////////////////////////////////////////////
private static final int BYTES_PER_INT = 4;
private static final int BITS_PER_BYTE = 8;
// /////////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////////
private final Map _charToValueMap = new HashMap<>();
private int _numberBase;
private int _bytesPerInt;
private char[] _charSet;
private int _bitsPerDigit;
private int _digitsPerInt;
private int _digitsPerByte;
private int _digitMask;
private char _paddingChar;
private int _bytesPerBlock;
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Instantiates a new base metrics impl.
*
* @param aBase the base
*/
public BaseMetricsImpl( int aBase ) {
this( aBase, CharSet.BASE64.getCharSet() );
}
/**
* Instantiates a new base metrics impl.
*
* @param aBase the base
* @param aCharSet the char set
*/
public BaseMetricsImpl( int aBase, char[] aCharSet ) {
this( aBase, aCharSet, PaddingChar.BASE64.getChar() );
}
/**
* Instantiates a new base metrics impl.
*
* @param aBase the base
* @param aCharSet the char set
* @param aPaddingChar the padding char
*/
public BaseMetricsImpl( int aBase, char[] aCharSet, char aPaddingChar ) {
_numberBase = aBase;
_charSet = aCharSet;
_bitsPerDigit = toBitsPerDigit( aBase );
_digitMask = toDigitMask( _bitsPerDigit );
_bytesPerInt = toBytesPerInt( _bitsPerDigit );
_digitsPerInt = toDigitsPerInt( _bytesPerInt, _bitsPerDigit );
_digitsPerByte = toDigitsPerByte( aBase );
_paddingChar = aPaddingChar;
_bytesPerBlock = toBytesPerBlock( _bitsPerDigit );
intiCharToValueMap( aCharSet );
}
/**
* Instantiates a new base metrics impl.
*
* @param aBase the base
* @param aBitsPerDigit the bits per digit
* @param aDigitsPerByte the digits per byte
* @param aDigitsPerInt the digits per int
* @param aBytesPerInt the bytes per int
* @param aCharSet the char set
*/
public BaseMetricsImpl( int aBase, int aBitsPerDigit, int aDigitsPerByte, int aDigitsPerInt, int aBytesPerInt, char[] aCharSet ) {
this( aBase, aBitsPerDigit, aDigitsPerByte, aDigitsPerInt, aBytesPerInt, aCharSet, PaddingChar.BASE64.getChar() );
}
/**
* Instantiates a new base metrics impl.
*
* @param aBase the base
* @param aBitsPerDigit the bits per digit
* @param aDigitsPerByte the digits per byte
* @param aDigitsPerInt the digits per int
* @param aBytesPerInt the bytes per int
* @param aCharSet the char set
* @param aPaddingChar the padding char
*/
public BaseMetricsImpl( int aBase, int aBitsPerDigit, int aDigitsPerByte, int aDigitsPerInt, int aBytesPerInt, char[] aCharSet, char aPaddingChar ) {
_numberBase = aBase;
_charSet = aCharSet;
_digitMask = (int) Math.pow( 2, aBitsPerDigit ) - 1;
_bytesPerInt = aBytesPerInt;
_bitsPerDigit = aBitsPerDigit;
_digitsPerInt = aDigitsPerInt;
_digitsPerByte = aDigitsPerByte;
intiCharToValueMap( aCharSet );
_paddingChar = aPaddingChar;
_bytesPerBlock = toBytesPerBlock( aBitsPerDigit );
}
/**
* Instantiates a new base metrics impl.
*
* @param aBaseMetrics the base metrics
*/
public BaseMetricsImpl( BaseMetrics aBaseMetrics ) {
_bitsPerDigit = aBaseMetrics.getBitsPerDigit();
_bytesPerInt = aBaseMetrics.getBytesPerInt();
intiCharToValueMap( aBaseMetrics.getCharSet() );
_digitMask = aBaseMetrics.getDigitMask();
_digitsPerByte = aBaseMetrics.getDigitsPerByte();
_digitsPerInt = aBaseMetrics.getDigitsPerInt();
_numberBase = aBaseMetrics.getNumberBase();
_paddingChar = aBaseMetrics.getPaddingChar();
_bytesPerBlock = toBytesPerBlock( aBaseMetrics.getBytesPerBlock() );
}
/**
* Inti char to value map.
*
* @param aCharSet the char set
*/
private void intiCharToValueMap( char[] aCharSet ) {
for ( int i = 0; i < aCharSet.length; i++ ) {
_charToValueMap.put( aCharSet[i], i );
}
}
// /////////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
public int getNumberBase() {
return _numberBase;
}
/**
* {@inheritDoc}
*/
@Override
public char[] getCharSet() {
return _charSet;
}
/**
* {@inheritDoc}
*/
@Override
public int getBytesPerInt() {
return _bytesPerInt;
}
/**
* {@inheritDoc}
*/
@Override
public int getBytesPerBlock() {
return _bytesPerBlock;
}
/**
* {@inheritDoc}
*/
@Override
public int getDigitsPerInt() {
return _digitsPerInt;
}
/**
* {@inheritDoc}
*/
@Override
public int getBitsPerDigit() {
return _bitsPerDigit;
}
/**
* {@inheritDoc}
*/
@Override
public int getDigitsPerByte() {
return _digitsPerByte;
}
/**
* {@inheritDoc}
*/
@Override
public int getDigitMask() {
return _digitMask;
}
/**
* {@inheritDoc}
*/
@Override
public int toValue( char aChar ) {
if ( aChar == _paddingChar ) {
return 0;
}
final Integer theValue = _charToValueMap.get( aChar );
if ( theValue == null ) {
throw new IllegalArgumentException( "The character '" + aChar + "' does not belong to the given <" + getNumberBase() + "> number base metrics with charset: " + VerboseTextBuilder.asString( getCharSet() ) );
}
return theValue;
}
/**
* {@inheritDoc}
*/
@Override
public char toChar( int aValue ) {
return _charSet[aValue];
}
/**
* {@inheritDoc}
*/
@Override
public char getPaddingChar() {
return _paddingChar;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + _bitsPerDigit;
result = prime * result + _bytesPerBlock;
result = prime * result + _bytesPerInt;
result = prime * result + Arrays.hashCode( _charSet );
result = prime * result + ( ( _charToValueMap == null ) ? 0 : _charToValueMap.hashCode() );
result = prime * result + _digitMask;
result = prime * result + _digitsPerByte;
result = prime * result + _digitsPerInt;
result = prime * result + _numberBase;
result = prime * result + _paddingChar;
return result;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
final BaseMetricsImpl other = (BaseMetricsImpl) obj;
if ( _bitsPerDigit != other._bitsPerDigit ) {
return false;
}
if ( _bytesPerBlock != other._bytesPerBlock ) {
return false;
}
if ( _bytesPerInt != other._bytesPerInt ) {
return false;
}
if ( !Arrays.equals( _charSet, other._charSet ) ) {
return false;
}
if ( _charToValueMap == null ) {
if ( other._charToValueMap != null ) {
return false;
}
}
else if ( !_charToValueMap.equals( other._charToValueMap ) ) {
return false;
}
if ( _digitMask != other._digitMask ) {
return false;
}
if ( _digitsPerByte != other._digitsPerByte ) {
return false;
}
if ( _digitsPerInt != other._digitsPerInt ) {
return false;
}
if ( _numberBase != other._numberBase ) {
return false;
}
if ( _paddingChar != other._paddingChar ) {
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getClass().getSimpleName() + " [numberBase=" + _numberBase + ", bytes/int=" + _bytesPerInt + ", bits/digit=" + _bitsPerDigit + ", digits/int=" + _digitsPerInt + ", digits/byte=" + _digitsPerByte + ", digitMask=" + _digitMask + ", paddingChar='" + _paddingChar + "', bytes/block=" + _bytesPerBlock + "]";
}
// /////////////////////////////////////////////////////////////////////////
// UTILITY:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// HELPER:
// /////////////////////////////////////////////////////////////////////////
/**
* To digit mask.
*
* @param aBitsPerDigit the bits per digit
*
* @return the int
*/
protected static int toDigitMask( int aBitsPerDigit ) {
return (int) Math.pow( 2, aBitsPerDigit ) - 1;
}
/**
* To bits per digit.
*
* @param aBase the base
*
* @return the int
*/
protected static int toBitsPerDigit( int aBase ) {
int theBitsPerDigit = Integer.toBinaryString( aBase - 1 ).length();
// Make it fit into byte portions of an integer:
while ( BITS_PER_BYTE % theBitsPerDigit != 0 && 2 * BITS_PER_BYTE % theBitsPerDigit != 0 && 3 * BITS_PER_BYTE % theBitsPerDigit != 0 && 4 * BITS_PER_BYTE % theBitsPerDigit != 0 ) { // && 5 * BITS_PER_BYTE % theBitsPerDigit != 0
theBitsPerDigit++;
}
return theBitsPerDigit;
}
/**
* To digits per int.
*
* @param aBytesPerInt the bytes per int
* @param aBitsPerDigit the bits per digit
*
* @return the int
*/
protected static int toDigitsPerInt( int aBytesPerInt, int aBitsPerDigit ) {
return BITS_PER_BYTE * aBytesPerInt / aBitsPerDigit;
}
/**
* To digits per byte.
*
* @param aBase the base
*
* @return the int
*/
protected static int toDigitsPerByte( int aBase ) {
int theDigitsPerByte = 0;
int eMax = 1;
while ( eMax < 255 ) {
theDigitsPerByte++;
eMax *= aBase;
}
return theDigitsPerByte;
}
/**
* To bytes per int.
*
* @param aBitsPerDigit the bits per digit
*
* @return the int
*/
protected static int toBytesPerInt( int aBitsPerDigit ) {
for ( int i = ( BYTES_PER_INT * BITS_PER_BYTE ); i > 0; i-- ) {
if ( i % aBitsPerDigit == 0 ) {
return i / BITS_PER_BYTE;
}
}
for ( int i = 1; i <= aBitsPerDigit; i++ ) {
if ( i * BITS_PER_BYTE % aBitsPerDigit == 0 ) {
return ( i * BITS_PER_BYTE ) / BITS_PER_BYTE;
}
}
throw new BugException( "We must have encountered a bug as we cannot determine the word length for a base codec with <" + aBitsPerDigit + "> bits per digit." );
}
/**
* Calculates the number of bytes which fully fit into a base encoded block.
*
* @param aBitsPerDigit The bits used per digit.
*
* @return The number of bytes completely fitting into one block.
*/
protected static int toBytesPerBlock( int aBitsPerDigit ) {
// if ( aBitsPerDigit < BITS_PER_BYTE ) return aBitsPerDigit % BITS_PER_BYTE;
int theBytesPerBlock = 1;
while ( ( theBytesPerBlock * BITS_PER_BYTE ) % aBitsPerDigit != 0 ) {
theBytesPerBlock++;
}
return theBytesPerBlock;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy