Refactor concat, add __concat metatag

This commit is contained in:
James Roseborough
2010-08-22 17:35:08 +00:00
parent 31c7c5f2b5
commit 02b22b1e0d
10 changed files with 227 additions and 64 deletions

View File

@@ -28,9 +28,12 @@ package org.luaj.vm2;
*/
public final class Buffer {
private static final int DEFAULT_CAPACITY = 64;
private static final byte[] NOBYTES = {};
private byte[] bytes;
private int length;
private int offset;
private LuaValue value;
public Buffer() {
this(DEFAULT_CAPACITY);
@@ -39,63 +42,98 @@ public final class Buffer {
public Buffer( int initialCapacity ) {
bytes = new byte[ initialCapacity ];
length = 0;
offset = 0;
value = null;
}
public final String tojstring() {
return LuaString.valueOf(bytes, 0, length).tojstring();
public Buffer(LuaValue value) {
bytes = NOBYTES;
length = offset = 0;
this.value = value;
}
public final Buffer append( byte b ) {
ensureCapacity( length + 1 );
bytes[ length++ ] = b;
public LuaValue value() {
return value != null? value: this.tostring();
}
public Buffer setvalue(LuaValue value) {
bytes = NOBYTES;
offset = length = 0;
this.value = value;
return this;
}
public final LuaString tostring() {
realloc( length, 0 );
return LuaString.valueOf( bytes, offset, length );
}
public String tojstring() {
return value().tojstring();
}
public String toString() {
return tojstring();
}
public final Buffer append( byte b ) {
makeroom( 0, 1 );
bytes[ offset + length++ ] = b;
return this;
}
public final Buffer append( LuaValue val ) {
if ( ! val.isstring() )
val.error("attempt to concatenate a '"+val.typename()+"' value");
append( val.strvalue() );
return this;
}
public final Buffer append( LuaString str ) {
final int alen = str.length();
ensureCapacity( length + alen );
str.copyInto( 0, bytes, length, alen );
length += alen;
final int n = str.m_length;
makeroom( 0, n );
str.copyInto( 0, bytes, offset + length, n );
length += n;
return this;
}
public final Buffer append( String str ) {
char[] chars = str.toCharArray();
final int alen = LuaString.lengthAsUtf8( chars );
ensureCapacity( length + alen );
LuaString.encodeToUtf8( chars, bytes, length );
length += alen;
final int n = LuaString.lengthAsUtf8( chars );
makeroom( 0, n );
LuaString.encodeToUtf8( chars, bytes, offset + length );
length += n;
return this;
}
public Buffer prepend(LuaString s) {
int n = s.m_length;
makeroom( n, 0 );
System.arraycopy( s.m_bytes, s.m_offset, bytes, offset-n, n );
offset -= n;
length += n;
value = null;
return this;
}
public final void setLength( int length ) {
ensureCapacity( length );
this.length = length;
public final void makeroom( int nbefore, int nafter ) {
if ( value != null ) {
LuaString s = value.strvalue();
value = null;
bytes = new byte[nbefore+s.m_length+nafter];
length = s.m_length;
offset = nbefore;
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset, length);
} else if ( offset+length+nafter > bytes.length || offset<nbefore ) {
realloc( Math.max(nbefore+length+nafter,length*2), nbefore );
}
}
public final LuaString tostring() {
return LuaString.valueOf( realloc( bytes, length ) );
}
public final void ensureCapacity( int minSize ) {
if ( minSize > bytes.length )
realloc( minSize );
}
private final void realloc( int minSize ) {
bytes = realloc( bytes, Math.max( bytes.length * 2, minSize ) );
}
private final static byte[] realloc( byte[] b, int newSize ) {
byte[] newBytes = new byte[ newSize ];
System.arraycopy( b, 0, newBytes, 0, Math.min( b.length, newSize ) );
return newBytes;
private final void realloc( int newSize, int newOffset ) {
if ( newSize != bytes.length ) {
byte[] newBytes = new byte[ newSize ];
System.arraycopy( bytes, offset, newBytes, newOffset, length );
bytes = newBytes;
offset = newOffset;
}
}
}

View File

@@ -236,10 +236,14 @@ public class LuaClosure extends LuaFunction {
b = i>>>23;
c = (i>>14)&0x1ff;
{
Buffer sb = new Buffer();
for ( ; b<=c; )
sb.append( stack[b++] );
stack[a] = sb.tostring();
LuaValue r = stack[c-1].concat(stack[c]);
if ( (c-=2) >= b ) {
Buffer sb = r.buffer();
while ( c>=b )
sb = stack[c--].concat(sb);
r = sb.value();
}
stack[a] = r;
}
continue;

View File

@@ -148,11 +148,7 @@ public class LuaDouble extends LuaNumber {
// string comparison
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
// concatenation
public String concat_s(LuaValue rhs) { return rhs.concatTo_s(Double.toString(v)); }
public String concatTo_s(String lhs) { return lhs + v; }
public String tojstring() {
/*
if ( v == 0.0 ) { // never occurs in J2me

View File

@@ -165,10 +165,6 @@ public class LuaInteger extends LuaNumber {
// string comparison
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
// concatenation
public String concat_s(LuaValue rhs) { return rhs.concatTo_s(Integer.toString(v)); }
public String concatTo_s(String lhs) { return lhs + v; }
public int checkint() {
return v;
}

View File

@@ -61,4 +61,10 @@ public class LuaNumber extends LuaValue {
public LuaValue getmetatable() {
return s_metatable;
}
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.prepend(this.strvalue()); }
public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); }
}

View File

@@ -155,8 +155,15 @@ public class LuaString extends LuaValue {
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
// concatenation
public String concat_s(LuaValue rhs) { return rhs.concatTo_s(tojstring()); }
public String concatTo_s(String lhs) { return lhs + tojstring(); }
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.prepend(this); }
public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) {
byte[] b = new byte[lhs.m_length+this.m_length];
System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
return new LuaString(b, 0, b.length);
}
// string comparison
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }

View File

@@ -78,6 +78,7 @@ public class LuaValue extends Varargs {
public static final LuaString LT = valueOf("__lt");
public static final LuaString LE = valueOf("__le");
public static final LuaString TOSTRING = valueOf("__tostring");
public static final LuaString CONCAT = valueOf("__concat");
public static final LuaString EMPTYSTRING = valueOf("");
private static int MAXSTACK = 250;
@@ -343,9 +344,20 @@ public class LuaValue extends Varargs {
public int strcmp( LuaString rhs ) { error("attempt to compare "+typename()); return 0; }
// concatenation
public LuaValue concat( LuaValue rhs ) { return valueOf(concat_s(rhs)); }
public String concat_s( LuaValue rhs ) { error("attempt to concatenate "+this.typename()); return null; }
public String concatTo_s( String lhs ) { error("attempt to concatenate "+this.typename()); return null; }
public LuaValue concat(LuaValue rhs) { return this.concatmt(rhs); }
public LuaValue concatTo(LuaNumber lhs) { return lhs.concatmt(this); }
public LuaValue concatTo(LuaString lhs) { return lhs.concatmt(this); }
public Buffer buffer() { return new Buffer(this); }
public Buffer concat(Buffer rhs) {
return rhs.setvalue(checkmetatag(CONCAT,"attempt to concatenate ").call(this, rhs.value()));
}
public LuaValue concatmt(LuaValue rhs) {
LuaValue h=metatag(CONCAT);
LuaValue v=this;
if ( h.isnil() || (h=(v=rhs).metatag(CONCAT)).isnil())
v.typerror("attempt to concatenate ");
return h.call(this,rhs);
}
// boolean operators
public LuaValue and( LuaValue rhs ) { return this.toboolean()? rhs: this; }
@@ -577,5 +589,4 @@ public class LuaValue extends Varargs {
}
}
}