dom/xslt/xpath/txNodeSet.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial