1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #include "CountersTable.hpp"
19 
20 
21 
22 #include <algorithm>
23 
24 
25 
26 #include "ElemNumber.hpp"
27 #include "StylesheetExecutionContext.hpp"
28 
29 
30 
31 namespace XALAN_CPP_NAMESPACE {
32 
33 
34 
35 inline void
appendBtoFList(CountersTable::NodeVectorType & flist,const CountersTable::NodeVectorType & blist)36 appendBtoFList(
37             CountersTable::NodeVectorType&          flist,
38             const CountersTable::NodeVectorType&    blist)
39 {
40     using std::back_inserter;
41     using std::copy;
42 
43     flist.reserve(flist.size() + blist.size());
44 
45     copy(
46         blist.rbegin(),
47         blist.rend(),
48         back_inserter(flist));
49 }
50 
51 
52 
53 CountersTable::CountType
countNode(StylesheetExecutionContext & support,const ElemNumber & numberElem,XalanNode * node)54 CountersTable::countNode(
55             StylesheetExecutionContext&     support,
56             const ElemNumber&               numberElem,
57             XalanNode*                      node)
58 {
59     assert(numberElem.getID() < m_countersVector.size());
60 
61     CountType   count = 0;
62 
63     CounterVectorType&  counters = m_countersVector[numberElem.getID()];
64 
65     const CounterVectorType::size_type  nCounters = counters.size();
66 
67     XalanNode*  target = numberElem.getTargetNode(support, node);
68 
69     if(0 != target)
70     {
71         for(CounterVectorType::size_type i = 0; i < nCounters; i++)
72         {
73             const Counter&  counter = counters[i];
74 
75             count = counter.getPreviouslyCounted(support, target);
76 
77             if(count > 0)
78             {
79                 return count;
80             }
81         }
82 
83         // In the loop below, we collect the nodes in backwards doc order, so
84         // we don't have to do inserts, but then we store the nodes in forwards
85         // document order, so we don't have to insert nodes into that list,
86         // so that's what the appendBtoFList stuff is all about.  In cases
87         // of forward counting by one, this will mean a single node copy from
88         // the backwards list (m_newFound) to the forwards list
89         // (counter.m_countNodes).
90         count = 0;
91 
92         for(; 0 != target; target = numberElem.getPreviousNode(support, target))
93         {
94             // First time in, we should not have to check for previous counts,
95             // since the original target node was already checked in the
96             // block above.
97             if(0 != count)
98             {
99                 for(CounterVectorType::size_type i = 0; i < nCounters; ++i)
100                 {
101                     Counter&    counter = counters[i];
102 
103                     const Counter::NodeVectorType::size_type    cacheLen = counter.m_countNodes.size();
104                     assert(cacheLen == CountType(cacheLen));
105 
106                     if(cacheLen > 0 && counter.m_countNodes[cacheLen - 1] == target)
107                     {
108                         count += CountType(cacheLen) + counter.m_countNodesStartCount;
109 
110                         if(cacheLen > 0)
111                         {
112                             appendBtoFList(counter.m_countNodes, m_newFound);
113                         }
114 
115                         m_newFound.clear();
116 
117                         return count;
118                     }
119                 }
120             }
121 
122             m_newFound.push_back(target);
123 
124             ++count;
125         }
126 
127         // If we got to this point, then we didn't find a counter, so make
128         // one and add it to the list.
129         counters.resize(counters.size() + 1);
130 
131         Counter&    counter = counters.back();
132 
133         counter.m_numberElem = &numberElem;
134 
135         appendBtoFList(counter.m_countNodes, m_newFound);
136 
137         m_newFound.clear();
138     }
139 
140     return count;
141 }
142 
143 
144 
145 Counter::CountType
getPreviouslyCounted(StylesheetExecutionContext & executionContext,const XalanNode * node) const146 Counter::getPreviouslyCounted(
147         StylesheetExecutionContext&     executionContext,
148         const XalanNode*                node) const
149 {
150     const NodeVectorType::size_type     n = m_countNodes.size();
151     assert(CountType(n) == n);
152 
153     CountType   result = 0;
154 
155     for(NodeVectorType::size_type i = n; i > 0; --i)
156     {
157         const XalanNode* const  countedNode = m_countNodes[i - 1];
158 
159         if(node == countedNode)
160         {
161             // Since the list is in backwards order, the count is
162             // how many are in the rest of the list.
163             result = CountType(i) + m_countNodesStartCount;
164 
165             break;
166         }
167 
168         // Try to see if the given node falls after the counted node...
169         // if it does, don't keep searching backwards.
170         if(executionContext.isNodeAfter(*countedNode, *node))
171         {
172             break;
173         }
174     }
175 
176     return result;
177 }
178 
179 
180 
181 }
182