Created
July 14, 2019 04:55
-
-
Save zhoulifu/8491bc97c26196ae95a8c62d1622ef2a to your computer and use it in GitHub Desktop.
bytes array based ascii sequence
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Arrays; | |
import java.util.Objects; | |
public class AsciiSequence implements CharSequence { | |
private static final AsciiSequence EMPTY_STRING = | |
new AsciiSequence(new byte[0]); | |
final byte[] value; | |
final int offset; | |
final int length; | |
private int hash = -1; | |
private String string = null; | |
public AsciiSequence(byte[] value) { | |
this(value, 0, true); | |
} | |
public AsciiSequence(byte[] value, boolean share) { | |
this(value, 0, share); | |
} | |
public AsciiSequence(byte[] value, int offset, boolean share) { | |
this(Objects.requireNonNull(value), offset, value.length, share); | |
} | |
public AsciiSequence(byte[] value, int offset, int length, boolean share) { | |
if (isOutOfBounds(offset, length, value.length)) { | |
throw new IndexOutOfBoundsException("expected: " + "0 <= offset(" + offset + ") <= offset + length(" + | |
length + ") <= " + "value.length(" + value.length + ')'); | |
} | |
for (int i = offset; i < (offset + length); i++) { | |
if (value[i] != (value[i] & 0x7f)) { | |
throw new IllegalArgumentException( | |
value[i] + " is not a valid ascii character"); | |
} | |
} | |
if (share) { | |
this.value = value; | |
this.offset = offset; | |
} else { | |
this.value = Arrays.copyOfRange(value, offset, offset + length); | |
this.offset = 0; | |
} | |
this.length = length; | |
} | |
private AsciiSequence(byte[] value, int offset, int length) { | |
this.value = value; | |
this.offset = offset; | |
this.length = length; | |
} | |
@Override | |
public int length() { | |
return length; | |
} | |
@Override | |
public char charAt(int index) { | |
return (char) byteAt(index); | |
} | |
public byte byteAt(int index) { | |
if (index < 0 || index >= length) { | |
throw new IndexOutOfBoundsException("index: " + index + " must be in the range [0," + length + ")"); | |
} | |
return value[index + offset]; | |
} | |
@Override | |
public AsciiSequence subSequence(int start, int end) { | |
return slice(start, end, true); | |
} | |
public AsciiSequence slice(int start) { | |
return slice(start, length(), true); | |
} | |
public AsciiSequence slice(int start, int end) { | |
return slice(start, end, true); | |
} | |
public AsciiSequence slice(int start, int end, boolean share) { | |
if (start == 0 && end == length()) { | |
return this; | |
} | |
if (end == start) { | |
return EMPTY_STRING; | |
} | |
int len = end - start; | |
if (isOutOfBounds(start, len, length())) { | |
throw new IndexOutOfBoundsException("expected: 0 <= start(" + start + ") <= end (" + end + ") <= length(" | |
+ length() + ')'); | |
} | |
return (share) ? | |
new AsciiSequence(this.value, offset + start, len) : | |
new AsciiSequence(Arrays.copyOfRange(this.value, offset + start, offset + start + len), 0, len); | |
} | |
/** | |
* @see Arrays#hashCode(byte[]) | |
*/ | |
@Override | |
public int hashCode() { | |
if (hash != -1) { | |
return hash; | |
} | |
int result = 1; | |
for (int i = offset; i <(offset + length) ; i++) { | |
result = 31 * result + value[i]; | |
} | |
hash = result; | |
return hash; | |
} | |
@Override | |
public boolean equals(Object obj) { | |
if (obj == null || obj.getClass() != AsciiSequence.class) { | |
return false; | |
} | |
if (this == obj) { | |
return true; | |
} | |
AsciiSequence other = (AsciiSequence) obj; | |
return length() == other.length() && | |
hashCode() == other.hashCode() && | |
valueEquals(value, offset, other.value, other.offset, length()); | |
} | |
@Override | |
public String toString() { | |
String cache = string; | |
if (cache == null) { | |
cache = _toString(); | |
string = cache; | |
} | |
return cache; | |
} | |
private String _toString() { | |
if (length == 0) { | |
return ""; | |
} | |
@SuppressWarnings("deprecation") | |
final String str = new String(value, 0, offset, length); | |
return str; | |
} | |
public static boolean isOutOfBounds(int index, int length, int capacity) { | |
return (index | length | (index + length) | (capacity - (index + length))) < 0; | |
} | |
private static boolean valueEquals(byte[] a1, int offset1, byte[] a2, int offset2, int length) { | |
if (a1 == a2 && offset1 == offset2) { | |
return true; | |
} | |
for (int i = 0; i < length; i++) { | |
if (a1[offset1 + i] != a2[offset2 + i]) { | |
return false; | |
} | |
} | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment