Node::List convert(Node::List list) { Node::List result; std::transform( list.begin(), list.end(), std::back_inserter(result), [] (const Node& node) { return T(node); } ); return result; }
void Variation::difference(Root const* root, Variation const* var, unsigned level, Node::List& nodes) const { //M_ASSERT(root); //M_ASSERT(var); Key const& endKey = var->successor(); unsigned i = 0; unsigned k = 0; unsigned m = m_list.size(); unsigned n = var->m_list.size(); if (m > 0 && n > 0) { KeyNode const* lhs = m_list[0]; // node from current game KeyNode const* rhs = var->m_list[0]; // node from previous game if (lhs->key() < rhs->key()) { do ++i; while (i < m && m_list[i]->key() < rhs->key()); nodes.push_back(root->newAction(Action::Insert, level, rhs->startKey())); nodes.insert(nodes.end(), m_list.begin(), m_list.begin() + i); nodes.push_back(root->newAction(Action::Finish, level)); } else if (rhs->key() < lhs->key()) { do ++k; while (k < n && var->m_list[k]->key() < lhs->key()); Key const& after = k == n ? endKey : var->m_list[k]->startKey(); nodes.push_back(root->newAction(Action::Remove, level, rhs->startKey(), after)); } } while (i < m && k < n) { KeyNode const* lhs = m_list[i]; // node from current game KeyNode const* rhs = var->m_list[k]; // node from previous game Type lhsType = lhs->type(); Type rhsType = rhs->type(); if (lhsType == rhsType) { if (lhsType == TVariation) { Variation const* lhsVar = static_cast<Variation const*>(lhs); Variation const* rhsVar = static_cast<Variation const*>(rhs); lhsVar->difference(root, rhsVar, level + 1, nodes); } else if (*lhs != rhs) { if ( lhsType == TMove && ( static_cast<Move const*>(lhs)->ply() == 0 || static_cast<Move const*>(rhs)->ply() == 0 || *static_cast<Move const*>(lhs)->ply() != static_cast<Move const*>(rhs)->ply())) { KeyNode const* const* lhsLast = m_list.begin() + i + 1; KeyNode const* const* lhsEnd = m_list.end(); KeyNode const* const* rhsLast = var->m_list.begin() + k + 1; KeyNode const* const* rhsEnd = var->m_list.end(); while ( lhsLast < lhsEnd && rhsLast < rhsEnd && (*lhsLast)->type() == (*rhsLast)->type() && (*lhsLast)->key() == (*rhsLast)->key() && *static_cast<Node const*>(*lhsLast) == static_cast<Node const*>(*rhsLast)) { ++lhsLast; ++rhsLast; } Key const& before = rhs->endKey(); Key const& after = rhsLast == var->m_list.end() ? endKey : (*rhsLast)->startKey(); nodes.push_back(root->newAction(Action::Replace, level, before, after)); nodes.insert(nodes.end(), m_list.begin() + i, lhsLast); nodes.push_back(root->newAction(Action::Finish, level)); i = lhsLast - m_list.begin() - 1; k = rhsLast - var->m_list.begin() - 1; } else { Key const& before = rhs->endKey(); Key const& after = (k == n - 1) ? endKey : var->m_list[k + 1]->startKey(); nodes.push_back(root->newAction(Action::Replace, level, before, after)); nodes.push_back(lhs); nodes.push_back(root->newAction(Action::Finish, level)); } } ++i; ++k; } else // if (lhsType != rhsType) { enum { Insert, Remove } action; switch (rhsType) { case TDiagram: action = Remove; break; case TMove: action = Insert; break; case TVariation: action = (lhsType == TMove) ? Remove : Insert; break; default: //M_ASSERT(!"should not happen"); return; } switch (action) { case Insert: nodes.push_back(root->newAction(Action::Insert, level, rhs->startKey())); nodes.push_back(lhs); nodes.push_back(root->newAction(Action::Finish, level)); ++i; break; case Remove: Key const& after = (k == n - 1) ? endKey : var->m_list[k + 1]->startKey(); nodes.push_back(root->newAction(Action::Remove, level, rhs->startKey(), after)); ++k; break; } } } if (i < m) { nodes.push_back(root->newAction(Action::Insert, level, successor())); nodes.insert(nodes.end(), m_list.begin() + i, m_list.end()); nodes.push_back(root->newAction(Action::Finish, level)); } if (k < n) nodes.push_back(root->newAction(Action::Remove, level, var->m_list[k]->startKey(), endKey)); }