<commit_before>/*
	This file is part of solidity.

	solidity is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	solidity 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * Analyzer part of inline assembly.
 */

#include <libsolidity/inlineasm/AsmAnalysis.h>

#include <libsolidity/inlineasm/AsmData.h>
#include <libsolidity/inlineasm/AsmScopeFiller.h>
#include <libsolidity/inlineasm/AsmScope.h>

#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/Utils.h>

#include <boost/range/adaptor/reversed.hpp>

#include <memory>
#include <functional>

using namespace std;
using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::assembly;

AsmAnalyzer::AsmAnalyzer(
	AsmAnalyzer::Scopes& _scopes,
	ErrorList& _errors,
	ExternalIdentifierAccess::Resolver const& _resolver
):
	m_resolver(_resolver), m_scopes(_scopes), m_errors(_errors)
{
}

bool AsmAnalyzer::analyze(Block const& _block)
{
	if (!(ScopeFiller(m_scopes, m_errors))(_block))
		return false;

	return (*this)(_block);
}

bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction)
{
	auto const& info = instructionInfo(_instruction.instruction);
	m_stackHeight += info.ret - info.args;
	return true;
}

bool AsmAnalyzer::operator()(assembly::Literal const& _literal)
{
	++m_stackHeight;
	if (!_literal.isNumber && _literal.value.size() > 32)
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::TypeError,
			"String literal too long (" + boost::lexical_cast<std::string>(_literal.value.size()) + " > 32)",
			_literal.location
		));
		return false;
	}
	return true;
}

bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
{
	bool success = true;
	if (m_currentScope->lookup(_identifier.name, Scope::Visitor(
		[&](Scope::Variable const& _var)
		{
			if (!_var.active)
			{
				m_errors.push_back(make_shared<Error>(
					Error::Type::DeclarationError,
					"Variable " + _identifier.name + " used before it was declared.",
					_identifier.location
				));
				success = false;
			}
			++m_stackHeight;
		},
		[&](Scope::Label const&)
		{
			++m_stackHeight;
		},
		[&](Scope::Function const&)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Function " + _identifier.name + " used without being called.",
				_identifier.location
			));
			success = false;
		}
	)))
	{
	}
	else
	{
		size_t stackSize(-1);
		if (m_resolver)
			stackSize = m_resolver(_identifier, IdentifierContext::RValue);
		if (stackSize == size_t(-1))
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::DeclarationError,
				"Identifier not found.",
				_identifier.location
			));
			success = false;
		}
		m_stackHeight += stackSize == size_t(-1) ? 1 : stackSize;
	}
	return success;
}

bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr)
{
	bool success = true;
	for (auto const& arg: _instr.arguments | boost::adaptors::reversed)
	{
		int const stackHeight = m_stackHeight;
		if (!boost::apply_visitor(*this, arg))
			success = false;
		if (!expectDeposit(1, stackHeight, locationOf(arg)))
			success = false;
	}
	// Parser already checks that the number of arguments is correct.
	solAssert(instructionInfo(_instr.instruction.instruction).args == int(_instr.arguments.size()), "");
	if (!(*this)(_instr.instruction))
		success = false;
	return success;
}

bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment)
{
	return checkAssignment(_assignment.variableName, size_t(-1));
}

bool AsmAnalyzer::operator()(FunctionalAssignment const& _assignment)
{
	int const stackHeight = m_stackHeight;
	bool success = boost::apply_visitor(*this, *_assignment.value);
	solAssert(m_stackHeight >= stackHeight, "Negative value size.");
	if (!checkAssignment(_assignment.variableName, m_stackHeight - stackHeight))
		success = false;
	return success;
}

bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
{
	bool success = boost::apply_visitor(*this, *_varDecl.value);
	boost::get<Scope::Variable>(m_currentScope->identifiers.at(_varDecl.name)).active = true;
	return success;
}

bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
{
	Scope& bodyScope = scope(&_funDef.body);
	for (auto const& var: _funDef.arguments + _funDef.returns)
		boost::get<Scope::Variable>(bodyScope.identifiers.at(var)).active = true;

	int const stackHeight = m_stackHeight;
	m_stackHeight = _funDef.arguments.size() + _funDef.returns.size();
	m_virtualVariablesInNextBlock = m_stackHeight;

	bool success = (*this)(_funDef.body);

	m_stackHeight = stackHeight;
	return success;
}

bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall)
{
	bool success = true;
	size_t arguments = 0;
	size_t returns = 0;
	if (!m_currentScope->lookup(_funCall.functionName.name, Scope::Visitor(
		[&](Scope::Variable const&)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Attempt to call variable instead of function.",
				_funCall.functionName.location
			));
			success = false;
		},
		[&](Scope::Label const&)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Attempt to call label instead of function.",
				_funCall.functionName.location
				));
			success = false;
		},
		[&](Scope::Function const& _fun)
		{
			arguments = _fun.arguments;
			returns = _fun.returns;
		}
	)))
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::DeclarationError,
			"Function not found.",
			_funCall.functionName.location
		));
		success = false;
	}
	if (success)
	{
		if (_funCall.arguments.size() != arguments)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Expected " +
				boost::lexical_cast<string>(arguments) +
				" arguments but got " +
				boost::lexical_cast<string>(_funCall.arguments.size()) +
				".",
				_funCall.functionName.location
				));
			success = false;
		}
	}
	for (auto const& arg: _funCall.arguments | boost::adaptors::reversed)
	{
		int const stackHeight = m_stackHeight;
		if (!boost::apply_visitor(*this, arg))
			success = false;
		if (!expectDeposit(1, stackHeight, locationOf(arg)))
			success = false;
	}
	m_stackHeight += int(returns) - int(arguments);
	return success;
}

bool AsmAnalyzer::operator()(Block const& _block)
{
	bool success = true;
	m_currentScope = &scope(&_block);

	int const initialStackHeight = m_stackHeight - m_virtualVariablesInNextBlock;
	m_virtualVariablesInNextBlock = 0;

	for (auto const& s: _block.statements)
		if (!boost::apply_visitor(*this, s))
			success = false;

	for (auto const& identifier: scope(&_block).identifiers)
		if (identifier.second.type() == typeid(Scope::Variable))
			--m_stackHeight;

	int const stackDiff = m_stackHeight - initialStackHeight;
	if (stackDiff != 0)
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::DeclarationError,
			"Unbalanced stack at the end of a block: " +
			(
				stackDiff > 0 ?
				to_string(stackDiff) + string(" surplus item(s).") :
				to_string(-stackDiff) + string(" missing item(s).")
			),
			_block.location
		));
		success = false;
	}

	m_currentScope = m_currentScope->superScope;
	return success;
}

bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t _valueSize)
{
	bool success = true;
	size_t variableSize(-1);
	if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name))
	{
		// Check that it is a variable
		if (var->type() != typeid(Scope::Variable))
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Assignment requires variable.",
				_variable.location
			));
			success = false;
		}
		else if (!boost::get<Scope::Variable>(*var).active)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::DeclarationError,
				"Variable " + _variable.name + " used before it was declared.",
				_variable.location
			));
			success = false;
		}
		variableSize = 1;
	}
	else if (m_resolver)
		variableSize = m_resolver(_variable, IdentifierContext::LValue);
	if (variableSize == size_t(-1))
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::DeclarationError,
			"Variable not found or variable not lvalue.",
			_variable.location
		));
		success = false;
	}
	if (_valueSize == size_t(-1))
		_valueSize = variableSize == size_t(-1) ? 1 : variableSize;

	m_stackHeight -= _valueSize;

	if (_valueSize != variableSize && variableSize != size_t(-1))
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::TypeError,
			"Variable size (" +
			to_string(variableSize) +
			") and value size (" +
			to_string(_valueSize) +
			") do not match.",
			_variable.location
		));
		success = false;
	}
	return success;
}

bool AsmAnalyzer::expectDeposit(int const _deposit, int const _oldHeight, SourceLocation const& _location)
{
	int stackDiff = m_stackHeight - _oldHeight;
	if (stackDiff != _deposit)
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::TypeError,
			"Expected instruction(s) to deposit " +
			boost::lexical_cast<string>(_deposit) +
			" item(s) to the stack, but did deposit " +
			boost::lexical_cast<string>(stackDiff) +
			" item(s).",
			_location
		));
		return false;
	}
	else
		return true;
}

Scope& AsmAnalyzer::scope(Block const* _block)
{
	auto scopePtr = m_scopes.at(_block);
	solAssert(scopePtr, "Scope requested but not present.");
	return *scopePtr;
}
<commit_msg>Another stack check.<commit_after>/*
	This file is part of solidity.

	solidity is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	solidity 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * Analyzer part of inline assembly.
 */

#include <libsolidity/inlineasm/AsmAnalysis.h>

#include <libsolidity/inlineasm/AsmData.h>
#include <libsolidity/inlineasm/AsmScopeFiller.h>
#include <libsolidity/inlineasm/AsmScope.h>

#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/Utils.h>

#include <boost/range/adaptor/reversed.hpp>

#include <memory>
#include <functional>

using namespace std;
using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::assembly;

AsmAnalyzer::AsmAnalyzer(
	AsmAnalyzer::Scopes& _scopes,
	ErrorList& _errors,
	ExternalIdentifierAccess::Resolver const& _resolver
):
	m_resolver(_resolver), m_scopes(_scopes), m_errors(_errors)
{
}

bool AsmAnalyzer::analyze(Block const& _block)
{
	if (!(ScopeFiller(m_scopes, m_errors))(_block))
		return false;

	return (*this)(_block);
}

bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction)
{
	auto const& info = instructionInfo(_instruction.instruction);
	m_stackHeight += info.ret - info.args;
	return true;
}

bool AsmAnalyzer::operator()(assembly::Literal const& _literal)
{
	++m_stackHeight;
	if (!_literal.isNumber && _literal.value.size() > 32)
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::TypeError,
			"String literal too long (" + boost::lexical_cast<std::string>(_literal.value.size()) + " > 32)",
			_literal.location
		));
		return false;
	}
	return true;
}

bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
{
	bool success = true;
	if (m_currentScope->lookup(_identifier.name, Scope::Visitor(
		[&](Scope::Variable const& _var)
		{
			if (!_var.active)
			{
				m_errors.push_back(make_shared<Error>(
					Error::Type::DeclarationError,
					"Variable " + _identifier.name + " used before it was declared.",
					_identifier.location
				));
				success = false;
			}
			++m_stackHeight;
		},
		[&](Scope::Label const&)
		{
			++m_stackHeight;
		},
		[&](Scope::Function const&)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Function " + _identifier.name + " used without being called.",
				_identifier.location
			));
			success = false;
		}
	)))
	{
	}
	else
	{
		size_t stackSize(-1);
		if (m_resolver)
			stackSize = m_resolver(_identifier, IdentifierContext::RValue);
		if (stackSize == size_t(-1))
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::DeclarationError,
				"Identifier not found.",
				_identifier.location
			));
			success = false;
		}
		m_stackHeight += stackSize == size_t(-1) ? 1 : stackSize;
	}
	return success;
}

bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr)
{
	bool success = true;
	for (auto const& arg: _instr.arguments | boost::adaptors::reversed)
	{
		int const stackHeight = m_stackHeight;
		if (!boost::apply_visitor(*this, arg))
			success = false;
		if (!expectDeposit(1, stackHeight, locationOf(arg)))
			success = false;
	}
	// Parser already checks that the number of arguments is correct.
	solAssert(instructionInfo(_instr.instruction.instruction).args == int(_instr.arguments.size()), "");
	if (!(*this)(_instr.instruction))
		success = false;
	return success;
}

bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment)
{
	return checkAssignment(_assignment.variableName, size_t(-1));
}

bool AsmAnalyzer::operator()(FunctionalAssignment const& _assignment)
{
	int const stackHeight = m_stackHeight;
	bool success = boost::apply_visitor(*this, *_assignment.value);
	solAssert(m_stackHeight >= stackHeight, "Negative value size.");
	if (!checkAssignment(_assignment.variableName, m_stackHeight - stackHeight))
		success = false;
	return success;
}

bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
{
	int const stackHeight = m_stackHeight;
	bool success = boost::apply_visitor(*this, *_varDecl.value);
	solAssert(m_stackHeight - stackHeight == 1, "Invalid value size.");
	boost::get<Scope::Variable>(m_currentScope->identifiers.at(_varDecl.name)).active = true;
	return success;
}

bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
{
	Scope& bodyScope = scope(&_funDef.body);
	for (auto const& var: _funDef.arguments + _funDef.returns)
		boost::get<Scope::Variable>(bodyScope.identifiers.at(var)).active = true;

	int const stackHeight = m_stackHeight;
	m_stackHeight = _funDef.arguments.size() + _funDef.returns.size();
	m_virtualVariablesInNextBlock = m_stackHeight;

	bool success = (*this)(_funDef.body);

	m_stackHeight = stackHeight;
	return success;
}

bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall)
{
	bool success = true;
	size_t arguments = 0;
	size_t returns = 0;
	if (!m_currentScope->lookup(_funCall.functionName.name, Scope::Visitor(
		[&](Scope::Variable const&)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Attempt to call variable instead of function.",
				_funCall.functionName.location
			));
			success = false;
		},
		[&](Scope::Label const&)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Attempt to call label instead of function.",
				_funCall.functionName.location
				));
			success = false;
		},
		[&](Scope::Function const& _fun)
		{
			arguments = _fun.arguments;
			returns = _fun.returns;
		}
	)))
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::DeclarationError,
			"Function not found.",
			_funCall.functionName.location
		));
		success = false;
	}
	if (success)
	{
		if (_funCall.arguments.size() != arguments)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Expected " +
				boost::lexical_cast<string>(arguments) +
				" arguments but got " +
				boost::lexical_cast<string>(_funCall.arguments.size()) +
				".",
				_funCall.functionName.location
				));
			success = false;
		}
	}
	for (auto const& arg: _funCall.arguments | boost::adaptors::reversed)
	{
		int const stackHeight = m_stackHeight;
		if (!boost::apply_visitor(*this, arg))
			success = false;
		if (!expectDeposit(1, stackHeight, locationOf(arg)))
			success = false;
	}
	m_stackHeight += int(returns) - int(arguments);
	return success;
}

bool AsmAnalyzer::operator()(Block const& _block)
{
	bool success = true;
	m_currentScope = &scope(&_block);

	int const initialStackHeight = m_stackHeight - m_virtualVariablesInNextBlock;
	m_virtualVariablesInNextBlock = 0;

	for (auto const& s: _block.statements)
		if (!boost::apply_visitor(*this, s))
			success = false;

	for (auto const& identifier: scope(&_block).identifiers)
		if (identifier.second.type() == typeid(Scope::Variable))
			--m_stackHeight;

	int const stackDiff = m_stackHeight - initialStackHeight;
	if (stackDiff != 0)
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::DeclarationError,
			"Unbalanced stack at the end of a block: " +
			(
				stackDiff > 0 ?
				to_string(stackDiff) + string(" surplus item(s).") :
				to_string(-stackDiff) + string(" missing item(s).")
			),
			_block.location
		));
		success = false;
	}

	m_currentScope = m_currentScope->superScope;
	return success;
}

bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t _valueSize)
{
	bool success = true;
	size_t variableSize(-1);
	if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name))
	{
		// Check that it is a variable
		if (var->type() != typeid(Scope::Variable))
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::TypeError,
				"Assignment requires variable.",
				_variable.location
			));
			success = false;
		}
		else if (!boost::get<Scope::Variable>(*var).active)
		{
			m_errors.push_back(make_shared<Error>(
				Error::Type::DeclarationError,
				"Variable " + _variable.name + " used before it was declared.",
				_variable.location
			));
			success = false;
		}
		variableSize = 1;
	}
	else if (m_resolver)
		variableSize = m_resolver(_variable, IdentifierContext::LValue);
	if (variableSize == size_t(-1))
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::DeclarationError,
			"Variable not found or variable not lvalue.",
			_variable.location
		));
		success = false;
	}
	if (_valueSize == size_t(-1))
		_valueSize = variableSize == size_t(-1) ? 1 : variableSize;

	m_stackHeight -= _valueSize;

	if (_valueSize != variableSize && variableSize != size_t(-1))
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::TypeError,
			"Variable size (" +
			to_string(variableSize) +
			") and value size (" +
			to_string(_valueSize) +
			") do not match.",
			_variable.location
		));
		success = false;
	}
	return success;
}

bool AsmAnalyzer::expectDeposit(int const _deposit, int const _oldHeight, SourceLocation const& _location)
{
	int stackDiff = m_stackHeight - _oldHeight;
	if (stackDiff != _deposit)
	{
		m_errors.push_back(make_shared<Error>(
			Error::Type::TypeError,
			"Expected instruction(s) to deposit " +
			boost::lexical_cast<string>(_deposit) +
			" item(s) to the stack, but did deposit " +
			boost::lexical_cast<string>(stackDiff) +
			" item(s).",
			_location
		));
		return false;
	}
	else
		return true;
}

Scope& AsmAnalyzer::scope(Block const* _block)
{
	auto scopePtr = m_scopes.at(_block);
	solAssert(scopePtr, "Scope requested but not present.");
	return *scopePtr;
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2014  P.L. Lucas <selairi@gmail.com>
    Copyright (C) 2014  Hong Jen Yee (PCMan) <pcman.tw@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "monitorwidget.h"

#include <QComboBox>
#include <QStringBuilder>
#include <QDialogButtonBox>
#include <KScreen/EDID>

QString modeToString(KScreen::ModePtr mode)
{
    // mode->name() can be anything, not just widthxheight. eg if added with cvt.
    return QString("%1x%2").arg(mode->size().width()).arg(mode->size().height());
}

KScreen::OutputPtr getOutputById(int id, KScreen::OutputList outputs)
{
    for (const KScreen::OutputPtr &output : outputs)
        if (output->id() == id)
            return output;

    return KScreen::OutputPtr(nullptr);
}

KScreen::ModePtr getModeById(QString id, KScreen::ModeList modes)
{
    for (const KScreen::ModePtr &mode : modes)
        if (mode->id() == id)
            return mode;

    return KScreen::ModePtr(NULL);
}

static bool sizeBiggerThan(const KScreen::ModePtr &modeA, const KScreen::ModePtr &modeB)
{
    QSize sizeA = modeA->size();
    QSize sizeB = modeB->size();
    return sizeA.width() * sizeA.height() > sizeB.width() * sizeB.height();
}

MonitorWidget::MonitorWidget(KScreen::OutputPtr output, KScreen::ConfigPtr config, QWidget* parent) :
    QGroupBox(parent)
{
    this->output = output;
    this->config = config;

    ui.setupUi(this);

    ui.enabledCheckbox->setChecked(output->isEnabled());

    QList <KScreen::ModePtr> modeList = output->modes().values();

    // Remove duplicate sizes
    QMap<QString, KScreen::ModePtr> noDuplicateModes;
    foreach(const KScreen::ModePtr &mode, modeList)
    {
        if( noDuplicateModes.keys().contains(modeToString(mode)) )
        {
            KScreen::ModePtr actual = noDuplicateModes[modeToString(mode)];
            bool isActualPreferred = output->preferredModes().contains(actual->id());
            bool isModePreferred = output->preferredModes().contains(mode->id());
            if( ( mode->refreshRate() > actual->refreshRate() && !isActualPreferred ) || isModePreferred )
                noDuplicateModes[modeToString(mode)] = mode;
        }
        else
            noDuplicateModes[modeToString(mode)] = mode;
    }

    // Sort modes by size
    modeList = noDuplicateModes.values();
    qSort(modeList.begin(), modeList.end(), sizeBiggerThan);

    // Add each mode to the list
    foreach (const KScreen::ModePtr &mode, modeList)
    {
        ui.resolutionCombo->addItem(modeToString(mode), mode->id());
        if(output->preferredModes().contains(mode->id()))
        {
             // Make bold preferredModes
             QFont font = ui.resolutionCombo->font();
             font.setBold(true);
             ui.resolutionCombo->setItemData(ui.resolutionCombo->count()-1, font, Qt::FontRole);
        }
    }
    connect(ui.resolutionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onResolutionChanged(int)));

    // Select actual mode in list
    if (output->currentMode())
    {
        // Set the current mode in dropdown
        int idx = ui.resolutionCombo->findData(output->currentMode()->id());
        if (idx < 0)
        {
            // Select mode with same size
            foreach (const KScreen::ModePtr &mode, modeList)
            {
                if( mode->size() == output->currentMode()->size() )
                    idx = ui.resolutionCombo->findData(output->currentMode()->id());
            }
        }
        if(idx < 0)
            idx = ui.resolutionCombo->findData(output->preferredMode()->id());
        if (idx >= 0)
            ui.resolutionCombo->setCurrentIndex(idx);
    }
    updateRefreshRates();

    // Update EDID information
    // KScreen doesn't make much public but that's ok...
    KScreen::Edid* edid = output->edid();
    if (edid && edid->isValid())
    {
        ui.outputInfoLabel->setText(
            tr("Name: %1\n").arg(edid->name()) %
            tr("Vendor: %1\n").arg(edid->vendor()) %
            tr("Serial: %1\n").arg(edid->serial()) %
            tr("Display size: %1cm x %2cm\n").arg(edid->width()).arg(edid->height()) %
            tr("Serial number: %1\n").arg(edid->serial()) %
            tr("EISA device ID: %1\n").arg(edid->eisaId())
        );
    }

    if (config->connectedOutputs().count() == 1)
    {
        setOnlyMonitor(true);
        // There isn't always a primary output. Gross.
        output->setPrimary(true);
    }

    ui.xPosSpinBox->setValue(output->pos().x());
    ui.yPosSpinBox->setValue(output->pos().y());

    // Behavior chooser
    if (output->isPrimary())
        ui.behaviorCombo->setCurrentIndex(PrimaryDisplay);

    // Insert orientations
    ui.orientationCombo->addItem(tr("None"), KScreen::Output::None);
    ui.orientationCombo->addItem(tr("Left"), KScreen::Output::Left);
    ui.orientationCombo->addItem(tr("Right"), KScreen::Output::Right);
    ui.orientationCombo->addItem(tr("Inverted"), KScreen::Output::Inverted);
    switch(output->rotation())
    {
    case KScreen::Output::None:
            ui.orientationCombo->setCurrentIndex(0);
        break;
    case KScreen::Output::Left:
        ui.orientationCombo->setCurrentIndex(1);
        break;
    case KScreen::Output::Right:
            ui.orientationCombo->setCurrentIndex(2);
        break;
    case KScreen::Output::Inverted:
        ui.orientationCombo->setCurrentIndex(3);
        break;
    }

    connect(ui.enabledCheckbox, SIGNAL(toggled(bool)), this, SLOT(onEnabledChanged(bool)));
    connect(ui.behaviorCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onBehaviorChanged(int)));
    connect(ui.xPosSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onPositionChanged(int)));
    connect(ui.yPosSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onPositionChanged(int)));
    connect(ui.orientationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onOrientationChanged(int)));

    // Force update behavior visibility
    onBehaviorChanged(ui.behaviorCombo->currentIndex());
}

MonitorWidget::~MonitorWidget()
{
}

void MonitorWidget::onEnabledChanged(bool enabled)
{
    output->setEnabled(enabled);

    // If we're enabling a disabled output for the first time
    if (enabled && !output->currentMode())
    {
        // order here matters
        onResolutionChanged(ui.resolutionCombo->currentIndex());
        onOrientationChanged(ui.orientationCombo->currentIndex());
        onBehaviorChanged(ui.behaviorCombo->currentIndex());
    }
}

void MonitorWidget::onOrientationChanged(int idx)
{
    output->setRotation((KScreen::Output::Rotation) ui.orientationCombo->currentData().toInt(0));
}

void MonitorWidget::onBehaviorChanged(int idx)
{
    // Behavior should match the index of the selected element
    ui.xPosSpinBox->setVisible(idx == ExtendDisplay);
    ui.yPosSpinBox->setVisible(idx == ExtendDisplay);

    output->setPrimary(idx == PrimaryDisplay);
    if(idx == PrimaryDisplay)
        emit primaryOutputChanged(this);
}

void MonitorWidget::onPositionChanged(int value)
{
    output->setPos(QPoint(ui.xPosSpinBox->value(), ui.yPosSpinBox->value()));
}

void MonitorWidget::onResolutionChanged(int index)
{
    output->setCurrentModeId(ui.resolutionCombo->currentData().toString());
    updateRefreshRates();
}

void MonitorWidget::onRateChanged(int index)
{
    output->setCurrentModeId(ui.rateCombo->currentData().toString());
}

void MonitorWidget::updateRefreshRates()
{
    disconnect(ui.rateCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onRateChanged(int)));
    ui.rateCombo->clear();

    if (output->modes().size() < 0)
        return;

    KScreen::ModePtr selectedMode = output->currentMode();
    if (selectedMode)
    {
        for (const KScreen::ModePtr &mode : output->modes())
            if (mode->size() == selectedMode->size())
                ui.rateCombo->addItem(tr("%1 Hz").arg(mode->refreshRate()), mode->id());

        int idx = ui.rateCombo->findData(selectedMode->id());
        if (idx >= 0)
            ui.rateCombo->setCurrentIndex(idx);
    }

    connect(ui.rateCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onRateChanged(int)));
}

void MonitorWidget::setOnlyMonitor(bool isOnlyMonitor)
{
    ui.enabledCheckbox->setEnabled(!isOnlyMonitor);
    ui.behaviorCombo->setEnabled(!isOnlyMonitor);
    ui.xPosSpinBox->setVisible(!isOnlyMonitor);
    ui.yPosSpinBox->setVisible(!isOnlyMonitor);
    if(isOnlyMonitor)
    {
        ui.xPosSpinBox->setValue(0);
        ui.yPosSpinBox->setValue(0);
    }
}

void MonitorWidget::onPrimaryOutputChanged(MonitorWidget *widget)
{
    if(widget == this)
        return;
    ui.behaviorCombo->setCurrentIndex(ExtendDisplay);
}
<commit_msg>Show non-primary screens in UI. (#116)<commit_after>/*
    Copyright (C) 2014  P.L. Lucas <selairi@gmail.com>
    Copyright (C) 2014  Hong Jen Yee (PCMan) <pcman.tw@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "monitorwidget.h"

#include <QComboBox>
#include <QStringBuilder>
#include <QDialogButtonBox>
#include <KScreen/EDID>

QString modeToString(KScreen::ModePtr mode)
{
    // mode->name() can be anything, not just widthxheight. eg if added with cvt.
    return QString("%1x%2").arg(mode->size().width()).arg(mode->size().height());
}

KScreen::OutputPtr getOutputById(int id, KScreen::OutputList outputs)
{
    for (const KScreen::OutputPtr &output : outputs)
        if (output->id() == id)
            return output;

    return KScreen::OutputPtr(nullptr);
}

KScreen::ModePtr getModeById(QString id, KScreen::ModeList modes)
{
    for (const KScreen::ModePtr &mode : modes)
        if (mode->id() == id)
            return mode;

    return KScreen::ModePtr(NULL);
}

static bool sizeBiggerThan(const KScreen::ModePtr &modeA, const KScreen::ModePtr &modeB)
{
    QSize sizeA = modeA->size();
    QSize sizeB = modeB->size();
    return sizeA.width() * sizeA.height() > sizeB.width() * sizeB.height();
}

MonitorWidget::MonitorWidget(KScreen::OutputPtr output, KScreen::ConfigPtr config, QWidget* parent) :
    QGroupBox(parent)
{
    this->output = output;
    this->config = config;

    ui.setupUi(this);

    ui.enabledCheckbox->setChecked(output->isEnabled());

    QList <KScreen::ModePtr> modeList = output->modes().values();

    // Remove duplicate sizes
    QMap<QString, KScreen::ModePtr> noDuplicateModes;
    foreach(const KScreen::ModePtr &mode, modeList)
    {
        if( noDuplicateModes.keys().contains(modeToString(mode)) )
        {
            KScreen::ModePtr actual = noDuplicateModes[modeToString(mode)];
            bool isActualPreferred = output->preferredModes().contains(actual->id());
            bool isModePreferred = output->preferredModes().contains(mode->id());
            if( ( mode->refreshRate() > actual->refreshRate() && !isActualPreferred ) || isModePreferred )
                noDuplicateModes[modeToString(mode)] = mode;
        }
        else
            noDuplicateModes[modeToString(mode)] = mode;
    }

    // Sort modes by size
    modeList = noDuplicateModes.values();
    qSort(modeList.begin(), modeList.end(), sizeBiggerThan);

    // Add each mode to the list
    foreach (const KScreen::ModePtr &mode, modeList)
    {
        ui.resolutionCombo->addItem(modeToString(mode), mode->id());
        if(output->preferredModes().contains(mode->id()))
        {
             // Make bold preferredModes
             QFont font = ui.resolutionCombo->font();
             font.setBold(true);
             ui.resolutionCombo->setItemData(ui.resolutionCombo->count()-1, font, Qt::FontRole);
        }
    }
    connect(ui.resolutionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onResolutionChanged(int)));

    // Select actual mode in list
    if (output->currentMode())
    {
        // Set the current mode in dropdown
        int idx = ui.resolutionCombo->findData(output->currentMode()->id());
        if (idx < 0)
        {
            // Select mode with same size
            foreach (const KScreen::ModePtr &mode, modeList)
            {
                if( mode->size() == output->currentMode()->size() )
                    idx = ui.resolutionCombo->findData(output->currentMode()->id());
            }
        }
        if(idx < 0)
            idx = ui.resolutionCombo->findData(output->preferredMode()->id());
        if (idx >= 0)
            ui.resolutionCombo->setCurrentIndex(idx);
    }
    updateRefreshRates();

    // Update EDID information
    // KScreen doesn't make much public but that's ok...
    KScreen::Edid* edid = output->edid();
    if (edid && edid->isValid())
    {
        ui.outputInfoLabel->setText(
            tr("Name: %1\n").arg(edid->name()) %
            tr("Vendor: %1\n").arg(edid->vendor()) %
            tr("Serial: %1\n").arg(edid->serial()) %
            tr("Display size: %1cm x %2cm\n").arg(edid->width()).arg(edid->height()) %
            tr("Serial number: %1\n").arg(edid->serial()) %
            tr("EISA device ID: %1\n").arg(edid->eisaId())
        );
    }

    if (config->connectedOutputs().count() == 1)
    {
        setOnlyMonitor(true);
        // There isn't always a primary output. Gross.
        output->setPrimary(true);
    }

    ui.xPosSpinBox->setValue(output->pos().x());
    ui.yPosSpinBox->setValue(output->pos().y());

    // Behavior chooser
    if (output->isPrimary())
        ui.behaviorCombo->setCurrentIndex(PrimaryDisplay);
    else
        ui.behaviorCombo->setCurrentIndex(ExtendDisplay);

    // Insert orientations
    ui.orientationCombo->addItem(tr("None"), KScreen::Output::None);
    ui.orientationCombo->addItem(tr("Left"), KScreen::Output::Left);
    ui.orientationCombo->addItem(tr("Right"), KScreen::Output::Right);
    ui.orientationCombo->addItem(tr("Inverted"), KScreen::Output::Inverted);
    switch(output->rotation())
    {
    case KScreen::Output::None:
            ui.orientationCombo->setCurrentIndex(0);
        break;
    case KScreen::Output::Left:
        ui.orientationCombo->setCurrentIndex(1);
        break;
    case KScreen::Output::Right:
            ui.orientationCombo->setCurrentIndex(2);
        break;
    case KScreen::Output::Inverted:
        ui.orientationCombo->setCurrentIndex(3);
        break;
    }

    connect(ui.enabledCheckbox, SIGNAL(toggled(bool)), this, SLOT(onEnabledChanged(bool)));
    connect(ui.behaviorCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onBehaviorChanged(int)));
    connect(ui.xPosSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onPositionChanged(int)));
    connect(ui.yPosSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onPositionChanged(int)));
    connect(ui.orientationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onOrientationChanged(int)));

    // Force update behavior visibility
    onBehaviorChanged(ui.behaviorCombo->currentIndex());
}

MonitorWidget::~MonitorWidget()
{
}

void MonitorWidget::onEnabledChanged(bool enabled)
{
    output->setEnabled(enabled);

    // If we're enabling a disabled output for the first time
    if (enabled && !output->currentMode())
    {
        // order here matters
        onResolutionChanged(ui.resolutionCombo->currentIndex());
        onOrientationChanged(ui.orientationCombo->currentIndex());
        onBehaviorChanged(ui.behaviorCombo->currentIndex());
    }
}

void MonitorWidget::onOrientationChanged(int idx)
{
    output->setRotation((KScreen::Output::Rotation) ui.orientationCombo->currentData().toInt(0));
}

void MonitorWidget::onBehaviorChanged(int idx)
{
    // Behavior should match the index of the selected element
    ui.xPosSpinBox->setVisible(idx == ExtendDisplay);
    ui.yPosSpinBox->setVisible(idx == ExtendDisplay);

    output->setPrimary(idx == PrimaryDisplay);
    if(idx == PrimaryDisplay)
        emit primaryOutputChanged(this);
}

void MonitorWidget::onPositionChanged(int value)
{
    output->setPos(QPoint(ui.xPosSpinBox->value(), ui.yPosSpinBox->value()));
}

void MonitorWidget::onResolutionChanged(int index)
{
    output->setCurrentModeId(ui.resolutionCombo->currentData().toString());
    updateRefreshRates();
}

void MonitorWidget::onRateChanged(int index)
{
    output->setCurrentModeId(ui.rateCombo->currentData().toString());
}

void MonitorWidget::updateRefreshRates()
{
    disconnect(ui.rateCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onRateChanged(int)));
    ui.rateCombo->clear();

    if (output->modes().size() < 0)
        return;

    KScreen::ModePtr selectedMode = output->currentMode();
    if (selectedMode)
    {
        for (const KScreen::ModePtr &mode : output->modes())
            if (mode->size() == selectedMode->size())
                ui.rateCombo->addItem(tr("%1 Hz").arg(mode->refreshRate()), mode->id());

        int idx = ui.rateCombo->findData(selectedMode->id());
        if (idx >= 0)
            ui.rateCombo->setCurrentIndex(idx);
    }

    connect(ui.rateCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onRateChanged(int)));
}

void MonitorWidget::setOnlyMonitor(bool isOnlyMonitor)
{
    ui.enabledCheckbox->setEnabled(!isOnlyMonitor);
    ui.behaviorCombo->setEnabled(!isOnlyMonitor);
    ui.xPosSpinBox->setVisible(!isOnlyMonitor);
    ui.yPosSpinBox->setVisible(!isOnlyMonitor);
    if(isOnlyMonitor)
    {
        ui.xPosSpinBox->setValue(0);
        ui.yPosSpinBox->setValue(0);
    }
}

void MonitorWidget::onPrimaryOutputChanged(MonitorWidget *widget)
{
    if(widget == this)
        return;
    ui.behaviorCombo->setCurrentIndex(ExtendDisplay);
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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.apache.org/licenses/LICENSE-2.0
//
// 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.

#include "google/cloud/spanner/client.h"
#include <iostream>
#include <stdexcept>
#include <chrono>

namespace {
namespace spanner = ::google::cloud::spanner;
using google::cloud::StatusOr;

const std::int64_t DEFAULTGAP = 100;
const std::int64_t BATCHSIZE = 1000;

void batchUpdateData(spanner::Client readClient, spanner::Client writeClient,
           std::int64_t batchSize)  {
  auto rows = readClient.Read("TestModels", spanner::KeySet::All(),
  		{"CdsId", "TrainingTime"});
  using RowType = std::tuple<std::int64_t, spanner::Timestamp>;

  // A helper to read a single Timestamp.
  const auto& get_expiration_time =
      [](spanner::Client client, std::int64_t cdsId)
      -> StatusOr<spanner::Timestamp> {
    auto key = spanner::KeySet().AddKey(spanner::MakeKey(cdsId));
    auto rows = client.Read("TestModels", std::move(key),
                            {"ExpirationTime"});
    using RowType = std::tuple<spanner::Timestamp>;
    auto row = spanner::GetSingularRow(spanner::StreamOf<RowType>(rows));
    if (!row) return std::move(row).status();
    return std::get<0>(*std::move(row));
  };

  spanner::Mutations mutations;
  std::int64_t i = 0;
  for(const auto& row : spanner::StreamOf<RowType>(rows)) {
    if(!row) throw std::runtime_error(row.status().message());
    i += 1;
    std::int64_t cdsId = std::get<0>(*row);
    spanner::Timestamp trainingTime = std::get<1>(*row);
    // auto expirationTime = get_expiration_time(readClient, cdsId);
    // if(!expirationTime) {
      spanner::sys_time<std::chrono::nanoseconds> expirationNS =
        trainingTime.get<spanner::sys_time<std::chrono::nanoseconds>>().value()
        + 60*std::chrono::hours(24);
      spanner::Timestamp newExpirationTime = spanner::MakeTimestamp(expirationNS).value();
      mutations.push_back(spanner::UpdateMutationBuilder(
		  "TestModels", {"CdsId", "ExpirationTime", "TrainingTime"})
		  .EmplaceRow(cdsId, newExpirationTime, trainingTime)
		  .Build());

      if(i % batchSize == 0) {
    	  auto commit_result = writeClient.Commit(mutations);
    	  if (!commit_result) {
     	    throw std::runtime_error(commit_result.status().message());
   	    }
	      mutations.clear();
	      i = 0;
      }
    // }
    // else: check validity
  }
}

void batchInsertData(google::cloud::spanner::Client client, std::int64_t batchSize) {
  namespace spanner = ::google::cloud::spanner;
  using ::google::cloud::StatusOr;

  auto commit_result = client.Commit(
	[&client, &batchSize](
		spanner::Transaction const& txn) -> StatusOr<spanner::Mutations> {
        spanner::Mutations mutations;
        spanner::sys_time<std::chrono::nanoseconds> trainingNS = std::chrono::system_clock::now();
        spanner::Timestamp trainingTime = spanner::MakeTimestamp(trainingNS).value();
        for(std::int64_t i = 3; i <= batchSize; i++) {
            mutations.push_back(spanner::InsertMutationBuilder(
			      "TestModels", {"CdsId", "TrainingTime"})
		        .EmplaceRow(i, trainingTime)
			      .Build());
        }
	      return mutations;
      });
  if (!commit_result) {
    throw std::runtime_error(commit_result.status().message());
  }
}

} // namespace

int main(int argc, char* argv[]) try {
  if (argc != 4) {
    std::cerr << "Usage: " << argv[0]
              << " project-id instance-id database-id\n";
    return 1;
  }

  spanner::Client readClient(
      spanner::MakeConnection(spanner::Database(argv[1], argv[2], argv[3])));
  spanner::Client writeClient(
      spanner::MakeConnection(spanner::Database(argv[1], argv[2], argv[3])));

  auto start = std::chrono::high_resolution_clock::now();

  batchUpdateData(readClient, writeClient, BATCHSIZE);
  // batchInsertData(writeClient, BATCHSIZE);
  auto stop = std::chrono::high_resolution_clock::now();
  auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop-start);
  std::cout <<
  "Time taken : " << duration.count() << " milliseconds" << std::endl;
  return 1;
  } catch (std::exception const& ex) {
  std::cerr << "Standard exception raised: " << ex.what() << "\n";
  return 1;
  }<commit_msg>update with check<commit_after>// Copyright 2020 Google LLC
//
// 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.apache.org/licenses/LICENSE-2.0
//
// 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.

#include "google/cloud/spanner/client.h"
#include <iostream>
#include <stdexcept>
#include <chrono>

namespace {
namespace spanner = ::google::cloud::spanner;
using google::cloud::StatusOr;

const std::int64_t DEFAULTGAP = 100;
const std::int64_t BATCHSIZE = 1000;

void batchUpdateData(spanner::Client readClient, spanner::Client writeClient,
           std::int64_t batchSize)  {
  auto rows = readClient.Read("TestModels", spanner::KeySet::All(),
  		{"CdsId", "ExpirationTime", "TrainingTime"});

  spanner::Mutations mutations;
  std::int64_t i = 0;
  for(const auto& row : rows) {
    if(!row) throw std::runtime_error(row.status().message());

    spanner::Value cds = (*row).get(0).value();
    spanner::Value expiration = (*row).get(1).value();
    spanner::Value training = (*row).get(2).value();

    std::int64_t cdsId = cds.get<std::int64_t>().value();
    StatusOr<spanner::Timestamp> expirationTime = expiration.get<spanner::Timestamp>();
    StatusOr<spanner::Timestamp> trainingTime = training.get<spanner::Timestamp>();

    if(!trainingTime) {
      throw std::runtime_error("TrainingTime shouldn't be null.");
    }
    if(expirationTime) {
      spanner::sys_time<std::chrono::nanoseconds> trainingNS =
        (*expirationTime).get<spanner::sys_time<std::chrono::nanoseconds>>().value()
        - 60*std::chrono::hours(24);
      spanner::Timestamp supposedTraining = spanner::MakeTimestamp(trainingNS).value();
      if(*trainingTime != supposedTraining) {
        throw std::runtime_error("Time gap for " + std::to_string(cdsId) + " is not correct.");
      }
    }
    else {
      spanner::sys_time<std::chrono::nanoseconds> expirationNS =
        (*trainingTime).get<spanner::sys_time<std::chrono::nanoseconds>>().value()
        + 60*std::chrono::hours(24);
      spanner::Timestamp newExpiration = spanner::MakeTimestamp(expirationNS).value();
      mutations.push_back(spanner::UpdateMutationBuilder(
		  "TestModels", {"CdsId", "ExpirationTime", "TrainingTime"})
		  .EmplaceRow(cdsId, newExpiration, *trainingTime)
		  .Build());

      ++i;
      if(i % batchSize == 0) {
    	  auto commit_result = writeClient.Commit(mutations);
    	  if (!commit_result) {
     	    throw std::runtime_error(commit_result.status().message());
   	    }
	      mutations.clear();
	      i = 0;
      }
    }
  }
}

void batchInsertData(google::cloud::spanner::Client client, std::int64_t batchSize) {
  namespace spanner = ::google::cloud::spanner;
  using ::google::cloud::StatusOr;

  auto commit_result = client.Commit(
	[&client, &batchSize](
		spanner::Transaction const& txn) -> StatusOr<spanner::Mutations> {
        spanner::Mutations mutations;
        spanner::sys_time<std::chrono::nanoseconds> trainingNS = std::chrono::system_clock::now();
        spanner::Timestamp trainingTime = spanner::MakeTimestamp(trainingNS).value();
        for(std::int64_t i = 3; i <= batchSize; i++) {
            mutations.push_back(spanner::InsertMutationBuilder(
			      "TestModels", {"CdsId", "TrainingTime"})
		        .EmplaceRow(i, trainingTime)
			      .Build());
        }
	      return mutations;
      });
  if (!commit_result) {
    throw std::runtime_error(commit_result.status().message());
  }
}

} // namespace

int main(int argc, char* argv[]) try {
  if (argc != 4) {
    std::cerr << "Usage: " << argv[0]
              << " project-id instance-id database-id\n";
    return 1;
  }

  spanner::Client readClient(
      spanner::MakeConnection(spanner::Database(argv[1], argv[2], argv[3])));
  spanner::Client writeClient(
      spanner::MakeConnection(spanner::Database(argv[1], argv[2], argv[3])));

  auto start = std::chrono::high_resolution_clock::now();

  batchUpdateData(readClient, writeClient, BATCHSIZE);
  // batchInsertData(writeClient, BATCHSIZE);
  auto stop = std::chrono::high_resolution_clock::now();
  auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop-start);
  std::cout <<
  "Time taken : " << duration.count() << " milliseconds" << std::endl;
  return 1;
  } catch (std::exception const& ex) {
  std::cerr << "Standard exception raised: " << ex.what() << "\n";
  return 1;
  }<|endoftext|>


<commit_before>// This file is part of the hdf5_handler implementing for the CF-compliant
// Copyright (c) 2011-2016 The HDF Group, Inc. and OPeNDAP, Inc.
//
// This is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This software 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 Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
// You can contact The HDF Group, Inc. at 1800 South Oak Street,
// Suite 203, Champaign, IL 61820

/////////////////////////////////////////////////////////////////////////////
/// \file HDFEOS5CFMissLLArray.cc
/// \brief The implementation of the retrieval of the missing lat/lon values for HDF-EOS5 products
///
/// \author Kent Yang <myang6@hdfgroup.org>
///
/// Copyright (C) 2011-2016 The HDF Group
///
/// All rights reserved.

#include "config_hdf5.h"
#include <iostream>
#include <sstream>
#include <cassert>
#include <BESDebug.h>
#include "InternalErr.h"
#include <Array.h>

#include "HDFEOS5CFMissLLArray.h"

BaseType *HDFEOS5CFMissLLArray::ptr_duplicate()
{
    return new HDFEOS5CFMissLLArray(*this);
}

bool HDFEOS5CFMissLLArray::read()
{

    BESDEBUG("h5","Coming to HDFEOS5CFMissLLArray read "<<endl);
    int nelms = -1;
    vector<int>offset;
    vector<int>count;
    vector<int>step;

    if (eos5_projcode != HE5_GCTP_GEO)
        throw InternalErr (__FILE__, __LINE__,"The projection is not supported.");

    if (rank <=  0)
       throw InternalErr (__FILE__, __LINE__,
                          "The number of dimension of this variable should be greater than 0");
    else {

         offset.resize(rank);
         count.resize(rank);
         step.resize(rank);
         nelms = format_constraint (&offset[0], &step[0], &count[0]);
    }

    if (nelms <= 0)
       throw InternalErr (__FILE__, __LINE__,
                          "The number of elments is negative.");

    float start = 0.0;
    float end   = 0.0;

    vector<float>val;
    val.resize(nelms);

    if (CV_LAT_MISS == cvartype) {

        if (HE5_HDFE_GD_UL == eos5_origin || HE5_HDFE_GD_UR == eos5_origin) {

            start = point_upper;
            end   = point_lower;

        }
        else {// (gridorigin == HE5_HDFE_GD_LL || gridorigin == HE5_HDFE_GD_LR)

            start = point_lower;
            end = point_upper;
        }

        if(ydimsize <=0)
           throw InternalErr (__FILE__, __LINE__,
                          "The number of elments should be greater than 0.");

        float lat_step = (end - start) /ydimsize;

        // Now offset,step and val will always be valid. line 74 and 85 assure this.
        if ( HE5_HDFE_CENTER == eos5_pixelreg ) {
            for (int i = 0; i < nelms; i++)
                val[i] = ((float)(offset[0]+i*step[0] + 0.5f) * lat_step + start) / 1000000.0;
        }
        else { // HE5_HDFE_CORNER
            for (int i = 0; i < nelms; i++)
                val[i] = ((float)(offset[0]+i * step[0])*lat_step + start) / 1000000.0;
        }

    }

    if (CV_LON_MISS == cvartype) {

        if (HE5_HDFE_GD_UL == eos5_origin || HE5_HDFE_GD_LL == eos5_origin) {

            start = point_left;
            end   = point_right;

        }
        else {// (gridorigin == HE5_HDFE_GD_UR || gridorigin == HE5_HDFE_GD_LR)

            start = point_right;
            end = point_left;
        }

        if(xdimsize <=0)
           throw InternalErr (__FILE__, __LINE__,
                          "The number of elments should be greater than 0.");
        float lon_step = (end - start) /xdimsize;

        if (HE5_HDFE_CENTER == eos5_pixelreg) {
            for (int i = 0; i < nelms; i++)
                val[i] = ((float)(offset[0] + i *step[0] + 0.5f) * lon_step + start ) / 1000000.0;
        }
        else { // HE5_HDFE_CORNER
            for (int i = 0; i < nelms; i++)
                val[i] = ((float)(offset[0]+i*step[0]) * lon_step + start) / 1000000.0;
        }

    }

#if 0
for (int i =0; i <nelms; i++)
"h5","final data val "<< i <<" is " << val[i] <<endl;
#endif

    set_value ((dods_float32 *) &val[0], nelms);
    return true;
}

// parse constraint expr. and make hdf5 coordinate point location.
// return number of elements to read.
int
HDFEOS5CFMissLLArray::format_constraint (int *offset, int *step, int *count)
{
        long nels = 1;
        int id = 0;

        Dim_iter p = dim_begin ();

        while (p != dim_end ()) {

                int start = dimension_start (p, true);
                int stride = dimension_stride (p, true);
                int stop = dimension_stop (p, true);

                // Check for illegical  constraint
                if (stride < 0 || start < 0 || stop < 0 || start > stop) {
                        ostringstream oss;

                        oss << "Array/Grid hyperslab indices are bad: [" << start <<
                                ":" << stride << ":" << stop << "]";
                        throw Error (malformed_expr, oss.str ());
                }

                // Check for an empty constraint and use the whole dimension if so.
                if (start == 0 && stop == 0 && stride == 0) {
                        start = dimension_start (p, false);
                        stride = dimension_stride (p, false);
                        stop = dimension_stop (p, false);
                }

                offset[id] = start;
                step[id] = stride;
                count[id] = ((stop - start) / stride) + 1;      // count of elements
                nels *= count[id];              // total number of values for variable

                BESDEBUG ("h5",
                         "=format_constraint():"
                         << "id=" << id << " offset=" << offset[id]
                         << " step=" << step[id]
                         << " count=" << count[id]
                         << endl);

                id++;
                p++;
        }

        return nels;
}

<commit_msg>HDVHANDLER-183, fix the 0-length array handling and the format_constraint index checking.<commit_after>// This file is part of the hdf5_handler implementing for the CF-compliant
// Copyright (c) 2011-2016 The HDF Group, Inc. and OPeNDAP, Inc.
//
// This is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This software 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 Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
// You can contact The HDF Group, Inc. at 1800 South Oak Street,
// Suite 203, Champaign, IL 61820

/////////////////////////////////////////////////////////////////////////////
/// \file HDFEOS5CFMissLLArray.cc
/// \brief The implementation of the retrieval of the missing lat/lon values for HDF-EOS5 products
///
/// \author Kent Yang <myang6@hdfgroup.org>
///
/// Copyright (C) 2011-2016 The HDF Group
///
/// All rights reserved.

#include "config_hdf5.h"
#include <iostream>
#include <sstream>
#include <cassert>
#include <BESDebug.h>
#include "InternalErr.h"
#include <Array.h>

#include "HDFEOS5CFMissLLArray.h"

BaseType *HDFEOS5CFMissLLArray::ptr_duplicate()
{
    return new HDFEOS5CFMissLLArray(*this);
}

bool HDFEOS5CFMissLLArray::read()
{

    BESDEBUG("h5","Coming to HDFEOS5CFMissLLArray read "<<endl);
    int nelms = -1;
    vector<int>offset;
    vector<int>count;
    vector<int>step;

    if (eos5_projcode != HE5_GCTP_GEO)
        throw InternalErr (__FILE__, __LINE__,"The projection is not supported.");

    if (rank <=  0)
       throw InternalErr (__FILE__, __LINE__,
                          "The number of dimension of this variable should be greater than 0");
    else {

         offset.resize(rank);
         count.resize(rank);
         step.resize(rank);
         nelms = format_constraint (&offset[0], &step[0], &count[0]);
    }

    if (nelms <= 0)
       throw InternalErr (__FILE__, __LINE__,
                          "The number of elments is negative.");

    float start = 0.0;
    float end   = 0.0;

    vector<float>val;
    val.resize(nelms);

    if (CV_LAT_MISS == cvartype) {

        if (HE5_HDFE_GD_UL == eos5_origin || HE5_HDFE_GD_UR == eos5_origin) {

            start = point_upper;
            end   = point_lower;

        }
        else {// (gridorigin == HE5_HDFE_GD_LL || gridorigin == HE5_HDFE_GD_LR)

            start = point_lower;
            end = point_upper;
        }

        if(ydimsize <=0)
           throw InternalErr (__FILE__, __LINE__,
                          "The number of elments should be greater than 0.");

        float lat_step = (end - start) /ydimsize;

        // Now offset,step and val will always be valid. line 74 and 85 assure this.
        if ( HE5_HDFE_CENTER == eos5_pixelreg ) {
            for (int i = 0; i < nelms; i++)
                val[i] = ((float)(offset[0]+i*step[0] + 0.5f) * lat_step + start) / 1000000.0;
        }
        else { // HE5_HDFE_CORNER
            for (int i = 0; i < nelms; i++)
                val[i] = ((float)(offset[0]+i * step[0])*lat_step + start) / 1000000.0;
        }

    }

    if (CV_LON_MISS == cvartype) {

        if (HE5_HDFE_GD_UL == eos5_origin || HE5_HDFE_GD_LL == eos5_origin) {

            start = point_left;
            end   = point_right;

        }
        else {// (gridorigin == HE5_HDFE_GD_UR || gridorigin == HE5_HDFE_GD_LR)

            start = point_right;
            end = point_left;
        }

        if(xdimsize <=0)
           throw InternalErr (__FILE__, __LINE__,
                          "The number of elments should be greater than 0.");
        float lon_step = (end - start) /xdimsize;

        if (HE5_HDFE_CENTER == eos5_pixelreg) {
            for (int i = 0; i < nelms; i++)
                val[i] = ((float)(offset[0] + i *step[0] + 0.5f) * lon_step + start ) / 1000000.0;
        }
        else { // HE5_HDFE_CORNER
            for (int i = 0; i < nelms; i++)
                val[i] = ((float)(offset[0]+i*step[0]) * lon_step + start) / 1000000.0;
        }

    }

#if 0
for (int i =0; i <nelms; i++)
"h5","final data val "<< i <<" is " << val[i] <<endl;
#endif

    set_value ((dods_float32 *) &val[0], nelms);
    return true;
}

// parse constraint expr. and make hdf5 coordinate point location.
// return number of elements to read.
int
HDFEOS5CFMissLLArray::format_constraint (int *offset, int *step, int *count)
{
        long nels = 1;
        int id = 0;

        Dim_iter p = dim_begin ();

        while (p != dim_end ()) {

                int start = dimension_start (p, true);
                int stride = dimension_stride (p, true);
                int stop = dimension_stop (p, true);

                // Check for illegal  constraint
                if (start > stop) {
                   ostringstream oss;

                   oss << "Array/Grid hyperslab start point "<< start <<
                         " is greater than stop point " <<  stop <<".";
                   throw Error(malformed_expr, oss.str());
                }

                offset[id] = start;
                step[id] = stride;
                count[id] = ((stop - start) / stride) + 1;      // count of elements
                nels *= count[id];              // total number of values for variable

                BESDEBUG ("h5",
                         "=format_constraint():"
                         << "id=" << id << " offset=" << offset[id]
                         << " step=" << step[id]
                         << " count=" << count[id]
                         << endl);

                id++;
                p++;
        }

        return nels;
}

<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015, Google Inc.
 * 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 Google Inc. 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
 * OWNER 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 <atomic>
#include <chrono>
#include <future>  // for async()
#include <iostream>
#include <memory>
#include <random>
#include <string>

#include "helper.h"
#include "route_guide.grpc_cb.pb.h"

using grpc_cb::Channel;
using grpc_cb::ChannelSptr;
using grpc_cb::ClientAsyncReader;
using grpc_cb::ClientAsyncReaderWriter;
using grpc_cb::ClientAsyncWriter;
using grpc_cb::ClientSyncReader;
using grpc_cb::ClientSyncReaderWriter;
using grpc_cb::ClientSyncWriter;
using grpc_cb::Status;
using routeguide::Point;
using routeguide::Feature;
using routeguide::Rectangle;
using routeguide::RouteSummary;
using routeguide::RouteNote;
using routeguide::RouteGuide::Stub;

const float kCoordFactor = 10000000.0;
static unsigned seed = (unsigned)std::chrono::system_clock::now().time_since_epoch().count();
static std::default_random_engine generator(seed);

Point MakePoint(long latitude, long longitude) {
  Point p;
  p.set_latitude(latitude);
  p.set_longitude(longitude);
  return p;
}

routeguide::Rectangle MakeRect(const Point& lo, const Point& hi) {
  routeguide::Rectangle rect;
  *rect.mutable_lo() = lo;
  *rect.mutable_hi() = hi;
  return rect;
}

routeguide::Rectangle MakeRect(long lo_latitude, long lo_longitude,
                   long hi_latitude, long hi_longitude) {
  return MakeRect(MakePoint(lo_latitude, lo_longitude),
                  MakePoint(hi_latitude, hi_longitude));
}

Feature MakeFeature(const std::string& name,
                    long latitude, long longitude) {
  Feature f;
  f.set_name(name);
  f.mutable_location()->CopyFrom(MakePoint(latitude, longitude));
  return f;
}

RouteNote MakeRouteNote(const std::string& message,
                        long latitude, long longitude) {
  RouteNote n;
  n.set_message(message);
  n.mutable_location()->CopyFrom(MakePoint(latitude, longitude));
  return n;
}

void PrintFeature(const Feature& feature) {
  if (!feature.has_location()) {
    std::cout << "Server returns incomplete feature." << std::endl;
    return;
  }
  if (feature.name().empty()) {
    std::cout << "Found no feature at "
        << feature.location().latitude()/kCoordFactor << ", "
        << feature.location().longitude()/kCoordFactor << std::endl;
  }
  else {
    std::cout << "Found feature called " << feature.name()  << " at "
        << feature.location().latitude()/kCoordFactor << ", "
        << feature.location().longitude()/kCoordFactor << std::endl;
  }
}  // PrintFeature()

void PrintServerNote(const RouteNote& server_note) {
  std::cout << "Got message " << server_note.message()
            << " at " << server_note.location().latitude() << ", "
            << server_note.location().longitude() << std::endl;
}

void RandomSleep() {
  std::uniform_int_distribution<int> delay_distribution(500, 1500);
  std::this_thread::sleep_for(std::chrono::milliseconds(
      delay_distribution(generator)));
}

void RunWriteRouteNote(ClientSyncReaderWriter<RouteNote, RouteNote>
    sync_reader_writer) {
  std::vector<RouteNote> notes{
    MakeRouteNote("First message", 0, 0),
    MakeRouteNote("Second message", 0, 1),
    MakeRouteNote("Third message", 1, 0),
    MakeRouteNote("Fourth message", 0, 0)};
  for (const RouteNote& note : notes) {
    std::cout << "Sending message " << note.message()
              << " at " << note.location().latitude() << ", "
              << note.location().longitude() << std::endl;
    sync_reader_writer.Write(note);
    // RandomSleep();
  }
  sync_reader_writer.CloseWriting();
}

class RouteGuideClient {
 public:
  RouteGuideClient(std::shared_ptr<Channel> channel, const std::string& db)
      : stub_(routeguide::RouteGuide::NewStub(channel)) {
    routeguide::ParseDb(db, &feature_list_);
    assert(!feature_list_.empty());
  }

  void BlockingGetFeature() {
    Point point;
    Feature feature;
    point = MakePoint(409146138, -746188906);
    BlockingGetOneFeature(point, &feature);
    point = MakePoint(0, 0);
    BlockingGetOneFeature(point, &feature);
  }

  void BlockingListFeatures() {
    routeguide::Rectangle rect = MakeRect(
        400000000, -750000000, 420000000, -730000000);
    Feature feature;

    std::cout << "Looking for features between 40, -75 and 42, -73"
        << std::endl;

    auto reader(stub_->SyncListFeatures(rect));
    while (reader.ReadOne(&feature)) {
      std::cout << "Found feature called "
                << feature.name() << " at "
                << feature.location().latitude()/kCoordFactor << ", "
                << feature.location().longitude()/kCoordFactor << std::endl;
    }
    Status status = reader.RecvStatus();
    if (status.ok()) {
      std::cout << "ListFeatures rpc succeeded." << std::endl;
    } else {
      std::cout << "ListFeatures rpc failed." << std::endl;
    }
  }

  void BlockingRecordRoute() {
    Point point;
    const int kPoints = 10;
    std::uniform_int_distribution<int> feature_distribution(
        0, feature_list_.size() - 1);

    auto writer(stub_->SyncRecordRoute());
    for (int i = 0; i < kPoints; i++) {
      const Feature& f = feature_list_[feature_distribution(generator)];
      std::cout << "Visiting point "
                << f.location().latitude()/kCoordFactor << ", "
                << f.location().longitude()/kCoordFactor << std::endl;
      if (!writer.Write(f.location())) {
        // Broken stream.
        break;
      }
      RandomSleep();
    }
    RouteSummary stats;
    // Recv reponse and status.
    Status status = writer.Close(&stats);  // Todo: timeout
    if (status.ok()) {
      std::cout << "Finished trip with " << stats.point_count() << " points\n"
                << "Passed " << stats.feature_count() << " features\n"
                << "Traveled " << stats.distance() << " meters\n"
                << "It took " << stats.elapsed_time() << " seconds"
                << std::endl;
    } else {
      std::cout << "RecordRoute rpc failed." << std::endl;
    }
  }

  // Todo: Callback on client stream response and status.

  void BlockingRouteChat() {
    ClientSyncReaderWriter<RouteNote, RouteNote> sync_reader_writer(
        stub_->SyncRouteChat());

    auto f = std::async(std::launch::async, [sync_reader_writer]() {
        RunWriteRouteNote(sync_reader_writer);
    });

    RouteNote server_note;
    while (sync_reader_writer.ReadOne(&server_note))
        PrintServerNote(server_note);

    f.wait();
    // Todo: Close() should auto close writing.
    Status status = sync_reader_writer.RecvStatus();
    if (!status.ok()) {
      std::cout << "RouteChat rpc failed." << std::endl;
    }
  }

 private:
  bool BlockingGetOneFeature(const Point& point, Feature* feature) {
    Status status = stub_->BlockingGetFeature(point, feature);
    if (!status.ok()) {
      std::cout << "GetFeature rpc failed." << std::endl;
      return false;
    }
    PrintFeature(*feature);
    return feature->has_location();
  }

  std::unique_ptr<Stub> stub_;
  std::vector<Feature> feature_list_;
};

void GetFeatureAsync(const ChannelSptr& channel) {
  Stub stub(channel);

  // Ignore error status.
  stub.AsyncGetFeature(MakePoint(0, 0),
                       [](const Feature& feature) { PrintFeature(feature); });

  // Ignore response.
  stub.AsyncGetFeature(MakePoint(0, 0));

  Point point1 = MakePoint(409146138, -746188906);
  stub.AsyncGetFeature(point1,
      [&stub](const Feature& feature) {
        PrintFeature(feature);
        stub.Shutdown();
      },
      [&stub](const Status& err) {
        std::cout << "AsyncGetFeature rpc failed. "
            << err.GetDetails() << std::endl;
        stub.Shutdown();
      });  // AsyncGetFeature()
  stub.BlockingRun();  // until stub.Shutdown()
}

void ListFeaturesAsync(const ChannelSptr& channel) {
  Stub stub(channel);
  routeguide::Rectangle rect = MakeRect(
      400000000, -750000000, 420000000, -730000000);
  std::cout << "Looking for features between 40, -75 and 42, -73" << std::endl;

  stub.AsyncListFeatures(rect,
    [](const Feature& feature){
      std::cout << "Got feature " << feature.name() << " at "
          << feature.location().latitude()/kCoordFactor << ", "
          << feature.location().longitude()/kCoordFactor << std::endl;
    },
    [&stub](const Status& status){
      std::cout << "End status: (" << status.GetCode() << ") "
          << status.GetDetails() << std::endl;
      stub.Shutdown();  // To break BlockingRun().
    });
  stub.BlockingRun();  // until stub.Shutdown()
}

void RecordRouteAsync(const ChannelSptr& channel,
                      const std::string& db) {
  assert(!db.empty());
  std::vector<Feature> feature_list;
  routeguide::ParseDb(db, &feature_list);
  assert(!feature_list.empty());

  Point point;
  const int kPoints = 10;
  std::uniform_int_distribution<int> feature_distribution(
      0, feature_list.size() - 1);

  Stub stub(channel);
  auto f = std::async(std::launch::async, [&stub]() { stub.BlockingRun(); });

  // ClientAsyncWriter<Point, RouteSummary> writer;
  auto writer = stub.AsyncRecordRoute();
  for (int i = 0; i < kPoints; i++) {
    const Feature& f = feature_list[feature_distribution(generator)];
    std::cout << "Visiting point "
              << f.location().latitude()/kCoordFactor << ", "
              << f.location().longitude()/kCoordFactor << std::endl;
    if (!writer.Write(f.location())) {
      // Broken stream.
      break;
    }
    RandomSleep();
  }
  // Recv reponse and status.
  writer.Close([](const Status& status, const RouteSummary& resp) {
    if (!status.ok()) {
      std::cout << "RecordRoute rpc failed." << std::endl;
      return;
    }
    std::cout << "Finished trip with " << resp.point_count() << " points\n"
              << "Passed " << resp.feature_count() << " features\n"
              << "Traveled " << resp.distance() << " meters\n"
              << "It took " << resp.elapsed_time() << " seconds" << std::endl;
  });

  // Todo: timeout

  stub.Shutdown();
}  // RecordRouteAsync()

void AsyncWriteRouteNotes(ClientAsyncReaderWriter<RouteNote, RouteNote>
    async_reader_writer) {
  std::vector<RouteNote> notes{
    MakeRouteNote("First message", 0, 0),
    MakeRouteNote("Second message", 0, 1),
    MakeRouteNote("Third message", 1, 0),
    MakeRouteNote("Fourth message", 0, 0)};
  for (const RouteNote& note : notes) {
    std::cout << "Sending message " << note.message()
              << " at " << note.location().latitude() << ", "
              << note.location().longitude() << std::endl;
    async_reader_writer.Write(note);
    // RandomSleep();
  }
  async_reader_writer.CloseWriting();  // Optional.
}

void RouteChatAsync(const ChannelSptr& channel) {
  Stub stub(channel);
  std::atomic_bool bReaderDone = false;
  ClientAsyncReaderWriter<RouteNote, RouteNote> async_reader_writer(
      stub.AsyncRouteChat([&bReaderDone](const Status& status) {
        if (!status.ok()) {
          std::cout << "RouteChat rpc failed. " << status.GetDetails()
                    << std::endl;
        }
        bReaderDone = true;
      }));

  async_reader_writer.ReadEach(
      [](const RouteNote& note) { PrintServerNote(note); });

  AsyncWriteRouteNotes(async_reader_writer);
  auto f = std::async(std::launch::async, [&stub]() {
    stub.BlockingRun();
  });

  while (!bReaderDone)
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  stub.Shutdown();  // To break BlockingRun().
}  // RouteChatAsync()

int main(int argc, char** argv) {
  // Expect only arg: --db_path=path/to/route_guide_db.json.
  std::string db = routeguide::GetDbFileContent(argc, argv);
  assert(!db.empty());
  ChannelSptr channel(new Channel("localhost:50051"));
  RouteGuideClient guide(channel, db);

  std::cout << "---- BlockingGetFeature --------------" << std::endl;
  guide.BlockingGetFeature();
  std::cout << "---- BlockingListFeatures --------------" << std::endl;
  guide.BlockingListFeatures();
  std::cout << "---- BlockingRecordRoute --------------" << std::endl;
  guide.BlockingRecordRoute();
  std::cout << "---- BlockingRouteChat --------------" << std::endl;
  guide.BlockingRouteChat();

  std::cout << "---- GetFeatureAsync ----" << std::endl;
  GetFeatureAsync(channel);
  std::cout << "---- ListFeaturesAsync ----" << std::endl;
  ListFeaturesAsync(channel);
  std::cout << "---- RecordRouteAsnyc ----" << std::endl;
  RecordRouteAsync(channel, db);
  std::cout << "---- RouteChatAsync ---" << std::endl;
  RouteChatAsync(channel);

  return 0;
}
<commit_msg>Use Stub internal types.<commit_after>/*
 *
 * Copyright 2015, Google Inc.
 * 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 Google Inc. 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
 * OWNER 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 <atomic>
#include <chrono>
#include <future>  // for async()
#include <iostream>
#include <memory>
#include <random>
#include <string>

#include "helper.h"
#include "route_guide.grpc_cb.pb.h"

using grpc_cb::Channel;
using grpc_cb::ChannelSptr;
using grpc_cb::Status;
using routeguide::Point;
using routeguide::Feature;
using routeguide::Rectangle;
using routeguide::RouteSummary;
using routeguide::RouteNote;
using routeguide::RouteGuide::Stub;

const float kCoordFactor = 10000000.0;
static unsigned seed = (unsigned)std::chrono::system_clock::now().time_since_epoch().count();
static std::default_random_engine generator(seed);

Point MakePoint(long latitude, long longitude) {
  Point p;
  p.set_latitude(latitude);
  p.set_longitude(longitude);
  return p;
}

routeguide::Rectangle MakeRect(const Point& lo, const Point& hi) {
  routeguide::Rectangle rect;
  *rect.mutable_lo() = lo;
  *rect.mutable_hi() = hi;
  return rect;
}

routeguide::Rectangle MakeRect(long lo_latitude, long lo_longitude,
                   long hi_latitude, long hi_longitude) {
  return MakeRect(MakePoint(lo_latitude, lo_longitude),
                  MakePoint(hi_latitude, hi_longitude));
}

Feature MakeFeature(const std::string& name,
                    long latitude, long longitude) {
  Feature f;
  f.set_name(name);
  f.mutable_location()->CopyFrom(MakePoint(latitude, longitude));
  return f;
}

RouteNote MakeRouteNote(const std::string& message,
                        long latitude, long longitude) {
  RouteNote n;
  n.set_message(message);
  n.mutable_location()->CopyFrom(MakePoint(latitude, longitude));
  return n;
}

void PrintFeature(const Feature& feature) {
  if (!feature.has_location()) {
    std::cout << "Server returns incomplete feature." << std::endl;
    return;
  }
  if (feature.name().empty()) {
    std::cout << "Found no feature at "
        << feature.location().latitude()/kCoordFactor << ", "
        << feature.location().longitude()/kCoordFactor << std::endl;
  }
  else {
    std::cout << "Found feature called " << feature.name()  << " at "
        << feature.location().latitude()/kCoordFactor << ", "
        << feature.location().longitude()/kCoordFactor << std::endl;
  }
}  // PrintFeature()

void PrintServerNote(const RouteNote& server_note) {
  std::cout << "Got message " << server_note.message()
            << " at " << server_note.location().latitude() << ", "
            << server_note.location().longitude() << std::endl;
}

void RandomSleep() {
  std::uniform_int_distribution<int> delay_distribution(500, 1500);
  std::this_thread::sleep_for(std::chrono::milliseconds(
      delay_distribution(generator)));
}

void RunWriteRouteNote(Stub::RouteChat_SyncReaderWriter sync_reader_writer) {
  std::vector<RouteNote> notes{
    MakeRouteNote("First message", 0, 0),
    MakeRouteNote("Second message", 0, 1),
    MakeRouteNote("Third message", 1, 0),
    MakeRouteNote("Fourth message", 0, 0)};
  for (const RouteNote& note : notes) {
    std::cout << "Sending message " << note.message()
              << " at " << note.location().latitude() << ", "
              << note.location().longitude() << std::endl;
    sync_reader_writer.Write(note);
    // RandomSleep();
  }
  sync_reader_writer.CloseWriting();
}

class RouteGuideClient {
 public:
  RouteGuideClient(std::shared_ptr<Channel> channel, const std::string& db)
      : stub_(routeguide::RouteGuide::NewStub(channel)) {
    routeguide::ParseDb(db, &feature_list_);
    assert(!feature_list_.empty());
  }

  void BlockingGetFeature() {
    Point point;
    Feature feature;
    point = MakePoint(409146138, -746188906);
    BlockingGetOneFeature(point, &feature);
    point = MakePoint(0, 0);
    BlockingGetOneFeature(point, &feature);
  }

  void BlockingListFeatures() {
    routeguide::Rectangle rect = MakeRect(
        400000000, -750000000, 420000000, -730000000);
    Feature feature;

    std::cout << "Looking for features between 40, -75 and 42, -73"
        << std::endl;

    auto reader(stub_->SyncListFeatures(rect));
    while (reader.ReadOne(&feature)) {
      std::cout << "Found feature called "
                << feature.name() << " at "
                << feature.location().latitude()/kCoordFactor << ", "
                << feature.location().longitude()/kCoordFactor << std::endl;
    }
    Status status = reader.RecvStatus();
    if (status.ok()) {
      std::cout << "ListFeatures rpc succeeded." << std::endl;
    } else {
      std::cout << "ListFeatures rpc failed." << std::endl;
    }
  }

  void BlockingRecordRoute() {
    Point point;
    const int kPoints = 10;
    std::uniform_int_distribution<int> feature_distribution(
        0, feature_list_.size() - 1);

    auto writer(stub_->SyncRecordRoute());
    for (int i = 0; i < kPoints; i++) {
      const Feature& f = feature_list_[feature_distribution(generator)];
      std::cout << "Visiting point "
                << f.location().latitude()/kCoordFactor << ", "
                << f.location().longitude()/kCoordFactor << std::endl;
      if (!writer.Write(f.location())) {
        // Broken stream.
        break;
      }
      RandomSleep();
    }
    RouteSummary stats;
    // Recv reponse and status.
    Status status = writer.Close(&stats);  // Todo: timeout
    if (status.ok()) {
      std::cout << "Finished trip with " << stats.point_count() << " points\n"
                << "Passed " << stats.feature_count() << " features\n"
                << "Traveled " << stats.distance() << " meters\n"
                << "It took " << stats.elapsed_time() << " seconds"
                << std::endl;
    } else {
      std::cout << "RecordRoute rpc failed." << std::endl;
    }
  }

  // Todo: Callback on client stream response and status.

  void BlockingRouteChat() {
    auto sync_reader_writer(stub_->SyncRouteChat());
    auto f = std::async(std::launch::async, [sync_reader_writer]() {
        RunWriteRouteNote(sync_reader_writer);
    });

    RouteNote server_note;
    while (sync_reader_writer.ReadOne(&server_note))
        PrintServerNote(server_note);

    f.wait();
    // Todo: Close() should auto close writing.
    Status status = sync_reader_writer.RecvStatus();
    if (!status.ok()) {
      std::cout << "RouteChat rpc failed." << std::endl;
    }
  }

 private:
  bool BlockingGetOneFeature(const Point& point, Feature* feature) {
    Status status = stub_->BlockingGetFeature(point, feature);
    if (!status.ok()) {
      std::cout << "GetFeature rpc failed." << std::endl;
      return false;
    }
    PrintFeature(*feature);
    return feature->has_location();
  }

  std::unique_ptr<Stub> stub_;
  std::vector<Feature> feature_list_;
};

void GetFeatureAsync(const ChannelSptr& channel) {
  Stub stub(channel);

  // Ignore error status.
  stub.AsyncGetFeature(MakePoint(0, 0),
                       [](const Feature& feature) { PrintFeature(feature); });

  // Ignore response.
  stub.AsyncGetFeature(MakePoint(0, 0));

  Point point1 = MakePoint(409146138, -746188906);
  stub.AsyncGetFeature(point1,
      [&stub](const Feature& feature) {
        PrintFeature(feature);
        stub.Shutdown();
      },
      [&stub](const Status& err) {
        std::cout << "AsyncGetFeature rpc failed. "
            << err.GetDetails() << std::endl;
        stub.Shutdown();
      });  // AsyncGetFeature()
  stub.BlockingRun();  // until stub.Shutdown()
}

void ListFeaturesAsync(const ChannelSptr& channel) {
  Stub stub(channel);
  routeguide::Rectangle rect = MakeRect(
      400000000, -750000000, 420000000, -730000000);
  std::cout << "Looking for features between 40, -75 and 42, -73" << std::endl;

  stub.AsyncListFeatures(rect,
    [](const Feature& feature){
      std::cout << "Got feature " << feature.name() << " at "
          << feature.location().latitude()/kCoordFactor << ", "
          << feature.location().longitude()/kCoordFactor << std::endl;
    },
    [&stub](const Status& status){
      std::cout << "End status: (" << status.GetCode() << ") "
          << status.GetDetails() << std::endl;
      stub.Shutdown();  // To break BlockingRun().
    });
  stub.BlockingRun();  // until stub.Shutdown()
}

void RecordRouteAsync(const ChannelSptr& channel,
                      const std::string& db) {
  assert(!db.empty());
  std::vector<Feature> feature_list;
  routeguide::ParseDb(db, &feature_list);
  assert(!feature_list.empty());

  Point point;
  const int kPoints = 10;
  std::uniform_int_distribution<int> feature_distribution(
      0, feature_list.size() - 1);

  Stub stub(channel);
  auto f = std::async(std::launch::async, [&stub]() { stub.BlockingRun(); });

  // ClientAsyncWriter<Point, RouteSummary> writer;
  auto writer = stub.AsyncRecordRoute();
  for (int i = 0; i < kPoints; i++) {
    const Feature& f = feature_list[feature_distribution(generator)];
    std::cout << "Visiting point "
              << f.location().latitude()/kCoordFactor << ", "
              << f.location().longitude()/kCoordFactor << std::endl;
    if (!writer.Write(f.location())) {
      // Broken stream.
      break;
    }
    RandomSleep();
  }
  // Recv reponse and status.
  writer.Close([](const Status& status, const RouteSummary& resp) {
    if (!status.ok()) {
      std::cout << "RecordRoute rpc failed." << std::endl;
      return;
    }
    std::cout << "Finished trip with " << resp.point_count() << " points\n"
              << "Passed " << resp.feature_count() << " features\n"
              << "Traveled " << resp.distance() << " meters\n"
              << "It took " << resp.elapsed_time() << " seconds" << std::endl;
  });

  // Todo: timeout

  stub.Shutdown();
}  // RecordRouteAsync()

void AsyncWriteRouteNotes(Stub::RouteChat_AsyncReaderWriter async_reader_writer) {
  std::vector<RouteNote> notes{
    MakeRouteNote("First message", 0, 0),
    MakeRouteNote("Second message", 0, 1),
    MakeRouteNote("Third message", 1, 0),
    MakeRouteNote("Fourth message", 0, 0)};
  for (const RouteNote& note : notes) {
    std::cout << "Sending message " << note.message()
              << " at " << note.location().latitude() << ", "
              << note.location().longitude() << std::endl;
    async_reader_writer.Write(note);
    // RandomSleep();
  }
  async_reader_writer.CloseWriting();  // Optional.
}

void RouteChatAsync(const ChannelSptr& channel) {
  Stub stub(channel);
  std::atomic_bool bReaderDone = false;
  auto async_reader_writer(
      stub.AsyncRouteChat([&bReaderDone](const Status& status) {
        if (!status.ok()) {
          std::cout << "RouteChat rpc failed. " << status.GetDetails()
                    << std::endl;
        }
        bReaderDone = true;
      }));

  async_reader_writer.ReadEach(
      [](const RouteNote& note) { PrintServerNote(note); });

  AsyncWriteRouteNotes(async_reader_writer);
  auto f = std::async(std::launch::async, [&stub]() {
    stub.BlockingRun();
  });

  while (!bReaderDone)
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  stub.Shutdown();  // To break BlockingRun().
}  // RouteChatAsync()

int main(int argc, char** argv) {
  // Expect only arg: --db_path=path/to/route_guide_db.json.
  std::string db = routeguide::GetDbFileContent(argc, argv);
  assert(!db.empty());
  ChannelSptr channel(new Channel("localhost:50051"));
  RouteGuideClient guide(channel, db);

  std::cout << "---- BlockingGetFeature --------------" << std::endl;
  guide.BlockingGetFeature();
  std::cout << "---- BlockingListFeatures --------------" << std::endl;
  guide.BlockingListFeatures();
  std::cout << "---- BlockingRecordRoute --------------" << std::endl;
  guide.BlockingRecordRoute();
  std::cout << "---- BlockingRouteChat --------------" << std::endl;
  guide.BlockingRouteChat();

  std::cout << "---- GetFeatureAsync ----" << std::endl;
  GetFeatureAsync(channel);
  std::cout << "---- ListFeaturesAsync ----" << std::endl;
  ListFeaturesAsync(channel);
  std::cout << "---- RecordRouteAsnyc ----" << std::endl;
  RecordRouteAsync(channel, db);
  std::cout << "---- RouteChatAsync ---" << std::endl;
  RouteChatAsync(channel);

  return 0;
}
<|endoftext|>