litesoft
@ 939
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
package org.litesoft.codec; import org.litesoft.charstreams.*; import org.litesoft.commonfoundation.annotations.*; public class PrimitiveLongCodec { public static final PrimitiveLongCodec SIGNED = new PrimitiveLongCodec( true ); public static final PrimitiveLongCodec NON_NEGATIVE = new PrimitiveLongCodec( false ); private final boolean mSignedValuesOK; private PrimitiveLongCodec( boolean pSignedValuesOK ) { mSignedValuesOK = pSignedValuesOK; } public void encode( @NotNull CharSink pCharSink, long pValue ) { if ( (pValue < 0) && !mSignedValuesOK ) { throw new IllegalArgumentException( "Negative values not supported: " + pValue ); } new Encoder( pCharSink, pValue ).encode(); } public long decode( @NotNull CharSource pCharSource ) { return new Decoder( pCharSource ).decode(); } private static final int NEGATIVE_1ST_CHAR_BIT = 16; private static final int NON_NEGATIVE_1ST_CHAR_BIT = 0; private static final int SIGNED_1ST_CHAR_MASK = 15; private static final int SIGNED_1ST_CHAR_FACTOR = 16; private static final int UNSIGNED_1ST_CHAR_MASK = 31; private static final int UNSIGNED_1ST_CHAR_FACTOR = 32; private static final int MORE_BIT = 32; private static final int MORE_MASK = 31; private static final int MORE_FACTOR = 32; private class Common { protected final int mFirstCharMask; protected final int mFirstCharFactor; protected Common() { if ( mSignedValuesOK ) { mFirstCharMask = SIGNED_1ST_CHAR_MASK; mFirstCharFactor = SIGNED_1ST_CHAR_FACTOR; } else { mFirstCharMask = UNSIGNED_1ST_CHAR_MASK; mFirstCharFactor = UNSIGNED_1ST_CHAR_FACTOR; } } } private class Encoder extends Common { private final CharSink mCharSink; private long mValue; private Encoder( CharSink pCharSink, long pValue ) { mCharSink = pCharSink; mValue = pValue; } public void encode() { if ( mSignedValuesOK && (mValue < 0) ) { if ( Long.MIN_VALUE == mValue ) { mCharSink.add( SixBitCodec.encode( NEGATIVE_1ST_CHAR_BIT ) ); // Record as '-0' } else { mValue = -mValue; encode( NEGATIVE_1ST_CHAR_BIT ); } return; } if ( mValue < mFirstCharFactor ) { mCharSink.add( SixBitCodec.encode( (int) mValue ) ); } else { encode( NON_NEGATIVE_1ST_CHAR_BIT ); } } private void encode( int pNegativeBit ) { int bits = extractBits( mFirstCharMask, mFirstCharFactor ); mCharSink.add( SixBitCodec.encode( bits | pNegativeBit ) ); while ( mValue > 0 ) { bits = extractBits( MORE_MASK, MORE_FACTOR ); mCharSink.add( SixBitCodec.encode( bits ) ); } } private int extractBits( int pBits, int pDivisor ) { int rv = (int) (mValue & pBits); if ( (mValue /= pDivisor) > 0 ) { rv |= MORE_BIT; } return rv; } } private class Decoder extends Common { private final CharSource mValue; private boolean negative; private Decoder( CharSource pValue ) { mValue = pValue; } public long decode() { int bits = SixBitCodec.decode( mValue.getRequired() ); negative = mSignedValuesOK & ((bits & NEGATIVE_1ST_CHAR_BIT) != 0); long result = (bits & mFirstCharMask); for ( long zMultiplier = mFirstCharFactor; (bits & MORE_BIT) != 0; zMultiplier *= MORE_FACTOR ) { bits = SixBitCodec.decode( mValue.getRequired() ); result += (bits & MORE_MASK) * zMultiplier; } if ( !negative ) { return result; } if ( result == 0 ) // '-0' { return Long.MIN_VALUE; } return -result; } } } |