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