SpanningCellSorter.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. // vim:cindent:ts=4:et:sw=4:
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. /*
  7. * Code to sort cells by their colspan, used by BasicTableLayoutStrategy.
  8. */
  9. #include "SpanningCellSorter.h"
  10. #include "nsQuickSort.h"
  11. #include "nsIPresShell.h"
  12. using mozilla::fallible;
  13. //#define DEBUG_SPANNING_CELL_SORTER
  14. SpanningCellSorter::SpanningCellSorter()
  15. : mState(ADDING)
  16. , mHashTable(&HashTableOps, sizeof(HashTableEntry))
  17. , mSortedHashTable(nullptr)
  18. {
  19. memset(mArray, 0, sizeof(mArray));
  20. }
  21. SpanningCellSorter::~SpanningCellSorter()
  22. {
  23. delete [] mSortedHashTable;
  24. }
  25. /* static */ const PLDHashTableOps
  26. SpanningCellSorter::HashTableOps = {
  27. HashTableHashKey,
  28. HashTableMatchEntry,
  29. PLDHashTable::MoveEntryStub,
  30. PLDHashTable::ClearEntryStub,
  31. nullptr
  32. };
  33. /* static */ PLDHashNumber
  34. SpanningCellSorter::HashTableHashKey(const void *key)
  35. {
  36. return NS_PTR_TO_INT32(key);
  37. }
  38. /* static */ bool
  39. SpanningCellSorter::HashTableMatchEntry(const PLDHashEntryHdr *hdr,
  40. const void *key)
  41. {
  42. const HashTableEntry *entry = static_cast<const HashTableEntry*>(hdr);
  43. return NS_PTR_TO_INT32(key) == entry->mColSpan;
  44. }
  45. bool
  46. SpanningCellSorter::AddCell(int32_t aColSpan, int32_t aRow, int32_t aCol)
  47. {
  48. NS_ASSERTION(mState == ADDING, "cannot call AddCell after GetNext");
  49. NS_ASSERTION(aColSpan >= ARRAY_BASE, "cannot add cells with colspan<2");
  50. Item *i = (Item*) mozilla::AutoStackArena::Allocate(sizeof(Item));
  51. NS_ENSURE_TRUE(i != nullptr, false);
  52. i->row = aRow;
  53. i->col = aCol;
  54. if (UseArrayForSpan(aColSpan)) {
  55. int32_t index = SpanToIndex(aColSpan);
  56. i->next = mArray[index];
  57. mArray[index] = i;
  58. } else {
  59. auto entry = static_cast<HashTableEntry*>
  60. (mHashTable.Add(NS_INT32_TO_PTR(aColSpan), fallible));
  61. NS_ENSURE_TRUE(entry, false);
  62. NS_ASSERTION(entry->mColSpan == 0 || entry->mColSpan == aColSpan,
  63. "wrong entry");
  64. NS_ASSERTION((entry->mColSpan == 0) == (entry->mItems == nullptr),
  65. "entry should be either new or properly initialized");
  66. entry->mColSpan = aColSpan;
  67. i->next = entry->mItems;
  68. entry->mItems = i;
  69. }
  70. return true;
  71. }
  72. /* static */ int
  73. SpanningCellSorter::SortArray(const void *a, const void *b, void *closure)
  74. {
  75. int32_t spanA = (*static_cast<HashTableEntry*const*>(a))->mColSpan;
  76. int32_t spanB = (*static_cast<HashTableEntry*const*>(b))->mColSpan;
  77. if (spanA < spanB)
  78. return -1;
  79. if (spanA == spanB)
  80. return 0;
  81. return 1;
  82. }
  83. SpanningCellSorter::Item*
  84. SpanningCellSorter::GetNext(int32_t *aColSpan)
  85. {
  86. NS_ASSERTION(mState != DONE, "done enumerating, stop calling");
  87. switch (mState) {
  88. case ADDING:
  89. /* prepare to enumerate the array */
  90. mState = ENUMERATING_ARRAY;
  91. mEnumerationIndex = 0;
  92. MOZ_FALLTHROUGH;
  93. case ENUMERATING_ARRAY:
  94. while (mEnumerationIndex < ARRAY_SIZE && !mArray[mEnumerationIndex])
  95. ++mEnumerationIndex;
  96. if (mEnumerationIndex < ARRAY_SIZE) {
  97. Item *result = mArray[mEnumerationIndex];
  98. *aColSpan = IndexToSpan(mEnumerationIndex);
  99. NS_ASSERTION(result, "logic error");
  100. #ifdef DEBUG_SPANNING_CELL_SORTER
  101. printf("SpanningCellSorter[%p]:"
  102. " returning list for colspan=%d from array\n",
  103. static_cast<void*>(this), *aColSpan);
  104. #endif
  105. ++mEnumerationIndex;
  106. return result;
  107. }
  108. /* prepare to enumerate the hash */
  109. mState = ENUMERATING_HASH;
  110. mEnumerationIndex = 0;
  111. if (mHashTable.EntryCount() > 0) {
  112. HashTableEntry **sh =
  113. new HashTableEntry*[mHashTable.EntryCount()];
  114. int32_t j = 0;
  115. for (auto iter = mHashTable.Iter(); !iter.Done(); iter.Next()) {
  116. sh[j++] = static_cast<HashTableEntry*>(iter.Get());
  117. }
  118. NS_QuickSort(sh, mHashTable.EntryCount(), sizeof(sh[0]),
  119. SortArray, nullptr);
  120. mSortedHashTable = sh;
  121. }
  122. MOZ_FALLTHROUGH;
  123. case ENUMERATING_HASH:
  124. if (mEnumerationIndex < mHashTable.EntryCount()) {
  125. Item *result = mSortedHashTable[mEnumerationIndex]->mItems;
  126. *aColSpan = mSortedHashTable[mEnumerationIndex]->mColSpan;
  127. NS_ASSERTION(result, "holes in hash table");
  128. #ifdef DEBUG_SPANNING_CELL_SORTER
  129. printf("SpanningCellSorter[%p]:"
  130. " returning list for colspan=%d from hash\n",
  131. static_cast<void*>(this), *aColSpan);
  132. #endif
  133. ++mEnumerationIndex;
  134. return result;
  135. }
  136. mState = DONE;
  137. MOZ_FALLTHROUGH;
  138. case DONE:
  139. ;
  140. }
  141. return nullptr;
  142. }