LCOV - code coverage report
Current view: top level - dom/xslt/xpath - txNodeSet.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 255 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "txNodeSet.h"
       7             : #include "txLog.h"
       8             : #include "nsMemory.h"
       9             : #include "txXPathTreeWalker.h"
      10             : #include <algorithm>
      11             : 
      12             : /**
      13             :  * Implementation of an XPath nodeset
      14             :  */
      15             : 
      16             : #ifdef NS_BUILD_REFCNT_LOGGING
      17             : #define LOG_CHUNK_MOVE(_start, _new_start, _count)            \
      18             : {                                                             \
      19             :     txXPathNode *start = const_cast<txXPathNode*>(_start);    \
      20             :     while (start < _start + _count) {                         \
      21             :         NS_LogDtor(start, "txXPathNode", sizeof(*start));     \
      22             :         ++start;                                              \
      23             :     }                                                         \
      24             :     start = const_cast<txXPathNode*>(_new_start);             \
      25             :     while (start < _new_start + _count) {                     \
      26             :         NS_LogCtor(start, "txXPathNode", sizeof(*start));     \
      27             :         ++start;                                              \
      28             :     }                                                         \
      29             : }
      30             : #else
      31             : #define LOG_CHUNK_MOVE(_start, _new_start, _count)
      32             : #endif
      33             : 
      34             : static const int32_t kTxNodeSetMinSize = 4;
      35             : static const int32_t kTxNodeSetGrowFactor = 2;
      36             : 
      37             : #define kForward   1
      38             : #define kReversed -1
      39             : 
      40           0 : txNodeSet::txNodeSet(txResultRecycler* aRecycler)
      41             :     : txAExprResult(aRecycler),
      42             :       mStart(nullptr),
      43             :       mEnd(nullptr),
      44             :       mStartBuffer(nullptr),
      45             :       mEndBuffer(nullptr),
      46             :       mDirection(kForward),
      47           0 :       mMarks(nullptr)
      48             : {
      49           0 : }
      50             : 
      51           0 : txNodeSet::txNodeSet(const txXPathNode& aNode, txResultRecycler* aRecycler)
      52             :     : txAExprResult(aRecycler),
      53             :       mStart(nullptr),
      54             :       mEnd(nullptr),
      55             :       mStartBuffer(nullptr),
      56             :       mEndBuffer(nullptr),
      57             :       mDirection(kForward),
      58           0 :       mMarks(nullptr)
      59             : {
      60           0 :     if (!ensureGrowSize(1)) {
      61           0 :         return;
      62             :     }
      63             : 
      64           0 :     new(mStart) txXPathNode(aNode);
      65           0 :     ++mEnd;
      66             : }
      67             : 
      68           0 : txNodeSet::txNodeSet(const txNodeSet& aSource, txResultRecycler* aRecycler)
      69             :     : txAExprResult(aRecycler),
      70             :       mStart(nullptr),
      71             :       mEnd(nullptr),
      72             :       mStartBuffer(nullptr),
      73             :       mEndBuffer(nullptr),
      74             :       mDirection(kForward),
      75           0 :       mMarks(nullptr)
      76             : {
      77           0 :     append(aSource);
      78           0 : }
      79             : 
      80           0 : txNodeSet::~txNodeSet()
      81             : {
      82           0 :     delete [] mMarks;
      83             : 
      84           0 :     if (mStartBuffer) {
      85           0 :         destroyElements(mStart, mEnd);
      86             : 
      87           0 :         free(mStartBuffer);
      88             :     }
      89           0 : }
      90             : 
      91           0 : nsresult txNodeSet::add(const txXPathNode& aNode)
      92             : {
      93           0 :     NS_ASSERTION(mDirection == kForward,
      94             :                  "only append(aNode) is supported on reversed nodesets");
      95             : 
      96           0 :     if (isEmpty()) {
      97           0 :         return append(aNode);
      98             :     }
      99             : 
     100             :     bool dupe;
     101           0 :     txXPathNode* pos = findPosition(aNode, mStart, mEnd, dupe);
     102             : 
     103           0 :     if (dupe) {
     104           0 :         return NS_OK;
     105             :     }
     106             : 
     107             :     // save pos, ensureGrowSize messes with the pointers
     108           0 :     int32_t moveSize = mEnd - pos;
     109           0 :     int32_t offset = pos - mStart;
     110           0 :     if (!ensureGrowSize(1)) {
     111           0 :         return NS_ERROR_OUT_OF_MEMORY;
     112             :     }
     113             :     // set pos to where it was
     114           0 :     pos = mStart + offset;
     115             : 
     116           0 :     if (moveSize > 0) {
     117           0 :         LOG_CHUNK_MOVE(pos, pos + 1, moveSize);
     118           0 :         memmove(pos + 1, pos, moveSize * sizeof(txXPathNode));
     119             :     }
     120             : 
     121           0 :     new(pos) txXPathNode(aNode);
     122           0 :     ++mEnd;
     123             : 
     124           0 :     return NS_OK;
     125             : }
     126             : 
     127           0 : nsresult txNodeSet::add(const txNodeSet& aNodes)
     128             : {
     129           0 :     return add(aNodes, copyElements, nullptr);
     130             : }
     131             : 
     132           0 : nsresult txNodeSet::addAndTransfer(txNodeSet* aNodes)
     133             : {
     134             :     // failure is out-of-memory, transfer didn't happen
     135           0 :     nsresult rv = add(*aNodes, transferElements, destroyElements);
     136           0 :     NS_ENSURE_SUCCESS(rv, rv);
     137             : 
     138             : #ifdef TX_DONT_RECYCLE_BUFFER
     139             :     if (aNodes->mStartBuffer) {
     140             :         free(aNodes->mStartBuffer);
     141             :         aNodes->mStartBuffer = aNodes->mEndBuffer = nullptr;
     142             :     }
     143             : #endif
     144           0 :     aNodes->mStart = aNodes->mEnd = aNodes->mStartBuffer;
     145             : 
     146           0 :     return NS_OK;
     147             : }
     148             : 
     149             : /**
     150             :  * add(aNodeSet, aTransferOp)
     151             :  *
     152             :  * The code is optimized to make a minimum number of calls to
     153             :  * Node::compareDocumentPosition. The idea is this:
     154             :  * We have the two nodesets (number indicate "document position")
     155             :  *
     156             :  * 1 3 7             <- source 1
     157             :  * 2 3 6 8 9         <- source 2
     158             :  * _ _ _ _ _ _ _ _   <- result
     159             :  *
     160             :  *
     161             :  * When merging these nodesets into the result, the nodes are transfered
     162             :  * in chunks to the end of the buffer so that each chunk does not contain
     163             :  * a node from the other nodeset, in document order.
     164             :  *
     165             :  * We select the last non-transfered node in the first nodeset and find
     166             :  * where in the other nodeset it would be inserted. In this case we would
     167             :  * take the 7 from the first nodeset and find the position between the
     168             :  * 6 and 8 in the second. We then take the nodes after the insert-position
     169             :  * and transfer them to the end of the resulting nodeset. Which in this case
     170             :  * means that we first transfered the 8 and 9 nodes, giving us the following:
     171             :  *
     172             :  * 1 3 7             <- source 1
     173             :  * 2 3 6             <- source 2
     174             :  * _ _ _ _ _ _ 8 9   <- result
     175             :  *
     176             :  * The corresponding procedure is done for the second nodeset, that is
     177             :  * the insertion position of the 6 in the first nodeset is found, which
     178             :  * is between the 3 and the 7. The 7 is memmoved (as it stays within
     179             :  * the same nodeset) to the result buffer.
     180             :  *
     181             :  * As the result buffer is filled from the end, it is safe to share the
     182             :  * buffer between this nodeset and the result.
     183             :  *
     184             :  * This is repeated until both of the nodesets are empty.
     185             :  *
     186             :  * If we find a duplicate node when searching for where insertposition we
     187             :  * check for sequences of duplicate nodes, which can be optimized.
     188             :  *
     189             :  */
     190           0 : nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer,
     191             :                         destroyOp aDestroy)
     192             : {
     193           0 :     NS_ASSERTION(mDirection == kForward,
     194             :                  "only append(aNode) is supported on reversed nodesets");
     195             : 
     196           0 :     if (aNodes.isEmpty()) {
     197           0 :         return NS_OK;
     198             :     }
     199             : 
     200           0 :     if (!ensureGrowSize(aNodes.size())) {
     201           0 :         return NS_ERROR_OUT_OF_MEMORY;
     202             :     }
     203             : 
     204             :     // This is probably a rather common case, so lets try to shortcut.
     205           0 :     if (mStart == mEnd ||
     206           0 :         txXPathNodeUtils::comparePosition(mEnd[-1], *aNodes.mStart) < 0) {
     207           0 :         aTransfer(mEnd, aNodes.mStart, aNodes.mEnd);
     208           0 :         mEnd += aNodes.size();
     209             : 
     210           0 :         return NS_OK;
     211             :     }
     212             : 
     213             :     // Last element in this nodeset
     214           0 :     txXPathNode* thisPos = mEnd;
     215             : 
     216             :     // Last element of the other nodeset
     217           0 :     txXPathNode* otherPos = aNodes.mEnd;
     218             : 
     219             :     // Pointer to the insertion point in this nodeset
     220           0 :     txXPathNode* insertPos = mEndBuffer;
     221             : 
     222             :     bool dupe;
     223             :     txXPathNode* pos;
     224             :     int32_t count;
     225           0 :     while (thisPos > mStart || otherPos > aNodes.mStart) {
     226             :         // Find where the last remaining node of this nodeset would
     227             :         // be inserted in the other nodeset.
     228           0 :         if (thisPos > mStart) {
     229           0 :             pos = findPosition(thisPos[-1], aNodes.mStart, otherPos, dupe);
     230             : 
     231           0 :             if (dupe) {
     232           0 :                 const txXPathNode *deletePos = thisPos;
     233           0 :                 --thisPos; // this is already added
     234             :                 // check dupe sequence
     235           0 :                 while (thisPos > mStart && pos > aNodes.mStart &&
     236           0 :                        thisPos[-1] == pos[-1]) {
     237           0 :                     --thisPos;
     238           0 :                     --pos;
     239             :                 }
     240             : 
     241           0 :                 if (aDestroy) {
     242           0 :                     aDestroy(thisPos, deletePos);
     243             :                 }
     244             :             }
     245             :         }
     246             :         else {
     247           0 :             pos = aNodes.mStart;
     248             :         }
     249             : 
     250             :         // Transfer the otherNodes after the insertion point to the result
     251           0 :         count = otherPos - pos;
     252           0 :         if (count > 0) {
     253           0 :             insertPos -= count;
     254           0 :             aTransfer(insertPos, pos, otherPos);
     255           0 :             otherPos -= count;
     256             :         }
     257             : 
     258             :         // Find where the last remaining node of the otherNodeset would
     259             :         // be inserted in this nodeset.
     260           0 :         if (otherPos > aNodes.mStart) {
     261           0 :             pos = findPosition(otherPos[-1], mStart, thisPos, dupe);
     262             : 
     263           0 :             if (dupe) {
     264           0 :                 const txXPathNode *deletePos = otherPos;
     265           0 :                 --otherPos; // this is already added
     266             :                 // check dupe sequence
     267           0 :                 while (otherPos > aNodes.mStart && pos > mStart &&
     268           0 :                        otherPos[-1] == pos[-1]) {
     269           0 :                     --otherPos;
     270           0 :                     --pos;
     271             :                 }
     272             : 
     273           0 :                 if (aDestroy) {
     274           0 :                     aDestroy(otherPos, deletePos);
     275             :                 }
     276             :             }
     277             :         }
     278             :         else {
     279           0 :             pos = mStart;
     280             :         }
     281             : 
     282             :         // Move the nodes from this nodeset after the insertion point
     283             :         // to the result
     284           0 :         count = thisPos - pos;
     285           0 :         if (count > 0) {
     286           0 :             insertPos -= count;
     287           0 :             LOG_CHUNK_MOVE(pos, insertPos, count);
     288           0 :             memmove(insertPos, pos, count * sizeof(txXPathNode));
     289           0 :             thisPos -= count;
     290             :         }
     291             :     }
     292           0 :     mStart = insertPos;
     293           0 :     mEnd = mEndBuffer;
     294             : 
     295           0 :     return NS_OK;
     296             : }
     297             : 
     298             : /**
     299             :  * Append API
     300             :  * These functions should be used with care.
     301             :  * They are intended to be used when the caller assures that the resulting
     302             :  * nodeset remains in document order.
     303             :  * Abuse will break document order, and cause errors in the result.
     304             :  * These functions are significantly faster than the add API, as no
     305             :  * order info operations will be performed.
     306             :  */
     307             : 
     308             : nsresult
     309           0 : txNodeSet::append(const txXPathNode& aNode)
     310             : {
     311           0 :     if (!ensureGrowSize(1)) {
     312           0 :         return NS_ERROR_OUT_OF_MEMORY;
     313             :     }
     314             : 
     315           0 :     if (mDirection == kForward) {
     316           0 :         new(mEnd) txXPathNode(aNode);
     317           0 :         ++mEnd;
     318             : 
     319           0 :         return NS_OK;
     320             :     }
     321             : 
     322           0 :     new(--mStart) txXPathNode(aNode);
     323             : 
     324           0 :     return NS_OK;
     325             : }
     326             : 
     327             : nsresult
     328           0 : txNodeSet::append(const txNodeSet& aNodes)
     329             : {
     330           0 :     NS_ASSERTION(mDirection == kForward,
     331             :                  "only append(aNode) is supported on reversed nodesets");
     332             : 
     333           0 :     if (aNodes.isEmpty()) {
     334           0 :         return NS_OK;
     335             :     }
     336             : 
     337           0 :     int32_t appended = aNodes.size();
     338           0 :     if (!ensureGrowSize(appended)) {
     339           0 :         return NS_ERROR_OUT_OF_MEMORY;
     340             :     }
     341             : 
     342           0 :     copyElements(mEnd, aNodes.mStart, aNodes.mEnd);
     343           0 :     mEnd += appended;
     344             : 
     345           0 :     return NS_OK;
     346             : }
     347             : 
     348             : nsresult
     349           0 : txNodeSet::mark(int32_t aIndex)
     350             : {
     351           0 :     NS_ASSERTION(aIndex >= 0 && mStart && mEnd - mStart > aIndex,
     352             :                  "index out of bounds");
     353           0 :     if (!mMarks) {
     354           0 :         int32_t length = size();
     355           0 :         mMarks = new bool[length];
     356           0 :         memset(mMarks, 0, length * sizeof(bool));
     357             :     }
     358           0 :     if (mDirection == kForward) {
     359           0 :         mMarks[aIndex] = true;
     360             :     }
     361             :     else {
     362           0 :         mMarks[size() - aIndex - 1] = true;
     363             :     }
     364             : 
     365           0 :     return NS_OK;
     366             : }
     367             : 
     368             : nsresult
     369           0 : txNodeSet::sweep()
     370             : {
     371           0 :     if (!mMarks) {
     372             :         // sweep everything
     373           0 :         clear();
     374             :     }
     375             : 
     376           0 :     int32_t chunk, pos = 0;
     377           0 :     int32_t length = size();
     378           0 :     txXPathNode* insertion = mStartBuffer;
     379             : 
     380           0 :     while (pos < length) {
     381           0 :         while (pos < length && !mMarks[pos]) {
     382             :             // delete unmarked
     383           0 :             mStart[pos].~txXPathNode();
     384           0 :             ++pos;
     385             :         }
     386             :         // find chunk to move
     387           0 :         chunk = 0;
     388           0 :         while (pos < length && mMarks[pos]) {
     389           0 :             ++pos;
     390           0 :             ++chunk;
     391             :         }
     392             :         // move chunk
     393           0 :         if (chunk > 0) {
     394           0 :             LOG_CHUNK_MOVE(mStart + pos - chunk, insertion, chunk);
     395           0 :             memmove(insertion, mStart + pos - chunk,
     396           0 :                     chunk * sizeof(txXPathNode));
     397           0 :             insertion += chunk;
     398             :         }
     399             :     }
     400           0 :     mStart = mStartBuffer;
     401           0 :     mEnd = insertion;
     402           0 :     delete [] mMarks;
     403           0 :     mMarks = nullptr;
     404             : 
     405           0 :     return NS_OK;
     406             : }
     407             : 
     408             : void
     409           0 : txNodeSet::clear()
     410             : {
     411           0 :     destroyElements(mStart, mEnd);
     412             : #ifdef TX_DONT_RECYCLE_BUFFER
     413             :     if (mStartBuffer) {
     414             :         free(mStartBuffer);
     415             :         mStartBuffer = mEndBuffer = nullptr;
     416             :     }
     417             : #endif
     418           0 :     mStart = mEnd = mStartBuffer;
     419           0 :     delete [] mMarks;
     420           0 :     mMarks = nullptr;
     421           0 :     mDirection = kForward;
     422           0 : }
     423             : 
     424             : int32_t
     425           0 : txNodeSet::indexOf(const txXPathNode& aNode, uint32_t aStart) const
     426             : {
     427           0 :     NS_ASSERTION(mDirection == kForward,
     428             :                  "only append(aNode) is supported on reversed nodesets");
     429             : 
     430           0 :     if (!mStart || mStart == mEnd) {
     431           0 :         return -1;
     432             :     }
     433             : 
     434           0 :     txXPathNode* pos = mStart + aStart;
     435           0 :     for (; pos < mEnd; ++pos) {
     436           0 :         if (*pos == aNode) {
     437           0 :             return pos - mStart;
     438             :         }
     439             :     }
     440             : 
     441           0 :     return -1;
     442             : }
     443             : 
     444             : const txXPathNode&
     445           0 : txNodeSet::get(int32_t aIndex) const
     446             : {
     447           0 :     if (mDirection == kForward) {
     448           0 :         return mStart[aIndex];
     449             :     }
     450             : 
     451           0 :     return mEnd[-aIndex - 1];
     452             : }
     453             : 
     454             : short
     455           0 : txNodeSet::getResultType()
     456             : {
     457           0 :     return txAExprResult::NODESET;
     458             : }
     459             : 
     460             : bool
     461           0 : txNodeSet::booleanValue()
     462             : {
     463           0 :     return !isEmpty();
     464             : }
     465             : double
     466           0 : txNodeSet::numberValue()
     467             : {
     468           0 :     nsAutoString str;
     469           0 :     stringValue(str);
     470             : 
     471           0 :     return txDouble::toDouble(str);
     472             : }
     473             : 
     474             : void
     475           0 : txNodeSet::stringValue(nsString& aStr)
     476             : {
     477           0 :     NS_ASSERTION(mDirection == kForward,
     478             :                  "only append(aNode) is supported on reversed nodesets");
     479           0 :     if (isEmpty()) {
     480           0 :         return;
     481             :     }
     482           0 :     txXPathNodeUtils::appendNodeValue(get(0), aStr);
     483             : }
     484             : 
     485             : const nsString*
     486           0 : txNodeSet::stringValuePointer()
     487             : {
     488           0 :     return nullptr;
     489             : }
     490             : 
     491           0 : bool txNodeSet::ensureGrowSize(int32_t aSize)
     492             : {
     493             :     // check if there is enough place in the buffer as is
     494           0 :     if (mDirection == kForward && aSize <= mEndBuffer - mEnd) {
     495           0 :         return true;
     496             :     }
     497             : 
     498           0 :     if (mDirection == kReversed && aSize <= mStart - mStartBuffer) {
     499           0 :         return true;
     500             :     }
     501             : 
     502             :     // check if we just have to align mStart to have enough space
     503           0 :     int32_t oldSize = mEnd - mStart;
     504           0 :     int32_t oldLength = mEndBuffer - mStartBuffer;
     505           0 :     int32_t ensureSize = oldSize + aSize;
     506           0 :     if (ensureSize <= oldLength) {
     507             :         // just move the buffer
     508           0 :         txXPathNode* dest = mStartBuffer;
     509           0 :         if (mDirection == kReversed) {
     510           0 :             dest = mEndBuffer - oldSize;
     511             :         }
     512           0 :         LOG_CHUNK_MOVE(mStart, dest, oldSize);
     513           0 :         memmove(dest, mStart, oldSize * sizeof(txXPathNode));
     514           0 :         mStart = dest;
     515           0 :         mEnd = dest + oldSize;
     516             : 
     517           0 :         return true;
     518             :     }
     519             : 
     520             :     // This isn't 100% safe. But until someone manages to make a 1gig nodeset
     521             :     // it should be ok.
     522           0 :     int32_t newLength = std::max(oldLength, kTxNodeSetMinSize);
     523             : 
     524           0 :     while (newLength < ensureSize) {
     525           0 :         newLength *= kTxNodeSetGrowFactor;
     526             :     }
     527             : 
     528             :     txXPathNode* newArr = static_cast<txXPathNode*>
     529           0 :                                      (moz_xmalloc(newLength *
     530           0 :                                                          sizeof(txXPathNode)));
     531           0 :     if (!newArr) {
     532           0 :         return false;
     533             :     }
     534             : 
     535           0 :     txXPathNode* dest = newArr;
     536           0 :     if (mDirection == kReversed) {
     537           0 :         dest += newLength - oldSize;
     538             :     }
     539             : 
     540           0 :     if (oldSize > 0) {
     541           0 :         LOG_CHUNK_MOVE(mStart, dest, oldSize);
     542           0 :         memcpy(dest, mStart, oldSize * sizeof(txXPathNode));
     543             :     }
     544             : 
     545           0 :     if (mStartBuffer) {
     546             : #ifdef DEBUG
     547           0 :         memset(mStartBuffer, 0,
     548           0 :                (mEndBuffer - mStartBuffer) * sizeof(txXPathNode));
     549             : #endif
     550           0 :         free(mStartBuffer);
     551             :     }
     552             : 
     553           0 :     mStartBuffer = newArr;
     554           0 :     mEndBuffer = mStartBuffer + newLength;
     555           0 :     mStart = dest;
     556           0 :     mEnd = dest + oldSize;
     557             : 
     558           0 :     return true;
     559             : }
     560             : 
     561             : txXPathNode*
     562           0 : txNodeSet::findPosition(const txXPathNode& aNode, txXPathNode* aFirst,
     563             :                         txXPathNode* aLast, bool& aDupe) const
     564             : {
     565           0 :     aDupe = false;
     566           0 :     if (aLast - aFirst <= 2) {
     567             :         // If we search 2 nodes or less there is no point in further divides
     568           0 :         txXPathNode* pos = aFirst;
     569           0 :         for (; pos < aLast; ++pos) {
     570           0 :             int cmp = txXPathNodeUtils::comparePosition(aNode, *pos);
     571           0 :             if (cmp < 0) {
     572           0 :                 return pos;
     573             :             }
     574             : 
     575           0 :             if (cmp == 0) {
     576           0 :                 aDupe = true;
     577             : 
     578           0 :                 return pos;
     579             :             }
     580             :         }
     581           0 :         return pos;
     582             :     }
     583             : 
     584             :     // (cannot add two pointers)
     585           0 :     txXPathNode* midpos = aFirst + (aLast - aFirst) / 2;
     586           0 :     int cmp = txXPathNodeUtils::comparePosition(aNode, *midpos);
     587           0 :     if (cmp == 0) {
     588           0 :         aDupe = true;
     589             : 
     590           0 :         return midpos;
     591             :     }
     592             : 
     593           0 :     if (cmp > 0) {
     594           0 :         return findPosition(aNode, midpos + 1, aLast, aDupe);
     595             :     }
     596             : 
     597             :     // midpos excluded as end of range
     598             : 
     599           0 :     return findPosition(aNode, aFirst, midpos, aDupe);
     600             : }
     601             : 
     602             : /* static */
     603             : void
     604           0 : txNodeSet::copyElements(txXPathNode* aDest,
     605             :                         const txXPathNode* aStart, const txXPathNode* aEnd)
     606             : {
     607           0 :     const txXPathNode* pos = aStart;
     608           0 :     while (pos < aEnd) {
     609           0 :         new(aDest) txXPathNode(*pos);
     610           0 :         ++aDest;
     611           0 :         ++pos;
     612             :     }
     613           0 : }
     614             : 
     615             : /* static */
     616             : void
     617           0 : txNodeSet::transferElements(txXPathNode* aDest,
     618             :                             const txXPathNode* aStart, const txXPathNode* aEnd)
     619             : {
     620           0 :     LOG_CHUNK_MOVE(aStart, aDest, (aEnd - aStart));
     621           0 :     memcpy(aDest, aStart, (aEnd - aStart) * sizeof(txXPathNode));
     622           0 : }

Generated by: LCOV version 1.13