package nebula.simpletemplate;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.common.collect.ImmutableMap;
public class CompiledST {
static int BUFFER_SIZE = 1;
static int BUFFER_MASK = BUFFER_SIZE - 1;
static int INITIAL_SIZE = 128;
final static Log log = LogFactory.getLog(CompiledST.class);
StringBuilder[] bufferes = new StringBuilder[BUFFER_SIZE];
Map<String, Action> bytecodeWithKnownClass;
boolean[] canuse = new boolean[BUFFER_SIZE];
int cntExec = 0;
int cntMiss = 0;
Code code;
String[] formalArguments;
boolean hasFormalArgs;
public List<CompiledST> implicitlyDefinedTemplates;
volatile int lastCanuse = 0;
ReentrantLock lock = new ReentrantLock();
String name;
public STGroup nativeGroup;
public String prefix;
public boolean isAnonSubtemplate;
CompiledST() {
}
CompiledST(STGroup group, final Code code) {
this.nativeGroup = group;
this.code = code;
this.bytecodeWithKnownClass = ImmutableMap.of();
bufferes[0] = new StringBuilder(INITIAL_SIZE);
this.formalArguments = new String[] { "at" };
for (int i = 0; i < BUFFER_SIZE; i++) {
canuse[i] = true;
}
}
CompiledST(STGroup group, final Code code, List<String> arguments) {
this.nativeGroup = group;
this.code = code;
this.bytecodeWithKnownClass = ImmutableMap.of();
bufferes[0] = new StringBuilder(INITIAL_SIZE);
this.formalArguments = arguments.toArray(new String[0]);
for (int i = 0; i < BUFFER_SIZE; i++) {
canuse[i] = true;
}
}
CompiledST(STGroup group, final Code code, List<String> arguments, List<CompiledST> implicitlyDefinedTemplates) {
this(group, code, arguments);
this.implicitlyDefinedTemplates = implicitlyDefinedTemplates;
}
public String exec(Object... argv) {
cntExec++;
String paramsNames = null;
if (argv.length == 1 && argv[0] != null) {
paramsNames = argv[0].getClass().getName();
} else if (argv.length > 1) {
StringBuilder sbParams = new StringBuilder();
for (Object obj : argv) {
if (obj != null) {
sbParams.append(obj.getClass().getName());
} else {
sbParams.append("NULL");
}
}
paramsNames = sbParams.toString();
} else {
paramsNames = "nop";
}
try {
StringBuilder sb = null;
int usedIndex = -1;
{// buffer string builder
int lastc = lastCanuse++ & BUFFER_MASK;
if (canuse[lastc]) {// 需要更加强健的代码,当然也要考量缓存机制是否划算。
usedIndex = lastc;
canuse[usedIndex] = false;
sb = bufferes[usedIndex];
} else {
sb = new StringBuilder(bufferes[0].capacity());
cntMiss++;
if (cntExec / cntMiss < 10) {
int lastBUFFER_SIZE = BUFFER_SIZE;
StringBuilder[] lastBufferes = bufferes;
boolean[] lastCanuse = canuse;
BUFFER_SIZE = BUFFER_SIZE + BUFFER_SIZE;
bufferes = new StringBuilder[BUFFER_SIZE];
canuse = new boolean[BUFFER_SIZE];
for (int i = 0; i < lastBUFFER_SIZE; i++) {
bufferes[i] = lastBufferes[i];
canuse[i] = lastCanuse[i];
}
for (int i = lastBUFFER_SIZE; i < BUFFER_SIZE; i++) {
bufferes[i] = new StringBuilder(bufferes[0].capacity());
canuse[i] = true;
}
BUFFER_MASK = BUFFER_SIZE - 1;
cntMiss = 0;
}
}
}
if (argv.length < this.formalArguments.length) {
Object[] lastArgv = argv;
argv = new Object[this.formalArguments.length];
System.arraycopy(lastArgv, 0, argv, 0, lastArgv.length);
}
get(paramsNames, argv).exec(this.nativeGroup, this, sb, argv);
String result = sb.toString();
{// clear string builder
if (usedIndex >= 0) {
sb.setLength(0);
canuse[usedIndex] = true;
}
}
return result;
} catch (IOException e) {
log.error(e);
throw new RuntimeException(e);
}
}
// 遍历对象
public <T> String execList(List<T> dataList, Object... argv) {
cntExec++;
StringBuilder sbParams = new StringBuilder();
{
Object obj = dataList.get(0);
if (obj != null) {
sbParams.append(obj.getClass().getName());
} else {
sbParams.append("NULL");
}
}
for (Object obj : argv) {
if (obj != null) {
sbParams.append(obj.getClass().getName());
} else {
sbParams.append("NULL");
}
}
sbParams.append(Integer.class.getName());
String paramsNames = sbParams.toString();
try {
StringBuilder sb = null;
int usedIndex = -1;
{// buffer string builder
int lastc = lastCanuse++ & BUFFER_MASK;
if (canuse[lastc]) {// 需要更加强健的代码,当然也要考量缓存机制是否划算。
usedIndex = lastc;
canuse[usedIndex] = false;
sb = bufferes[usedIndex];
} else {
sb = new StringBuilder(bufferes[0].capacity());
cntMiss++;
if (cntExec / cntMiss < 10) {
int lastBUFFER_SIZE = BUFFER_SIZE;
StringBuilder[] lastBufferes = bufferes;
boolean[] lastCanuse = canuse;
BUFFER_SIZE = BUFFER_SIZE + BUFFER_SIZE;
bufferes = new StringBuilder[BUFFER_SIZE];
canuse = new boolean[BUFFER_SIZE];
for (int i = 0; i < lastBUFFER_SIZE; i++) {
bufferes[i] = lastBufferes[i];
canuse[i] = lastCanuse[i];
}
for (int i = lastBUFFER_SIZE; i < BUFFER_SIZE; i++) {
bufferes[i] = new StringBuilder(bufferes[0].capacity());
canuse[i] = true;
}
BUFFER_MASK = BUFFER_SIZE - 1;
cntMiss = 0;
}
}
}
for (int i = 0; i < dataList.size(); i++) {
Object[] datas = new Object[] { dataList.get(i), argv, i };
get(paramsNames, datas).exec(this.nativeGroup, this, sb, datas);
}
String result = sb.toString();
{// clear string builder
if (usedIndex >= 0) {
sb.setLength(0);
canuse[usedIndex] = true;
}
}
return result;
} catch (IOException e) {
log.error(e);
throw new RuntimeException(e);
}
}
public <T> String execList(Object... argv) {
cntExec++;
@SuppressWarnings("unchecked")
List<T> dataList = (List<T>) argv[0];
String paramsNames = dataList.get(0).getClass().getName();
try {
StringBuilder sb = null;
int usedIndex = -1;
{// buffer string builder
int lastc = lastCanuse++ & BUFFER_MASK;
if (canuse[lastc]) {// 需要更加强健的代码,当然也要考量缓存机制是否划算。
usedIndex = lastc;
canuse[usedIndex] = false;
sb = bufferes[usedIndex];
} else {
sb = new StringBuilder(bufferes[0].capacity());
cntMiss++;
if (cntExec / cntMiss < 10) {
int lastBUFFER_SIZE = BUFFER_SIZE;
StringBuilder[] lastBufferes = bufferes;
boolean[] lastCanuse = canuse;
BUFFER_SIZE = BUFFER_SIZE + BUFFER_SIZE;
bufferes = new StringBuilder[BUFFER_SIZE];
canuse = new boolean[BUFFER_SIZE];
for (int i = 0; i < lastBUFFER_SIZE; i++) {
bufferes[i] = lastBufferes[i];
canuse[i] = lastCanuse[i];
}
for (int i = lastBUFFER_SIZE; i < BUFFER_SIZE; i++) {
bufferes[i] = new StringBuilder(bufferes[0].capacity());
canuse[i] = true;
}
BUFFER_MASK = BUFFER_SIZE - 1;
cntMiss = 0;
}
}
}
for (int i = 0; i < dataList.size(); i++) {
argv[0] = dataList.get(i);
get(paramsNames, argv).exec(this.nativeGroup, this, sb, argv);
}
String result = sb.toString();
{// clear string builder
if (usedIndex >= 0) {
sb.setLength(0);
canuse[usedIndex] = true;
}
}
return result;
} catch (IOException e) {
log.error(e);
throw new RuntimeException(e);
}
}
// 命名参数形式数据
public <T> String execNamed(Map<String, T> data) {
Object[] args = new Object[this.formalArguments.length];
int max = this.formalArguments.length;
for (int i = 0; i < max; i++) {
args[i] = data.get(formalArguments[i]);
}
return this.exec(args);
}
public Action get(String paramsNames, Object... argv) {
Action builder = bytecodeWithKnownClass.get(paramsNames);
if (builder != null) return builder;
lock.lock();
try {
builder = bytecodeWithKnownClass.get(paramsNames);
if (builder != null) return builder;
CompilerContext c = new CompilerContext(this,argv);
if (this.name != null) {
builder = ActionComplier.DEFAULT.compileAndGetInstance(c, this.name + "__" + paramsNames, this);
} else {
builder = ActionComplier.DEFAULT.compileAndGetInstance(c, paramsNames, this);
}
ImmutableMap.Builder<String, Action> mapBuilder = ImmutableMap.builder();
bytecodeWithKnownClass = mapBuilder.putAll(bytecodeWithKnownClass).put(paramsNames, builder).build();
return builder;
} finally {
lock.unlock();
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("String template");
if (formalArguments.length > 0) {
sb.append("(");
for (String argName : formalArguments) {
sb.append(argName);
sb.append(',');
}
sb.setCharAt(sb.length() - 1, ')');
} else {
sb.append("()");
}
sb.append(code);
sb.append("\n");
return sb.toString();
}
public void dump() {
System.out.println(this.toString());
}
}