8269957: facilitate alternate impls of NameTable and Name
Reviewed-by: jjg, vromero
This commit is contained in:
parent
725ec0ce1b
commit
11da15d142
src/jdk.compiler/share/classes/com/sun/tools/javac
@ -5192,7 +5192,7 @@ public class Types {
|
||||
append(rawOuter ? '$' : '.');
|
||||
Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname));
|
||||
append(rawOuter
|
||||
? c.flatname.subName(c.owner.enclClass().flatname.getByteLength() + 1, c.flatname.getByteLength())
|
||||
? c.flatname.subName(c.owner.enclClass().flatname.length() + 1)
|
||||
: c.name);
|
||||
} else {
|
||||
append(externalize(c.flatname));
|
||||
|
@ -73,7 +73,7 @@ public class Gen extends JCTree.Visitor {
|
||||
private final TreeMaker make;
|
||||
private final Names names;
|
||||
private final Target target;
|
||||
private final Name accessDollar;
|
||||
private final String accessDollar;
|
||||
private final Types types;
|
||||
private final Lower lower;
|
||||
private final Annotate annotate;
|
||||
@ -112,8 +112,7 @@ public class Gen extends JCTree.Visitor {
|
||||
concat = StringConcat.instance(context);
|
||||
|
||||
methodType = new MethodType(null, null, null, syms.methodClass);
|
||||
accessDollar = names.
|
||||
fromString("access" + target.syntheticNameChar());
|
||||
accessDollar = "access" + target.syntheticNameChar();
|
||||
lower = Lower.instance(context);
|
||||
|
||||
Options options = Options.instance(context);
|
||||
@ -341,9 +340,10 @@ public class Gen extends JCTree.Visitor {
|
||||
/** Does given name start with "access$" and end in an odd digit?
|
||||
*/
|
||||
private boolean isOddAccessName(Name name) {
|
||||
final String string = name.toString();
|
||||
return
|
||||
name.startsWith(accessDollar) &&
|
||||
(name.getByteAt(name.getByteLength() - 1) & 1) == 1;
|
||||
string.startsWith(accessDollar) &&
|
||||
(string.charAt(string.length() - 1) & 1) != 0;
|
||||
}
|
||||
|
||||
/* ************************************************************************
|
||||
|
@ -27,7 +27,6 @@ package com.sun.tools.javac.jvm;
|
||||
import com.sun.tools.javac.util.ByteBuffer;
|
||||
import com.sun.tools.javac.util.ByteBuffer.UnderflowException;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import com.sun.tools.javac.util.Name.NameMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -146,10 +146,13 @@ public class ByteBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
/** Append a name.
|
||||
/** Append a name encoded in Modified UTF-8.
|
||||
*/
|
||||
public void appendName(Name name) {
|
||||
appendBytes(name.getByteArray(), name.getByteOffset(), name.getByteLength());
|
||||
int utf8len = name.getUtf8Length();
|
||||
elems = ArrayUtils.ensureCapacity(elems, length + utf8len);
|
||||
name.getUtf8Bytes(elems, length);
|
||||
length += utf8len;
|
||||
}
|
||||
|
||||
/** Append the content of the given input stream.
|
||||
|
@ -214,6 +214,24 @@ public class Convert {
|
||||
return new String(dst, 0, len1);
|
||||
}
|
||||
|
||||
/** Count the number of characters encoded in a Modified UTF-8 encoding.
|
||||
* This method does not check for invalid data.
|
||||
* @param buf data buffer
|
||||
* @param off starting offset of UTF-8 data
|
||||
* @param len number of bytes of UTF-8 data
|
||||
* @return the number of encoded characters
|
||||
*/
|
||||
public static int utfNumChars(byte[] buf, int off, int len) {
|
||||
int numChars = 0;
|
||||
while (len-- > 0) {
|
||||
int byte1 = buf[off++];
|
||||
if (byte1 < 0)
|
||||
len -= ((byte1 & 0xe0) == 0xc0) ? 1 : 2;
|
||||
numChars++;
|
||||
}
|
||||
return numChars;
|
||||
}
|
||||
|
||||
/** Copy characters in source array to bytes in target array,
|
||||
* converting them to Utf8 representation.
|
||||
* The target array must be large enough to hold the result.
|
||||
@ -346,17 +364,14 @@ public class Convert {
|
||||
|
||||
/* Conversion routines for qualified name splitting
|
||||
*/
|
||||
|
||||
/** Return the last part of a qualified name.
|
||||
* @param name the qualified name
|
||||
* @return the last part of the qualified name
|
||||
*/
|
||||
public static Name shortName(Name name) {
|
||||
int start = name.lastIndexOf((byte)'.') + 1;
|
||||
int end = name.getByteLength();
|
||||
if (start == 0 && end == name.length()) {
|
||||
return name;
|
||||
}
|
||||
return name.subName(start, end);
|
||||
int start = name.lastIndexOfAscii('.') + 1;
|
||||
return start > 0 ? name.subName(start) : name;
|
||||
}
|
||||
|
||||
/** Return the last part of a qualified name from its string representation
|
||||
@ -371,7 +386,8 @@ public class Convert {
|
||||
* "" if not existent.
|
||||
*/
|
||||
public static Name packagePart(Name classname) {
|
||||
return classname.subName(0, classname.lastIndexOf((byte)'.'));
|
||||
int end = Math.max(classname.lastIndexOfAscii('.'), 0);
|
||||
return classname.subName(0, end);
|
||||
}
|
||||
|
||||
public static String packagePart(String classname) {
|
||||
@ -382,7 +398,7 @@ public class Convert {
|
||||
public static List<Name> enclosingCandidates(Name name) {
|
||||
List<Name> names = List.nil();
|
||||
int index;
|
||||
while ((index = name.lastIndexOf((byte)'$')) > 0) {
|
||||
while ((index = name.lastIndexOfAscii('$')) > 0) {
|
||||
name = name.subName(0, index);
|
||||
names = names.prepend(name);
|
||||
}
|
||||
|
@ -27,11 +27,13 @@ package com.sun.tools.javac.util;
|
||||
|
||||
import com.sun.tools.javac.jvm.ClassFile;
|
||||
import com.sun.tools.javac.jvm.PoolConstant;
|
||||
import com.sun.tools.javac.jvm.PoolReader;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
|
||||
/** An abstraction for internal compiler strings. They are stored in
|
||||
* Utf8 format. Names are stored in a Name.Table, and are unique within
|
||||
* that table.
|
||||
/** An abstraction for internal compiler strings.
|
||||
*
|
||||
* <p>
|
||||
* Names are stored in a {@link Name.Table}, and are unique within that table.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
@ -40,76 +42,102 @@ import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
*/
|
||||
public abstract class Name implements javax.lang.model.element.Name, PoolConstant, Comparable<Name> {
|
||||
|
||||
/**
|
||||
* The {@link Table} that contains this instance.
|
||||
*/
|
||||
public final Table table;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param table the {@link Table} that will contain this instance
|
||||
*/
|
||||
protected Name(Table table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public boolean contentEquals(CharSequence cs) {
|
||||
return toString().equals(cs.toString());
|
||||
}
|
||||
// PoolConstant
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
public final int poolTag() {
|
||||
return ClassFile.CONSTANT_Utf8;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
// CharSequence
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return toString().length();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* The implementation in {@link Name} invokes {@link Object#toString}
|
||||
* on this instance and then delegates to {@link String#charAt}.
|
||||
*/
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return toString().charAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* The implementation in {@link Name} invokes {@link Object#toString}
|
||||
* on this instance and then delegates to {@link String#subSequence}.
|
||||
*/
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return toString().subSequence(start, end);
|
||||
}
|
||||
|
||||
/** Return the concatenation of this name and name `n'.
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
// javax.lang.model.element.Name
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* The implementation in {@link Name} invokes {@link Object#toString}
|
||||
* on this instance and then delegates to {@link String#equals}.
|
||||
*/
|
||||
public Name append(Name n) {
|
||||
int len = getByteLength();
|
||||
byte[] bs = new byte[len + n.getByteLength()];
|
||||
getBytes(bs, 0);
|
||||
n.getBytes(bs, len);
|
||||
try {
|
||||
return table.fromUtf(bs, 0, bs.length, Convert.Validation.NONE);
|
||||
} catch (InvalidUtfException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@Override
|
||||
public boolean contentEquals(CharSequence cs) {
|
||||
return toString().equals(cs.toString());
|
||||
}
|
||||
|
||||
/** Return the concatenation of this name, the given ASCII
|
||||
* character, and name `n'.
|
||||
*/
|
||||
public Name append(char c, Name n) {
|
||||
int len = getByteLength();
|
||||
byte[] bs = new byte[len + 1 + n.getByteLength()];
|
||||
getBytes(bs, 0);
|
||||
bs[len] = (byte) c;
|
||||
n.getBytes(bs, len+1);
|
||||
try {
|
||||
return table.fromUtf(bs, 0, bs.length, Convert.Validation.NONE);
|
||||
} catch (InvalidUtfException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj == null || obj.getClass() != getClass())
|
||||
return false;
|
||||
final Name that = (Name)obj;
|
||||
return table == that.table && nameEquals(that);
|
||||
}
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@Override
|
||||
public abstract int hashCode();
|
||||
|
||||
/**
|
||||
* Subclass check for equality.
|
||||
*
|
||||
* <p>
|
||||
* This method can assume that the given instance is the same type
|
||||
* as this instance and is associated to the same {@link Table}.
|
||||
*/
|
||||
protected abstract boolean nameEquals(Name that);
|
||||
|
||||
// Comparable
|
||||
|
||||
/** Order names lexicographically.
|
||||
*
|
||||
* <p>
|
||||
@ -119,168 +147,161 @@ public abstract class Name implements javax.lang.model.element.Name, PoolConstan
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Name name) {
|
||||
byte[] buf1 = getByteArray();
|
||||
byte[] buf2 = name.getByteArray();
|
||||
int off1 = getByteOffset();
|
||||
int off2 = name.getByteOffset();
|
||||
int len1 = getByteLength();
|
||||
int len2 = name.getByteLength();
|
||||
while (len1 > 0 && len2 > 0) {
|
||||
int val1 = buf1[off1++] & 0xff;
|
||||
int val2 = buf2[off2++] & 0xff;
|
||||
if (val1 == 0xc0 && (buf1[off1] & 0x3f) == 0) {
|
||||
val1 = 0; // char 0x0000 encoded in two bytes
|
||||
off1++;
|
||||
len1--;
|
||||
}
|
||||
if (val2 == 0xc0 && (buf2[off2] & 0x3f) == 0) {
|
||||
val2 = 0; // char 0x0000 encoded in two bytes
|
||||
off2++;
|
||||
len2--;
|
||||
}
|
||||
int diff = val1 - val2;
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
len1--;
|
||||
len2--;
|
||||
}
|
||||
return len1 > 0 ? 1 : len2 > 0 ? -1 : 0;
|
||||
return toString().compareTo(name.toString());
|
||||
}
|
||||
|
||||
/** Return true if this is the empty name.
|
||||
// Other methods
|
||||
|
||||
/** Return the concatenation of this name and the given name.
|
||||
* The given name must come from the same table as this one.
|
||||
*/
|
||||
public Name append(Name name) {
|
||||
return table.fromString(toString() + name.toString());
|
||||
}
|
||||
|
||||
/** Return the concatenation of this name, the given ASCII
|
||||
* character, and the given name.
|
||||
* The given name must come from the same table as this one.
|
||||
*/
|
||||
public Name append(char c, Name name) {
|
||||
return table.fromString(toString() + c + name.toString());
|
||||
}
|
||||
|
||||
/** Determine if this is the empty name.
|
||||
* <p>
|
||||
* The implementation in {@link Name} compares {@link #length()} to zero.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return getByteLength() == 0;
|
||||
return length() == 0;
|
||||
}
|
||||
|
||||
/** Returns last occurrence of byte b in this name, -1 if not found.
|
||||
/** Returns last occurrence of the given ASCII character in this name, -1 if not found.
|
||||
* <p>
|
||||
* The implementation in {@link Name} converts this instance to {@link String}
|
||||
* and then delegates to {@link String#lastIndexOf(int)}.
|
||||
*/
|
||||
public int lastIndexOf(byte b) {
|
||||
byte[] bytes = getByteArray();
|
||||
int offset = getByteOffset();
|
||||
int i = getByteLength() - 1;
|
||||
while (i >= 0 && bytes[offset + i] != b) i--;
|
||||
return i;
|
||||
public int lastIndexOfAscii(char ch) {
|
||||
return toString().lastIndexOf(ch);
|
||||
}
|
||||
|
||||
/** Does this name start with prefix?
|
||||
/** Determine whether this name has the given Name as a prefix.
|
||||
* <p>
|
||||
* The implementation in {@link Name} converts this and the given instance
|
||||
* to {@link String} and then delegates to {@link String#startsWith}.
|
||||
*/
|
||||
public boolean startsWith(Name prefix) {
|
||||
byte[] thisBytes = this.getByteArray();
|
||||
int thisOffset = this.getByteOffset();
|
||||
int thisLength = this.getByteLength();
|
||||
byte[] prefixBytes = prefix.getByteArray();
|
||||
int prefixOffset = prefix.getByteOffset();
|
||||
int prefixLength = prefix.getByteLength();
|
||||
|
||||
if (thisLength < prefixLength)
|
||||
return false;
|
||||
|
||||
int i = 0;
|
||||
while (i < prefixLength &&
|
||||
thisBytes[thisOffset + i] == prefixBytes[prefixOffset + i])
|
||||
i++;
|
||||
return i == prefixLength;
|
||||
return toString().startsWith(prefix.toString());
|
||||
}
|
||||
|
||||
/** Returns the sub-name starting at position start, up to and
|
||||
* excluding position end.
|
||||
/** Returns the sub-name extending between two character positions.
|
||||
* <p>
|
||||
* The implementation in {@link Name} converts this instance to {@link String},
|
||||
* delegates to {@link String#substring(int, int)} and then {@link Table#fromString}.
|
||||
* @param start starting character offset, inclusive
|
||||
* @param end ending character offset, exclusive
|
||||
* @throws IndexOutOfBoundsException if bounds are out of range or invalid
|
||||
*/
|
||||
public Name subName(int start, int end) {
|
||||
if (end < start) end = start;
|
||||
try {
|
||||
return table.fromUtf(getByteArray(), getByteOffset() + start, end - start, Convert.Validation.NONE);
|
||||
} catch (InvalidUtfException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return table.fromString(toString().substring(start, end));
|
||||
}
|
||||
|
||||
/** Return the string representation of this name.
|
||||
/** Returns the suffix of this name starting at the given offset.
|
||||
* <p>
|
||||
* The implementation in {@link Name} converts this instance to {@link String},
|
||||
* delegates to {@link String#substring(int)}, and then to {@link Table#fromString}.
|
||||
* @param off starting character offset
|
||||
* @throws IndexOutOfBoundsException if {@code off} is out of range or invalid
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return Convert.utf2string(getByteArray(), getByteOffset(), getByteLength(), Convert.Validation.NONE);
|
||||
} catch (InvalidUtfException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
public Name subName(int off) {
|
||||
return table.fromString(toString().substring(off));
|
||||
}
|
||||
|
||||
/** Return the Utf8 representation of this name.
|
||||
/** Return the Modified UTF-8 encoding of this name.
|
||||
* <p>
|
||||
* The implementation in {@link Name} populates a new byte array of length
|
||||
* {@link #getUtf8Length} with data from {@link #getUtf8Bytes}.
|
||||
*/
|
||||
public byte[] toUtf() {
|
||||
byte[] bs = new byte[getByteLength()];
|
||||
getBytes(bs, 0);
|
||||
byte[] bs = new byte[getUtf8Length()];
|
||||
getUtf8Bytes(bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
/* Get a "reasonably small" value that uniquely identifies this name
|
||||
* within its name table.
|
||||
/** Get the length of the Modified UTF-8 encoding of this name.
|
||||
*/
|
||||
public abstract int getIndex();
|
||||
public abstract int getUtf8Length();
|
||||
|
||||
/** Get the length (in bytes) of this name.
|
||||
/** Write the Modified UTF-8 encoding of this name into the given
|
||||
* buffer starting at the specified offset.
|
||||
*/
|
||||
public abstract int getByteLength();
|
||||
public abstract void getUtf8Bytes(byte buf[], int off);
|
||||
|
||||
/** Returns i'th byte of this name.
|
||||
// Mapping
|
||||
|
||||
/** Maps the Modified UTF-8 encoding of a {@link Name} to something.
|
||||
*/
|
||||
public abstract byte getByteAt(int i);
|
||||
|
||||
/** Copy all bytes of this name to buffer cs, starting at start.
|
||||
*/
|
||||
public void getBytes(byte cs[], int start) {
|
||||
System.arraycopy(getByteArray(), getByteOffset(), cs, start, getByteLength());
|
||||
}
|
||||
|
||||
/** Get the underlying byte array for this name. The contents of the
|
||||
* array must not be modified.
|
||||
*/
|
||||
public abstract byte[] getByteArray();
|
||||
|
||||
/** Get the start offset of this name within its byte array.
|
||||
*/
|
||||
public abstract int getByteOffset();
|
||||
|
||||
@FunctionalInterface
|
||||
public interface NameMapper<X> {
|
||||
X map(byte[] bytes, int offset, int len);
|
||||
}
|
||||
|
||||
/** Decode this name's Modified UTF-8 encoding into something.
|
||||
*/
|
||||
public <X> X map(NameMapper<X> mapper) {
|
||||
return mapper.map(getByteArray(), getByteOffset(), getByteLength());
|
||||
byte[] buf = toUtf();
|
||||
return mapper.map(buf, 0, buf.length);
|
||||
}
|
||||
|
||||
/** An abstraction for the hash table used to create unique Name instances.
|
||||
// Table
|
||||
|
||||
/** An abstraction for the hash table used to create unique {@link Name} instances.
|
||||
*/
|
||||
public abstract static class Table {
|
||||
|
||||
/** Standard name table.
|
||||
*/
|
||||
public final Names names;
|
||||
|
||||
Table(Names names) {
|
||||
protected Table(Names names) {
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
/** Get the name from the characters in cs[start..start+len-1].
|
||||
/** Get the unique {@link Name} corresponding to the given characters.
|
||||
* @param buf character buffer
|
||||
* @param off starting offset
|
||||
* @param len number of characters
|
||||
* @return the corresponding {@link Name}
|
||||
*/
|
||||
public abstract Name fromChars(char[] cs, int start, int len);
|
||||
public abstract Name fromChars(char[] cs, int off, int len);
|
||||
|
||||
/** Get the name for the characters in string s.
|
||||
/** Get the unique {@link Name} corresponding to the given string.
|
||||
* <p>
|
||||
* The implementation in {@link Table} delegates to {@link String#toCharArray}
|
||||
* and then {@link #fromChars}.
|
||||
* @param s character string
|
||||
*/
|
||||
public Name fromString(String s) {
|
||||
char[] cs = s.toCharArray();
|
||||
return fromChars(cs, 0, cs.length);
|
||||
}
|
||||
|
||||
/** Get the name for the bytes in array cs.
|
||||
* Assume that bytes are in strictly valid "Modified UTF-8" format.
|
||||
/** Get the unique {@link Name} corresponding to the given Modified UTF-8 encoding.
|
||||
* <p>
|
||||
* The implementation in {@link Table} delegates to {@link #fromUtf(byte[], int, int)}.
|
||||
* @param buf character string
|
||||
* @return the corresponding {@link Name}
|
||||
* @throws IllegalArgumentException if the data is not valid Modified UTF-8
|
||||
*/
|
||||
public Name fromUtf(byte[] cs) throws InvalidUtfException {
|
||||
return fromUtf(cs, 0, cs.length, Convert.Validation.STRICT);
|
||||
}
|
||||
|
||||
/** get the name for the bytes in cs[start..start+len-1].
|
||||
* Assume that bytes are in utf8 format.
|
||||
/** Get the unique {@link Name} corresponding to the given Modified UTF-8 encoding.
|
||||
* @param buf character buffer
|
||||
* @param off starting offset
|
||||
* @param len number of bytes
|
||||
* @return the corresponding {@link Name}
|
||||
* @throws IllegalArgumentException if the data is not valid Modified UTF-8
|
||||
* @throws InvalidUtfException if invalid Modified UTF-8 is encountered
|
||||
*/
|
||||
public abstract Name fromUtf(byte[] cs, int start, int len, Convert.Validation validation)
|
||||
@ -289,28 +310,5 @@ public abstract class Name implements javax.lang.model.element.Name, PoolConstan
|
||||
/** Release any resources used by this table.
|
||||
*/
|
||||
public abstract void dispose();
|
||||
|
||||
/** The hashcode of a name.
|
||||
*/
|
||||
protected static int hashValue(byte bytes[], int offset, int length) {
|
||||
int h = 0;
|
||||
int off = offset;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
h = (h << 5) - h + bytes[off++];
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/** Compare two subarrays
|
||||
*/
|
||||
protected static boolean equals(byte[] bytes1, int offset1,
|
||||
byte[] bytes2, int offset2, int length) {
|
||||
int i = 0;
|
||||
while (i < length && bytes1[offset1 + i] == bytes2[offset2 + i]) {
|
||||
i++;
|
||||
}
|
||||
return i == length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -428,11 +428,25 @@ public class Names {
|
||||
}
|
||||
|
||||
protected Name.Table createTable(Options options) {
|
||||
boolean useStringTable = options.isSet("useStringTable");
|
||||
if (useStringTable)
|
||||
return newStringNameTable();
|
||||
boolean useUnsharedTable = options.isSet("useUnsharedTable");
|
||||
if (useUnsharedTable)
|
||||
return UnsharedNameTable.create(this);
|
||||
else
|
||||
return SharedNameTable.create(this);
|
||||
return newUnsharedNameTable();
|
||||
return newSharedNameTable();
|
||||
}
|
||||
|
||||
public StringNameTable newStringNameTable() {
|
||||
return StringNameTable.create(this);
|
||||
}
|
||||
|
||||
public SharedNameTable newSharedNameTable() {
|
||||
return SharedNameTable.create(this);
|
||||
}
|
||||
|
||||
public UnsharedNameTable newUnsharedNameTable() {
|
||||
return UnsharedNameTable.create(this);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
@ -39,7 +39,7 @@ import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class SharedNameTable extends Name.Table {
|
||||
public class SharedNameTable extends Utf8NameTable {
|
||||
// maintain a freelist of recently used name tables for reuse.
|
||||
private static List<SoftReference<SharedNameTable>> freelist = List.nil();
|
||||
|
||||
@ -79,19 +79,23 @@ public class SharedNameTable extends Name.Table {
|
||||
* @param hashSize the (constant) size to be used for the hash table
|
||||
* needs to be a power of two.
|
||||
* @param nameSize the initial size of the name table.
|
||||
* @throws IllegalArgumentException if {@code hashSize} is not a power of two
|
||||
*/
|
||||
public SharedNameTable(Names names, int hashSize, int nameSize) {
|
||||
super(names);
|
||||
if (Integer.bitCount(hashSize) != 1)
|
||||
throw new IllegalArgumentException(); // hashSize is not a power of two
|
||||
hashMask = hashSize - 1;
|
||||
hashes = new NameImpl[hashSize];
|
||||
bytes = new byte[nameSize];
|
||||
|
||||
}
|
||||
|
||||
public SharedNameTable(Names names) {
|
||||
this(names, 0x8000, 0x20000);
|
||||
}
|
||||
|
||||
// Name.Table
|
||||
|
||||
@Override
|
||||
public Name fromChars(char[] cs, int start, int len) {
|
||||
int nc = this.nc;
|
||||
@ -104,17 +108,8 @@ public class SharedNameTable extends Name.Table {
|
||||
!equals(bytes, n.index, bytes, nc, nbytes))) {
|
||||
n = n.next;
|
||||
}
|
||||
if (n == null) {
|
||||
n = new NameImpl(this);
|
||||
n.index = nc;
|
||||
n.length = nbytes;
|
||||
n.next = hashes[h];
|
||||
hashes[h] = n;
|
||||
this.nc = nc + nbytes;
|
||||
if (nbytes == 0) {
|
||||
this.nc++;
|
||||
}
|
||||
}
|
||||
if (n == null)
|
||||
n = addName(nc, nbytes, h);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -130,86 +125,71 @@ public class SharedNameTable extends Name.Table {
|
||||
n = n.next;
|
||||
}
|
||||
if (n == null) {
|
||||
int nc = this.nc;
|
||||
names = this.bytes = ArrayUtils.ensureCapacity(names, nc + len);
|
||||
System.arraycopy(cs, start, names, nc, len);
|
||||
n = new NameImpl(this);
|
||||
n.index = nc;
|
||||
n.length = len;
|
||||
n.next = hashes[h];
|
||||
hashes[h] = n;
|
||||
this.nc = nc + len;
|
||||
if (len == 0) {
|
||||
this.nc++;
|
||||
}
|
||||
n = addName(nc, len, h);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private NameImpl addName(int index, int len, int hash) {
|
||||
NameImpl name = new NameImpl(this, index, len, hashes[hash]);
|
||||
hashes[hash] = name;
|
||||
this.nc = index + Math.max(len, 1);
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
dispose(this);
|
||||
}
|
||||
|
||||
static class NameImpl extends Name {
|
||||
// NameImpl
|
||||
|
||||
static final class NameImpl extends Utf8NameTable.NameImpl {
|
||||
|
||||
/** The next name occupying the same hash bucket.
|
||||
*/
|
||||
NameImpl next;
|
||||
final NameImpl next;
|
||||
|
||||
/** The index where the bytes of this name are stored in the global name
|
||||
* buffer `byte'.
|
||||
*/
|
||||
int index;
|
||||
final int index;
|
||||
|
||||
/** The number of bytes in this name.
|
||||
*/
|
||||
int length;
|
||||
final int length;
|
||||
|
||||
NameImpl(SharedNameTable table) {
|
||||
// Constructor
|
||||
|
||||
NameImpl(SharedNameTable table, int index, int length, NameImpl next) {
|
||||
super(table);
|
||||
this.index = index;
|
||||
this.length = length;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
// Utf8NameTable.NameImpl
|
||||
|
||||
@Override
|
||||
protected byte[] getByteData() {
|
||||
return ((SharedNameTable)table).bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
protected int getByteOffset() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getByteLength() {
|
||||
protected int getByteLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByteAt(int i) {
|
||||
return getByteArray()[index + i];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
return ((SharedNameTable) table).bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getByteOffset() {
|
||||
protected int getNameIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/** Return the hash value of this name.
|
||||
*/
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public int hashCode() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/** Is this name equal to other?
|
||||
*/
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public boolean equals(Object other) {
|
||||
return (other instanceof Name name)
|
||||
&& table == name.table
|
||||
&& index == name.getIndex();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Straightforward implementation of {@link Name.Table} using {@link String}s.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class StringNameTable extends Name.Table {
|
||||
|
||||
private final HashMap<String, Name> nameMap;
|
||||
|
||||
// Factory
|
||||
|
||||
public static StringNameTable create(Names names) {
|
||||
return new StringNameTable(names);
|
||||
}
|
||||
|
||||
// Constructors
|
||||
|
||||
public StringNameTable(Names names) {
|
||||
this(names, 0x8000);
|
||||
}
|
||||
|
||||
public StringNameTable(Names names, int initialCapacity) {
|
||||
super(names);
|
||||
this.nameMap = new HashMap<>(initialCapacity);
|
||||
}
|
||||
|
||||
// Name.Table
|
||||
|
||||
@Override
|
||||
public Name fromString(String string) {
|
||||
return this.nameMap.computeIfAbsent(string, s -> new NameImpl(this, s));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Name fromChars(char[] buf, int off, int len) {
|
||||
return this.fromString(new String(buf, off, len));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Name fromUtf(byte[] buf, int off, int len, Convert.Validation validation) throws InvalidUtfException {
|
||||
return this.fromString(Convert.utf2string(buf, off, len, validation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
this.nameMap.clear();
|
||||
}
|
||||
|
||||
// NameImpl
|
||||
|
||||
private static final class NameImpl extends Name {
|
||||
|
||||
private final String string;
|
||||
|
||||
// Constructor
|
||||
|
||||
NameImpl(StringNameTable table, String string) {
|
||||
super(table);
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contentEquals(CharSequence cs) {
|
||||
return string.contentEquals(cs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean nameEquals(Name that) {
|
||||
return ((NameImpl)that).string.equals(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return string.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUtf8Length() {
|
||||
int slen = string.length();
|
||||
int extra = 0;
|
||||
for (int i = 0; i < slen; i++) {
|
||||
int ch = string.charAt(i);
|
||||
if (ch > 0x007f || ch == 0x0000) {
|
||||
extra++;
|
||||
if (ch > 0x07ff)
|
||||
extra++;
|
||||
}
|
||||
}
|
||||
return slen + extra;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getUtf8Bytes(byte buf[], int off) {
|
||||
Convert.chars2utf(string.toCharArray(), 0, buf, off, string.length());
|
||||
}
|
||||
}
|
||||
}
|
@ -37,8 +37,8 @@ import java.lang.ref.WeakReference;
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class UnsharedNameTable extends Name.Table {
|
||||
public static Name.Table create(Names names) {
|
||||
public class UnsharedNameTable extends Utf8NameTable {
|
||||
public static UnsharedNameTable create(Names names) {
|
||||
return new UnsharedNameTable(names);
|
||||
}
|
||||
|
||||
@ -61,13 +61,18 @@ public class UnsharedNameTable extends Name.Table {
|
||||
*/
|
||||
public int index;
|
||||
|
||||
// Constructors
|
||||
|
||||
/** Allocator
|
||||
* @param names The main name table
|
||||
* @param hashSize the (constant) size to be used for the hash table
|
||||
* needs to be a power of two.
|
||||
* @throws IllegalArgumentException if {@code hashSize} is not a power of two
|
||||
*/
|
||||
public UnsharedNameTable(Names names, int hashSize) {
|
||||
super(names);
|
||||
if (Integer.bitCount(hashSize) != 1)
|
||||
throw new IllegalArgumentException(); // hashSize is not a power of two
|
||||
hashMask = hashSize - 1;
|
||||
hashes = new HashEntry[hashSize];
|
||||
}
|
||||
@ -76,6 +81,7 @@ public class UnsharedNameTable extends Name.Table {
|
||||
this(names, 0x8000);
|
||||
}
|
||||
|
||||
// Name.Table
|
||||
|
||||
@Override
|
||||
public Name fromChars(char[] cs, int start, int len) {
|
||||
@ -145,41 +151,41 @@ public class UnsharedNameTable extends Name.Table {
|
||||
hashes = null;
|
||||
}
|
||||
|
||||
static class NameImpl extends Name {
|
||||
// NameImpl
|
||||
|
||||
static final class NameImpl extends Utf8NameTable.NameImpl {
|
||||
|
||||
final byte[] bytes;
|
||||
final int index;
|
||||
|
||||
// Constructor
|
||||
|
||||
NameImpl(UnsharedNameTable table, byte[] bytes, int index) {
|
||||
super(table);
|
||||
this.bytes = bytes;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
final byte[] bytes;
|
||||
final int index;
|
||||
// Utf8NameTable.NameImpl
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getByteLength() {
|
||||
return bytes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByteAt(int i) {
|
||||
return bytes[i];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
protected byte[] getByteData() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getByteOffset() {
|
||||
protected int getByteOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
protected int getByteLength() {
|
||||
return bytes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getNameIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.util;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
|
||||
/**
|
||||
* Support superclass for {@link Name.Table} implementations that store
|
||||
* names as Modified UTF-8 data in {@code byte[]} arrays.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public abstract class Utf8NameTable extends Name.Table {
|
||||
|
||||
/** Constructor.
|
||||
* @param names The main name table
|
||||
*/
|
||||
protected Utf8NameTable(Names names) {
|
||||
super(names);
|
||||
}
|
||||
|
||||
// Utility methods
|
||||
|
||||
/** Generate a hash value for a subarray.
|
||||
*/
|
||||
protected static int hashValue(byte buf[], int off, int len) {
|
||||
int hash = 0;
|
||||
while (len-- > 0)
|
||||
hash = (hash << 5) - hash + buf[off++];
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** Compare two subarrays.
|
||||
*/
|
||||
protected static boolean equals(byte[] buf1, int off1, byte[] buf2, int off2, int len) {
|
||||
while (len-- > 0) {
|
||||
if (buf1[off1++] != buf2[off2++])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// NameImpl
|
||||
|
||||
protected abstract static class NameImpl extends Name {
|
||||
|
||||
// Constructor
|
||||
|
||||
NameImpl(Utf8NameTable table) {
|
||||
super(table);
|
||||
}
|
||||
|
||||
// Subclass hooks
|
||||
|
||||
/**
|
||||
* Get the {@code byte[]} array in which the Modified UTF-8 data is stored.
|
||||
*/
|
||||
protected abstract byte[] getByteData();
|
||||
|
||||
/**
|
||||
* Get the Modified UTF-8 data offset into the byte array.
|
||||
*/
|
||||
protected abstract int getByteOffset();
|
||||
|
||||
/**
|
||||
* Get the Modified UTF-8 data length in the byte array.
|
||||
*/
|
||||
protected abstract int getByteLength();
|
||||
|
||||
/**
|
||||
* Get a unique index corresponding to this instance.
|
||||
*/
|
||||
protected abstract int getNameIndex();
|
||||
|
||||
// CharSequence
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return Convert.utfNumChars(getByteData(), getByteOffset(), getByteLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return Convert.utf2string(getByteData(), getByteOffset(), getByteLength(), Convert.Validation.NONE);
|
||||
} catch (InvalidUtfException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
// javax.lang.model.element.Name
|
||||
|
||||
@Override
|
||||
protected boolean nameEquals(Name that) {
|
||||
return ((NameImpl)that).getNameIndex() == getNameIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getNameIndex();
|
||||
}
|
||||
|
||||
// Comparable
|
||||
|
||||
@Override
|
||||
public int compareTo(Name name0) {
|
||||
NameImpl name = (NameImpl)name0;
|
||||
Assert.check(name.table == table);
|
||||
byte[] buf1 = getByteData();
|
||||
byte[] buf2 = name.getByteData();
|
||||
int off1 = getByteOffset();
|
||||
int off2 = name.getByteOffset();
|
||||
int len1 = getByteLength();
|
||||
int len2 = name.getByteLength();
|
||||
while (len1 > 0 && len2 > 0) {
|
||||
int val1 = buf1[off1++] & 0xff;
|
||||
int val2 = buf2[off2++] & 0xff;
|
||||
if (val1 == 0xc0 && (buf1[off1] & 0x3f) == 0) {
|
||||
val1 = 0; // char 0x0000 encoded in two bytes
|
||||
off1++;
|
||||
len1--;
|
||||
}
|
||||
if (val2 == 0xc0 && (buf2[off2] & 0x3f) == 0) {
|
||||
val2 = 0; // char 0x0000 encoded in two bytes
|
||||
off2++;
|
||||
len2--;
|
||||
}
|
||||
int diff = val1 - val2;
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
len1--;
|
||||
len2--;
|
||||
}
|
||||
return len1 > 0 ? 1 : len2 > 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
// Name
|
||||
|
||||
@Override
|
||||
public Name append(Name name0) {
|
||||
NameImpl name = (NameImpl)name0;
|
||||
Assert.check(name.table == table);
|
||||
byte[] buf1 = getByteData();
|
||||
byte[] buf2 = name.getByteData();
|
||||
int off1 = getByteOffset();
|
||||
int off2 = name.getByteOffset();
|
||||
int len1 = getByteLength();
|
||||
int len2 = name.getByteLength();
|
||||
byte[] result = new byte[len1 + len2];
|
||||
System.arraycopy(buf1, off1, result, 0, len1);
|
||||
System.arraycopy(buf2, off2, result, len1, len2);
|
||||
try {
|
||||
return table.fromUtf(result, 0, result.length, Convert.Validation.NONE);
|
||||
} catch (InvalidUtfException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Name append(char ch, Name name0) {
|
||||
Assert.check((ch & ~0x7f) == 0);
|
||||
NameImpl name = (NameImpl)name0;
|
||||
Assert.check(name.table == table);
|
||||
byte[] buf1 = getByteData();
|
||||
byte[] buf2 = name.getByteData();
|
||||
int off1 = getByteOffset();
|
||||
int off2 = name.getByteOffset();
|
||||
int len1 = getByteLength();
|
||||
int len2 = name.getByteLength();
|
||||
byte[] result = new byte[len1 + 1 + len2];
|
||||
System.arraycopy(buf1, off1, result, 0, len1);
|
||||
result[len1] = (byte)ch;
|
||||
System.arraycopy(buf2, off2, result, len1 + 1, len2);
|
||||
try {
|
||||
return table.fromUtf(result, 0, result.length, Convert.Validation.NONE);
|
||||
} catch (InvalidUtfException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOfAscii(char ch) {
|
||||
Assert.check((ch & ~0x7f) == 0);
|
||||
|
||||
// Find the last *byte* index of 'ch'
|
||||
byte b = (byte)ch;
|
||||
byte[] buf = getByteData();
|
||||
int off = getByteOffset();
|
||||
int len = getByteLength();
|
||||
int pos = len - 1;
|
||||
while (pos >= 0 && buf[off + pos] != b)
|
||||
pos--;
|
||||
|
||||
// Not found, or index is zero?
|
||||
if (pos <= 0)
|
||||
return pos;
|
||||
|
||||
// Convert the byte index into a char index
|
||||
return Convert.utfNumChars(buf, off, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startsWith(Name prefix0) {
|
||||
NameImpl prefix = (NameImpl)prefix0;
|
||||
Assert.check(prefix.table == table);
|
||||
int thisLen = getByteLength();
|
||||
int prefLen = prefix.getByteLength();
|
||||
if (thisLen < prefLen)
|
||||
return false;
|
||||
byte[] thisData = getByteData();
|
||||
byte[] prefData = prefix.getByteData();
|
||||
int thisOff = getByteOffset() + prefLen;
|
||||
int prefOff = prefix.getByteOffset() + prefLen;
|
||||
while (prefLen-- > 0) {
|
||||
if (thisData[--thisOff] != prefData[--prefOff])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUtf8Length() {
|
||||
return getByteLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getUtf8Bytes(byte buf[], int off) {
|
||||
System.arraycopy(getByteData(), getByteOffset(), buf, off, getByteLength());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user