/** * Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.codesourcery.jasm16; /** * A memory/ data volume size. * * <p>This class provides an abstraction to avoid conversion errors when converting between sizes in bytes and words.</p> * * @author tobias.gierke@code-sourcery.de */ public abstract class Size implements Comparable<Size> { private final int value; public static final SizeInWords ZERO_WORDS = new SizeInWords(0); public static final SizeInWords ONE_WORD = new SizeInWords(1); public static final SizeInWords TWO_WORDS = new SizeInWords(2); public static final SizeInWords THREE_WORDS = new SizeInWords(3); public static final SizeInBytes ZERO_BYTES = new SizeInBytes(0); public static final SizeInBytes ONE_BYTES = new SizeInBytes(1); public static final SizeInBytes TWO_BYTES = new SizeInBytes(2); public static final SizeInBytes THREE_BYTES = new SizeInBytes(3); public static final SizeInBytes FOUR_BYTES = new SizeInBytes(4); public static final SizeInBytes FIVE_BYTES = new SizeInBytes(5); public static final SizeInBytes SIX_BYTES = new SizeInBytes(6); public static SizeInBytes bytes(int size) { switch( size ) { case 0: return ZERO_BYTES; case 1: return ONE_BYTES; case 2: return TWO_BYTES; case 3: return THREE_BYTES; case 4: return FOUR_BYTES; case 5: return FIVE_BYTES; case 6: return SIX_BYTES; default: return new SizeInBytes( size ); } } public static SizeInWords words(int size) { switch(size) { case 0: return ZERO_WORDS; case 1: return ONE_WORD; case 2: return TWO_WORDS; case 3: return THREE_WORDS; default: return new SizeInWords( size ); } } protected Size(int value) { if ( value < 0 ) { throw new IllegalArgumentException("size must not be negative (size: "+value+")"); } this.value = value; } public int getValue() { return value; } public abstract int getSizeInBytes(); public abstract int getSizeInWords(); @Override public final boolean equals(Object obj) { if ( obj == this ) { return true; } if ( obj instanceof Size) { return getSizeInBytes() == ((Size) obj).getSizeInBytes(); } return false; } public abstract Size multiply(int factor); @Override public final int hashCode() { return getSizeInBytes(); } public final Size minus(Size other) { return new SizeInBytes( this.getSizeInBytes() - other.getSizeInBytes() ); } public final Size plus(Size other) { return new SizeInBytes( this.getSizeInBytes() + other.getSizeInBytes() ); } public abstract SizeInBytes toSizeInBytes(); public abstract SizeInWords toSizeInWords(); public static final class SizeInBytes extends Size { protected SizeInBytes(int size) { super(size); } public int getSizeInBytes() { return getValue(); } public int getSizeInWords() { int result = getValue() >>> 1; if ( (result << 1) != getValue() ) { throw new RuntimeException("Internal error, converting byte-size "+getValue()+" to words causes loss of precision"); } return result; } @Override public SizeInBytes toSizeInBytes() { return this; } @Override public SizeInWords toSizeInWords() { int convertedValue = getValue() >>> 1; if ( ( convertedValue << 1 ) != getValue() ) { throw new RuntimeException("Internal error, converting uneven value "+getValue()+" to a size in words would cause data loss"); } return new SizeInWords( getValue() >>> 1); } @Override public String toString() { return getValue()+" bytes"; } @Override public Size multiply(int factor) { if ( factor < 0 ) { throw new IllegalArgumentException("Factor must be positive"); } return Size.bytes( getSizeInBytes() * factor ); } } public static final class SizeInWords extends Size { protected SizeInWords(int size) { super(size); } public int getSizeInBytes() { return getValue() << 1; } public int getSizeInWords() { return getValue(); } @Override public SizeInBytes toSizeInBytes() { return new SizeInBytes( getValue() << 1); } @Override public Size multiply(int factor) { if ( factor < 0 ) { throw new IllegalArgumentException("Factor must be positive"); } return Size.words( getSizeInWords() * factor ); } @Override public SizeInWords toSizeInWords() { return this; } @Override public String toString() { return getValue()+" words"; } } public final boolean isGreaterThan(Size availableSize) { return getSizeInBytes() > availableSize.getSizeInBytes(); } public final boolean isLessThan(Size availableSize) { return getSizeInBytes() < availableSize.getSizeInBytes(); } @Override public final int compareTo(Size o) { final int s1 = getSizeInBytes(); final int s2 = o.getSizeInBytes(); if ( s1 < s2 ) { return -1; } if ( s1 > s2 ) { return 1; } return 0; } }