<commit_before>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
 *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/dom/ShadowTreeStyleSheetCollection.h"

#include "HTMLNames.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/dom/Element.h"
#include "core/dom/StyleEngine.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/html/HTMLStyleElement.h"

namespace WebCore {

using namespace HTMLNames;

ShadowTreeStyleSheetCollection::ShadowTreeStyleSheetCollection(ShadowRoot& shadowRoot)
    : TreeScopeStyleSheetCollection(shadowRoot)
{
}

void ShadowTreeStyleSheetCollection::collectStyleSheets(StyleEngine* engine, StyleSheetCollection& collection)
{
    DocumentOrderedList::iterator begin = m_styleSheetCandidateNodes.begin();
    DocumentOrderedList::iterator end = m_styleSheetCandidateNodes.end();
    for (DocumentOrderedList::iterator it = begin; it != end; ++it) {
        Node* node = *it;
        StyleSheet* sheet = 0;
        CSSStyleSheet* activeSheet = 0;

        if (!isHTMLStyleElement(*node))
            continue;

        HTMLStyleElement* element = toHTMLStyleElement(node);
        const AtomicString& title = element->fastGetAttribute(titleAttr);
        bool enabledViaScript = false;

        sheet = element->sheet();
        if (sheet && !sheet->disabled() && sheet->isCSSStyleSheet())
            activeSheet = toCSSStyleSheet(sheet);

        // FIXME: clarify how PREFERRED or ALTERNATE works in shadow trees.
        // Should we set preferred/selected stylesheets name in shadow trees and
        // use the name in document?
        const AtomicString& rel = element->fastGetAttribute(relAttr);
        if (!enabledViaScript && sheet && !title.isEmpty()) {
            if (engine->preferredStylesheetSetName().isEmpty()) {
                if (element->hasLocalName(styleTag) || !rel.contains("alternate")) {
                    engine->setPreferredStylesheetSetName(title);
                    engine->setSelectedStylesheetSetName(title);
                }
            }
            if (title != engine->preferredStylesheetSetName())
                activeSheet = 0;
        }

        if (rel.contains("alternate") && title.isEmpty())
            activeSheet = 0;

        if (sheet)
            collection.appendSheetForList(sheet);
        if (activeSheet)
            collection.appendActiveStyleSheet(activeSheet);
    }
}

bool ShadowTreeStyleSheetCollection::updateActiveStyleSheets(StyleEngine* engine, StyleResolverUpdateMode updateMode)
{
    StyleSheetCollection collection;
    collectStyleSheets(engine, collection);

    StyleSheetChange change;
    analyzeStyleSheetChange(updateMode, collection, change);

    if (StyleResolver* styleResolver = engine->resolver()) {
        // FIXME: We might have already had styles in child treescope. In this case, we cannot use buildScopedStyleTreeInDocumentOrder.
        // Need to change "false" to some valid condition.
        styleResolver->setBuildScopedStyleTreeInDocumentOrder(false);
        if (change.styleResolverUpdateType != Additive) {
            // We should not destroy StyleResolver when we find any stylesheet update in a shadow tree.
            // In this case, we will reset rulesets created from style elements in the shadow tree.
            resetAllRuleSetsInTreeScope(styleResolver);
            styleResolver->removePendingAuthorStyleSheets(m_activeAuthorStyleSheets);
            styleResolver->lazyAppendAuthorStyleSheets(0, collection.activeAuthorStyleSheets());
        } else {
            styleResolver->lazyAppendAuthorStyleSheets(m_activeAuthorStyleSheets.size(), collection.activeAuthorStyleSheets());
        }
    }
    if (change.requiresFullStyleRecalc)
        toShadowRoot(m_treeScope.rootNode()).host()->setNeedsStyleRecalc(SubtreeStyleChange);

    m_scopingNodesForStyleScoped.didRemoveScopingNodes();
    collection.swap(*this);
    updateUsesRemUnits();

    return change.requiresFullStyleRecalc;
}

}
<commit_msg>Remove bogus if check in ShadowTreeStyleSheetCollection::collectStyleSheets()<commit_after>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
 *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/dom/ShadowTreeStyleSheetCollection.h"

#include "HTMLNames.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/dom/Element.h"
#include "core/dom/StyleEngine.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/html/HTMLStyleElement.h"

namespace WebCore {

using namespace HTMLNames;

ShadowTreeStyleSheetCollection::ShadowTreeStyleSheetCollection(ShadowRoot& shadowRoot)
    : TreeScopeStyleSheetCollection(shadowRoot)
{
}

void ShadowTreeStyleSheetCollection::collectStyleSheets(StyleEngine* engine, StyleSheetCollection& collection)
{
    DocumentOrderedList::iterator begin = m_styleSheetCandidateNodes.begin();
    DocumentOrderedList::iterator end = m_styleSheetCandidateNodes.end();
    for (DocumentOrderedList::iterator it = begin; it != end; ++it) {
        Node* node = *it;
        StyleSheet* sheet = 0;
        CSSStyleSheet* activeSheet = 0;

        if (!isHTMLStyleElement(*node))
            continue;

        HTMLStyleElement* element = toHTMLStyleElement(node);
        const AtomicString& title = element->fastGetAttribute(titleAttr);
        bool enabledViaScript = false;

        sheet = element->sheet();
        if (sheet && !sheet->disabled() && sheet->isCSSStyleSheet())
            activeSheet = toCSSStyleSheet(sheet);

        // FIXME: clarify how PREFERRED or ALTERNATE works in shadow trees.
        // Should we set preferred/selected stylesheets name in shadow trees and
        // use the name in document?
        if (!enabledViaScript && sheet && !title.isEmpty()) {
            if (engine->preferredStylesheetSetName().isEmpty()) {
                engine->setPreferredStylesheetSetName(title);
                engine->setSelectedStylesheetSetName(title);
            }
            if (title != engine->preferredStylesheetSetName())
                activeSheet = 0;
        }

        const AtomicString& rel = element->fastGetAttribute(relAttr);
        if (rel.contains("alternate") && title.isEmpty())
            activeSheet = 0;

        if (sheet)
            collection.appendSheetForList(sheet);
        if (activeSheet)
            collection.appendActiveStyleSheet(activeSheet);
    }
}

bool ShadowTreeStyleSheetCollection::updateActiveStyleSheets(StyleEngine* engine, StyleResolverUpdateMode updateMode)
{
    StyleSheetCollection collection;
    collectStyleSheets(engine, collection);

    StyleSheetChange change;
    analyzeStyleSheetChange(updateMode, collection, change);

    if (StyleResolver* styleResolver = engine->resolver()) {
        // FIXME: We might have already had styles in child treescope. In this case, we cannot use buildScopedStyleTreeInDocumentOrder.
        // Need to change "false" to some valid condition.
        styleResolver->setBuildScopedStyleTreeInDocumentOrder(false);
        if (change.styleResolverUpdateType != Additive) {
            // We should not destroy StyleResolver when we find any stylesheet update in a shadow tree.
            // In this case, we will reset rulesets created from style elements in the shadow tree.
            resetAllRuleSetsInTreeScope(styleResolver);
            styleResolver->removePendingAuthorStyleSheets(m_activeAuthorStyleSheets);
            styleResolver->lazyAppendAuthorStyleSheets(0, collection.activeAuthorStyleSheets());
        } else {
            styleResolver->lazyAppendAuthorStyleSheets(m_activeAuthorStyleSheets.size(), collection.activeAuthorStyleSheets());
        }
    }
    if (change.requiresFullStyleRecalc)
        toShadowRoot(m_treeScope.rootNode()).host()->setNeedsStyleRecalc(SubtreeStyleChange);

    m_scopingNodesForStyleScoped.didRemoveScopingNodes();
    collection.swap(*this);
    updateUsesRemUnits();

    return change.requiresFullStyleRecalc;
}

}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
** disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
** following disclaimer in the documentation and/or other materials provided with the distribution.
** * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "Merge.h"
#include "GitRepository.h"
#include "GitPiecewiseLoader.h"

#include "ConflictUnitDetector.h"
#include "ListMergeComponent.h"
#include "../simple/SimpleTextFileStore.h"

namespace FilePersistence {

bool Merge::commit(const Signature& author, const Signature& committer, const QString& message)
{
	Q_ASSERT(stage_ == Stage::WroteToIndex);

	QString treeSHA1 = repository_->writeIndexToTree();

	QStringList parents;
	parents.append(headCommitId_);
	parents.append(revisionCommitId_);

	repository_->newCommit(treeSHA1, message, author, committer, parents);

	stage_ = Stage::Committed;

	return true;
}

std::shared_ptr<GenericTree> Merge::mergedTree()
{
	Q_ASSERT(stage_ >= Stage::BuiltMergedTree);
	return treeMerged_;
}

Merge::Merge(QString revision, bool fastForward, GitRepository* repository)
	: repository_{repository}
{
	// TODO: fill those lists correctly
	const QStringList listTypes = {"StatementItemList",
					  "TypedListOfResult",
					  "TypedListOfFormalTypeArgument",
					  "TypedListOfExpression",
					  "TypedListOfDeclaration",
					  "TypedListOfMemberInitializer",
					  "TypedListOfEnumerator"
					 };

	const QStringList unorderedTypes = {"TypedListOfClass",
							 "TypedListOfMethod",
							 "TypedListOfFormalArgument",
							 "TypedListOfFormalResult",
							 "TypedListOfField",
							 "TypedListOfUsedLibrary"
							};

	const QStringList statements = {"Block",
											  "BreakStatement",
											  "CaseStatement",
											  "ContinueStatement",
											  "DeclarationStatement",
											  "ExpressionStatement",
											  "ForEachStatement",
											  "IfStatement",
											  "LoopStatement",
											  "ReturnStatement",
											  "Statement",
											  "SwitchStatement",
											  "TryCatchFinallyStatement"};

	const QStringList declarations = {"Class",
												 "Declaration",
												 "ExplicitTemplateInstantiation",
												 "Field",
												 "Method",
												 "Module",
												 "NameImport",
												 "Project",
												 "TypeAlias",
												 "VariableDeclaration"};

	const QStringList extraUnitTypes = {"CommentStatementItem",
													"CatchClause",
													"StatementItemList"};

	const QStringList debugAndTestUnitTypes = {"TestConflictType",
															 "TestListType",
															 "TestUnorderedType",
															 "ListElement",
															 "project",
															 "package",
															 "class",
															 "fieldList",
															 "methodList",
															 "field",
															 "method",
															 "Method",
															 "loop",
															 "TypedListOfMethod"};

	const QStringList debugAndTestListTypes = {"TestListType",
															 "TestNoConflictList",
															 "project",
															 "package",
															 "fieldList",
															 "methodList",
															 "method"};

	const QStringList debugAndTestUnordered = {"TestUnorderedType",
															 "TypedListOfMethod"};

	listTypes_ = QSet<QString>::fromList(listTypes + debugAndTestListTypes);
	unorderedTypes_ = QSet<QString>::fromList(unorderedTypes + debugAndTestUnordered);
	conflictTypes_ = listTypes_ + unorderedTypes_ +
			QSet<QString>::fromList(statements + declarations + extraUnitTypes + debugAndTestUnitTypes);

	headCommitId_ = repository_->getSHA1("HEAD");
	revisionCommitId_ = repository_->getSHA1(revision);
	baseCommitId_ = repository_->findMergeBase("HEAD", revision);

	Q_ASSERT(!baseCommitId_.isNull());

	stage_ = Stage::FoundMergeBase;

	Kind kind;
	if (baseCommitId_.compare(revisionCommitId_) == 0) kind = Kind::AlreadyUpToDate;
	else if (baseCommitId_.compare(headCommitId_) == 0) kind = Kind::FastForward;
	else kind = Kind::TrueMerge;

	stage_ = Stage::Classified;

	switch (kind)
	{
		case Kind::AlreadyUpToDate:
			stage_ = Merge::Stage::Committed;
			break;

		case Kind::FastForward:
			if (fastForward)
			{
				QString branch = repository_->currentBranch();
				repository_->setReferenceTarget(branch, revisionCommitId_);
				repository_->checkout(revisionCommitId_, true);
				stage_ = Stage::Committed;
			}
			else
			{
				repository_->checkout(revisionCommitId_, true);
				repository_->writeRevisionIntoIndex(revisionCommitId_);
				stage_ = Stage::WroteToIndex;
			}
			break;

		case Kind::TrueMerge:
			performTrueMerge();
			break;

		default:
			Q_ASSERT(false);
	}
}

Merge::~Merge()
{
	treeA_ = nullptr;
	treeB_ = nullptr;
	treeBase_ = nullptr;
	treeMerged_ = nullptr;
}

void Merge::initializeComponents()
{
	pipelineInitializer_ = std::shared_ptr<ConflictUnitDetector>(
				new ConflictUnitDetector{conflictTypes_, USE_LINKED_SETS});

	auto listMergeComponent = std::make_shared<ListMergeComponent>(conflictTypes_, listTypes_, unorderedTypes_);
	conflictPipeline_.append(listMergeComponent);
}

void Merge::performTrueMerge()
{
	initializeComponents();

	treeA_ = std::shared_ptr<GenericTree>(new GenericTree{repository_->projectName()});
	new GitPiecewiseLoader{treeA_, repository_, headCommitId_};
	treeB_ = std::unique_ptr<GenericTree>(new GenericTree{repository_->projectName()});
	new GitPiecewiseLoader{treeB_, repository_, revisionCommitId_};
	treeBase_ = std::unique_ptr<GenericTree>(new GenericTree{repository_->projectName()});
	new GitPiecewiseLoader{treeBase_, repository_, baseCommitId_};

	Diff diffA = repository_->diff(baseCommitId_, headCommitId_, treeBase_, treeA_);
	Diff diffB = repository_->diff(baseCommitId_, revisionCommitId_, treeBase_, treeB_);

	auto cdgA = ChangeDependencyGraph{diffA};
	auto cdgB = ChangeDependencyGraph{diffB};
	conflictingChanges_ = {};
	conflictPairs_ = {};

	LinkedChangesSet linkedChangesSet;
	if (USE_LINKED_SETS)
		linkedChangesSet = LinkedChangesSet{cdgA, cdgB};

	// ### PIPELINE INITIALIZER ###
	LinkedChangesTransition transition = pipelineInitializer_->run(treeA_, treeB_, treeBase_,
																						cdgA, cdgB, conflictingChanges_,
																						conflictPairs_, linkedChangesSet);
	// NOTE this is where one would check the transition of the initializer.

	// ### THE PIPLELINE ###
	for (auto component : conflictPipeline_)
	{
		// deep copy current state
		linkedChangesSet = LinkedChangesSet{transition.getNewState()};
		transition = component->run(treeA_, treeB_, treeBase_, cdgA, cdgB,
											 conflictingChanges_, conflictPairs_, linkedChangesSet);
		// NOTE this is where one would check the transition of a component.
	}

	IdToChangeDescriptionHash applicableChanges;
	for (auto change : cdgA.changes())
		if (!conflictingChanges_.contains(change) && !change->onlyStructureChange())
			applicableChanges.insert(change->nodeId(), change);
	for (auto change : cdgB.changes())
		if (!conflictingChanges_.contains(change) && !change->onlyStructureChange())
			applicableChanges.insert(change->nodeId(), change);

	stage_ = Stage::AutoMerged;

	treeMerged_ = std::shared_ptr<GenericTree>(new GenericTree{repository_->projectName()});
	repository_->loadGenericTree(treeMerged_, baseCommitId_);
	treeMerged_->buildLookupHash();
	applyChangesToTree(treeMerged_, cdgA);
	applyChangesToTree(treeMerged_, cdgB);

	// remove holes in lists
	for (auto changeIt = cdgA.changes().constBegin(); changeIt != cdgA.changes().constEnd(); ++changeIt)
	{
		const auto& change = changeIt.value();
		auto list = treeMerged_->find(change->nodeId());
		if (list && (listTypes_.contains(list->type()) ||
						 unorderedTypes_.contains(list->type())))
		{
			// list is a list container that has changed and exists in the merged tree
			int gapSize = 0;
			for (int curIdx = 0; curIdx < list->children().size(); ++curIdx)
			{
				GenericNode* elem;
				while (!(elem = list->child(QString::number(curIdx + gapSize))))
					++gapSize;
				elem->setLabel(QString::number(curIdx));
			}
		}
	}

	stage_ = Stage::BuiltMergedTree;

	SimpleTextFileStore::saveGenericTree(treeMerged_, repository_->projectName(),
													 repository_->workdirPath(), {"Project", "Module"});

	if (conflictingChanges_.isEmpty())
	{
		stage_ = Stage::WroteToWorkDir;

		repository_->writeWorkdirToIndex();

		stage_ = Stage::WroteToIndex;
	}
	else
	{
		// TODO prepare for manual merge
		// TODO write conflicts to file maybe.
	}
}

void Merge::addDependencies(QList<std::shared_ptr<ChangeDescription>>& queue,
									 const std::shared_ptr<ChangeDescription>& change,
									 const ChangeDependencyGraph& cdg)
{
	for (auto dependency : cdg.getDependencies(change))
	{
		if (!queue.contains(dependency))
		{
			Q_ASSERT(!conflictingChanges_.contains(dependency));
			addDependencies(queue, dependency, cdg);
			queue.append(dependency);
		}
	}
}

void Merge::applyChangesToTree(const std::shared_ptr<GenericTree>& tree,
										 const ChangeDependencyGraph& cdg)
{
	// sort changes topologically before applying
	QList<std::shared_ptr<ChangeDescription>> queue;
	for (auto change : cdg.changes())
	{
		if (!conflictingChanges_.contains(change) && !queue.contains(change))
		{
			addDependencies(queue, change, cdg);
			queue.append(change);
		}
	}

	/* We apply changes in a way that make them indempotent.
	 * This makes it possible for both branches to make the exact same change
	 * e.g. delete the same node.
	 */

	for (auto change : queue)
	{
		switch (change->type())
		{
			case ChangeType::Insertion:
			{
				auto existing = tree->find(change->nodeB()->id());
				if (existing)
					Q_ASSERT(existing->equalTo(change->nodeB()));
				else
				{
					auto persistentUnitName = change->nodeB()->persistentUnit()->name();
					auto persistentUnit = tree->persistentUnit(persistentUnitName);
					if (!persistentUnit)
						persistentUnit = &tree->newPersistentUnit(persistentUnitName);
					auto node = persistentUnit->newNode(change->nodeB());
					node->linkNode();
					Q_ASSERT(node->parent()->id() == change->nodeB()->parentId());
					Q_ASSERT(tree->find(change->nodeId()));
				}
				break;
			}

			case ChangeType::Deletion:
			{
				auto node = tree->find(change->nodeA()->id());
				if (node)
				{
					Q_ASSERT(node->children().empty());
					tree->remove(change->nodeId());
					Q_ASSERT(!tree->find(change->nodeA()->id()));
				}
				break;
			}

			case ChangeType::Move:
			{
				auto node = tree->find(change->nodeA()->id());
				node->detachFromParent();
				node->setParentId(change->nodeB()->parentId());
				node->attachToParent();
				Q_ASSERT(node->parent()->id() == change->nodeB()->parentId());
				// no break, need to do the same stuff as for stationary.
			}

			case ChangeType::Stationary:
			{
				auto node = tree->find(change->nodeA()->id());

				if (change->hasFlags(ChangeDescription::Value))
				{
					auto valueType = change->nodeB()->valueType();
					auto value = change->nodeB()->rawValue();
					node->resetValue(valueType, value);
				}

				if (change->hasFlags(ChangeDescription::Type))
					node->setType(change->nodeB()->type());

				if (change->hasFlags(ChangeDescription::Label))
					node->setLabel(change->nodeB()->label());

				break;
			}

			default:
				Q_ASSERT(false);
		}
	}
}

}
<commit_msg>use different syntax<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
** disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
** following disclaimer in the documentation and/or other materials provided with the distribution.
** * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "Merge.h"
#include "GitRepository.h"
#include "GitPiecewiseLoader.h"

#include "ConflictUnitDetector.h"
#include "ListMergeComponent.h"
#include "../simple/SimpleTextFileStore.h"

namespace FilePersistence {

bool Merge::commit(const Signature& author, const Signature& committer, const QString& message)
{
	Q_ASSERT(stage_ == Stage::WroteToIndex);

	QString treeSHA1 = repository_->writeIndexToTree();

	QStringList parents;
	parents.append(headCommitId_);
	parents.append(revisionCommitId_);

	repository_->newCommit(treeSHA1, message, author, committer, parents);

	stage_ = Stage::Committed;

	return true;
}

std::shared_ptr<GenericTree> Merge::mergedTree()
{
	Q_ASSERT(stage_ >= Stage::BuiltMergedTree);
	return treeMerged_;
}

Merge::Merge(QString revision, bool fastForward, GitRepository* repository)
	: repository_{repository}
{
	// TODO: fill those lists correctly
	const QStringList listTypes{"StatementItemList",
										 "TypedListOfResult",
										 "TypedListOfFormalTypeArgument",
										 "TypedListOfExpression",
										 "TypedListOfDeclaration",
										 "TypedListOfMemberInitializer",
										 "TypedListOfEnumerator"
										};

	const QStringList unorderedTypes{"TypedListOfClass",
												"TypedListOfMethod",
												"TypedListOfFormalArgument",
												"TypedListOfFormalResult",
												"TypedListOfField",
												"TypedListOfUsedLibrary"
											  };

	const QStringList statements{"Block",
										  "BreakStatement",
										  "CaseStatement",
										  "ContinueStatement",
										  "DeclarationStatement",
										  "ExpressionStatement",
										  "ForEachStatement",
										  "IfStatement",
										  "LoopStatement",
										  "ReturnStatement",
										  "Statement",
										  "SwitchStatement",
										  "TryCatchFinallyStatement"};

	const QStringList declarations{"Class",
											 "Declaration",
											 "ExplicitTemplateInstantiation",
											 "Field",
											 "Method",
											 "Module",
											 "NameImport",
											 "Project",
											 "TypeAlias",
											 "VariableDeclaration"};

	const QStringList extraUnitTypes{"CommentStatementItem",
												"CatchClause",
												"StatementItemList"};

	const QStringList debugAndTestUnitTypes{"TestConflictType",
														 "TestListType",
														 "TestUnorderedType",
														 "ListElement",
														 "project",
														 "package",
														 "class",
														 "fieldList",
														 "methodList",
														 "field",
														 "method",
														 "Method",
														 "loop",
														 "TypedListOfMethod"};

	const QStringList debugAndTestListTypes{"TestListType",
														 "TestNoConflictList",
														 "project",
														 "package",
														 "fieldList",
														 "methodList",
														 "method"};

	const QStringList debugAndTestUnordered{"TestUnorderedType",
														 "TypedListOfMethod"};

	listTypes_ = QSet<QString>::fromList(listTypes + debugAndTestListTypes);
	unorderedTypes_ = QSet<QString>::fromList(unorderedTypes + debugAndTestUnordered);
	conflictTypes_ = listTypes_ + unorderedTypes_ +
			QSet<QString>::fromList(statements + declarations + extraUnitTypes + debugAndTestUnitTypes);

	headCommitId_ = repository_->getSHA1("HEAD");
	revisionCommitId_ = repository_->getSHA1(revision);
	baseCommitId_ = repository_->findMergeBase("HEAD", revision);

	Q_ASSERT(!baseCommitId_.isNull());

	stage_ = Stage::FoundMergeBase;

	Kind kind;
	if (baseCommitId_.compare(revisionCommitId_) == 0) kind = Kind::AlreadyUpToDate;
	else if (baseCommitId_.compare(headCommitId_) == 0) kind = Kind::FastForward;
	else kind = Kind::TrueMerge;

	stage_ = Stage::Classified;

	switch (kind)
	{
		case Kind::AlreadyUpToDate:
			stage_ = Merge::Stage::Committed;
			break;

		case Kind::FastForward:
			if (fastForward)
			{
				QString branch = repository_->currentBranch();
				repository_->setReferenceTarget(branch, revisionCommitId_);
				repository_->checkout(revisionCommitId_, true);
				stage_ = Stage::Committed;
			}
			else
			{
				repository_->checkout(revisionCommitId_, true);
				repository_->writeRevisionIntoIndex(revisionCommitId_);
				stage_ = Stage::WroteToIndex;
			}
			break;

		case Kind::TrueMerge:
			performTrueMerge();
			break;

		default:
			Q_ASSERT(false);
	}
}

Merge::~Merge()
{
	treeA_ = nullptr;
	treeB_ = nullptr;
	treeBase_ = nullptr;
	treeMerged_ = nullptr;
}

void Merge::initializeComponents()
{
	pipelineInitializer_ = std::shared_ptr<ConflictUnitDetector>(
				new ConflictUnitDetector{conflictTypes_, USE_LINKED_SETS});

	auto listMergeComponent = std::make_shared<ListMergeComponent>(conflictTypes_, listTypes_, unorderedTypes_);
	conflictPipeline_.append(listMergeComponent);
}

void Merge::performTrueMerge()
{
	initializeComponents();

	treeA_ = std::shared_ptr<GenericTree>(new GenericTree{repository_->projectName()});
	new GitPiecewiseLoader{treeA_, repository_, headCommitId_};
	treeB_ = std::unique_ptr<GenericTree>(new GenericTree{repository_->projectName()});
	new GitPiecewiseLoader{treeB_, repository_, revisionCommitId_};
	treeBase_ = std::unique_ptr<GenericTree>(new GenericTree{repository_->projectName()});
	new GitPiecewiseLoader{treeBase_, repository_, baseCommitId_};

	Diff diffA = repository_->diff(baseCommitId_, headCommitId_, treeBase_, treeA_);
	Diff diffB = repository_->diff(baseCommitId_, revisionCommitId_, treeBase_, treeB_);

	auto cdgA = ChangeDependencyGraph{diffA};
	auto cdgB = ChangeDependencyGraph{diffB};
	conflictingChanges_ = {};
	conflictPairs_ = {};

	LinkedChangesSet linkedChangesSet;
	if (USE_LINKED_SETS)
		linkedChangesSet = LinkedChangesSet{cdgA, cdgB};

	// ### PIPELINE INITIALIZER ###
	LinkedChangesTransition transition = pipelineInitializer_->run(treeA_, treeB_, treeBase_,
																						cdgA, cdgB, conflictingChanges_,
																						conflictPairs_, linkedChangesSet);
	// NOTE this is where one would check the transition of the initializer.

	// ### THE PIPLELINE ###
	for (auto component : conflictPipeline_)
	{
		// deep copy current state
		linkedChangesSet = LinkedChangesSet{transition.getNewState()};
		transition = component->run(treeA_, treeB_, treeBase_, cdgA, cdgB,
											 conflictingChanges_, conflictPairs_, linkedChangesSet);
		// NOTE this is where one would check the transition of a component.
	}

	IdToChangeDescriptionHash applicableChanges;
	for (auto change : cdgA.changes())
		if (!conflictingChanges_.contains(change) && !change->onlyStructureChange())
			applicableChanges.insert(change->nodeId(), change);
	for (auto change : cdgB.changes())
		if (!conflictingChanges_.contains(change) && !change->onlyStructureChange())
			applicableChanges.insert(change->nodeId(), change);

	stage_ = Stage::AutoMerged;

	treeMerged_ = std::shared_ptr<GenericTree>(new GenericTree{repository_->projectName()});
	repository_->loadGenericTree(treeMerged_, baseCommitId_);
	treeMerged_->buildLookupHash();
	applyChangesToTree(treeMerged_, cdgA);
	applyChangesToTree(treeMerged_, cdgB);

	// remove holes in lists
	for (auto changeIt = cdgA.changes().constBegin(); changeIt != cdgA.changes().constEnd(); ++changeIt)
	{
		const auto& change = changeIt.value();
		auto list = treeMerged_->find(change->nodeId());
		if (list && (listTypes_.contains(list->type()) ||
						 unorderedTypes_.contains(list->type())))
		{
			// list is a list container that has changed and exists in the merged tree
			int gapSize = 0;
			for (int curIdx = 0; curIdx < list->children().size(); ++curIdx)
			{
				GenericNode* elem;
				while (!(elem = list->child(QString::number(curIdx + gapSize))))
					++gapSize;
				elem->setLabel(QString::number(curIdx));
			}
		}
	}

	stage_ = Stage::BuiltMergedTree;

	SimpleTextFileStore::saveGenericTree(treeMerged_, repository_->projectName(),
													 repository_->workdirPath(), {"Project", "Module"});

	if (conflictingChanges_.isEmpty())
	{
		stage_ = Stage::WroteToWorkDir;

		repository_->writeWorkdirToIndex();

		stage_ = Stage::WroteToIndex;
	}
	else
	{
		// TODO prepare for manual merge
		// TODO write conflicts to file maybe.
	}
}

void Merge::addDependencies(QList<std::shared_ptr<ChangeDescription>>& queue,
									 const std::shared_ptr<ChangeDescription>& change,
									 const ChangeDependencyGraph& cdg)
{
	for (auto dependency : cdg.getDependencies(change))
	{
		if (!queue.contains(dependency))
		{
			Q_ASSERT(!conflictingChanges_.contains(dependency));
			addDependencies(queue, dependency, cdg);
			queue.append(dependency);
		}
	}
}

void Merge::applyChangesToTree(const std::shared_ptr<GenericTree>& tree,
										 const ChangeDependencyGraph& cdg)
{
	// sort changes topologically before applying
	QList<std::shared_ptr<ChangeDescription>> queue;
	for (auto change : cdg.changes())
	{
		if (!conflictingChanges_.contains(change) && !queue.contains(change))
		{
			addDependencies(queue, change, cdg);
			queue.append(change);
		}
	}

	/* We apply changes in a way that make them indempotent.
	 * This makes it possible for both branches to make the exact same change
	 * e.g. delete the same node.
	 */

	for (auto change : queue)
	{
		switch (change->type())
		{
			case ChangeType::Insertion:
			{
				auto existing = tree->find(change->nodeB()->id());
				if (existing)
					Q_ASSERT(existing->equalTo(change->nodeB()));
				else
				{
					auto persistentUnitName = change->nodeB()->persistentUnit()->name();
					auto persistentUnit = tree->persistentUnit(persistentUnitName);
					if (!persistentUnit)
						persistentUnit = &tree->newPersistentUnit(persistentUnitName);
					auto node = persistentUnit->newNode(change->nodeB());
					node->linkNode();
					Q_ASSERT(node->parent()->id() == change->nodeB()->parentId());
					Q_ASSERT(tree->find(change->nodeId()));
				}
				break;
			}

			case ChangeType::Deletion:
			{
				auto node = tree->find(change->nodeA()->id());
				if (node)
				{
					Q_ASSERT(node->children().empty());
					tree->remove(change->nodeId());
					Q_ASSERT(!tree->find(change->nodeA()->id()));
				}
				break;
			}

			case ChangeType::Move:
			{
				auto node = tree->find(change->nodeA()->id());
				node->detachFromParent();
				node->setParentId(change->nodeB()->parentId());
				node->attachToParent();
				Q_ASSERT(node->parent()->id() == change->nodeB()->parentId());
				// no break, need to do the same stuff as for stationary.
			}

			case ChangeType::Stationary:
			{
				auto node = tree->find(change->nodeA()->id());

				if (change->hasFlags(ChangeDescription::Value))
				{
					auto valueType = change->nodeB()->valueType();
					auto value = change->nodeB()->rawValue();
					node->resetValue(valueType, value);
				}

				if (change->hasFlags(ChangeDescription::Type))
					node->setType(change->nodeB()->type());

				if (change->hasFlags(ChangeDescription::Label))
					node->setLabel(change->nodeB()->label());

				break;
			}

			default:
				Q_ASSERT(false);
		}
	}
}

}
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "platform/graphics/paint/DrawingRecorder.h"

#include "platform/RuntimeEnabledFeatures.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/GraphicsLayer.h"
#include "platform/graphics/paint/CachedDisplayItem.h"
#include "platform/graphics/paint/DisplayItemList.h"
#include "platform/graphics/paint/DrawingDisplayItem.h"
#include "third_party/skia/include/core/SkPicture.h"

namespace blink {

DrawingRecorder::DrawingRecorder(GraphicsContext& context, const DisplayItemClientWrapper& displayItemClient, DisplayItem::Type displayItemType, const FloatRect& bounds)
    : m_context(context)
    , m_displayItemClient(displayItemClient)
    , m_displayItemType(displayItemType)
    , m_canUseCachedDrawing(false)
#if ENABLE(ASSERT)
    , m_checkedCachedDrawing(false)
    , m_displayItemPosition(RuntimeEnabledFeatures::slimmingPaintEnabled() ? m_context.displayItemList()->newDisplayItemsSize() : 0)
#endif
{
    if (!RuntimeEnabledFeatures::slimmingPaintEnabled())
        return;

    ASSERT(DisplayItem::isDrawingType(displayItemType));
#if ENABLE(ASSERT)
    context.setInDrawingRecorder(true);
#endif
    ASSERT(context.displayItemList());
    m_canUseCachedDrawing = context.displayItemList()->clientCacheIsValid(displayItemClient.displayItemClient())
        && !RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled();

#ifndef NDEBUG
    // Enable recording to check if any painter is still doing unnecessary painting when we can use cache.
    context.beginRecording(bounds);
#else
    if (!m_canUseCachedDrawing)
        context.beginRecording(bounds);
#endif
}

DrawingRecorder::~DrawingRecorder()
{
    if (!RuntimeEnabledFeatures::slimmingPaintEnabled())
        return;

#if ENABLE(ASSERT)
    ASSERT(m_checkedCachedDrawing);
    m_context.setInDrawingRecorder(false);
#endif

    OwnPtr<DisplayItem> displayItem;

    if (m_canUseCachedDrawing) {
#ifndef NDEBUG
        RefPtr<const SkPicture> picture = m_context.endRecording();
        if (picture && picture->approximateOpCount()) {
            WTF_LOG_ERROR("Unnecessary painting for %s\n. Should check recorder.canUseCachedDrawing() before painting",
                m_displayItemClient.debugName().utf8().data());
        }
#endif
        displayItem = CachedDisplayItem::create(m_displayItemClient, DisplayItem::drawingTypeToCachedType(m_displayItemType));
    } else {
        displayItem = DrawingDisplayItem::create(m_displayItemClient, m_displayItemType, m_context.endRecording());
    }

#if ENABLE(ASSERT)
    ASSERT(m_displayItemPosition == m_context.displayItemList()->newDisplayItemsSize());
#endif
    m_context.displayItemList()->add(displayItem.release());
}

} // namespace blink
<commit_msg>Remove OwnPtr from DrawingRecorder<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "platform/graphics/paint/DrawingRecorder.h"

#include "platform/RuntimeEnabledFeatures.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/GraphicsLayer.h"
#include "platform/graphics/paint/CachedDisplayItem.h"
#include "platform/graphics/paint/DisplayItemList.h"
#include "platform/graphics/paint/DrawingDisplayItem.h"
#include "third_party/skia/include/core/SkPicture.h"

namespace blink {

DrawingRecorder::DrawingRecorder(GraphicsContext& context, const DisplayItemClientWrapper& displayItemClient, DisplayItem::Type displayItemType, const FloatRect& bounds)
    : m_context(context)
    , m_displayItemClient(displayItemClient)
    , m_displayItemType(displayItemType)
    , m_canUseCachedDrawing(false)
#if ENABLE(ASSERT)
    , m_checkedCachedDrawing(false)
    , m_displayItemPosition(RuntimeEnabledFeatures::slimmingPaintEnabled() ? m_context.displayItemList()->newDisplayItemsSize() : 0)
#endif
{
    if (!RuntimeEnabledFeatures::slimmingPaintEnabled())
        return;

    ASSERT(DisplayItem::isDrawingType(displayItemType));
#if ENABLE(ASSERT)
    context.setInDrawingRecorder(true);
#endif
    ASSERT(context.displayItemList());
    m_canUseCachedDrawing = context.displayItemList()->clientCacheIsValid(displayItemClient.displayItemClient())
        && !RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled();

#ifndef NDEBUG
    // Enable recording to check if any painter is still doing unnecessary painting when we can use cache.
    context.beginRecording(bounds);
#else
    if (!m_canUseCachedDrawing)
        context.beginRecording(bounds);
#endif
}

DrawingRecorder::~DrawingRecorder()
{
    if (!RuntimeEnabledFeatures::slimmingPaintEnabled())
        return;

#if ENABLE(ASSERT)
    ASSERT(m_checkedCachedDrawing);
    m_context.setInDrawingRecorder(false);
    ASSERT(m_displayItemPosition == m_context.displayItemList()->newDisplayItemsSize());
#endif

    if (m_canUseCachedDrawing) {
#ifndef NDEBUG
        RefPtr<const SkPicture> picture = m_context.endRecording();
        if (picture && picture->approximateOpCount()) {
            WTF_LOG_ERROR("Unnecessary painting for %s\n. Should check recorder.canUseCachedDrawing() before painting",
                m_displayItemClient.debugName().utf8().data());
        }
#endif
        m_context.displayItemList()->add(CachedDisplayItem::create(m_displayItemClient, DisplayItem::drawingTypeToCachedType(m_displayItemType)));
    } else {
        m_context.displayItemList()->add(DrawingDisplayItem::create(m_displayItemClient, m_displayItemType, m_context.endRecording()));
    }
}

} // namespace blink
<|endoftext|>


<commit_before>/*=========================================================================

  Library:   CTK

  Copyright (c) 2010  Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.commontk.org/LICENSE

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Qt includes
#include <QFile>
#include <QTextStream>
#include <QRegExp>
#include <QStringList>
#include <QDebug>

// CTK includes
#include <ctkDependencyGraph.h>

// STD includes
#include <cstdlib>
#include <iostream>

//----------------------------------------------------------------------------
QString help(const QString& progName)
{
  QString msg = "Usage: %1 <graphfile> [-paths Label]";
  return msg.arg(progName);
}

//----------------------------------------------------------------------------
void displayError(const QString& progName, const QString& msg)
{
  std::cerr << QString("%1\n%2\n%3\n").arg(progName).
                                       arg(msg).
                                       arg(help(progName)).toStdString();
}

//----------------------------------------------------------------------------
int getOrGenerateId(QHash<int, QString>& vertexIdToLabel,
                    QHash<QString, int>& vertexLabelToId,
                    const QString& label)
{
  // If needed, generate vertex id
  int vertexId = -1;
  if (!vertexLabelToId.keys().contains(label))
    {
    vertexId = vertexLabelToId.keys().size() + 1;
    vertexLabelToId[label] = vertexId;
    vertexIdToLabel[vertexId] = label;
    }
  else
    {
    vertexId = vertexLabelToId[label];
    }
  return vertexId;
}

//----------------------------------------------------------------------------
int main(int argc, char** argv)
{
  bool verbose = false;
  bool outputTopologicalOrder = true;

  // a graph file is expected
  if (argc < 2)
    {
    displayError(argv[0], QLatin1String("Missing one argument"));
    return EXIT_FAILURE;
    }

  bool outputPath = false;
  bool outputSort = false;
  QString label;
  if (argc == 3)
    {
    displayError(argv[0], QLatin1String("Wrong argument"));
    return EXIT_FAILURE;
    }
  if (argc == 4)
    {
    QString arg2 = QString::fromLatin1(argv[2]);
    if (arg2.compare("-paths")!=0 && arg2.compare("-sort")!=0)
      {
      displayError(argv[0], QString("Wrong argument: %1").arg(arg2));
      return EXIT_FAILURE;
      }
    label = QLatin1String(argv[3]);
    outputTopologicalOrder = false;
    if (arg2.compare("-paths") == 0)
      {
      outputPath = true;
      }
    else
      {
      outputSort = true;
      }

    if (verbose)
      {
      qDebug() << "label:" << label;
      }
    }

  QString filepath = QString::fromLatin1(argv[1]);
  if (!QFile::exists(filepath))
    {
    displayError(argv[0], QString("File '%1' doesn't exists !").arg(filepath));
    return EXIT_FAILURE;
    }

  QFile data(filepath);
  if (!data.open(QFile::ReadOnly))
    {
    displayError(argv[0], QString("Failed to open file '%1' !").arg(filepath));
    return EXIT_FAILURE;
    }

  QTextStream in(&data);
  QString header = in.readLine();
  if (header.isNull())
    {
    displayError(argv[0], QString("Failed to read Header line in file '%1' !").arg(filepath));
    return EXIT_FAILURE;
    }

  // Regular expression to extract two integers
  QRegExp twoint_re("^([0-9]+)\\s+([0-9]+)");

  // Extract numberOfVertices and numberOfEdges
  int pos = twoint_re.indexIn(header.trimmed());
  if (pos != 0)
    {
    displayError(argv[0], QString("Error in file '%1' - First line should look like: <#Vertices> <#Edges>")
      .arg(filepath));
    return EXIT_FAILURE;
    }
  QStringList list = twoint_re.capturedTexts();
  Q_ASSERT(list.size() == 3);

  int numberOfVertices = list[1].toInt();
  int numberOfEdges = list[2].toInt();

  if (verbose)
    {
    qDebug() << "#Vertices:" << numberOfVertices << "#Edges:" << numberOfEdges;
    }

  // Init
  ctkDependencyGraph mygraph(numberOfVertices);
  mygraph.setVerbose(verbose);

  // Map between vertex label and vertex id
  QHash<int, QString> vertexIdToLabel;
  QHash<QString, int> vertexLabelToId;

  // Regular expression to extract two label
  QRegExp twolabel_re("^(.+)\\s+(.+)");

  // Read vertex connection
  int lineNumber = 2;
  QString line = in.readLine();
  do
    {
    // Skip empty line or commented line
    if (line.isEmpty() || line.startsWith("#"))
      {
      line = in.readLine();
      continue;
      }

    // Extract vertex points

    int pos = twolabel_re.indexIn(line.trimmed());
    if (pos != 0)
      {
      displayError(argv[0], QString("Error in file '%1' - line:%2 - Expected format is: <label> <label>")
        .arg(filepath).arg(lineNumber));
      return EXIT_FAILURE;
      }
    lineNumber++;

    QStringList list = twolabel_re.capturedTexts();
    Q_ASSERT(list.size() == 3);

    int from = getOrGenerateId(vertexIdToLabel, vertexLabelToId, list[1]);
    int to = getOrGenerateId(vertexIdToLabel, vertexLabelToId, list[2]);

    // Insert edge
    mygraph.insertEdge(from, to);

    line = in.readLine();
    }
  while (!line.isNull());

  Q_ASSERT(numberOfEdges == mygraph.numberOfEdges());

  if (verbose)
    {
    mygraph.printGraph();
    qDebug() << "> Check for cycle ...";
    }

  mygraph.checkForCycle();

  if (mygraph.cycleDetected())
    {
    std::cerr << "Cycle detected !" << std::endl;
    QList<int> path;
    mygraph.findPath(mygraph.cycleOrigin(), mygraph.cycleEnd(), path);

    for(int i = 0; i < path.size(); ++i)
      {
      std::cerr << vertexIdToLabel[path[i]].toStdString();
      if (i != path.size() - 1)
        {
        std::cerr << " -> ";
        }
      }
    std::cerr << std::endl;

    path.clear();
    mygraph.findPath(mygraph.cycleEnd(), mygraph.cycleOrigin(), path);

    for(int i = 0; i < path.size(); ++i)
      {
      std::cerr << vertexIdToLabel[path[i]].toStdString();
      if (i != path.size() - 1)
        {
        std::cerr << " -> ";
        }
      }
    std::cerr << std::endl;

    return EXIT_FAILURE;
    }

  if (outputTopologicalOrder)
    {
    if (verbose)
      {
      qDebug() << "> Topological order ...";
      }
    QList<int> out;
    if (mygraph.topologicalSort(out))
      {
      for(int i=out.size() - 1; i >= 0; --i)
        {
        std::cout << vertexIdToLabel[out[i]].toStdString();
        if (i != 0)
          {
          std::cout << " ";
          }
        }
      std::cout << std::endl;
      }
    }

  if (verbose)
    {
    QList<int> sources;
    mygraph.sourceVertices(sources);
    qDebug() << "Source vertices: " << sources;
    }

  if (outputPath)
    {
    // TODO Make sure label is valid
    QList<int> out;
    if (mygraph.topologicalSort(out))
      {
      for(int i=0; i < out.size(); i++)
        {
        // Assume all targets depend on the first lib
        // We could get all sinks and find all paths
        // from the rootId to the sink vertices.
        int rootId = out.last();
        int labelId = vertexLabelToId[label];
        QList<QList<int>*> paths;
        mygraph.findPaths(labelId, rootId, paths);
        for(int i=0; i < paths.size(); i++)
          {
          QList<int>* p = paths[i];
          Q_ASSERT(p);
          for(int j=0; j < p->size(); j++)
            {
            int id = p->at(j);
            std::cout << vertexIdToLabel[id].toStdString();
            if (j != p->size() - 1)
              {
              std::cout << " ";
              }
            }
          if (i != paths.size() - 1)
            {
            std::cout << ";";
            }
          }
        }
      }
    }

  if (outputSort)
    {
    // TODO Make sure label is valid
    QList<int> out;
    int labelId = vertexLabelToId[label];
    if (mygraph.topologicalSort(out, labelId))
      {
      for(int i=0; i < out.size(); i++)
        {
        int id = out.at(i);
        std::cout << vertexIdToLabel[id].toStdString();

        if (i != out.size() - 1)
          {
          std::cout << " ";
          }
        }
      }
    }

  return EXIT_SUCCESS;
}
<commit_msg>STYLE: DGraph: added the -sort argument to the help message<commit_after>/*=========================================================================

  Library:   CTK

  Copyright (c) 2010  Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.commontk.org/LICENSE

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Qt includes
#include <QFile>
#include <QTextStream>
#include <QRegExp>
#include <QStringList>
#include <QDebug>

// CTK includes
#include <ctkDependencyGraph.h>

// STD includes
#include <cstdlib>
#include <iostream>

//----------------------------------------------------------------------------
QString help(const QString& progName)
{
  QString msg = "Usage: %1 <graphfile> [-paths Label | -sort Label]";
  return msg.arg(progName);
}

//----------------------------------------------------------------------------
void displayError(const QString& progName, const QString& msg)
{
  std::cerr << QString("%1\n%2\n%3\n").arg(progName).
                                       arg(msg).
                                       arg(help(progName)).toStdString();
}

//----------------------------------------------------------------------------
int getOrGenerateId(QHash<int, QString>& vertexIdToLabel,
                    QHash<QString, int>& vertexLabelToId,
                    const QString& label)
{
  // If needed, generate vertex id
  int vertexId = -1;
  if (!vertexLabelToId.keys().contains(label))
    {
    vertexId = vertexLabelToId.keys().size() + 1;
    vertexLabelToId[label] = vertexId;
    vertexIdToLabel[vertexId] = label;
    }
  else
    {
    vertexId = vertexLabelToId[label];
    }
  return vertexId;
}

//----------------------------------------------------------------------------
int main(int argc, char** argv)
{
  bool verbose = false;
  bool outputTopologicalOrder = true;

  // a graph file is expected
  if (argc < 2)
    {
    displayError(argv[0], QLatin1String("Missing one argument"));
    return EXIT_FAILURE;
    }

  bool outputPath = false;
  bool outputSort = false;
  QString label;
  if (argc == 3)
    {
    displayError(argv[0], QLatin1String("Wrong argument"));
    return EXIT_FAILURE;
    }
  if (argc == 4)
    {
    QString arg2 = QString::fromLatin1(argv[2]);
    if (arg2.compare("-paths")!=0 && arg2.compare("-sort")!=0)
      {
      displayError(argv[0], QString("Wrong argument: %1").arg(arg2));
      return EXIT_FAILURE;
      }
    label = QLatin1String(argv[3]);
    outputTopologicalOrder = false;
    if (arg2.compare("-paths") == 0)
      {
      outputPath = true;
      }
    else
      {
      outputSort = true;
      }

    if (verbose)
      {
      qDebug() << "label:" << label;
      }
    }

  QString filepath = QString::fromLatin1(argv[1]);
  if (!QFile::exists(filepath))
    {
    displayError(argv[0], QString("File '%1' doesn't exists !").arg(filepath));
    return EXIT_FAILURE;
    }

  QFile data(filepath);
  if (!data.open(QFile::ReadOnly))
    {
    displayError(argv[0], QString("Failed to open file '%1' !").arg(filepath));
    return EXIT_FAILURE;
    }

  QTextStream in(&data);
  QString header = in.readLine();
  if (header.isNull())
    {
    displayError(argv[0], QString("Failed to read Header line in file '%1' !").arg(filepath));
    return EXIT_FAILURE;
    }

  // Regular expression to extract two integers
  QRegExp twoint_re("^([0-9]+)\\s+([0-9]+)");

  // Extract numberOfVertices and numberOfEdges
  int pos = twoint_re.indexIn(header.trimmed());
  if (pos != 0)
    {
    displayError(argv[0], QString("Error in file '%1' - First line should look like: <#Vertices> <#Edges>")
      .arg(filepath));
    return EXIT_FAILURE;
    }
  QStringList list = twoint_re.capturedTexts();
  Q_ASSERT(list.size() == 3);

  int numberOfVertices = list[1].toInt();
  int numberOfEdges = list[2].toInt();

  if (verbose)
    {
    qDebug() << "#Vertices:" << numberOfVertices << "#Edges:" << numberOfEdges;
    }

  // Init
  ctkDependencyGraph mygraph(numberOfVertices);
  mygraph.setVerbose(verbose);

  // Map between vertex label and vertex id
  QHash<int, QString> vertexIdToLabel;
  QHash<QString, int> vertexLabelToId;

  // Regular expression to extract two label
  QRegExp twolabel_re("^(.+)\\s+(.+)");

  // Read vertex connection
  int lineNumber = 2;
  QString line = in.readLine();
  do
    {
    // Skip empty line or commented line
    if (line.isEmpty() || line.startsWith("#"))
      {
      line = in.readLine();
      continue;
      }

    // Extract vertex points

    int pos = twolabel_re.indexIn(line.trimmed());
    if (pos != 0)
      {
      displayError(argv[0], QString("Error in file '%1' - line:%2 - Expected format is: <label> <label>")
        .arg(filepath).arg(lineNumber));
      return EXIT_FAILURE;
      }
    lineNumber++;

    QStringList list = twolabel_re.capturedTexts();
    Q_ASSERT(list.size() == 3);

    int from = getOrGenerateId(vertexIdToLabel, vertexLabelToId, list[1]);
    int to = getOrGenerateId(vertexIdToLabel, vertexLabelToId, list[2]);

    // Insert edge
    mygraph.insertEdge(from, to);

    line = in.readLine();
    }
  while (!line.isNull());

  Q_ASSERT(numberOfEdges == mygraph.numberOfEdges());

  if (verbose)
    {
    mygraph.printGraph();
    qDebug() << "> Check for cycle ...";
    }

  mygraph.checkForCycle();

  if (mygraph.cycleDetected())
    {
    std::cerr << "Cycle detected !" << std::endl;
    QList<int> path;
    mygraph.findPath(mygraph.cycleOrigin(), mygraph.cycleEnd(), path);

    for(int i = 0; i < path.size(); ++i)
      {
      std::cerr << vertexIdToLabel[path[i]].toStdString();
      if (i != path.size() - 1)
        {
        std::cerr << " -> ";
        }
      }
    std::cerr << std::endl;

    path.clear();
    mygraph.findPath(mygraph.cycleEnd(), mygraph.cycleOrigin(), path);

    for(int i = 0; i < path.size(); ++i)
      {
      std::cerr << vertexIdToLabel[path[i]].toStdString();
      if (i != path.size() - 1)
        {
        std::cerr << " -> ";
        }
      }
    std::cerr << std::endl;

    return EXIT_FAILURE;
    }

  if (outputTopologicalOrder)
    {
    if (verbose)
      {
      qDebug() << "> Topological order ...";
      }
    QList<int> out;
    if (mygraph.topologicalSort(out))
      {
      for(int i=out.size() - 1; i >= 0; --i)
        {
        std::cout << vertexIdToLabel[out[i]].toStdString();
        if (i != 0)
          {
          std::cout << " ";
          }
        }
      std::cout << std::endl;
      }
    }

  if (verbose)
    {
    QList<int> sources;
    mygraph.sourceVertices(sources);
    qDebug() << "Source vertices: " << sources;
    }

  if (outputPath)
    {
    // TODO Make sure label is valid
    QList<int> out;
    if (mygraph.topologicalSort(out))
      {
      for(int i=0; i < out.size(); i++)
        {
        // Assume all targets depend on the first lib
        // We could get all sinks and find all paths
        // from the rootId to the sink vertices.
        int rootId = out.last();
        int labelId = vertexLabelToId[label];
        QList<QList<int>*> paths;
        mygraph.findPaths(labelId, rootId, paths);
        for(int i=0; i < paths.size(); i++)
          {
          QList<int>* p = paths[i];
          Q_ASSERT(p);
          for(int j=0; j < p->size(); j++)
            {
            int id = p->at(j);
            std::cout << vertexIdToLabel[id].toStdString();
            if (j != p->size() - 1)
              {
              std::cout << " ";
              }
            }
          if (i != paths.size() - 1)
            {
            std::cout << ";";
            }
          }
        }
      }
    }

  if (outputSort)
    {
    // TODO Make sure label is valid
    QList<int> out;
    int labelId = vertexLabelToId[label];
    if (mygraph.topologicalSort(out, labelId))
      {
      for(int i=0; i < out.size(); i++)
        {
        int id = out.at(i);
        std::cout << vertexIdToLabel[id].toStdString();

        if (i != out.size() - 1)
          {
          std::cout << " ";
          }
        }
      }
    }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "ExpressionVisitor.h"
#include "../JavaExportException.h"
#include "VisitorDefs.h"

using namespace Export;
using namespace OOModel;

namespace JavaExport {

template <class T> Export::SourceFragment* ExpressionVisitor::optional(T* node)
{
	return node ? visit(node) : nullptr;
}

SourceFragment* ExpressionVisitor::visit(Expression* expression)
{
	auto fragment = new CompositeFragment(expression);

	// Types ============================================================================================================
	if (auto e = DCast<ArrayTypeExpression>(expression))
		*fragment << visit(e->typeExpression()) << "[" << optional(e->fixedSize()) << "]";
	else if (auto e = DCast<ReferenceTypeExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<PointerTypeExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<ClassTypeExpression>(expression)) *fragment << visit(e->typeExpression());
	else if (auto e = DCast<PrimitiveTypeExpression>(expression))
	{
		switch (e->typeValue())
		{
			case PrimitiveTypeExpression::PrimitiveTypes::INT: *fragment << "int"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::LONG: *fragment << "long"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::UNSIGNED_INT: notAllowed(e); break;
			case PrimitiveTypeExpression::PrimitiveTypes::UNSIGNED_LONG: notAllowed(e); break;
			case PrimitiveTypeExpression::PrimitiveTypes::FLOAT: *fragment << "float"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::DOUBLE: *fragment << "double"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::BOOLEAN: *fragment << "boolean"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::CHAR: *fragment << "char"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::VOID: *fragment << "void"; break;
			default: error(e, "Unkown primitive type");
		}
	}
	else if (auto e = DCast<TypeQualifierExpression>(expression))
	{
		switch (e->qualifier())
		{
			case TypeQualifierExpression::Qualifier::CONST: notAllowed(e); break;
			case TypeQualifierExpression::Qualifier::VOLATILE: *fragment << "volatile"; break;
			default: error(e, "Unkown qualifier");
		}
		*fragment << " " << visit(e->typeExpression());
	}
	else if (auto e = DCast<AutoTypeExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<FunctionTypeExpression>(expression)) notAllowed(e);

	// Operators ========================================================================================================

	else if (auto e = DCast<AssignmentExpression>(expression))
	{
		*fragment << visit(e->left()) << " ";
		switch (e->op())
		{
			case AssignmentExpression::ASSIGN: *fragment << "="; break;
			case AssignmentExpression::PLUS_ASSIGN: *fragment << "+="; break;
			case AssignmentExpression::MINUS_ASSIGN: *fragment << "-="; break;
			case AssignmentExpression::TIMES_ASSIGN: *fragment << "*="; break;
			case AssignmentExpression::DIVIDE_ASSIGN: *fragment << "/="; break;
			case AssignmentExpression::BIT_AND_ASSIGN: *fragment << "&="; break;
			case AssignmentExpression::BIT_OR_ASSIGN: *fragment << "|="; break;
			case AssignmentExpression::BIT_XOR_ASSIGN: *fragment << "^="; break;
			case AssignmentExpression::REMAINDER_ASSIGN: *fragment << "%="; break;
			case AssignmentExpression::LEFT_SHIFT_ASSIGN: *fragment << "<<="; break;
			case AssignmentExpression::RIGHT_SHIFT_SIGNED_ASSIGN: *fragment << ">>="; break;
			case AssignmentExpression::RIGHT_SHIFT_UNSIGNED_ASSIGN: *fragment << ">>>="; break;
			default: error(e, "Unkown assignment type");
		}
		*fragment << " " << visit(e->right());
	}
	else if (auto e = DCast<BinaryOperation>(expression))
	{
		*fragment << visit(e->left());
		switch (e->op())
		{
			case BinaryOperation::TIMES: *fragment << "*"; break;
			case BinaryOperation::DIVIDE: *fragment << "/"; break;
			case BinaryOperation::REMAINDER: *fragment << "%"; break;
			case BinaryOperation::PLUS: *fragment << "+"; break;
			case BinaryOperation::MINUS: *fragment << "-"; break;
			case BinaryOperation::LEFT_SHIFT: *fragment << " << "; break;
			case BinaryOperation::RIGHT_SHIFT_SIGNED: *fragment << " >> "; break;
			case BinaryOperation::RIGHT_SHIFT_UNSIGNED: *fragment << " >>> "; break;
			case BinaryOperation::LESS: *fragment << " < "; break;
			case BinaryOperation::GREATER: *fragment << " > "; break;
			case BinaryOperation::LESS_EQUALS: *fragment << " <= "; break;
			case BinaryOperation::GREATER_EQUALS: *fragment << " >= "; break;
			case BinaryOperation::EQUALS: *fragment << " == "; break;
			case BinaryOperation::NOT_EQUALS: *fragment << " != "; break;
			case BinaryOperation::XOR: *fragment << " ^ "; break;
			case BinaryOperation::AND: *fragment << " & "; break;
			case BinaryOperation::OR: *fragment << " | "; break;
			case BinaryOperation::CONDITIONAL_AND: *fragment << " && "; break;
			case BinaryOperation::CONDITIONAL_OR: *fragment << " || "; break;
			case BinaryOperation::ARRAY_INDEX: *fragment << "["; break;
			default: error(e, "Unkown binary operator type");
		}
		*fragment << visit(e->right());
		if (e->op() == BinaryOperation::ARRAY_INDEX) *fragment << "]";
	}
	else if (auto e = DCast<UnaryOperation>(expression))
	{
		switch (e->op())
		{
			case UnaryOperation::PREINCREMENT: *fragment << "++" << visit(e->operand()); break;
			case UnaryOperation::PREDECREMENT: *fragment << "--" << visit(e->operand()); break;
			case UnaryOperation::POSTINCREMENT: *fragment << visit(e->operand()) << "++"; break;
			case UnaryOperation::POSTDECREMENT: *fragment << visit(e->operand()) << "--"; break;
			case UnaryOperation::PLUS: *fragment << "+" << visit(e->operand()); break;
			case UnaryOperation::MINUS: *fragment << "-" << visit(e->operand()); break;
			case UnaryOperation::NOT: *fragment << "!" << visit(e->operand()); break;
			case UnaryOperation::COMPLEMENT: *fragment << "~" << visit(e->operand()); break;
			case UnaryOperation::PARENTHESIS: *fragment << "(" << visit(e->operand()) << ")"; break;
			case UnaryOperation::DEREFERENCE: notAllowed(e); break;
			case UnaryOperation::ADDRESSOF: notAllowed(e); break;
			default: error(e, "Unkown unary operator type");
		}
	}
	else if (auto e = DCast<TypeTraitExpression>(expression)) notAllowed(e);

	// Literals =========================================================================================================

	else if (auto e = DCast<BooleanLiteral>(expression)) *fragment << (e->value() ? "true" : "false");
	else if (auto e = DCast<IntegerLiteral>(expression)) *fragment << QString::number( e->value());
	else if (auto e = DCast<FloatLiteral>(expression)) *fragment << QString::number( e->value());
	else if (DCast<NullLiteral>(expression)) *fragment << "null";
	else if (auto e = DCast<StringLiteral>(expression)) *fragment << "\"" << e->value() << "\"";
	else if (auto e = DCast<CharacterLiteral>(expression)) *fragment << "'" << e->value() << "'";

	// Misc =============================================================================================================

	else if (auto e = DCast<CastExpression>(expression))
		*fragment << "(" << visit(e->castType()) << ") " << visit(e->expr());
	else if (auto e = DCast<CommaExpression>(expression)) *fragment << visit(e->left()) << ", " << visit(e->right());
	else if (auto e = DCast<ConditionalExpression>(expression))
		*fragment << visit(e->condition()) << " ? " << visit(e->trueExpression()) << " : " << visit(e->falseExpression());
	else if (DCast<ThisExpression>(expression)) *fragment << "this";
	else if (auto e = DCast<GlobalScopeExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<ThrowExpression>(expression)) *fragment << "throw " << visit(e->expr());
	else if (auto e = DCast<TypeNameOperator>(expression)) notAllowed(e);
	else if (auto e = DCast<DeleteExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<VariableDeclarationExpression>(expression)) *fragment << declaration(e->decl());
	else if (auto e = DCast<LambdaExpression>(expression))
	{
		*fragment << list(e->arguments(), ElementVisitor(data()), "argsList") << " -> ";
		*fragment << list(e->body(), StatementVisitor(data()), "body");

		if (e->results()->size() > 1) error(e->results(), "Cannot have more than one return value in Java");
	}
	else if (auto e = DCast<ArrayInitializer>(expression)) *fragment << list(e->values(), this, "initializerList");
	else if (auto e = DCast<MethodCallExpression>(expression))
		*fragment << visit(e->callee()) << list(e->arguments(), this, "argsList");
	else if (auto e = DCast<NewExpression>(expression))
	{
		*fragment << "new " << visit(e->newType());
		for (auto dim : *e->dimensions())
			*fragment << "[" << visit(dim) << "]";
		if (e->initializer()) *fragment << " = " << visit(e->initializer());
	}
	else if (auto e = DCast<ReferenceExpression>(expression))
	{
		if (e->prefix()) *fragment << visit(e->prefix()) << ".";
		*fragment << e->name();
		if (!e->typeArguments()->isEmpty()) *fragment << list(e->typeArguments(), this, "typeArgsList");
	}

	// Flexible input support ===========================================================================================

	else if (DCast<EmptyExpression>(expression)); // do nothing
	else if (auto e = DCast<ErrorExpression>(expression))
	{
		if (!e->prefix().isEmpty()) *fragment << e->prefix();
		*fragment << visit(e->arg());
		if (!e->postfix().isEmpty()) *fragment << e->postfix();
	}
	else if (auto e = DCast<UnfinishedOperator>(expression))
	{
		QStringList result;

		for (int i=0; i< e->operands()->size(); ++i)
			*fragment << e->delimiters()->at(i) << visit(e->operands()->at(i));

		if (e->delimiters()->size() > e->operands()->size())
			*fragment << e->delimiters()->last();
	}
	else
	{
		throw JavaExportException("Unhandled expression of type " + expression->typeName());
	}

	return fragment;
}

} // namespace JavaExport
<commit_msg>Fix export of new expression<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "ExpressionVisitor.h"
#include "../JavaExportException.h"
#include "VisitorDefs.h"

using namespace Export;
using namespace OOModel;

namespace JavaExport {

template <class T> Export::SourceFragment* ExpressionVisitor::optional(T* node)
{
	return node ? visit(node) : nullptr;
}

SourceFragment* ExpressionVisitor::visit(Expression* expression)
{
	auto fragment = new CompositeFragment(expression);

	// Types ============================================================================================================
	if (auto e = DCast<ArrayTypeExpression>(expression))
		*fragment << visit(e->typeExpression()) << "[" << optional(e->fixedSize()) << "]";
	else if (auto e = DCast<ReferenceTypeExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<PointerTypeExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<ClassTypeExpression>(expression)) *fragment << visit(e->typeExpression());
	else if (auto e = DCast<PrimitiveTypeExpression>(expression))
	{
		switch (e->typeValue())
		{
			case PrimitiveTypeExpression::PrimitiveTypes::INT: *fragment << "int"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::LONG: *fragment << "long"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::UNSIGNED_INT: notAllowed(e); break;
			case PrimitiveTypeExpression::PrimitiveTypes::UNSIGNED_LONG: notAllowed(e); break;
			case PrimitiveTypeExpression::PrimitiveTypes::FLOAT: *fragment << "float"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::DOUBLE: *fragment << "double"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::BOOLEAN: *fragment << "boolean"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::CHAR: *fragment << "char"; break;
			case PrimitiveTypeExpression::PrimitiveTypes::VOID: *fragment << "void"; break;
			default: error(e, "Unkown primitive type");
		}
	}
	else if (auto e = DCast<TypeQualifierExpression>(expression))
	{
		switch (e->qualifier())
		{
			case TypeQualifierExpression::Qualifier::CONST: notAllowed(e); break;
			case TypeQualifierExpression::Qualifier::VOLATILE: *fragment << "volatile"; break;
			default: error(e, "Unkown qualifier");
		}
		*fragment << " " << visit(e->typeExpression());
	}
	else if (auto e = DCast<AutoTypeExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<FunctionTypeExpression>(expression)) notAllowed(e);

	// Operators ========================================================================================================

	else if (auto e = DCast<AssignmentExpression>(expression))
	{
		*fragment << visit(e->left()) << " ";
		switch (e->op())
		{
			case AssignmentExpression::ASSIGN: *fragment << "="; break;
			case AssignmentExpression::PLUS_ASSIGN: *fragment << "+="; break;
			case AssignmentExpression::MINUS_ASSIGN: *fragment << "-="; break;
			case AssignmentExpression::TIMES_ASSIGN: *fragment << "*="; break;
			case AssignmentExpression::DIVIDE_ASSIGN: *fragment << "/="; break;
			case AssignmentExpression::BIT_AND_ASSIGN: *fragment << "&="; break;
			case AssignmentExpression::BIT_OR_ASSIGN: *fragment << "|="; break;
			case AssignmentExpression::BIT_XOR_ASSIGN: *fragment << "^="; break;
			case AssignmentExpression::REMAINDER_ASSIGN: *fragment << "%="; break;
			case AssignmentExpression::LEFT_SHIFT_ASSIGN: *fragment << "<<="; break;
			case AssignmentExpression::RIGHT_SHIFT_SIGNED_ASSIGN: *fragment << ">>="; break;
			case AssignmentExpression::RIGHT_SHIFT_UNSIGNED_ASSIGN: *fragment << ">>>="; break;
			default: error(e, "Unkown assignment type");
		}
		*fragment << " " << visit(e->right());
	}
	else if (auto e = DCast<BinaryOperation>(expression))
	{
		*fragment << visit(e->left());
		switch (e->op())
		{
			case BinaryOperation::TIMES: *fragment << "*"; break;
			case BinaryOperation::DIVIDE: *fragment << "/"; break;
			case BinaryOperation::REMAINDER: *fragment << "%"; break;
			case BinaryOperation::PLUS: *fragment << "+"; break;
			case BinaryOperation::MINUS: *fragment << "-"; break;
			case BinaryOperation::LEFT_SHIFT: *fragment << " << "; break;
			case BinaryOperation::RIGHT_SHIFT_SIGNED: *fragment << " >> "; break;
			case BinaryOperation::RIGHT_SHIFT_UNSIGNED: *fragment << " >>> "; break;
			case BinaryOperation::LESS: *fragment << " < "; break;
			case BinaryOperation::GREATER: *fragment << " > "; break;
			case BinaryOperation::LESS_EQUALS: *fragment << " <= "; break;
			case BinaryOperation::GREATER_EQUALS: *fragment << " >= "; break;
			case BinaryOperation::EQUALS: *fragment << " == "; break;
			case BinaryOperation::NOT_EQUALS: *fragment << " != "; break;
			case BinaryOperation::XOR: *fragment << " ^ "; break;
			case BinaryOperation::AND: *fragment << " & "; break;
			case BinaryOperation::OR: *fragment << " | "; break;
			case BinaryOperation::CONDITIONAL_AND: *fragment << " && "; break;
			case BinaryOperation::CONDITIONAL_OR: *fragment << " || "; break;
			case BinaryOperation::ARRAY_INDEX: *fragment << "["; break;
			default: error(e, "Unkown binary operator type");
		}
		*fragment << visit(e->right());
		if (e->op() == BinaryOperation::ARRAY_INDEX) *fragment << "]";
	}
	else if (auto e = DCast<UnaryOperation>(expression))
	{
		switch (e->op())
		{
			case UnaryOperation::PREINCREMENT: *fragment << "++" << visit(e->operand()); break;
			case UnaryOperation::PREDECREMENT: *fragment << "--" << visit(e->operand()); break;
			case UnaryOperation::POSTINCREMENT: *fragment << visit(e->operand()) << "++"; break;
			case UnaryOperation::POSTDECREMENT: *fragment << visit(e->operand()) << "--"; break;
			case UnaryOperation::PLUS: *fragment << "+" << visit(e->operand()); break;
			case UnaryOperation::MINUS: *fragment << "-" << visit(e->operand()); break;
			case UnaryOperation::NOT: *fragment << "!" << visit(e->operand()); break;
			case UnaryOperation::COMPLEMENT: *fragment << "~" << visit(e->operand()); break;
			case UnaryOperation::PARENTHESIS: *fragment << "(" << visit(e->operand()) << ")"; break;
			case UnaryOperation::DEREFERENCE: notAllowed(e); break;
			case UnaryOperation::ADDRESSOF: notAllowed(e); break;
			default: error(e, "Unkown unary operator type");
		}
	}
	else if (auto e = DCast<TypeTraitExpression>(expression)) notAllowed(e);

	// Literals =========================================================================================================

	else if (auto e = DCast<BooleanLiteral>(expression)) *fragment << (e->value() ? "true" : "false");
	else if (auto e = DCast<IntegerLiteral>(expression)) *fragment << QString::number( e->value());
	else if (auto e = DCast<FloatLiteral>(expression)) *fragment << QString::number( e->value());
	else if (DCast<NullLiteral>(expression)) *fragment << "null";
	else if (auto e = DCast<StringLiteral>(expression)) *fragment << "\"" << e->value() << "\"";
	else if (auto e = DCast<CharacterLiteral>(expression)) *fragment << "'" << e->value() << "'";

	// Misc =============================================================================================================

	else if (auto e = DCast<CastExpression>(expression))
		*fragment << "(" << visit(e->castType()) << ") " << visit(e->expr());
	else if (auto e = DCast<CommaExpression>(expression)) *fragment << visit(e->left()) << ", " << visit(e->right());
	else if (auto e = DCast<ConditionalExpression>(expression))
		*fragment << visit(e->condition()) << " ? " << visit(e->trueExpression()) << " : " << visit(e->falseExpression());
	else if (DCast<ThisExpression>(expression)) *fragment << "this";
	else if (auto e = DCast<GlobalScopeExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<ThrowExpression>(expression)) *fragment << "throw " << visit(e->expr());
	else if (auto e = DCast<TypeNameOperator>(expression)) notAllowed(e);
	else if (auto e = DCast<DeleteExpression>(expression)) notAllowed(e);
	else if (auto e = DCast<VariableDeclarationExpression>(expression)) *fragment << declaration(e->decl());
	else if (auto e = DCast<LambdaExpression>(expression))
	{
		*fragment << list(e->arguments(), ElementVisitor(data()), "argsList") << " -> ";
		*fragment << list(e->body(), StatementVisitor(data()), "body");

		if (e->results()->size() > 1) error(e->results(), "Cannot have more than one return value in Java");
	}
	else if (auto e = DCast<ArrayInitializer>(expression)) *fragment << list(e->values(), this, "initializerList");
	else if (auto e = DCast<MethodCallExpression>(expression))
		*fragment << visit(e->callee()) << list(e->arguments(), this, "argsList");
	else if (auto e = DCast<NewExpression>(expression))
	{
		*fragment << "new " << visit(e->newType());
		for (auto dim : *e->dimensions())
			*fragment << "[" << visit(dim) << "]";
		if (e->initializer()) *fragment << visit(e->initializer());
	}
	else if (auto e = DCast<ReferenceExpression>(expression))
	{
		if (e->prefix()) *fragment << visit(e->prefix()) << ".";
		*fragment << e->name();
		if (!e->typeArguments()->isEmpty()) *fragment << list(e->typeArguments(), this, "typeArgsList");
	}

	// Flexible input support ===========================================================================================

	else if (DCast<EmptyExpression>(expression)); // do nothing
	else if (auto e = DCast<ErrorExpression>(expression))
	{
		if (!e->prefix().isEmpty()) *fragment << e->prefix();
		*fragment << visit(e->arg());
		if (!e->postfix().isEmpty()) *fragment << e->postfix();
	}
	else if (auto e = DCast<UnfinishedOperator>(expression))
	{
		QStringList result;

		for (int i=0; i< e->operands()->size(); ++i)
			*fragment << e->delimiters()->at(i) << visit(e->operands()->at(i));

		if (e->delimiters()->size() > e->operands()->size())
			*fragment << e->delimiters()->last();
	}
	else
	{
		throw JavaExportException("Unhandled expression of type " + expression->typeName());
	}

	return fragment;
}

} // namespace JavaExport
<|endoftext|>


<commit_before>#include "DAIUserInstance.h"
#include <iostream>

namespace dai {

DAIUserInstance::DAIUserInstance(const InstanceInfo& info)
    : DataInstance(info)
{
    m_frameBuffer[0].reset(new UserFrame(640, 480));
    m_frameBuffer[1].reset(new UserFrame(640, 480));
    DataInstance::initFrameBuffer(m_frameBuffer[0], m_frameBuffer[1]);
    m_width = 0;
    m_height = 0;
}

DAIUserInstance::~DAIUserInstance()
{
    m_width = 0;
    m_height = 0;
    closeInstance();
}

bool DAIUserInstance::is_open() const
{
    return m_file.is_open();
}

void DAIUserInstance::openInstance()
{
    QString instancePath = m_info.getDatasetPath() + "/" + m_info.getFileName();

    if (!m_file.is_open())
    {
        m_file.open(instancePath.toStdString().c_str(), ios::in|ios::binary);

        if (!m_file.is_open()) {
            cerr << "Error opening file" << endl;
            return;
        }

        m_file.seekg(0, ios_base::beg);
        m_file.read((char *) &m_nFrames, 4);
        m_file.read((char *) &m_width, 4);
        m_file.read((char *) &m_height, 4);

        if (m_width != 640 || m_height != 480)
            exit(1);
    }
}

void DAIUserInstance::closeInstance()
{
    if (m_file.is_open()) {
        m_file.close();
    }
}

void DAIUserInstance::restartInstance()
{
    if (m_file.is_open()) {
        m_file.seekg(12, ios_base::beg);
    }
}

void DAIUserInstance::nextFrame(DataFrame &frame)
{
    // Read Data from File
    UserFrame& userFrame = (UserFrame&) frame;
    m_file.read( (char *) m_readBuffer, sizeof(m_readBuffer) );

    for (int y=0; y<m_height; ++y)
    {
        for (int x=0; x<m_width; ++x)
        {
            userFrame.setItem(y, x, m_readBuffer[y].userRow[x]);
        }
    }
}

} // End Namespace
<commit_msg>Improve reading from DAI dataset *.user files<commit_after>#include "DAIUserInstance.h"
#include <iostream>

namespace dai {

DAIUserInstance::DAIUserInstance(const InstanceInfo& info)
    : DataInstance(info)
{
    m_frameBuffer[0].reset(new UserFrame(640, 480));
    m_frameBuffer[1].reset(new UserFrame(640, 480));
    DataInstance::initFrameBuffer(m_frameBuffer[0], m_frameBuffer[1]);
    m_width = 0;
    m_height = 0;
}

DAIUserInstance::~DAIUserInstance()
{
    m_width = 0;
    m_height = 0;
    closeInstance();
}

bool DAIUserInstance::is_open() const
{
    return m_file.is_open();
}

void DAIUserInstance::openInstance()
{
    QString instancePath = m_info.getDatasetPath() + "/" + m_info.getFileName();

    if (!m_file.is_open())
    {
        m_file.open(instancePath.toStdString().c_str(), ios::in|ios::binary);

        if (!m_file.is_open()) {
            cerr << "Error opening file" << endl;
            return;
        }

        m_file.seekg(0, ios_base::beg);
        m_file.read((char *) &m_nFrames, 4);
        m_file.read((char *) &m_width, 4);
        m_file.read((char *) &m_height, 4);

        if (m_width != 640 || m_height != 480)
            exit(1);
    }
}

void DAIUserInstance::closeInstance()
{
    if (m_file.is_open()) {
        m_file.close();
    }
}

void DAIUserInstance::restartInstance()
{
    if (m_file.is_open()) {
        m_file.seekg(12, ios_base::beg);
    }
}

void DAIUserInstance::nextFrame(DataFrame &frame)
{
    // Read Data from File
    UserFrame& userFrame = (UserFrame&) frame;
    u_int8_t* ptrImg = (u_int8_t*) userFrame.getDataPtr();
    m_file.read( (char *) ptrImg, userFrame.getWidth() * userFrame.getHeight() * sizeof(u_int8_t) );
}

} // End Namespace
<|endoftext|>


<commit_before>#include "ClusterMessage.h"

ClusterMessage::ClusterMessage()
{
}

bool ClusterMessage::SetNodeID(uint64_t nodeID_)
{
    type = CLUSTERMESSAGE_SET_NODEID;
    nodeID = nodeID_;
    return true;
}

bool ClusterMessage::Heartbeat(uint64_t nodeID_,
 List<QuorumPaxosID>& quorumPaxosIDs_, List<QuorumShardInfo>& quorumShardInfos_,
 unsigned httpPort_, unsigned sdbpPort_)
{
    type = CLUSTERMESSAGE_HEARTBEAT;
    nodeID = nodeID_;
    quorumPaxosIDs = quorumPaxosIDs_;
    quorumShardInfos = quorumShardInfos_;
    httpPort = httpPort_;
    sdbpPort = sdbpPort_;
    return true;
}

bool ClusterMessage::SetConfigState(ConfigState& configState_)
{
    type = CLUSTERMESSAGE_SET_CONFIG_STATE;
    configState = configState_;
    return true;
}

bool ClusterMessage::RequestLease(uint64_t nodeID_, uint64_t quorumID_,
 uint64_t proposalID_, uint64_t paxosID_, uint64_t configID_, unsigned duration_)
{
    type = CLUSTERMESSAGE_REQUEST_LEASE;
    nodeID = nodeID_;
    quorumID = quorumID_;
    proposalID = proposalID_;
    paxosID = paxosID_;
    configID = configID_;
    duration = duration_;
    return true;
}

bool ClusterMessage::ReceiveLease(uint64_t nodeID_, uint64_t quorumID_,
 uint64_t proposalID_, uint64_t configID_, unsigned duration_,
 bool watchingPaxosID_, List<uint64_t>& activeNodes_, SortedList<uint64_t>& shards_)
{
    type = CLUSTERMESSAGE_RECEIVE_LEASE;
    nodeID = nodeID_;
    quorumID = quorumID_;
    proposalID = proposalID_;
    configID = configID_;
    duration = duration_;
    activeNodes = activeNodes_;
    shards = shards_;
    watchingPaxosID = watchingPaxosID_;
    return true;
}

bool ClusterMessage::Read(ReadBuffer& buffer)
{
#define READ_SEPARATOR() \
    read = buffer.Readf(":"); \
    if (read != 1) \
        return false; \
    buffer.Advance(read); \

    int             read;
    ReadBuffer      tempBuffer;

    if (buffer.GetLength() < 1)
        return false;

    switch (buffer.GetCharAt(0))
    {
        case CLUSTERMESSAGE_SET_NODEID:
            read = buffer.Readf("%c:%U",
             &type, &nodeID);
            break;
        case CLUSTERMESSAGE_HEARTBEAT:
            read = buffer.Readf("%c:%U:%u:%u",
             &type, &nodeID, &httpPort, &sdbpPort);
            if (read < 3)
                return false;
            buffer.Advance(read);
            READ_SEPARATOR();
            if (!QuorumPaxosID::ReadList(buffer, quorumPaxosIDs))
                return false;
            READ_SEPARATOR();
            if (!QuorumShardInfo::ReadList(buffer, quorumShardInfos))
                return false;
            return true;
            break;
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            type = CLUSTERMESSAGE_SET_CONFIG_STATE;
            return configState.Read(buffer, true);
        case CLUSTERMESSAGE_REQUEST_LEASE:
            read = buffer.Readf("%c:%U:%U:%U:%U:%U:%u",
             &type, &nodeID, &quorumID, &proposalID, &paxosID, &configID, &duration);
            break;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            read = buffer.Readf("%c:%U:%U:%U:%U:%u:%b",
             &type, &nodeID, &quorumID, &proposalID, &configID, &duration, &watchingPaxosID);
             if (read < 9)
                return false;
            buffer.Advance(read);
            READ_SEPARATOR();
            if (!ConfigState::ReadIDList< List<uint64_t> >(activeNodes, buffer))
                return false;
            READ_SEPARATOR();
            if (!ConfigState::ReadIDList< SortedList<uint64_t> >(shards, buffer))
                return false;
            return true;
        default:
            return false;
    }

    return (read == (signed)buffer.GetLength());
}

bool ClusterMessage::Write(Buffer& buffer)
{
    Buffer          tempBuffer;

    switch (type)
    {
        case CLUSTERMESSAGE_SET_NODEID:
            buffer.Writef("%c:%U",
             type, nodeID);
            return true;
        case CLUSTERMESSAGE_HEARTBEAT:
            buffer.Writef("%c:%U:%u:%u",
             type, nodeID, httpPort, sdbpPort);
            buffer.Appendf(":");
            QuorumPaxosID::WriteList(buffer, quorumPaxosIDs);
            buffer.Appendf(":");
            QuorumShardInfo::WriteList(buffer, quorumShardInfos);
            return true;
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            buffer.Clear();
            return configState.Write(buffer, true);
        case CLUSTERMESSAGE_REQUEST_LEASE:
            buffer.Writef("%c:%U:%U:%U:%U:%U:%u",
             type, nodeID, quorumID, proposalID, paxosID, configID, duration);
            return true;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            buffer.Writef("%c:%U:%U:%U:%U:%u:%b",
             type, nodeID, quorumID, proposalID, configID, duration, watchingPaxosID);
            buffer.Appendf(":");
            ConfigState::WriteIDList< List<uint64_t> >(activeNodes, buffer);
            buffer.Appendf(":");
            ConfigState::WriteIDList< SortedList<uint64_t> >(shards, buffer);
            return true;
        default:
            return false;
    }
}<commit_msg>Fixed template parameter issue.<commit_after>#include "ClusterMessage.h"

ClusterMessage::ClusterMessage()
{
}

bool ClusterMessage::SetNodeID(uint64_t nodeID_)
{
    type = CLUSTERMESSAGE_SET_NODEID;
    nodeID = nodeID_;
    return true;
}

bool ClusterMessage::Heartbeat(uint64_t nodeID_,
 List<QuorumPaxosID>& quorumPaxosIDs_, List<QuorumShardInfo>& quorumShardInfos_,
 unsigned httpPort_, unsigned sdbpPort_)
{
    type = CLUSTERMESSAGE_HEARTBEAT;
    nodeID = nodeID_;
    quorumPaxosIDs = quorumPaxosIDs_;
    quorumShardInfos = quorumShardInfos_;
    httpPort = httpPort_;
    sdbpPort = sdbpPort_;
    return true;
}

bool ClusterMessage::SetConfigState(ConfigState& configState_)
{
    type = CLUSTERMESSAGE_SET_CONFIG_STATE;
    configState = configState_;
    return true;
}

bool ClusterMessage::RequestLease(uint64_t nodeID_, uint64_t quorumID_,
 uint64_t proposalID_, uint64_t paxosID_, uint64_t configID_, unsigned duration_)
{
    type = CLUSTERMESSAGE_REQUEST_LEASE;
    nodeID = nodeID_;
    quorumID = quorumID_;
    proposalID = proposalID_;
    paxosID = paxosID_;
    configID = configID_;
    duration = duration_;
    return true;
}

bool ClusterMessage::ReceiveLease(uint64_t nodeID_, uint64_t quorumID_,
 uint64_t proposalID_, uint64_t configID_, unsigned duration_,
 bool watchingPaxosID_, List<uint64_t>& activeNodes_, SortedList<uint64_t>& shards_)
{
    type = CLUSTERMESSAGE_RECEIVE_LEASE;
    nodeID = nodeID_;
    quorumID = quorumID_;
    proposalID = proposalID_;
    configID = configID_;
    duration = duration_;
    activeNodes = activeNodes_;
    shards = shards_;
    watchingPaxosID = watchingPaxosID_;
    return true;
}

bool ClusterMessage::Read(ReadBuffer& buffer)
{
#define READ_SEPARATOR() \
    read = buffer.Readf(":"); \
    if (read != 1) \
        return false; \
    buffer.Advance(read); \

    int             read;
    ReadBuffer      tempBuffer;

    if (buffer.GetLength() < 1)
        return false;

    switch (buffer.GetCharAt(0))
    {
        case CLUSTERMESSAGE_SET_NODEID:
            read = buffer.Readf("%c:%U",
             &type, &nodeID);
            break;
        case CLUSTERMESSAGE_HEARTBEAT:
            read = buffer.Readf("%c:%U:%u:%u",
             &type, &nodeID, &httpPort, &sdbpPort);
            if (read < 3)
                return false;
            buffer.Advance(read);
            READ_SEPARATOR();
            if (!QuorumPaxosID::ReadList(buffer, quorumPaxosIDs))
                return false;
            READ_SEPARATOR();
            if (!QuorumShardInfo::ReadList(buffer, quorumShardInfos))
                return false;
            return true;
            break;
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            type = CLUSTERMESSAGE_SET_CONFIG_STATE;
            return configState.Read(buffer, true);
        case CLUSTERMESSAGE_REQUEST_LEASE:
            read = buffer.Readf("%c:%U:%U:%U:%U:%U:%u",
             &type, &nodeID, &quorumID, &proposalID, &paxosID, &configID, &duration);
            break;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            read = buffer.Readf("%c:%U:%U:%U:%U:%u:%b",
             &type, &nodeID, &quorumID, &proposalID, &configID, &duration, &watchingPaxosID);
             if (read < 9)
                return false;
            buffer.Advance(read);
            READ_SEPARATOR();
            if (!ConfigState::ReadIDList< List<uint64_t> >(activeNodes, buffer))
                return false;
            READ_SEPARATOR();
            if (!ConfigState::ReadIDList< SortedList<uint64_t> >(shards, buffer))
                return false;
            return true;
        default:
            return false;
    }

    return (read == (signed)buffer.GetLength());
}

bool ClusterMessage::Write(Buffer& buffer)
{
    Buffer          tempBuffer;

    switch (type)
    {
        case CLUSTERMESSAGE_SET_NODEID:
            buffer.Writef("%c:%U",
             type, nodeID);
            return true;
        case CLUSTERMESSAGE_HEARTBEAT:
            buffer.Writef("%c:%U:%u:%u",
             type, nodeID, httpPort, sdbpPort);
            buffer.Appendf(":");
            QuorumPaxosID::WriteList(buffer, quorumPaxosIDs);
            buffer.Appendf(":");
            QuorumShardInfo::WriteList(buffer, quorumShardInfos);
            return true;
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            buffer.Clear();
            return configState.Write(buffer, true);
        case CLUSTERMESSAGE_REQUEST_LEASE:
            buffer.Writef("%c:%U:%U:%U:%U:%U:%u",
             type, nodeID, quorumID, proposalID, paxosID, configID, duration);
            return true;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            buffer.Writef("%c:%U:%U:%U:%U:%u:%b",
             type, nodeID, quorumID, proposalID, configID, duration, watchingPaxosID);
            buffer.Appendf(":");
            ConfigState::WriteIDList(activeNodes, buffer);
            buffer.Appendf(":");
            ConfigState::WriteIDList(shards, buffer);
            return true;
        default:
            return false;
    }
}<|endoftext|>