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&#174; 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
 -----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.