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

org.refcodes.codec.impls.BaseCodecMetricsImpl 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.9
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.impls;

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

import org.refcodes.codec.BaseCodecConfig;
import org.refcodes.codec.BaseCodecMetrics;
import org.refcodes.data.CharSet;
import org.refcodes.data.Padding;
import org.refcodes.exception.BugException;

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

	// /////////////////////////////////////////////////////////////////////////
	// 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:
	// /////////////////////////////////////////////////////////////////////////

	public BaseCodecMetricsImpl( int aNumberBase ) {
		this( aNumberBase, CharSet.BASE64_CHARS.getCharSet() );
	}

	public BaseCodecMetricsImpl( int aNumberBase, char[] aCharSet ) {
		this( aNumberBase, aCharSet, Padding.BASE64.getChar() );
	}

	public BaseCodecMetricsImpl( int aNumberBase, char[] aCharSet, char aPaddingChar ) {
		_numberBase = aNumberBase;
		_charSet = aCharSet;
		_bitsPerDigit = toBitsPerDigit( aNumberBase );
		_digitMask = toDigitMask( _bitsPerDigit );
		_bytesPerInt = toBytesPerInt( _bitsPerDigit );
		_digitsPerInt = toDigitsPerInt( _bytesPerInt, _bitsPerDigit );
		_digitsPerByte = toDigitsPerByte( aNumberBase );
		_paddingChar = aPaddingChar;
		intiCharToValueMap( aCharSet );
	}

	public BaseCodecMetricsImpl( int aNumberBase, int aBitsPerDigit, int aDigitsPerByte, int aDigitsPerInt, int aBytesPerInt, char[] aCharSet ) {
		this( aNumberBase, aBitsPerDigit, aDigitsPerByte, aDigitsPerInt, aBytesPerInt, aCharSet, Padding.BASE64.getChar() );
	}

	public BaseCodecMetricsImpl( int aNumberBase, int aBitsPerDigit, int aDigitsPerByte, int aDigitsPerInt, int aBytesPerInt, char[] aCharSet, char aPaddingChar ) {
		_numberBase = aNumberBase;
		_charSet = aCharSet;
		_digitMask = (int) Math.pow( 2, aBitsPerDigit ) - 1;
		_bytesPerInt = aBytesPerInt;
		_bitsPerDigit = aBitsPerDigit;
		_digitsPerInt = aDigitsPerInt;
		_digitsPerByte = aDigitsPerByte;
		intiCharToValueMap( aCharSet );
		_paddingChar = aPaddingChar;
	}

	public BaseCodecMetricsImpl( BaseCodecMetrics aBaseCodecMetrics ) {
		_bitsPerDigit = aBaseCodecMetrics.getBitsPerDigit();
		_bytesPerInt = aBaseCodecMetrics.getBytesPerInt();
		intiCharToValueMap( aBaseCodecMetrics.getCharSet() );
		_digitMask = aBaseCodecMetrics.getDigitMask();
		_digitsPerByte = aBaseCodecMetrics.getDigitsPerByte();
		_digitsPerInt = aBaseCodecMetrics.getDigitsPerInt();
		_numberBase = aBaseCodecMetrics.getNumberBase();
		_paddingChar = aBaseCodecMetrics.getPaddingChar();
	}

	private void intiCharToValueMap( char[] aCharSet ) {
		for ( int i = 0; i < 64; i++ ) {
			_charToValueMap.put( aCharSet[i], i );
		}
	}

	// /////////////////////////////////////////////////////////////////////////
	// METHODS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Number base as integer.
	 */
	@Override
	public int getNumberBase() {
		return _numberBase;
	}

	/**
	 * Character set to be used by the given enumeration.
	 */
	@Override
	public char[] getCharSet() {
		return _charSet;
	}

	/**
	 * Number of bytes to exactly store a minimum number of digits.
	 */
	@Override
	public int getBytesPerInt() {
		return _bytesPerInt;
	}

	/**
	 * Number of digits stored in an integer.
	 */
	@Override
	public int getDigitsPerInt() {
		return _digitsPerInt;
	}

	/**
	 * Number in bits for one digit.
	 */
	@Override
	public int getBitsPerDigit() {
		return _bitsPerDigit;
	}

	/**
	 * Number of digits required to represent a byte.
	 */
	@Override
	public int getDigitsPerByte() {
		return _digitsPerByte;
	}

	/**
	 * The digit mask is the bit-field covering just the digit's bits (starting
	 * at bit 0). Those bits in the mask are set to one which are required to
	 * represent a digit.
	 */
	@Override
	public int getDigitMask() {
		return _digitMask;
	}

	@Override
	public int toValue( char aChar ) {
		if ( aChar == Padding.BASE64.getChar() ) return 0;
		return _charToValueMap.get( aChar );

	}

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

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

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

	@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;
	}

	@Override
	public boolean equals( Object obj ) {
		if ( this == obj ) return true;
		if ( obj == null ) return false;
		if ( getClass() != obj.getClass() ) return false;
		BaseCodecMetricsImpl other = (BaseCodecMetricsImpl) 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:
	// /////////////////////////////////////////////////////////////////////////

	protected static int toDigitMask( int aBitsPerDigit ) {
		return (int) Math.pow( 2, aBitsPerDigit ) - 1;
	}

	protected static int toBitsPerDigit( int aNumberBase ) {
		int theBitsPerDigit = Integer.toBinaryString( aNumberBase - 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 ) {
			theBitsPerDigit++;
		}
		return theBitsPerDigit;
	}

	protected static int toDigitsPerInt( int aBytesPerInt, int aBitsPerDigit ) {
		return 8 * aBytesPerInt / aBitsPerDigit;
	}

	protected static int toDigitsPerByte( int aNumberBase ) {
		int theDigitsPerByte = 0;
		int eMax = 1;
		while ( eMax < 255 ) {
			theDigitsPerByte++;
			eMax *= aNumberBase;
		}
		return theDigitsPerByte;
	}

	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 - 2025 Weber Informatics LLC | Privacy Policy