| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "CountersTable.hpp" |
| |
| |
| |
| #include <algorithm> |
| |
| |
| |
| #include "ElemNumber.hpp" |
| #include "StylesheetExecutionContext.hpp" |
| |
| |
| |
| namespace XALAN_CPP_NAMESPACE { |
| |
| |
| |
| inline void |
| appendBtoFList( |
| CountersTable::NodeVectorType& flist, |
| const CountersTable::NodeVectorType& blist) |
| { |
| using std::back_inserter; |
| using std::copy; |
| |
| flist.reserve(flist.size() + blist.size()); |
| |
| copy( |
| blist.rbegin(), |
| blist.rend(), |
| back_inserter(flist)); |
| } |
| |
| |
| |
| CountersTable::CountType |
| CountersTable::countNode( |
| StylesheetExecutionContext& support, |
| const ElemNumber& numberElem, |
| XalanNode* node) |
| { |
| assert(numberElem.getID() < m_countersVector.size()); |
| |
| CountType count = 0; |
| |
| CounterVectorType& counters = m_countersVector[numberElem.getID()]; |
| |
| const CounterVectorType::size_type nCounters = counters.size(); |
| |
| XalanNode* target = numberElem.getTargetNode(support, node); |
| |
| if(0 != target) |
| { |
| for(CounterVectorType::size_type i = 0; i < nCounters; i++) |
| { |
| const Counter& counter = counters[i]; |
| |
| count = counter.getPreviouslyCounted(support, target); |
| |
| if(count > 0) |
| { |
| return count; |
| } |
| } |
| |
| // In the loop below, we collect the nodes in backwards doc order, so |
| // we don't have to do inserts, but then we store the nodes in forwards |
| // document order, so we don't have to insert nodes into that list, |
| // so that's what the appendBtoFList stuff is all about. In cases |
| // of forward counting by one, this will mean a single node copy from |
| // the backwards list (m_newFound) to the forwards list |
| // (counter.m_countNodes). |
| count = 0; |
| |
| for(; 0 != target; target = numberElem.getPreviousNode(support, target)) |
| { |
| // First time in, we should not have to check for previous counts, |
| // since the original target node was already checked in the |
| // block above. |
| if(0 != count) |
| { |
| for(CounterVectorType::size_type i = 0; i < nCounters; ++i) |
| { |
| Counter& counter = counters[i]; |
| |
| const Counter::NodeVectorType::size_type cacheLen = counter.m_countNodes.size(); |
| assert(cacheLen == CountType(cacheLen)); |
| |
| if(cacheLen > 0 && counter.m_countNodes[cacheLen - 1] == target) |
| { |
| count += CountType(cacheLen) + counter.m_countNodesStartCount; |
| |
| if(cacheLen > 0) |
| { |
| appendBtoFList(counter.m_countNodes, m_newFound); |
| } |
| |
| m_newFound.clear(); |
| |
| return count; |
| } |
| } |
| } |
| |
| m_newFound.push_back(target); |
| |
| ++count; |
| } |
| |
| // If we got to this point, then we didn't find a counter, so make |
| // one and add it to the list. |
| counters.resize(counters.size() + 1); |
| |
| Counter& counter = counters.back(); |
| |
| counter.m_numberElem = &numberElem; |
| |
| appendBtoFList(counter.m_countNodes, m_newFound); |
| |
| m_newFound.clear(); |
| } |
| |
| return count; |
| } |
| |
| |
| |
| Counter::CountType |
| Counter::getPreviouslyCounted( |
| StylesheetExecutionContext& executionContext, |
| const XalanNode* node) const |
| { |
| const NodeVectorType::size_type n = m_countNodes.size(); |
| assert(CountType(n) == n); |
| |
| CountType result = 0; |
| |
| for(NodeVectorType::size_type i = n; i > 0; --i) |
| { |
| const XalanNode* const countedNode = m_countNodes[i - 1]; |
| |
| if(node == countedNode) |
| { |
| // Since the list is in backwards order, the count is |
| // how many are in the rest of the list. |
| result = CountType(i) + m_countNodesStartCount; |
| |
| break; |
| } |
| |
| // Try to see if the given node falls after the counted node... |
| // if it does, don't keep searching backwards. |
| if(executionContext.isNodeAfter(*countedNode, *node)) |
| { |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| |
| } |