All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.refcodes.codec.BaseMetricsImpl Maven / Gradle / Ivy

Go to download

Artifact with encoding and decoding (not in terms of encryption/decryption) implementations (codecs) such as BASE64 encoding / decoding.

There is a newer version: 3.3.8
Show newest version
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany and licensed
// 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/LICENSE-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.Padding;
import org.refcodes.exception.BugException;

/**
 * {@link BaseMetrics} implementation for playing around with your own
 * configuration. You may use a template as one provided by {@link BaseConfig}
 * and tweak some attributes as you wish.
 */
public class BaseMetricsImpl implements BaseMetrics {

	// /////////////////////////////////////////////////////////////////////////
	// STATICS:
	// /////////////////////////////////////////////////////////////////////////

	// /////////////////////////////////////////////////////////////////////////
	// CONSTANTS:
	// /////////////////////////////////////////////////////////////////////////

	private static final int BYTES_PER_INT = 4;

	private static final int BITS_PER_BYTE = 8;

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	private 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;

	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTOR:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * 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, Padding.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;
		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, Padding.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;
	}

	/**
	 * 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();
	}

	/**
	 * 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 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;
		return _charToValueMap.get( aChar );

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public char toChar( int aValue ) {
		return _charSet[aValue];
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public char getPaddingChar() {
		return _paddingChar;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toString() {
		return getClass().getSimpleName() + "(base := " + _numberBase + ", digits/int := " + _digitsPerInt + ", bytes/int := " + _bytesPerInt + ", bits/digit := " + _bitsPerDigit + ")@" + hashCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + _bytesPerInt;
		result = prime * result + Arrays.hashCode( _charSet );
		result = prime * result + _digitMask;
		result = prime * result + _digitsPerByte;
		result = prime * result + _numberBase;
		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;
		BaseMetricsImpl other = (BaseMetricsImpl) obj;
		if ( _bytesPerInt != other._bytesPerInt ) return false;
		if ( !Arrays.equals( _charSet, other._charSet ) ) return false;
		if ( _digitMask != other._digitMask ) return false;
		if ( _digitsPerByte != other._digitsPerByte ) return false;
		if ( _numberBase != other._numberBase ) return false;
		return true;
	}

	// /////////////////////////////////////////////////////////////////////////
	// UTILITY:
	// /////////////////////////////////////////////////////////////////////////

	// /////////////////////////////////////////////////////////////////////////
	// HOOKS:
	// /////////////////////////////////////////////////////////////////////////

	// /////////////////////////////////////////////////////////////////////////
	// 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." );
	}

	// /////////////////////////////////////////////////////////////////////////
	// INNER CLASSES:
	// /////////////////////////////////////////////////////////////////////////

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy