Re: UnmodifiableSet
Daniel Dekany <[email protected]>
| Newsgroups | gmane.comp.web.freemarker.user |
|---|---|
| Message-ID | <[email protected]> |
Tuesday, March 9, 2010, 7:19:41 AM, Leos Literak wrote: > With 2.3.13 I cannot use seq_contains builtin because: > Underlying collection is not a list, it's > java.util.Collections$UnmodifiableSet > > I think that the Set shall be sequence, right? I guess this what I have fixed a month ago, but then didn't make it into the release... I will put it back for the next release. (Anyway, there is diff I made back then... but I didn't tested it enough yet.) -- Best regards, Daniel Dekany ------------------------------------------------------------------------------ Download Intel® Parallel Studio Eval Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance. See why Intel Parallel Studio got high marks during beta. http://p.sf.net/sfu/intel-sw-dev _______________________________________________ FreeMarker-user mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/freemarker-user
fm.diff
(application/octet-stream, 17.1 KB)
Index: src/freemarker/core/SequenceBuiltins.java
===================================================================
--- src/freemarker/core/SequenceBuiltins.java (revision 1130)
+++ src/freemarker/core/SequenceBuiltins.java (working copy)
@@ -526,10 +526,10 @@
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
- if (model instanceof TemplateSequenceModel) {
+ if (model instanceof TemplateCollectionModel) {
+ return new BIMethodForCollection((TemplateCollectionModel) model, env);
+ } else if (model instanceof TemplateSequenceModel) {
return new BIMethodForSequence((TemplateSequenceModel) model, env);
- } else if (model instanceof TemplateCollectionModel) {
- return new BIMethodForCollection((TemplateCollectionModel) model, env);
} else {
throw invalidTypeException(model, target, env, "sequence or collection");
}
@@ -586,6 +586,7 @@
}
static class seq_index_ofBI extends BuiltIn {
+
private int m_dir;
public seq_index_ofBI(int dir) {
@@ -594,22 +595,40 @@
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
- TemplateModel model = target.getAsTemplateModel(env);
- if (!(model instanceof TemplateSequenceModel))
- throw invalidTypeException(model, target, env, "sequence");
- return new BIMethod((TemplateSequenceModel) model, env);
+ return new BIMethod(env);
}
-
+
private class BIMethod implements TemplateMethodModelEx {
- private TemplateSequenceModel m_seq;
- private Environment m_env;
+
+ protected final TemplateSequenceModel m_seq;
+ protected final TemplateCollectionModel m_col;
+ protected final Environment m_env;
- private BIMethod(TemplateSequenceModel seq, Environment env) {
- m_seq = seq;
+ private BIMethod(Environment env)
+ throws TemplateException {
+ TemplateModel model = target.getAsTemplateModel(env);
+ m_seq = model instanceof TemplateSequenceModel
+ && !isBuggySequenceImplementation(model)
+ ? (TemplateSequenceModel) model
+ : null;
+ m_col = model instanceof TemplateCollectionModel
+ ? (TemplateCollectionModel) model
+ : null;
+ if (m_seq == null && m_col == null) {
+ throw invalidTypeException(
+ model, target, env, "sequence or collection");
+ }
+
m_env = env;
}
- public Object exec(List args)
+ private boolean isBuggySequenceImplementation(
+ TemplateModel model) {
+ // FIXME: It's too strict this way...
+ return model instanceof freemarker.ext.beans.CollectionModel;
+ }
+
+ public final Object exec(List args)
throws TemplateModelException {
int argcnt = args.size();
if (argcnt != 1 && argcnt != 2) {
@@ -617,9 +636,8 @@
getBuiltinTemplate() + " expects 1 or 2 arguments.");
}
- int startIndex;
- int seqSize = m_seq.size();
- TemplateModel arg = (TemplateModel) args.get(0);
+ TemplateModel target = (TemplateModel) args.get(0);
+ int foundAtIdx;
if (argcnt > 1) {
Object obj = args.get(1);
if (!(obj instanceof TemplateNumberModel)) {
@@ -627,51 +645,126 @@
getBuiltinTemplate()
+ "expects a number as its second argument.");
}
- startIndex = ((TemplateNumberModel) obj).getAsNumber().intValue();
- if (m_dir == 1) {
- if (startIndex >= seqSize) {
- return Constants.MINUS_ONE;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- } else {
- if (startIndex >= seqSize) {
- startIndex = seqSize - 1;
- }
- if (startIndex < 0) {
- return Constants.MINUS_ONE;
- }
+ int startIndex = ((TemplateNumberModel) obj).getAsNumber().intValue();
+ foundAtIdx = (m_col != null && startIndex == 0 && m_dir == 1)
+ || m_seq == null
+ ? findInCol(target, startIndex)
+ : findInSeq(target, startIndex);
+ } else {
+ foundAtIdx = (m_col != null && m_dir == 1) || m_seq == null
+ ? findInCol(target)
+ : findInSeq(target);
+ }
+ return foundAtIdx == -1 ? Constants.MINUS_ONE : new SimpleNumber(foundAtIdx);
+ }
+
+ private final String getBuiltinTemplate() {
+ if (m_dir == 1)
+ return "?seq_indexOf(...)";
+ else
+ return "?seq_lastIndexOf(...)";
+ }
+
+ public int findInSeq(TemplateModel target)
+ throws TemplateModelException {
+ final int seqSize = m_seq.size();
+ final int actualStartIndex;
+
+ if (m_dir == 1) {
+ actualStartIndex = 0;
+ } else {
+ actualStartIndex = seqSize - 1;
+ }
+
+ return findInSeq(target, actualStartIndex, seqSize);
+ }
+
+ private int findInSeq(TemplateModel target, int startIndex)
+ throws TemplateModelException {
+ int seqSize = m_seq.size();
+
+ if (m_dir == 1) {
+ if (startIndex >= seqSize) {
+ return -1;
}
+ if (startIndex < 0) {
+ startIndex = 0;
+ }
} else {
- if (m_dir == 1) {
- startIndex = 0;
- } else {
+ if (startIndex >= seqSize) {
startIndex = seqSize - 1;
}
+ if (startIndex < 0) {
+ return -1;
+ }
}
+ return findInSeq(target, startIndex, seqSize);
+ }
+
+ private int findInSeq(
+ TemplateModel target, int scanStartIndex, int seqSize)
+ throws TemplateModelException {
if (m_dir == 1) {
- for (int i = startIndex; i < seqSize; i++) {
- if (modelsEqual(m_seq.get(i), arg, m_env))
- return new SimpleNumber(i);
+ for (int i = scanStartIndex; i < seqSize; i++) {
+ if (modelsEqual(m_seq.get(i), target, m_env))
+ return i;
}
} else {
- for (int i = startIndex; i >= 0; i--) {
- if (modelsEqual(m_seq.get(i), arg, m_env))
- return new SimpleNumber(i);
+ for (int i = scanStartIndex; i >= 0; i--) {
+ if (modelsEqual(m_seq.get(i), target, m_env))
+ return i;
}
}
- return Constants.MINUS_ONE;
+ return -1;
}
+
+ public int findInCol(TemplateModel target) throws TemplateModelException {
+ return findInCol(target, 0, Integer.MAX_VALUE);
+ }
+
+ protected int findInCol(TemplateModel target, int startIndex)
+ throws TemplateModelException {
+ if (m_dir == 1) {
+ return findInCol(target, startIndex, Integer.MAX_VALUE);
+ } else {
+ return findInCol(target, 0, startIndex);
+ }
+ }
- private String getBuiltinTemplate() {
- if (m_dir == 1)
- return "?seq_indexOf(...)";
- else
- return "?seq_lastIndexOf(...)";
+ protected int findInCol(TemplateModel target,
+ final int allowedRangeStart, final int allowedRangeEnd)
+ throws TemplateModelException {
+ // Just a little optimization:
+ if (allowedRangeEnd < 0) {
+ return -1;
+ }
+
+ TemplateModelIterator it = m_col.iterator();
+
+ int foundAtIdx = -1; // return value for "not found"
+ int idx = 0;
+ searchItem: while (it.hasNext()) {
+ if (idx > allowedRangeEnd) {
+ break searchItem;
+ }
+ TemplateModel current = it.next();
+ if (idx >= allowedRangeStart) {
+ if (modelsEqual(current, target, m_env)) {
+ foundAtIdx = idx;
+ if (m_dir == 1) { // 1 means "find first"...
+ break searchItem;
+ }
+ // ... otherwise it's "find last".
+ }
+ }
+ idx++;
+ }
+ return foundAtIdx;
}
+
}
+
}
static class chunkBI extends SequenceBuiltIn {
Index: src/freemarker/testcase/TemplateTestCase.java
===================================================================
--- src/freemarker/testcase/TemplateTestCase.java (revision 1130)
+++ src/freemarker/testcase/TemplateTestCase.java (working copy)
@@ -71,8 +71,10 @@
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
+import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone;
+import java.util.TreeSet;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -375,6 +377,14 @@
NodeModel nm = NodeModel.parse(is);
dataModel.put("doc", nm);
}
+
+ else if (testName.equals("sequence-builtins")) {
+ Set abcSet = new TreeSet();
+ abcSet.add("a");
+ abcSet.add("b");
+ abcSet.add("c");
+ dataModel.put("abcSet", abcSet);
+ }
}
public void runTest() {
Index: src/freemarker/testcase/testcases.xml
===================================================================
--- src/freemarker/testcase/testcases.xml (revision 1130)
+++ src/freemarker/testcase/testcases.xml (working copy)
@@ -93,7 +93,9 @@
<testcase name="precedence" filename="test-precedence.html"/>
<testcase name="recover" filename="test-recover.ftl" />
<testcase name="root" filename="test-root.html" />
- <testcase name="sequence-builtins" filename="test-sequencebuiltins.txt" />
+ <testcase name="sequence-builtins" filename="test-sequencebuiltins.txt">
+ <config object_wrapper="freemarker.ext.beans.BeansWrapper"/>
+ </testcase>
<testcase name="strictinheader" filename="test-strictinheader.html">
<config strict_syntax="N"/>
</testcase>
Index: src/freemarker/testcase/reference/test-sequencebuiltins.txt
===================================================================
--- src/freemarker/testcase/reference/test-sequencebuiltins.txt (revision 1130)
+++ src/freemarker/testcase/reference/test-sequencebuiltins.txt (working copy)
@@ -98,12 +98,18 @@
true
true
true
+true
+true
+true
False:
false
false
false
false
+false
+false
+false
False: false
@@ -114,11 +120,17 @@
1 = 1
2 = 2
6 = 6
+0 = 0
+1 = 1
+2 = 2
-1 = -1
-1 = -1
-1 = -1
-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
-1 = -1
@@ -130,6 +142,10 @@
2 = 2
7 = 7
-1 = -1
+0 = 0
+1 = 1
+2 = 2
+-1 = -1
Index_of and last_index_of with starting indices
------------------------------------------------
@@ -170,6 +186,56 @@
3 = 3
3 = 3
+seq_index_of "a":
+0 = 0
+0 = 0
+0 = 0
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+
+seq_index_of "b":
+1 = 1
+1 = 1
+1 = 1
+1 = 1
+-1 = -1
+-1 = -1
+
+seq_index_of "c":
+2 = 2
+2 = 2
+2 = 2
+2 = 2
+2 = 2
+-1 = -1
+
+seq_last_index_of "a":
+-1 = -1
+-1 = -1
+0 = 0
+0 = 0
+0 = 0
+0 = 0
+0 = 0
+
+seq_last_index_of "b":
+-1 = -1
+-1 = -1
+-1 = -1
+1 = 1
+1 = 1
+1 = 1
+
+seq_last_index_of "c":
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+2 = 2
+2 = 2
+
Chunk
-----
Index: src/freemarker/testcase/template/test-sequencebuiltins.txt
===================================================================
--- src/freemarker/testcase/template/test-sequencebuiltins.txt (revision 1130)
+++ src/freemarker/testcase/template/test-sequencebuiltins.txt (working copy)
@@ -109,12 +109,18 @@
${x?seq_contains("2")?string}
${x?seq_contains(true)?string}
${x?seq_contains('1992-02-21'?date('yyyy-MM-dd'))?string}
+${abcSet?seq_contains("a")?string}
+${abcSet?seq_contains("b")?string}
+${abcSet?seq_contains("c")?string}
False:
${x?seq_contains("1")?string}
${x?seq_contains(2)?string}
${x?seq_contains(false)?string}
${x?seq_contains('1992-02-22'?date('yyyy-MM-dd'))?string}
+${abcSet?seq_contains("A")?string}
+${abcSet?seq_contains(1)?string}
+${abcSet?seq_contains(true)?string}
<#assign x = []>
False: ${x?seq_contains(1)?string}
@@ -127,11 +133,17 @@
1 = ${x?seq_index_of("2")}
2 = ${x?seq_index_of(true)}
6 = ${x?seq_index_of('1992-02-21'?date('yyyy-MM-dd'))}
+0 = ${abcSet?seq_index_of("a")}
+1 = ${abcSet?seq_index_of("b")}
+2 = ${abcSet?seq_index_of("c")}
-1 = ${x?seq_index_of("1")}
-1 = ${x?seq_index_of(2)}
-1 = ${x?seq_index_of(false)}
-1 = ${x?seq_index_of('1992-02-22'?date('yyyy-MM-dd'))}
+-1 = ${abcSet?seq_index_of("A")}
+-1 = ${abcSet?seq_index_of(1)}
+-1 = ${abcSet?seq_index_of(true)}
<#assign x = []>
-1 = ${x?seq_index_of(1)}
@@ -145,6 +157,10 @@
2 = ${x?seq_last_index_of(true)}
7 = ${x?seq_last_index_of('1992-02-21'?date('yyyy-MM-dd'))}
-1 = ${x?seq_last_index_of("1")}
+0 = ${abcSet?seq_last_index_of("a")}
+1 = ${abcSet?seq_last_index_of("b")}
+2 = ${abcSet?seq_last_index_of("c")}
+-1 = ${abcSet?seq_last_index_of("A")}
Index_of and last_index_of with starting indices
------------------------------------------------
@@ -186,6 +202,56 @@
3 = ${names?seq_last_index_of("Susan", 3)}
3 = ${names?seq_last_index_of("Susan", 4)}
+seq_index_of "a":
+0 = ${abcSet?seq_index_of("a", -2)}
+0 = ${abcSet?seq_index_of("a", -1)}
+0 = ${abcSet?seq_index_of("a", 0)}
+-1 = ${abcSet?seq_index_of("a", 1)}
+-1 = ${abcSet?seq_index_of("a", 2)}
+-1 = ${abcSet?seq_index_of("a", 3)}
+-1 = ${abcSet?seq_index_of("a", 4)}
+
+seq_index_of "b":
+1 = ${abcSet?seq_index_of("b", -2)}
+1 = ${abcSet?seq_index_of("b", -1)}
+1 = ${abcSet?seq_index_of("b", 0)}
+1 = ${abcSet?seq_index_of("b", 1)}
+-1 = ${abcSet?seq_index_of("b", 2)}
+-1 = ${abcSet?seq_index_of("b", 3)}
+
+seq_index_of "c":
+2 = ${abcSet?seq_index_of("c", -2)}
+2 = ${abcSet?seq_index_of("c", -1)}
+2 = ${abcSet?seq_index_of("c", 0)}
+2 = ${abcSet?seq_index_of("c", 1)}
+2 = ${abcSet?seq_index_of("c", 2)}
+-1 = ${abcSet?seq_index_of("c", 3)}
+
+seq_last_index_of "a":
+-1 = ${abcSet?seq_last_index_of("a", -2)}
+-1 = ${abcSet?seq_last_index_of("a", -1)}
+0 = ${abcSet?seq_last_index_of("a", 0)}
+0 = ${abcSet?seq_last_index_of("a", 1)}
+0 = ${abcSet?seq_last_index_of("a", 2)}
+0 = ${abcSet?seq_last_index_of("a", 3)}
+0 = ${abcSet?seq_last_index_of("a", 4)}
+
+seq_last_index_of "b":
+-1 = ${abcSet?seq_last_index_of("b", -2)}
+-1 = ${abcSet?seq_last_index_of("b", -1)}
+-1 = ${abcSet?seq_last_index_of("b", 0)}
+1 = ${abcSet?seq_last_index_of("b", 1)}
+1 = ${abcSet?seq_last_index_of("b", 2)}
+1 = ${abcSet?seq_last_index_of("b", 3)}
+
+seq_last_index_of "c":
+-1 = ${abcSet?seq_last_index_of("c", -2)}
+-1 = ${abcSet?seq_last_index_of("c", -1)}
+-1 = ${abcSet?seq_last_index_of("c", 0)}
+-1 = ${abcSet?seq_last_index_of("c", 1)}
+2 = ${abcSet?seq_last_index_of("c", 2)}
+2 = ${abcSet?seq_last_index_of("c", 3)}
+
Chunk
-----