bool
WMemoryMap::canMerge(const RowGroup &rg, MemoryMap::NodeIterator mmNode) {
    ASSERT_not_null(memoryMap_);
    ASSERT_require(mmNode != memoryMap_->nodes().end());
    MemoryMap::NodeIterator mmNext = mmNode; ++mmNext;
    return mmNext!=memoryMap_->nodes().end() && mmNode->key().greatest()+1 == mmNext->key().least();
}
void
WMemoryMap::updateRowGroupDataWidgets(RowGroup &rg, MemoryMap::NodeIterator mmNode) {
    ASSERT_not_null(memoryMap_);
    ASSERT_require(mmNode != memoryMap_->nodes().end());
    const AddressInterval &interval = mmNode->key();
    ASSERT_forbid(interval.isEmpty());
    ASSERT_require(rg.segmentVa == interval.least());

    rg.wSplit->setHidden(!isEditable_ || rg.editingColumn==SplitColumn || !canSplit(rg, mmNode));
    rg.wMerge->setHidden(!isEditable_ || rg.editingColumn==MergeColumn || !canMerge(rg, mmNode));

    rg.wLeastVa->setText(StringUtility::addrToString(interval.least()));
    rg.wGreatestVa->setText(StringUtility::addrToString(interval.greatest()));

    if (interval.isWhole()) {
        rg.wSize->setText("whole");                    // since size would overflow back to zero
    } else {
        rg.wSize->setText(StringUtility::addrToString(interval.size()));
    }

    const MemoryMap::Segment &segment = mmNode->value();
    rg.wReadable->setChecked(0 != (segment.accessibility() & MemoryMap::READABLE));
    rg.wWritable->setChecked(0 != (segment.accessibility() & MemoryMap::WRITABLE));
    rg.wExecutable->setChecked(0 != (segment.accessibility() & MemoryMap::EXECUTABLE));

    rg.wName->setText(StringUtility::cEscape(segment.name()));
}
// Synchronize the RowGroup list and the WTable rows with the MemoryMap
void
WMemoryMap::synchronize() {
    ASSERT_not_null(memoryMap_);
    memoryMap_->checkConsistency();
    MemoryMap::NodeIterator mmNode = memoryMap_->nodes().begin();
    RowGroups::iterator rg = rowGroups_.begin();
    size_t rgIdx = 0;

    for (/*void*/; mmNode != memoryMap_->nodes().end(); ++mmNode, ++rg, ++rgIdx) {
        size_t tableIdx = rowGroupTableIndex(rgIdx);
        if (rg == rowGroups_.end()) {
            // Append a RowGroup and the corresponding table rows
            rg = rowGroups_.insert(rg, RowGroup(mmNode->key().least()));
            instantiateTableWidgets(*rg, tableIdx);
        } else {
            // Make sure the existing RowGroup is linked to the correct MemoryMap node.  Since MemoryMap::NodeIterator is not
            // stable over insert and erase, we need to store a lookup key rather than an iterator.
            ASSERT_require2(rowGroupTableIndex(rgIdx+1)-1 < (size_t)wTable_->rowCount(), "table rows must already exist");
            rg->segmentVa = mmNode->key().least();
        }

        // Make sure the table is showing correct data.
        rg->editingColumn = ZeroColumn;
        rg->wId->setText(StringUtility::numberToString(rgIdx+1));
        updateRowGroupWidgets(*rg, mmNode);
    }

    // Remove extra RowGroup entries and their corresponding WTable rows.
    rowGroups_.erase(rg, rowGroups_.end());
    size_t tableIdx = rowGroupTableIndex(rgIdx);
    while ((size_t)wTable_->rowCount() > tableIdx)
        wTable_->deleteRow(wTable_->rowCount()-1);
}
MemoryMap::NodeIterator
WMemoryMap::findMapNode(const RowGroup &rg) {
    MemoryMap::NodeIterator mmNode = memoryMap_.at(rg.segmentVa).findNode();
    ASSERT_require(mmNode != memoryMap_.nodes().end());
    ASSERT_require(mmNode->key().least() == rg.segmentVa);
    return mmNode;
}
// Synchronize edit rows of the table with the RowGroups
void
WMemoryMap::synchronizeEdits(RowGroup &rg, ColumnNumber toEdit) {
    rg.editingColumn = toEdit;
    MemoryMap::NodeIterator mmNode = memoryMap_.nodes().begin();
    RowGroups::iterator rgIter = rowGroups_.begin();
    for (/*void*/; mmNode != memoryMap_.nodes().end(); ++mmNode, ++rgIter) {
        ASSERT_require(rgIter != rowGroups_.end());
        ASSERT_require(mmNode->key().least() == rgIter->segmentVa);
        if (rgIter->wId != rg.wId || !isEditable_)
            rgIter->editingColumn = ZeroColumn;
        updateRowGroupEditWidgets(*rgIter, mmNode);
    }
}
bool
WMemoryMap::canSplit(const RowGroup &rg, MemoryMap::NodeIterator mmNode) {
    ASSERT_not_null(memoryMap_);
    ASSERT_require(mmNode != memoryMap_->nodes().end());
    return !mmNode->key().isEmpty() && mmNode->key().size() > 1;
}