<commit_before>/*!
	@file
	@author		Albert Semenov
	@date		08/2010
*/
#include "precompiled.h"
#include "SkinListControl.h"
#include "SkinManager.h"
#include "ActionManager.h"
#include <limits>

namespace tools
{

	SkinListControl::SkinListControl(MyGUI::Widget* _parent) :
		wraps::BaseLayout("SkinListControl.layout", _parent),
		mList(nullptr),
		mCreate(nullptr),
		mRename(nullptr),
		mDelete(nullptr),
		mTextFieldControl(nullptr)
	{
		assignWidget(mList, "List");
		assignWidget(mCreate, "Create");
		assignWidget(mRename, "Rename");
		assignWidget(mDelete, "Delete");

		mList->eventListChangePosition += MyGUI::newDelegate(this, &SkinListControl::notifyChangePosition);
		mCreate->eventMouseButtonClick += MyGUI::newDelegate(this, &SkinListControl::notifyCreate);
		mRename->eventMouseButtonClick += MyGUI::newDelegate(this, &SkinListControl::notifyRename);
		mDelete->eventMouseButtonClick += MyGUI::newDelegate(this, &SkinListControl::notifyDelete);

		SkinManager::getInstance().eventChangeList += MyGUI::newDelegate(this, &SkinListControl::notifyChangeList);
	}

	SkinListControl::~SkinListControl()
	{
		SkinManager::getInstance().eventChangeList -= MyGUI::newDelegate(this, &SkinListControl::notifyChangeList);

		hideTextField();

		mCreate->eventMouseButtonClick -= MyGUI::newDelegate(this, &SkinListControl::notifyCreate);
		mRename->eventMouseButtonClick -= MyGUI::newDelegate(this, &SkinListControl::notifyRename);
		mDelete->eventMouseButtonClick -= MyGUI::newDelegate(this, &SkinListControl::notifyDelete);
		mList->eventListChangePosition -= MyGUI::newDelegate(this, &SkinListControl::notifyChangePosition);
	}

	void SkinListControl::notifyChangePosition(MyGUI::List* _sender, size_t _index)
	{
		SkinItem* item = nullptr;

		if (_index != MyGUI::ITEM_NONE)
			item = *mList->getItemDataAt<SkinItem*>(_index);

		SkinManager::getInstance().setItemSelected(item);
	}

	void SkinListControl::notifyCreate(MyGUI::Widget* _sender)
	{
		//showTextField(nullptr);
		createItem(getNextFreeName());
	}

	void SkinListControl::notifyRename(MyGUI::Widget* _sender)
	{
		SkinItem* item = SkinManager::getInstance().getItemSelected();
		if (item != nullptr)
			showTextField(item);
	}

	void SkinListControl::notifyDelete(MyGUI::Widget* _sender)
	{
		SkinItem* item = SkinManager::getInstance().getItemSelected();
		if (item != nullptr)
		{
			MyGUI::Message* message = MyGUI::Message::createMessageBox(
				"Message",
				L"Внимание",
				L"Вы уверены?",
				MyGUI::MessageBoxStyle::IconQuest | MyGUI::MessageBoxStyle::Yes | MyGUI::MessageBoxStyle::No);
			message->eventMessageBoxResult += MyGUI::newDelegate(this, &SkinListControl::notifyDeleteMessageBoxResult);
		}
	}

	void SkinListControl::notifyDeleteMessageBoxResult(MyGUI::Message* _sender, MyGUI::MessageBoxStyle _style)
	{
		if (_style == MyGUI::MessageBoxStyle::Yes)
		{
			SkinItem* item = SkinManager::getInstance().getItemSelected();

			// выделяем следующий за удаляемым
			SkinItem* prev = nullptr;
			SkinItem* next = nullptr;

			ItemHolder<SkinItem>::EnumeratorItem items = SkinManager::getInstance().getChildsEnumerator();
			while (items.next())
			{
				SkinItem* current = items.current();
				if (current == item)
				{
					if (items.next())
						next = items.current();
					break;
				}
				prev = current;
			}

			if (next != nullptr)
				SkinManager::getInstance().setItemSelected(next);
			else if (prev != nullptr)
				SkinManager::getInstance().setItemSelected(prev);

			SkinManager::getInstance().destroyChild(item);

			updateList();

			ActionManager::getInstance().setChanges(true);
		}
	}

	void SkinListControl::updateList()
	{
		mList->setIndexSelected(MyGUI::ITEM_NONE);
		mList->removeAllItems();

		SkinItem* selectedItem = SkinManager::getInstance().getItemSelected();

		ItemHolder<SkinItem>::EnumeratorItem items = SkinManager::getInstance().getChildsEnumerator();
		while (items.next())
		{
			size_t index = mList->getItemCount();

			SkinItem* item = items.current();

			size_t count = getNameCount(item->getName());
			if (count == 1)
				mList->addItem(item->getName());
			else
				mList->addItem("#FF0000" + item->getName());

			mList->setItemDataAt(index, item);
			if (item == selectedItem)
				mList->setIndexSelected(index);
		}
	}

	void SkinListControl::hideTextField()
	{
		if (mTextFieldControl != nullptr)
		{
			mTextFieldControl->hide();

			mTextFieldControl->eventResult = nullptr;

			delete mTextFieldControl;
			mTextFieldControl = nullptr;
		}
	}

	void SkinListControl::showTextField(SkinItem* _item)
	{
		hideTextField();

		mTextFieldControl = new TextFieldControl();
		mTextFieldControl->setCaption(_item == nullptr ? "Create" : "Rename");
		mTextFieldControl->setTextField(_item == nullptr ? getNextFreeName() : _item->getName());
		mTextFieldControl->setUserData(_item);
		mTextFieldControl->show();

		mTextFieldControl->eventResult = MyGUI::newDelegate(this, &SkinListControl::notifyTextFieldResult);
	}

	MyGUI::UString SkinListControl::getNextFreeName()
	{
		MyGUI::UString pattern = "SkinName";

		for (size_t index=0; index<std::numeric_limits<size_t>::max(); index++)
		{
			MyGUI::UString name = MyGUI::utility::toString(pattern, index);
			if (!isNameExist(name))
				return name;
		}

		return "";
	}

	bool SkinListControl::isNameExist(const MyGUI::UString& _value)
	{
		ItemHolder<SkinItem>::EnumeratorItem items = SkinManager::getInstance().getChildsEnumerator();
		while (items.next())
		{
			SkinItem* item = items.current();
			if (item->getName() == _value)
				return true;
		}
		return false;
	}

	size_t SkinListControl::getNameCount(const MyGUI::UString& _value)
	{
		size_t result = 0;
		ItemHolder<SkinItem>::EnumeratorItem items = SkinManager::getInstance().getChildsEnumerator();
		while (items.next())
		{
			SkinItem* item = items.current();
			if (item->getName() == _value)
				++result;
		}
		return result;
	}

	void SkinListControl::notifyTextFieldResult(bool _result)
	{
		if (_result)
		{
			SkinItem* item = *mTextFieldControl->getUserData<SkinItem*>();
			if (item != nullptr)
				renameItem(item, mTextFieldControl->getTextField());
			else
				createItem(mTextFieldControl->getTextField());
		}

		hideTextField();
	}

	void SkinListControl::renameItem(SkinItem* _item, const MyGUI::UString& _value)
	{
		_item->setName(_value);
		updateList();

		ActionManager::getInstance().setChanges(true);
	}

	void SkinListControl::createItem(const MyGUI::UString& _value)
	{
		SkinItem* item = SkinManager::getInstance().createChild();
		item->setName(_value);
		SkinManager::getInstance().setItemSelected(item);

		updateList();

		ActionManager::getInstance().setChanges(true);
	}

	void SkinListControl::notifyChangeList()
	{
		updateList();
	}

} // namespace tools
<commit_msg>SE: convert to anci<commit_after>/*!
	@file
	@author		Albert Semenov
	@date		08/2010
*/
#include "precompiled.h"
#include "SkinListControl.h"
#include "SkinManager.h"
#include "ActionManager.h"
#include <limits>

namespace tools
{

	SkinListControl::SkinListControl(MyGUI::Widget* _parent) :
		wraps::BaseLayout("SkinListControl.layout", _parent),
		mList(nullptr),
		mCreate(nullptr),
		mRename(nullptr),
		mDelete(nullptr),
		mTextFieldControl(nullptr)
	{
		assignWidget(mList, "List");
		assignWidget(mCreate, "Create");
		assignWidget(mRename, "Rename");
		assignWidget(mDelete, "Delete");

		mList->eventListChangePosition += MyGUI::newDelegate(this, &SkinListControl::notifyChangePosition);
		mCreate->eventMouseButtonClick += MyGUI::newDelegate(this, &SkinListControl::notifyCreate);
		mRename->eventMouseButtonClick += MyGUI::newDelegate(this, &SkinListControl::notifyRename);
		mDelete->eventMouseButtonClick += MyGUI::newDelegate(this, &SkinListControl::notifyDelete);

		SkinManager::getInstance().eventChangeList += MyGUI::newDelegate(this, &SkinListControl::notifyChangeList);
	}

	SkinListControl::~SkinListControl()
	{
		SkinManager::getInstance().eventChangeList -= MyGUI::newDelegate(this, &SkinListControl::notifyChangeList);

		hideTextField();

		mCreate->eventMouseButtonClick -= MyGUI::newDelegate(this, &SkinListControl::notifyCreate);
		mRename->eventMouseButtonClick -= MyGUI::newDelegate(this, &SkinListControl::notifyRename);
		mDelete->eventMouseButtonClick -= MyGUI::newDelegate(this, &SkinListControl::notifyDelete);
		mList->eventListChangePosition -= MyGUI::newDelegate(this, &SkinListControl::notifyChangePosition);
	}

	void SkinListControl::notifyChangePosition(MyGUI::List* _sender, size_t _index)
	{
		SkinItem* item = nullptr;

		if (_index != MyGUI::ITEM_NONE)
			item = *mList->getItemDataAt<SkinItem*>(_index);

		SkinManager::getInstance().setItemSelected(item);
	}

	void SkinListControl::notifyCreate(MyGUI::Widget* _sender)
	{
		//showTextField(nullptr);
		createItem(getNextFreeName());
	}

	void SkinListControl::notifyRename(MyGUI::Widget* _sender)
	{
		SkinItem* item = SkinManager::getInstance().getItemSelected();
		if (item != nullptr)
			showTextField(item);
	}

	void SkinListControl::notifyDelete(MyGUI::Widget* _sender)
	{
		SkinItem* item = SkinManager::getInstance().getItemSelected();
		if (item != nullptr)
		{
			MyGUI::Message* message = MyGUI::Message::createMessageBox(
				"Message",
				L"",
				L" ?",
				MyGUI::MessageBoxStyle::IconQuest | MyGUI::MessageBoxStyle::Yes | MyGUI::MessageBoxStyle::No);
			message->eventMessageBoxResult += MyGUI::newDelegate(this, &SkinListControl::notifyDeleteMessageBoxResult);
		}
	}

	void SkinListControl::notifyDeleteMessageBoxResult(MyGUI::Message* _sender, MyGUI::MessageBoxStyle _style)
	{
		if (_style == MyGUI::MessageBoxStyle::Yes)
		{
			SkinItem* item = SkinManager::getInstance().getItemSelected();

			//
			SkinItem* prev = nullptr;
			SkinItem* next = nullptr;

			ItemHolder<SkinItem>::EnumeratorItem items = SkinManager::getInstance().getChildsEnumerator();
			while (items.next())
			{
				SkinItem* current = items.current();
				if (current == item)
				{
					if (items.next())
						next = items.current();
					break;
				}
				prev = current;
			}

			if (next != nullptr)
				SkinManager::getInstance().setItemSelected(next);
			else if (prev != nullptr)
				SkinManager::getInstance().setItemSelected(prev);

			SkinManager::getInstance().destroyChild(item);

			updateList();

			ActionManager::getInstance().setChanges(true);
		}
	}

	void SkinListControl::updateList()
	{
		mList->setIndexSelected(MyGUI::ITEM_NONE);
		mList->removeAllItems();

		SkinItem* selectedItem = SkinManager::getInstance().getItemSelected();

		ItemHolder<SkinItem>::EnumeratorItem items = SkinManager::getInstance().getChildsEnumerator();
		while (items.next())
		{
			size_t index = mList->getItemCount();

			SkinItem* item = items.current();

			size_t count = getNameCount(item->getName());
			if (count == 1)
				mList->addItem(item->getName());
			else
				mList->addItem("#FF0000" + item->getName());

			mList->setItemDataAt(index, item);
			if (item == selectedItem)
				mList->setIndexSelected(index);
		}
	}

	void SkinListControl::hideTextField()
	{
		if (mTextFieldControl != nullptr)
		{
			mTextFieldControl->hide();

			mTextFieldControl->eventResult = nullptr;

			delete mTextFieldControl;
			mTextFieldControl = nullptr;
		}
	}

	void SkinListControl::showTextField(SkinItem* _item)
	{
		hideTextField();

		mTextFieldControl = new TextFieldControl();
		mTextFieldControl->setCaption(_item == nullptr ? "Create" : "Rename");
		mTextFieldControl->setTextField(_item == nullptr ? getNextFreeName() : _item->getName());
		mTextFieldControl->setUserData(_item);
		mTextFieldControl->show();

		mTextFieldControl->eventResult = MyGUI::newDelegate(this, &SkinListControl::notifyTextFieldResult);
	}

	MyGUI::UString SkinListControl::getNextFreeName()
	{
		MyGUI::UString pattern = "SkinName";

		for (size_t index=0; index<std::numeric_limits<size_t>::max(); index++)
		{
			MyGUI::UString name = MyGUI::utility::toString(pattern, index);
			if (!isNameExist(name))
				return name;
		}

		return "";
	}

	bool SkinListControl::isNameExist(const MyGUI::UString& _value)
	{
		ItemHolder<SkinItem>::EnumeratorItem items = SkinManager::getInstance().getChildsEnumerator();
		while (items.next())
		{
			SkinItem* item = items.current();
			if (item->getName() == _value)
				return true;
		}
		return false;
	}

	size_t SkinListControl::getNameCount(const MyGUI::UString& _value)
	{
		size_t result = 0;
		ItemHolder<SkinItem>::EnumeratorItem items = SkinManager::getInstance().getChildsEnumerator();
		while (items.next())
		{
			SkinItem* item = items.current();
			if (item->getName() == _value)
				++result;
		}
		return result;
	}

	void SkinListControl::notifyTextFieldResult(bool _result)
	{
		if (_result)
		{
			SkinItem* item = *mTextFieldControl->getUserData<SkinItem*>();
			if (item != nullptr)
				renameItem(item, mTextFieldControl->getTextField());
			else
				createItem(mTextFieldControl->getTextField());
		}

		hideTextField();
	}

	void SkinListControl::renameItem(SkinItem* _item, const MyGUI::UString& _value)
	{
		_item->setName(_value);
		updateList();

		ActionManager::getInstance().setChanges(true);
	}

	void SkinListControl::createItem(const MyGUI::UString& _value)
	{
		SkinItem* item = SkinManager::getInstance().createChild();
		item->setName(_value);
		SkinManager::getInstance().setItemSelected(item);

		updateList();

		ActionManager::getInstance().setChanges(true);
	}

	void SkinListControl::notifyChangeList()
	{
		updateList();
	}

} // namespace tools
<|endoftext|>


<commit_before>/*
 * PrimeSieveProcess.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@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 3 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, see <http://www.gnu.org/licenses/>
 */

#include "PrimeSieveProcess.h"

#include <QStringList>
#include <QCoreApplication>
#include <stdexcept>
#if defined(Q_OS_WIN)
#  include <windows.h>
#else
#  include <unistd.h>
#endif

PrimeSieveProcess::PrimeSieveProcess(QObject* parent = 0) :
  QProcess(parent) {
  sharedMemory_.setParent(parent);
  sharedMemory_.setKey(QString::number(this->getProcessId()));
}

PrimeSieveProcess::~PrimeSieveProcess() {
  // disconnect all signals, must be used to avoid zombie processes
  this->disconnect();
  // kill() and terminate() = trouble, close() works fine
  this->close();
  sharedMemory_.detach();
}

/**
 * Get the process ID of the current process. I tried to use
 * QProcess::pid() but got a lot of trouble on Windows and Mac OS X,
 * also it is not portable.
 */
int PrimeSieveProcess::getProcessId() {
#if defined(Q_OS_WIN)
  return static_cast<int> (GetCurrentProcessId());
#else
  return static_cast<int> (getpid());
#endif
}

/**
 * Create a shared memory segement for communication with the
 * ParallelPrimeSieve process.
 */
void PrimeSieveProcess::createSharedMemory() {
  // attach the shared memory
  if (!sharedMemory_.isAttached() &&
      !sharedMemory_.create(sizeof(shm_))) {
    throw std::runtime_error(
        "Interprocess communication error, could not allocate shared memory.");
  }
  // map the attached shared memory to the shm_ segment
  shm_ = static_cast<ParallelPrimeSieve::SharedMemory*> (sharedMemory_.data());
}

/**
 * Start a new ParallelPrimeSieve process that sieves the
 * prime numbers and/or k-tuplets between startNumber and stopNumber.
 */
void PrimeSieveProcess::start(qulonglong startNumber, qulonglong stopNumber,
    int sieveSize, int flags, int threads) {
  this->createSharedMemory();
  // initialize the shared memory segment
  shm_->startNumber = startNumber;
  shm_->stopNumber  = stopNumber;
  shm_->sieveSize   = sieveSize;
  shm_->flags       = flags;
  shm_->threads     = threads;
  for (int i = 0; i < COUNTS_SIZE; i++)
    shm_->counts[i] = 0;
  shm_->status      = 0.0;
  shm_->timeElapsed = 0.0;
  // path + file name of the aplication
  QString path = QCoreApplication::applicationFilePath();
  // process arguments, see main.cpp
  QStringList args;
  args << "PrimeSieveProcess" << sharedMemory_.key();
  /// start a new ParallelPrimeSieve process
  /// @see main.cpp
  QProcess::start(path, args, QIODevice::ReadOnly);
}

bool PrimeSieveProcess::isFinished() {
  return (shm_->status == 100.0);
}

/**
 * @return The count of prime numbers or prime k-tuplets between
 *         startNumber and stopNumber.
 * @param  index 0 = Count of prime numbers
 *               1 = Count of twin primes
 *               2 = Count of prime triplets
 *               3 = Count of prime quadruplets
 *               4 = Count of prime quintuplets
 *               5 = Count of prime sextuplets
 *               6 = Count of prime septuplets
 */
qlonglong PrimeSieveProcess::getCounts(unsigned int index) const {
  return shm_->counts[index];
}

/**
 * @return The sieving status in percent.
 */
double PrimeSieveProcess::getStatus() const {
  return shm_->status;
}

/**
 * @return The time elapsed in seconds (if sieving is finished).
 */
double PrimeSieveProcess::getTimeElapsed() const {
  return shm_->timeElapsed;
}
<commit_msg>minor changes<commit_after>/*
 * PrimeSieveProcess.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@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 3 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, see <http://www.gnu.org/licenses/>
 */

#include "PrimeSieveProcess.h"
#include "../soe/ParallelPrimeSieve.h"

#include <QtGlobal>
#include <QStringList>
#include <QCoreApplication>
#include <stdexcept>
#if defined(Q_OS_WIN)
#  include <windows.h>
#else
#  include <unistd.h>
#endif

PrimeSieveProcess::PrimeSieveProcess(QObject* parent = 0) :
  QProcess(parent) {
  sharedMemory_.setParent(parent);
  sharedMemory_.setKey(QString::number(this->getProcessId()));
}

PrimeSieveProcess::~PrimeSieveProcess() {
  // disconnect all signals, must be used to avoid zombie processes
  this->disconnect();
  // kill() and terminate() = trouble, close() works fine
  this->close();
  sharedMemory_.detach();
}

/**
 * Get the process ID of the current process. I tried to use
 * QProcess::pid() but got a lot of trouble on Windows and Mac OS X,
 * also it is not portable.
 */
int PrimeSieveProcess::getProcessId() {
#if defined(Q_OS_WIN)
  return static_cast<int> (GetCurrentProcessId());
#else
  return static_cast<int> (getpid());
#endif
}

/**
 * Create a shared memory segement for communication with the
 * ParallelPrimeSieve process.
 */
void PrimeSieveProcess::createSharedMemory() {
  // attach the shared memory
  if (!sharedMemory_.isAttached() &&
      !sharedMemory_.create(sizeof(shm_))) {
    throw std::runtime_error(
        "Interprocess communication error, could not allocate shared memory.");
  }
  // map the attached shared memory to the shm_ segment
  shm_ = static_cast<ParallelPrimeSieve::SharedMemory*> (sharedMemory_.data());
}

/**
 * Start a new ParallelPrimeSieve process that sieves the
 * prime numbers and/or k-tuplets between startNumber and stopNumber.
 */
void PrimeSieveProcess::start(quint64 startNumber, quint64 stopNumber,
    int sieveSize, int flags, int threads) {
  this->createSharedMemory();
  // initialize the shared memory segment
  shm_->startNumber = startNumber;
  shm_->stopNumber  = stopNumber;
  shm_->sieveSize   = static_cast<quint32> (sieveSize);
  shm_->flags       = static_cast<quint32> (flags);
  shm_->threads     = threads;
  for (int i = 0; i < ParallelPrimeSieve::COUNTS_SIZE; i++)
    shm_->counts[i] = 0;
  shm_->status      = 0.0;
  shm_->timeElapsed = 0.0;
  // path + file name of the aplication
  QString path = QCoreApplication::applicationFilePath();
  // process arguments, see main.cpp
  QStringList args;
  args << "PrimeSieveProcess" << sharedMemory_.key();
  /// start a new ParallelPrimeSieve process
  /// @see main.cpp
  QProcess::start(path, args, QIODevice::ReadOnly);
}

bool PrimeSieveProcess::isFinished() {
  return (shm_->status == 100.0);
}

/**
 * @return The count of prime numbers or prime k-tuplets between
 *         startNumber and stopNumber.
 * @param  index <= 6
 */
quint64 PrimeSieveProcess::getCounts(unsigned int index) const {
  return shm_->counts[index];
}

/**
 * @return The sieving status in percent.
 */
double PrimeSieveProcess::getStatus() const {
  return shm_->status;
}

/**
 * @return The time elapsed in seconds (if sieving is finished).
 */
double PrimeSieveProcess::getTimeElapsed() const {
  return shm_->timeElapsed;
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2014-2015 Paul T. Bauman, Roy H. Stogner
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// 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
// 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
//
//-----------------------------------------------------------------------el-

// This class
#include "grins/unsteady_visualization.h"

// GRINS
#include "grins/multiphysics_sys.h"
#include "grins/composite_qoi.h"

// libMesh
#include "libmesh/getpot.h"
#include "libmesh/parameter_vector.h"
#include "libmesh/steady_solver.h"

namespace GRINS
{

  UnsteadyVisualization::UnsteadyVisualization
    ( const GetPot& input,
      const libMesh::Parallel::Communicator &comm )
    : Visualization(input, comm)
  {
    return;
  }

  UnsteadyVisualization::~UnsteadyVisualization()
  {
    return;
  }

  void UnsteadyVisualization::output_residual
    ( SharedPtr<libMesh::EquationSystems> equation_system,
      MultiphysicsSystem* system,
      const unsigned int time_step,
      const libMesh::Real time )
  {
    std::stringstream suffix;
    suffix << time_step;

    std::string filename = this->_vis_output_file_prefix+"_unsteady_residual";

    filename+="."+suffix.str();

    // For the unsteady residual, we just want to evaluate F(u) from
    // dU/dt = F(u). What we do is swap out the time solver to a
    // SteadySolver and reassemble the residual. Then, we'll need to swap
    // the solution and the rhs vector stashed in the system. Once we're done,
    // we'll reset the time solver pointer back to the original guy.

    libMesh::UniquePtr<libMesh::TimeSolver> prev_time_solver(system->time_solver);

    libMesh::SteadySolver* steady_solver = new libMesh::SteadySolver( *(system) );

    system->time_solver = libMesh::UniquePtr<libMesh::TimeSolver>(steady_solver);

    system->assembly( true /*residual*/, false /*jacobian*/ );
    system->rhs->close();

    // Swap solution with newly computed residual
    system->solution->swap( *(system->rhs) );
    // Update equation systems
    equation_system->update();

    this->dump_visualization( equation_system, filename, time );

    // Now swap back and reupdate
    system->solution->swap( *(system->rhs) );
    equation_system->update();

    system->time_solver = prev_time_solver;

    return;
  }

  void UnsteadyVisualization::output_residual_sensitivities
    (SharedPtr<libMesh::EquationSystems> equation_system,
     MultiphysicsSystem* system,
     const libMesh::ParameterVector & params,
     const unsigned int time_step,
     const libMesh::Real time )
  {
    for (unsigned int p=0; p != params.size(); ++p)
      {
        std::stringstream suffix;
        suffix << time_step;

        std::stringstream pstr;
        pstr << p;

        std::string filename =
          this->_vis_output_file_prefix + "_unsteady_dRdp" +
          pstr.str() + '.' + suffix.str();

        // Swap solution with precomputed sensitivity rhs
        system->solution->swap(system->get_sensitivity_rhs(p));
        equation_system->update();

        this->dump_visualization( equation_system, filename, time );

        // Now swap back and reupdate
        system->solution->swap(system->get_sensitivity_rhs(p));
        equation_system->update();
      }
  }

  void UnsteadyVisualization::output_adjoint
    ( SharedPtr<libMesh::EquationSystems> equation_system,
      MultiphysicsSystem* system,
      const unsigned int time_step,
      const libMesh::Real time )
  {
    std::stringstream suffix;
    suffix << time_step;

    const libMesh::DifferentiableQoI* raw_qoi = system->get_qoi();
    const CompositeQoI* qoi = dynamic_cast<const CompositeQoI*>( raw_qoi );

    unsigned int n_qois = qoi->n_qois();

    for( unsigned int q = 0; q < n_qois; q++ )
      {
        libMesh::NumericVector<libMesh::Number>& dual_solution = system->get_adjoint_solution(q);

        const std::string& qoi_name = qoi->get_qoi(q).name();
        std::string filename = this->_vis_output_file_prefix+"_unsteady_adjoint_"+qoi_name;
        filename+="."+suffix.str();

        system->solution->swap( dual_solution );
        equation_system->update();

        this->dump_visualization( equation_system, filename, time );

        // Now swap back and reupdate
        system->solution->swap( dual_solution );
        equation_system->update();
      }
  }

  void UnsteadyVisualization::output_solution_sensitivities
    (SharedPtr<libMesh::EquationSystems> equation_system,
     MultiphysicsSystem* system,
     const libMesh::ParameterVector & params,
     const unsigned int time_step,
     const libMesh::Real time )
  {
    for (unsigned int p=0; p != params.size(); ++p)
      {
        std::stringstream suffix;
        suffix << time_step;

        std::stringstream pstr;
        pstr << p;

        std::string filename =
          this->_vis_output_file_prefix + "_unsteady_dudp" +
          pstr.str() + '.' + suffix.str();

        // Swap solution with precomputed sensitivity solution
        system->solution->swap(system->get_sensitivity_solution(p));
        equation_system->update();

        this->dump_visualization( equation_system, filename, time );

        // Now swap back and reupdate
        system->solution->swap(system->get_sensitivity_solution(p));
        equation_system->update();
      }
  }

} // namespace GRINS
<commit_msg>Proper pointer handling for outputing du/dt<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2014-2015 Paul T. Bauman, Roy H. Stogner
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// 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
// 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
//
//-----------------------------------------------------------------------el-

// This class
#include "grins/unsteady_visualization.h"

// GRINS
#include "grins/multiphysics_sys.h"
#include "grins/composite_qoi.h"

// libMesh
#include "libmesh/getpot.h"
#include "libmesh/parameter_vector.h"
#include "libmesh/steady_solver.h"

namespace GRINS
{

  UnsteadyVisualization::UnsteadyVisualization
    ( const GetPot& input,
      const libMesh::Parallel::Communicator &comm )
    : Visualization(input, comm)
  {
    return;
  }

  UnsteadyVisualization::~UnsteadyVisualization()
  {
    return;
  }

  void UnsteadyVisualization::output_residual
    ( SharedPtr<libMesh::EquationSystems> equation_system,
      MultiphysicsSystem* system,
      const unsigned int time_step,
      const libMesh::Real time )
  {
    std::stringstream suffix;
    suffix << time_step;

    std::string filename = this->_vis_output_file_prefix+"_unsteady_residual";

    filename+="."+suffix.str();

    // For the unsteady residual, we just want to evaluate F(u) from
    // dU/dt = F(u). What we do is swap out the time solver to a
    // SteadySolver and reassemble the residual. Then, we'll need to swap
    // the solution and the rhs vector stashed in the system. Once we're done,
    // we'll reset the time solver pointer back to the original guy.

    libMesh::TimeSolver* prev_time_solver = system->time_solver.get();

    libMesh::SteadySolver* steady_solver = new libMesh::SteadySolver( *(system) );

    system->time_solver = libMesh::UniquePtr<libMesh::TimeSolver>(steady_solver);

    system->assembly( true /*residual*/, false /*jacobian*/ );
    system->rhs->close();

    // Swap solution with newly computed residual
    system->solution->swap( *(system->rhs) );
    // Update equation systems
    equation_system->update();

    this->dump_visualization( equation_system, filename, time );

    // Now swap back and reupdate
    system->solution->swap( *(system->rhs) );
    equation_system->update();

    system->time_solver.reset(prev_time_solver);
  }

  void UnsteadyVisualization::output_residual_sensitivities
    (SharedPtr<libMesh::EquationSystems> equation_system,
     MultiphysicsSystem* system,
     const libMesh::ParameterVector & params,
     const unsigned int time_step,
     const libMesh::Real time )
  {
    for (unsigned int p=0; p != params.size(); ++p)
      {
        std::stringstream suffix;
        suffix << time_step;

        std::stringstream pstr;
        pstr << p;

        std::string filename =
          this->_vis_output_file_prefix + "_unsteady_dRdp" +
          pstr.str() + '.' + suffix.str();

        // Swap solution with precomputed sensitivity rhs
        system->solution->swap(system->get_sensitivity_rhs(p));
        equation_system->update();

        this->dump_visualization( equation_system, filename, time );

        // Now swap back and reupdate
        system->solution->swap(system->get_sensitivity_rhs(p));
        equation_system->update();
      }
  }

  void UnsteadyVisualization::output_adjoint
    ( SharedPtr<libMesh::EquationSystems> equation_system,
      MultiphysicsSystem* system,
      const unsigned int time_step,
      const libMesh::Real time )
  {
    std::stringstream suffix;
    suffix << time_step;

    const libMesh::DifferentiableQoI* raw_qoi = system->get_qoi();
    const CompositeQoI* qoi = dynamic_cast<const CompositeQoI*>( raw_qoi );

    unsigned int n_qois = qoi->n_qois();

    for( unsigned int q = 0; q < n_qois; q++ )
      {
        libMesh::NumericVector<libMesh::Number>& dual_solution = system->get_adjoint_solution(q);

        const std::string& qoi_name = qoi->get_qoi(q).name();
        std::string filename = this->_vis_output_file_prefix+"_unsteady_adjoint_"+qoi_name;
        filename+="."+suffix.str();

        system->solution->swap( dual_solution );
        equation_system->update();

        this->dump_visualization( equation_system, filename, time );

        // Now swap back and reupdate
        system->solution->swap( dual_solution );
        equation_system->update();
      }
  }

  void UnsteadyVisualization::output_solution_sensitivities
    (SharedPtr<libMesh::EquationSystems> equation_system,
     MultiphysicsSystem* system,
     const libMesh::ParameterVector & params,
     const unsigned int time_step,
     const libMesh::Real time )
  {
    for (unsigned int p=0; p != params.size(); ++p)
      {
        std::stringstream suffix;
        suffix << time_step;

        std::stringstream pstr;
        pstr << p;

        std::string filename =
          this->_vis_output_file_prefix + "_unsteady_dudp" +
          pstr.str() + '.' + suffix.str();

        // Swap solution with precomputed sensitivity solution
        system->solution->swap(system->get_sensitivity_solution(p));
        equation_system->update();

        this->dump_visualization( equation_system, filename, time );

        // Now swap back and reupdate
        system->solution->swap(system->get_sensitivity_solution(p));
        equation_system->update();
      }
  }

} // namespace GRINS
<|endoftext|>


<commit_before>// Copyright 2018 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 "riegeli/bytes/zlib_writer.h"

#include <stddef.h>

#include <limits>
#include <memory>
#include <string>

#include "absl/base/optimization.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "riegeli/base/base.h"
#include "riegeli/base/recycling_pool.h"
#include "riegeli/base/status.h"
#include "riegeli/bytes/buffered_writer.h"
#include "riegeli/bytes/writer.h"
#include "zconf.h"
#include "zlib.h"

namespace riegeli {

// Before C++17 if a constexpr static data member is ODR-used, its definition at
// namespace scope is required. Since C++17 these definitions are deprecated:
// http://en.cppreference.com/w/cpp/language/static
#if __cplusplus < 201703
constexpr int ZlibWriterBase::Options::kMinCompressionLevel;
constexpr int ZlibWriterBase::Options::kMaxCompressionLevel;
constexpr int ZlibWriterBase::Options::kDefaultCompressionLevel;
constexpr int ZlibWriterBase::Options::kMinWindowLog;
constexpr int ZlibWriterBase::Options::kMaxWindowLog;
constexpr int ZlibWriterBase::Options::kDefaultWindowLog;
constexpr ZlibWriterBase::Header ZlibWriterBase::Options::kDefaultHeader;
#endif

void ZlibWriterBase::Initialize(Writer* dest, int compression_level,
                                int window_bits) {
  RIEGELI_ASSERT(dest != nullptr)
      << "Failed precondition of ZlibWriter: null Writer pointer";
  if (ABSL_PREDICT_FALSE(!dest->healthy())) {
    Fail(*dest);
    return;
  }
  compressor_ =
      RecyclingPool<z_stream, ZStreamDeleter, ZStreamKey>::global().Get(
          ZStreamKey{compression_level, window_bits},
          [&] {
            std::unique_ptr<z_stream, ZStreamDeleter> ptr(new z_stream());
            if (ABSL_PREDICT_FALSE(deflateInit2(ptr.get(), compression_level,
                                                Z_DEFLATED, window_bits, 8,
                                                Z_DEFAULT_STRATEGY) != Z_OK)) {
              FailOperation("deflateInit2()");
            }
            return ptr;
          },
          [&](z_stream* ptr) {
            if (ABSL_PREDICT_FALSE(deflateReset(ptr) != Z_OK)) {
              FailOperation("deflateReset()");
            }
          });
}

void ZlibWriterBase::Done() {
  if (ABSL_PREDICT_TRUE(healthy())) {
    Writer& dest = *dest_writer();
    const absl::string_view data(start(), written_to_buffer());
    set_buffer();
    WriteInternal(data, dest, Z_FINISH);
  }
  compressor_.reset();
  BufferedWriter::Done();
}

inline bool ZlibWriterBase::FailOperation(absl::string_view operation) {
  RIEGELI_ASSERT(!closed())
      << "Failed precondition of ZlibWriterBase::FailOperation(): "
         "Object closed";
  Writer& dest = *dest_writer();
  std::string message = absl::StrCat(operation, " failed");
  if (compressor_->msg != nullptr) {
    absl::StrAppend(&message, ": ", compressor_->msg);
  }
  return Fail(Annotate(absl::InternalError(message),
                       absl::StrCat("at byte ", dest.pos())));
}

bool ZlibWriterBase::Fail(absl::Status status) {
  RIEGELI_ASSERT(!status.ok())
      << "Failed precondition of Object::Fail(): status not failed";
  return FailWithoutAnnotation(
      Annotate(status, absl::StrCat("at uncompressed byte ", pos())));
}

bool ZlibWriterBase::WriteInternal(absl::string_view src) {
  RIEGELI_ASSERT(!src.empty())
      << "Failed precondition of BufferedWriter::WriteInternal(): "
         "nothing to write";
  RIEGELI_ASSERT(healthy())
      << "Failed precondition of BufferedWriter::WriteInternal(): " << status();
  RIEGELI_ASSERT_EQ(written_to_buffer(), 0u)
      << "Failed precondition of BufferedWriter::WriteInternal(): "
         "buffer not empty";
  Writer& dest = *dest_writer();
  return WriteInternal(src, dest, Z_NO_FLUSH);
}

inline bool ZlibWriterBase::WriteInternal(absl::string_view src, Writer& dest,
                                          int flush) {
  RIEGELI_ASSERT(healthy())
      << "Failed precondition of ZlibWriterBase::WriteInternal(): " << status();
  RIEGELI_ASSERT_EQ(written_to_buffer(), 0u)
      << "Failed precondition of ZlibWriterBase::WriteInternal(): "
         "buffer not empty";
  if (ABSL_PREDICT_FALSE(src.size() >
                         std::numeric_limits<Position>::max() - limit_pos())) {
    return FailOverflow();
  }
  compressor_->next_in =
      const_cast<z_const Bytef*>(reinterpret_cast<const Bytef*>(src.data()));
  for (;;) {
    // If `compressor_->avail_out == 0` then `deflate()` returns `Z_BUF_ERROR`,
    // so `dest.Push()` first.
    if (ABSL_PREDICT_FALSE(!dest.Push())) return Fail(dest);
    size_t avail_in =
        PtrDistance(reinterpret_cast<const char*>(compressor_->next_in),
                    src.data() + src.size());
    int op = flush;
    if (ABSL_PREDICT_FALSE(avail_in > std::numeric_limits<uInt>::max())) {
      avail_in = size_t{std::numeric_limits<uInt>::max()};
      op = Z_NO_FLUSH;
    }
    compressor_->avail_in = IntCast<uInt>(avail_in);
    compressor_->next_out = reinterpret_cast<Bytef*>(dest.cursor());
    compressor_->avail_out = SaturatingIntCast<uInt>(dest.available());
    const int result = deflate(compressor_.get(), op);
    dest.set_cursor(reinterpret_cast<char*>(compressor_->next_out));
    const size_t length_written = PtrDistance(
        src.data(), reinterpret_cast<const char*>(compressor_->next_in));
    switch (result) {
      case Z_OK:
        if (compressor_->avail_out == 0 ||
            ABSL_PREDICT_FALSE(length_written < src.size())) {
          continue;
        }
        break;
      case Z_STREAM_END:
        break;
      case Z_BUF_ERROR:
        RIEGELI_ASSERT_EQ(op, Z_PARTIAL_FLUSH)
            << "deflate() returned an unexpected Z_BUF_ERROR";
        break;
      default:
        return FailOperation("deflate()");
    }
    RIEGELI_ASSERT_EQ(length_written, src.size())
        << "deflate() returned but there are still input data";
    move_start_pos(length_written);
    return true;
  }
}

bool ZlibWriterBase::Flush(FlushType flush_type) {
  if (ABSL_PREDICT_FALSE(!healthy())) return false;
  Writer& dest = *dest_writer();
  const absl::string_view data(start(), written_to_buffer());
  set_buffer();
  if (ABSL_PREDICT_FALSE(!WriteInternal(data, dest, Z_PARTIAL_FLUSH))) {
    return false;
  }
  if (ABSL_PREDICT_FALSE(!dest.Flush(flush_type))) return Fail(dest);
  return true;
}

}  // namespace riegeli
<commit_msg>Use `Z_SYNC_FLUSH` instead of `Z_PARTIAL_FLUSH` in `ZlibWriterBase::Flush()`.<commit_after>// Copyright 2018 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 "riegeli/bytes/zlib_writer.h"

#include <stddef.h>

#include <limits>
#include <memory>
#include <string>

#include "absl/base/optimization.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "riegeli/base/base.h"
#include "riegeli/base/recycling_pool.h"
#include "riegeli/base/status.h"
#include "riegeli/bytes/buffered_writer.h"
#include "riegeli/bytes/writer.h"
#include "zconf.h"
#include "zlib.h"

namespace riegeli {

// Before C++17 if a constexpr static data member is ODR-used, its definition at
// namespace scope is required. Since C++17 these definitions are deprecated:
// http://en.cppreference.com/w/cpp/language/static
#if __cplusplus < 201703
constexpr int ZlibWriterBase::Options::kMinCompressionLevel;
constexpr int ZlibWriterBase::Options::kMaxCompressionLevel;
constexpr int ZlibWriterBase::Options::kDefaultCompressionLevel;
constexpr int ZlibWriterBase::Options::kMinWindowLog;
constexpr int ZlibWriterBase::Options::kMaxWindowLog;
constexpr int ZlibWriterBase::Options::kDefaultWindowLog;
constexpr ZlibWriterBase::Header ZlibWriterBase::Options::kDefaultHeader;
#endif

void ZlibWriterBase::Initialize(Writer* dest, int compression_level,
                                int window_bits) {
  RIEGELI_ASSERT(dest != nullptr)
      << "Failed precondition of ZlibWriter: null Writer pointer";
  if (ABSL_PREDICT_FALSE(!dest->healthy())) {
    Fail(*dest);
    return;
  }
  compressor_ =
      RecyclingPool<z_stream, ZStreamDeleter, ZStreamKey>::global().Get(
          ZStreamKey{compression_level, window_bits},
          [&] {
            std::unique_ptr<z_stream, ZStreamDeleter> ptr(new z_stream());
            if (ABSL_PREDICT_FALSE(deflateInit2(ptr.get(), compression_level,
                                                Z_DEFLATED, window_bits, 8,
                                                Z_DEFAULT_STRATEGY) != Z_OK)) {
              FailOperation("deflateInit2()");
            }
            return ptr;
          },
          [&](z_stream* ptr) {
            if (ABSL_PREDICT_FALSE(deflateReset(ptr) != Z_OK)) {
              FailOperation("deflateReset()");
            }
          });
}

void ZlibWriterBase::Done() {
  if (ABSL_PREDICT_TRUE(healthy())) {
    Writer& dest = *dest_writer();
    const absl::string_view data(start(), written_to_buffer());
    set_buffer();
    WriteInternal(data, dest, Z_FINISH);
  }
  compressor_.reset();
  BufferedWriter::Done();
}

inline bool ZlibWriterBase::FailOperation(absl::string_view operation) {
  RIEGELI_ASSERT(!closed())
      << "Failed precondition of ZlibWriterBase::FailOperation(): "
         "Object closed";
  Writer& dest = *dest_writer();
  std::string message = absl::StrCat(operation, " failed");
  if (compressor_->msg != nullptr) {
    absl::StrAppend(&message, ": ", compressor_->msg);
  }
  return Fail(Annotate(absl::InternalError(message),
                       absl::StrCat("at byte ", dest.pos())));
}

bool ZlibWriterBase::Fail(absl::Status status) {
  RIEGELI_ASSERT(!status.ok())
      << "Failed precondition of Object::Fail(): status not failed";
  return FailWithoutAnnotation(
      Annotate(status, absl::StrCat("at uncompressed byte ", pos())));
}

bool ZlibWriterBase::WriteInternal(absl::string_view src) {
  RIEGELI_ASSERT(!src.empty())
      << "Failed precondition of BufferedWriter::WriteInternal(): "
         "nothing to write";
  RIEGELI_ASSERT(healthy())
      << "Failed precondition of BufferedWriter::WriteInternal(): " << status();
  RIEGELI_ASSERT_EQ(written_to_buffer(), 0u)
      << "Failed precondition of BufferedWriter::WriteInternal(): "
         "buffer not empty";
  Writer& dest = *dest_writer();
  return WriteInternal(src, dest, Z_NO_FLUSH);
}

inline bool ZlibWriterBase::WriteInternal(absl::string_view src, Writer& dest,
                                          int flush) {
  RIEGELI_ASSERT(healthy())
      << "Failed precondition of ZlibWriterBase::WriteInternal(): " << status();
  RIEGELI_ASSERT_EQ(written_to_buffer(), 0u)
      << "Failed precondition of ZlibWriterBase::WriteInternal(): "
         "buffer not empty";
  if (ABSL_PREDICT_FALSE(src.size() >
                         std::numeric_limits<Position>::max() - limit_pos())) {
    return FailOverflow();
  }
  compressor_->next_in =
      const_cast<z_const Bytef*>(reinterpret_cast<const Bytef*>(src.data()));
  for (;;) {
    // If `compressor_->avail_out == 0` then `deflate()` returns `Z_BUF_ERROR`,
    // so `dest.Push()` first.
    if (ABSL_PREDICT_FALSE(!dest.Push())) return Fail(dest);
    size_t avail_in =
        PtrDistance(reinterpret_cast<const char*>(compressor_->next_in),
                    src.data() + src.size());
    int op = flush;
    if (ABSL_PREDICT_FALSE(avail_in > std::numeric_limits<uInt>::max())) {
      avail_in = size_t{std::numeric_limits<uInt>::max()};
      op = Z_NO_FLUSH;
    }
    compressor_->avail_in = IntCast<uInt>(avail_in);
    compressor_->next_out = reinterpret_cast<Bytef*>(dest.cursor());
    compressor_->avail_out = SaturatingIntCast<uInt>(dest.available());
    const int result = deflate(compressor_.get(), op);
    dest.set_cursor(reinterpret_cast<char*>(compressor_->next_out));
    const size_t length_written = PtrDistance(
        src.data(), reinterpret_cast<const char*>(compressor_->next_in));
    switch (result) {
      case Z_OK:
        if (compressor_->avail_out == 0 ||
            ABSL_PREDICT_FALSE(length_written < src.size())) {
          continue;
        }
        break;
      case Z_STREAM_END:
        break;
      case Z_BUF_ERROR:
        RIEGELI_ASSERT_EQ(op, Z_SYNC_FLUSH)
            << "deflate() returned an unexpected Z_BUF_ERROR";
        break;
      default:
        return FailOperation("deflate()");
    }
    RIEGELI_ASSERT_EQ(length_written, src.size())
        << "deflate() returned but there are still input data";
    move_start_pos(length_written);
    return true;
  }
}

bool ZlibWriterBase::Flush(FlushType flush_type) {
  if (ABSL_PREDICT_FALSE(!healthy())) return false;
  Writer& dest = *dest_writer();
  const absl::string_view data(start(), written_to_buffer());
  set_buffer();
  if (ABSL_PREDICT_FALSE(!WriteInternal(data, dest, Z_SYNC_FLUSH))) {
    return false;
  }
  if (ABSL_PREDICT_FALSE(!dest.Flush(flush_type))) return Fail(dest);
  return true;
}

}  // namespace riegeli
<|endoftext|>


<commit_before><commit_msg>Roughness error.<commit_after><|endoftext|>


<commit_before>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix 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.

    MRtrix 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 MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "args.h"
#include "app.h"
#include "debug.h"
#include "version.h"

#define HELP_WIDTH  80

#define HELP_PURPOSE_INDENT 0, 4
#define HELP_ARG_INDENT 8, 20
#define HELP_OPTION_INDENT 2, 20

namespace MR
{
  namespace App
  {

    const char* project_version = NULL;
    const char* build_date = __DATE__;

    namespace
    {

      inline size_t size (const std::string& text)
      {
        return text.size() - 2*std::count (text.begin(), text.end(), 0x08U);
      }

      inline void resize (std::string& text, size_t new_size, char fill)
      {
        text.resize (text.size() + new_size - size(text), fill);
      }

      std::string paragraph (
          const std::string& header,
          const std::string& text,
          size_t header_indent,
          size_t indent)
      {
        std::string out, line = std::string (header_indent, ' ') + header + " ";
        if (size (line) < indent)
          resize (line, indent, ' ');

        std::vector<std::string> paragraphs = split (text, "\n");

        for (size_t n = 0; n < paragraphs.size(); ++n) {
          size_t i = 0;
          std::vector<std::string> words = split (paragraphs[n]);
          while (i < words.size()) {
            do {
              line += " " + words[i++];
              if (i >= words.size())
                break;
            }
            while (size (line) + 1 + size (words[i]) < HELP_WIDTH);
            out += line + "\n";
            line = std::string (indent, ' ');
          }
        }
        return out;
      }

      std::string bold (const std::string& text)
      {
        std::string retval (3*text.size(), '\0');
        for (size_t n = 0; n < text.size(); ++n) {
          retval[3*n] = retval[3*n+2] = text[n];
          retval[3*n+1] = 0x08U;
        }
        return retval;
      }

      std::string underline (const std::string& text)
      {
        std::string retval (3*text.size(), '\0');
        for (size_t n = 0; n < text.size(); ++n) {
          retval[3*n] = '_';
          retval[3*n+1] = 0x08U;
          retval[3*n+2] = text[n];
        }
        return retval;
      }

    }

    const char* argtype_description (ArgType type)
    {
      switch (type) {
        case Integer:
          return ("integer");
        case Float:
          return ("float");
        case Text:
          return ("string");
        case ArgFile:
          return ("file");
        case ImageIn:
          return ("image in");
        case ImageOut:
          return ("image out");
        case Choice:
          return ("choice");
        case IntSeq:
          return ("int seq");
        case FloatSeq:
          return ("float seq");
        default:
          return ("undefined");
      }
    }

    std::string help_head (int format)
    {
      std::string cmd_version =
          ( project_version ? std::string ("version ") + project_version + ", external module" : std::string("part") ) +
          " of the MRtrix package\n\n";

      if (!format)
        return std::string (NAME) + ": " + cmd_version;

      std::string mrtrix_version = "MRtrix " MRTRIX_GIT_VERSION;
      std::string date (build_date);

      std::string topline = mrtrix_version + std::string (40-size(mrtrix_version)-size(App::NAME)/2, ' ') + bold (App::NAME);
      topline += std::string (80-size(topline)-size(date), ' ') + date;

      return topline + "\n\n     " + bold (NAME) + ": " + cmd_version;
    }

    std::string help_tail (int format)
    {
      std::string retval;
      if (!format)
        return retval;

      return bold ("AUTHOR") + "\n"
        + paragraph ("", AUTHOR, HELP_PURPOSE_INDENT) + "\n"
        + bold ("COPYRIGHT") + "\n"
        + paragraph ("", COPYRIGHT, HELP_PURPOSE_INDENT) + "\n";
    }

    std::string Description::syntax (int format) const
    {
      std::string s;
      if (format)
        s += bold ("DESCRIPTION") + "\n\n";
      for (size_t i = 0; i < size(); ++i)
        s += paragraph ("", (*this)[i], HELP_PURPOSE_INDENT) + "\n";
      return s;
    }

    std::string help_syntax (int format)
    {
      std::string s = "SYNOPSIS";
      if (format)
        s = bold (s) + "\n\n     ";
      else
        s += ": ";
      s += ( format ? underline (NAME) : NAME ) + " [ options ]";

      for (size_t i = 0; i < ARGUMENTS.size(); ++i) {

        if (ARGUMENTS[i].flags & Optional)
          s += "[";
        s += std::string(" ") + ARGUMENTS[i].id;

        if (ARGUMENTS[i].flags & AllowMultiple) {
          if (! (ARGUMENTS[i].flags & Optional))
            s += std::string(" [ ") + ARGUMENTS[i].id;
          s += " ...";
        }
        if (ARGUMENTS[i].flags & (Optional | AllowMultiple))
          s += " ]";
      }
        return s + "\n\n";
      }

    std::string Argument::syntax (int format) const
    {
      std::string retval = paragraph (( format ? underline (id) : id ), desc, HELP_ARG_INDENT);
      if (format)
        retval += "\n";
      return retval;
    }

    std::string ArgumentList::syntax (int format) const
    {
      std::string s;
      for (size_t i = 0; i < size(); ++i)
        s += (*this)[i].syntax (format);
      return s + "\n";
    }

    std::string Option::syntax (int format) const
    {
      std::string opt ("-");
      opt += id;

      if (format)
        opt = underline (opt);

      for (size_t i = 0; i < size(); ++i)
        opt += std::string (" ") + (*this)[i].id;

      if (format)
        opt = "  " + opt + "\n" + paragraph ("", desc, HELP_PURPOSE_INDENT);
      else
        opt = paragraph (opt, desc, HELP_OPTION_INDENT);
      if (format)
        opt += "\n";
      return opt;
    }

    std::string OptionGroup::header (int format) const
    {
      return format ? bold (name) + "\n\n" : std::string (name) + ":\n";
    }

    std::string OptionGroup::contents (int format) const
    {
      std::string s;
      for (size_t i = 0; i < size(); ++i)
        s += (*this)[i].syntax (format);
      return s;
    }

    std::string OptionGroup::footer (int format)
    {
      return format ? "" : "\n";
    }

    std::string OptionList::syntax (int format) const
    {
      std::vector<std::string> group_names;
      for (size_t i = 0; i < size(); ++i) {
        if (std::find (group_names.begin(), group_names.end(), (*this)[i].name) == group_names.end())
          group_names.push_back ((*this)[i].name);
      }

      std::string s;
      for (size_t i = 0; i < group_names.size(); ++i) {
        size_t n = i;
        while ((*this)[n].name != group_names[i])
          ++n;
        s += (*this)[n].header (format);
        while (n < size()) {
          if ((*this)[n].name == group_names[i])
            s += (*this)[n].contents (format);
          ++n;
        }
        s += OptionGroup::footer (format);
      }

      return s;
    }

    std::string Argument::usage () const
    {
      std::ostringstream stream;
      stream << "ARGUMENT " << id << " "
        << (flags & Optional ? '1' : '0') << " "
        << (flags & AllowMultiple ? '1' : '0') << " ";

      switch (type) {
        case Integer:
          stream << "INT " << defaults.i.min << " " << defaults.i.max << " " << defaults.i.def;
          break;
        case Float:
          stream << "FLOAT " << defaults.f.min << " " << defaults.f.max << " " << defaults.f.def;
          break;
        case Text:
          stream << "TEXT";
          if (defaults.text)
            stream << " " << defaults.text;
          break;
        case ArgFile:
          stream << "FILE";
          break;
        case Choice:
          stream << "CHOICE";
          for (const char* const* p = defaults.choices.list; *p; ++p)
            stream << " " << *p;
          stream << " " << defaults.choices.def;
          break;
        case ImageIn:
          stream << "IMAGEIN";
          break;
        case ImageOut:
          stream << "IMAGEOUT";
          break;
        case IntSeq:
          stream << "ISEQ";
          break;
        case FloatSeq:
          stream << "FSEQ";
          break;
        default:
          assert (0);
      }
      stream << "\n";
      if (desc.size())
        stream << desc << "\n";

      return stream.str();
    }

    std::string Option::usage () const
    {
      std::ostringstream stream;
      stream << "OPTION " << id << " "
        << (flags & Optional ? '1' : '0') << " "
        << (flags & AllowMultiple ? '1' : '0') << "\n";

      if (desc.size())
        stream << desc << "\n";

      for (size_t i = 0; i < size(); ++i)
        stream << (*this)[i].usage ();

      return stream.str();
    }

  }
}

<commit_msg>Change help page display to prevent crash with long command names<commit_after>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix 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.

    MRtrix 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 MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "args.h"
#include "app.h"
#include "debug.h"
#include "version.h"

#define HELP_WIDTH  80

#define HELP_PURPOSE_INDENT 0, 4
#define HELP_ARG_INDENT 8, 20
#define HELP_OPTION_INDENT 2, 20

namespace MR
{
  namespace App
  {

    const char* project_version = NULL;
    const char* build_date = __DATE__;

    namespace
    {

      inline size_t size (const std::string& text)
      {
        return text.size() - 2*std::count (text.begin(), text.end(), 0x08U);
      }

      inline void resize (std::string& text, size_t new_size, char fill)
      {
        text.resize (text.size() + new_size - size(text), fill);
      }

      std::string paragraph (
          const std::string& header,
          const std::string& text,
          size_t header_indent,
          size_t indent)
      {
        std::string out, line = std::string (header_indent, ' ') + header + " ";
        if (size (line) < indent)
          resize (line, indent, ' ');

        std::vector<std::string> paragraphs = split (text, "\n");

        for (size_t n = 0; n < paragraphs.size(); ++n) {
          size_t i = 0;
          std::vector<std::string> words = split (paragraphs[n]);
          while (i < words.size()) {
            do {
              line += " " + words[i++];
              if (i >= words.size())
                break;
            }
            while (size (line) + 1 + size (words[i]) < HELP_WIDTH);
            out += line + "\n";
            line = std::string (indent, ' ');
          }
        }
        return out;
      }

      std::string bold (const std::string& text)
      {
        std::string retval (3*text.size(), '\0');
        for (size_t n = 0; n < text.size(); ++n) {
          retval[3*n] = retval[3*n+2] = text[n];
          retval[3*n+1] = 0x08U;
        }
        return retval;
      }

      std::string underline (const std::string& text)
      {
        std::string retval (3*text.size(), '\0');
        for (size_t n = 0; n < text.size(); ++n) {
          retval[3*n] = '_';
          retval[3*n+1] = 0x08U;
          retval[3*n+2] = text[n];
        }
        return retval;
      }

    }

    const char* argtype_description (ArgType type)
    {
      switch (type) {
        case Integer:
          return ("integer");
        case Float:
          return ("float");
        case Text:
          return ("string");
        case ArgFile:
          return ("file");
        case ImageIn:
          return ("image in");
        case ImageOut:
          return ("image out");
        case Choice:
          return ("choice");
        case IntSeq:
          return ("int seq");
        case FloatSeq:
          return ("float seq");
        default:
          return ("undefined");
      }
    }

    std::string help_head (int format)
    {
      std::string cmd_version =
          ( project_version ? std::string ("version ") + project_version + ", external module" : std::string("part") ) +
          " of the MRtrix package";

      if (!format)
        return std::string (NAME) + ": " + cmd_version + "\n\n";

      std::string mrtrix_version = "MRtrix " MRTRIX_GIT_VERSION;
      std::string date (build_date);

      std::string topline = mrtrix_version + std::string (80-size(mrtrix_version)-size(date), ' ') + date;

      return topline + "\n\n" + std::string (40-size(NAME)/2, ' ') + bold (NAME) + "\n\n"
        + std::string (40-size(cmd_version)/2, ' ') + cmd_version + "\n\n";
    }

    std::string help_tail (int format)
    {
      std::string retval;
      if (!format)
        return retval;

      return bold ("AUTHOR") + "\n"
        + paragraph ("", AUTHOR, HELP_PURPOSE_INDENT) + "\n"
        + bold ("COPYRIGHT") + "\n"
        + paragraph ("", COPYRIGHT, HELP_PURPOSE_INDENT) + "\n";
    }

    std::string Description::syntax (int format) const
    {
      std::string s;
      if (format)
        s += bold ("DESCRIPTION") + "\n\n";
      for (size_t i = 0; i < size(); ++i)
        s += paragraph ("", (*this)[i], HELP_PURPOSE_INDENT) + "\n";
      return s;
    }

    std::string help_syntax (int format)
    {
      std::string s = "SYNOPSIS";
      if (format)
        s = bold (s) + "\n\n     ";
      else
        s += ": ";
      s += ( format ? underline (NAME) : NAME ) + " [ options ]";

      for (size_t i = 0; i < ARGUMENTS.size(); ++i) {

        if (ARGUMENTS[i].flags & Optional)
          s += "[";
        s += std::string(" ") + ARGUMENTS[i].id;

        if (ARGUMENTS[i].flags & AllowMultiple) {
          if (! (ARGUMENTS[i].flags & Optional))
            s += std::string(" [ ") + ARGUMENTS[i].id;
          s += " ...";
        }
        if (ARGUMENTS[i].flags & (Optional | AllowMultiple))
          s += " ]";
      }
        return s + "\n\n";
      }

    std::string Argument::syntax (int format) const
    {
      std::string retval = paragraph (( format ? underline (id) : id ), desc, HELP_ARG_INDENT);
      if (format)
        retval += "\n";
      return retval;
    }

    std::string ArgumentList::syntax (int format) const
    {
      std::string s;
      for (size_t i = 0; i < size(); ++i)
        s += (*this)[i].syntax (format);
      return s + "\n";
    }

    std::string Option::syntax (int format) const
    {
      std::string opt ("-");
      opt += id;

      if (format)
        opt = underline (opt);

      for (size_t i = 0; i < size(); ++i)
        opt += std::string (" ") + (*this)[i].id;

      if (format)
        opt = "  " + opt + "\n" + paragraph ("", desc, HELP_PURPOSE_INDENT);
      else
        opt = paragraph (opt, desc, HELP_OPTION_INDENT);
      if (format)
        opt += "\n";
      return opt;
    }

    std::string OptionGroup::header (int format) const
    {
      return format ? bold (name) + "\n\n" : std::string (name) + ":\n";
    }

    std::string OptionGroup::contents (int format) const
    {
      std::string s;
      for (size_t i = 0; i < size(); ++i)
        s += (*this)[i].syntax (format);
      return s;
    }

    std::string OptionGroup::footer (int format)
    {
      return format ? "" : "\n";
    }

    std::string OptionList::syntax (int format) const
    {
      std::vector<std::string> group_names;
      for (size_t i = 0; i < size(); ++i) {
        if (std::find (group_names.begin(), group_names.end(), (*this)[i].name) == group_names.end())
          group_names.push_back ((*this)[i].name);
      }

      std::string s;
      for (size_t i = 0; i < group_names.size(); ++i) {
        size_t n = i;
        while ((*this)[n].name != group_names[i])
          ++n;
        s += (*this)[n].header (format);
        while (n < size()) {
          if ((*this)[n].name == group_names[i])
            s += (*this)[n].contents (format);
          ++n;
        }
        s += OptionGroup::footer (format);
      }

      return s;
    }

    std::string Argument::usage () const
    {
      std::ostringstream stream;
      stream << "ARGUMENT " << id << " "
        << (flags & Optional ? '1' : '0') << " "
        << (flags & AllowMultiple ? '1' : '0') << " ";

      switch (type) {
        case Integer:
          stream << "INT " << defaults.i.min << " " << defaults.i.max << " " << defaults.i.def;
          break;
        case Float:
          stream << "FLOAT " << defaults.f.min << " " << defaults.f.max << " " << defaults.f.def;
          break;
        case Text:
          stream << "TEXT";
          if (defaults.text)
            stream << " " << defaults.text;
          break;
        case ArgFile:
          stream << "FILE";
          break;
        case Choice:
          stream << "CHOICE";
          for (const char* const* p = defaults.choices.list; *p; ++p)
            stream << " " << *p;
          stream << " " << defaults.choices.def;
          break;
        case ImageIn:
          stream << "IMAGEIN";
          break;
        case ImageOut:
          stream << "IMAGEOUT";
          break;
        case IntSeq:
          stream << "ISEQ";
          break;
        case FloatSeq:
          stream << "FSEQ";
          break;
        default:
          assert (0);
      }
      stream << "\n";
      if (desc.size())
        stream << desc << "\n";

      return stream.str();
    }

    std::string Option::usage () const
    {
      std::ostringstream stream;
      stream << "OPTION " << id << " "
        << (flags & Optional ? '1' : '0') << " "
        << (flags & AllowMultiple ? '1' : '0') << "\n";

      if (desc.size())
        stream << desc << "\n";

      for (size_t i = 0; i < size(); ++i)
        stream << (*this)[i].usage ();

      return stream.str();
    }

  }
}

<|endoftext|>


<commit_before>// Copyright 2015 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 "sky/shell/ui/engine.h"

#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/threading/worker_pool.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "mojo/data_pipe_utils/data_pipe_utils.h"
#include "mojo/public/cpp/application/connect.h"
#include "services/asset_bundle/zip_asset_bundle.h"
#include "sky/engine/bindings/mojo_services.h"
#include "sky/engine/core/script/dart_init.h"
#include "sky/engine/core/script/ui_dart_state.h"
#include "sky/engine/public/platform/WebInputEvent.h"
#include "sky/engine/public/web/Sky.h"
#include "sky/shell/dart/dart_library_provider_files.h"
#include "sky/shell/shell.h"
#include "sky/shell/ui/animator.h"
#include "sky/shell/ui/flutter_font_selector.h"
#include "sky/shell/ui/platform_impl.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"

namespace sky {
namespace shell {
namespace {

PlatformImpl* g_platform_impl = nullptr;

}  // namespace

using mojo::asset_bundle::ZipAssetBundle;
using mojo::asset_bundle::ZipAssetService;

Engine::Config::Config() {}

Engine::Config::~Config() {}

Engine::Engine(const Config& config, rasterizer::RasterizerPtr rasterizer)
    : config_(config),
      animator_(new Animator(config, rasterizer.Pass(), this)),
      binding_(this),
      activity_running_(false),
      have_surface_(false),
      weak_factory_(this) {}

Engine::~Engine() {}

base::WeakPtr<Engine> Engine::GetWeakPtr() {
  return weak_factory_.GetWeakPtr();
}

void Engine::Init() {
  TRACE_EVENT0("flutter", "Engine::Init");

  DCHECK(!g_platform_impl);
  g_platform_impl = new PlatformImpl();
  blink::initialize(g_platform_impl);
}

std::unique_ptr<flow::LayerTree> Engine::BeginFrame(
    base::TimeTicks frame_time) {
  TRACE_EVENT0("flutter", "Engine::BeginFrame");

  if (!sky_view_)
    return nullptr;

  auto begin_time = base::TimeTicks::Now();
  std::unique_ptr<flow::LayerTree> layer_tree =
      sky_view_->BeginFrame(frame_time);
  if (layer_tree) {
    layer_tree->set_scene_version(viewport_metrics_->scene_version);
    layer_tree->set_frame_size(SkISize::Make(viewport_metrics_->physical_width,
                                             viewport_metrics_->physical_height));
    layer_tree->set_construction_time(base::TimeTicks::Now() - begin_time);
  }
  return layer_tree;
}

void Engine::ConnectToEngine(mojo::InterfaceRequest<SkyEngine> request) {
  binding_.Bind(request.Pass());
}

void Engine::OnOutputSurfaceCreated(const base::Closure& gpu_continuation) {
  config_.gpu_task_runner->PostTask(FROM_HERE, gpu_continuation);
  have_surface_ = true;
  StartAnimatorIfPossible();
  if (sky_view_)
    ScheduleFrame();
}

void Engine::OnOutputSurfaceDestroyed(const base::Closure& gpu_continuation) {
  have_surface_ = false;
  StopAnimator();
  config_.gpu_task_runner->PostTask(FROM_HERE, gpu_continuation);
}

void Engine::SetServices(ServicesDataPtr services) {
  services_ = services.Pass();

  if (services_->incoming_services) {
    incoming_services_ = mojo::ServiceProviderPtr::Create(
        services_->incoming_services.Pass());
    service_provider_impl_.set_fallback_service_provider(
        incoming_services_.get());
  }

  if (services_->scene_scheduler) {
    animator_->Reset();
    animator_->set_scene_scheduler(services_->scene_scheduler.Pass());
  } else {
#if defined(OS_ANDROID) || defined(OS_IOS)
    vsync::VSyncProviderPtr vsync_provider;
    if (services_->shell) {
      // We bind and unbind our Shell here, since this is the only place we use
      // it in this class.
      auto shell = mojo::ShellPtr::Create(services_->shell.Pass());
      mojo::ConnectToService(shell.get(), "mojo:vsync", &vsync_provider);
      services_->shell = shell.Pass();
    } else {
      mojo::ConnectToService(incoming_services_.get(), &vsync_provider);
    }
    animator_->Reset();
    animator_->set_vsync_provider(vsync_provider.Pass());
#endif
  }
}

void Engine::OnViewportMetricsChanged(ViewportMetricsPtr metrics) {
  viewport_metrics_ = metrics.Pass();
  if (sky_view_)
    sky_view_->SetViewportMetrics(viewport_metrics_);
}

void Engine::OnLocaleChanged(const mojo::String& language_code,
                             const mojo::String& country_code) {
  language_code_ = language_code;
  country_code_ = country_code;
  if (sky_view_)
    sky_view_->SetLocale(language_code_, country_code_);
}

void Engine::OnPointerPacket(pointer::PointerPacketPtr packet) {
  TRACE_EVENT0("flutter", "Engine::OnPointerPacket");

  // Convert the pointers' x and y coordinates to logical pixels.
  for (auto it = packet->pointers.begin(); it != packet->pointers.end(); ++it) {
    (*it)->x /= viewport_metrics_->device_pixel_ratio;
    (*it)->y /= viewport_metrics_->device_pixel_ratio;
  }

  if (sky_view_)
    sky_view_->HandlePointerPacket(packet);
}

void Engine::RunFromLibrary(const std::string& name) {
  TRACE_EVENT0("flutter", "Engine::RunFromLibrary");
  sky_view_ = blink::SkyView::Create(this);
  sky_view_->CreateView(name);
  sky_view_->RunFromLibrary(name, dart_library_provider_.get());
  sky_view_->SetViewportMetrics(viewport_metrics_);
  sky_view_->SetLocale(language_code_, country_code_);
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
}

void Engine::RunFromSnapshotStream(
    const std::string& script_uri,
    mojo::ScopedDataPipeConsumerHandle snapshot) {
  TRACE_EVENT0("flutter", "Engine::RunFromSnapshotStream");
  sky_view_ = blink::SkyView::Create(this);
  sky_view_->CreateView(script_uri);
  sky_view_->RunFromSnapshot(snapshot.Pass());
  sky_view_->SetViewportMetrics(viewport_metrics_);
  sky_view_->SetLocale(language_code_, country_code_);
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
}

void Engine::ConfigureZipAssetBundle(const mojo::String& path) {
  zip_asset_bundle_ = new ZipAssetBundle(base::FilePath(std::string{path}),
                                         base::WorkerPool::GetTaskRunner(true));
  ZipAssetService::Create(mojo::GetProxy(&root_bundle_), zip_asset_bundle_);
}

void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot");

  ConfigureZipAssetBundle(bundle_path);

  sky_view_ = blink::SkyView::Create(this);
  sky_view_->CreateView("http://localhost");
  sky_view_->RunFromPrecompiledSnapshot();
  sky_view_->SetViewportMetrics(viewport_metrics_);
  sky_view_->SetLocale(language_code_, country_code_);
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
}

void Engine::RunFromFile(const mojo::String& main,
                         const mojo::String& packages,
                         const mojo::String& bundle) {
  TRACE_EVENT0("flutter", "Engine::RunFromFile");
  std::string main_str(main);
  if (bundle.size() != 0) {
    // The specification of an FLX bundle is optional.
    ConfigureZipAssetBundle(bundle);
  }
  base::FilePath packages_path = base::FilePath(std::string(packages));
  if (packages_path.empty()) {
    base::FilePath main_dir = base::FilePath(main_str).DirName();
    packages_path = main_dir.Append(FILE_PATH_LITERAL(".packages"));
    if (!base::PathExists(packages_path)) {
      packages_path = main_dir
          .Append(base::FilePath::kParentDirectory)
          .Append(FILE_PATH_LITERAL(".packages"));
      if (!base::PathExists(packages_path))
        packages_path = base::FilePath();
    }
  }
  DartLibraryProviderFiles* provider = new DartLibraryProviderFiles();
  dart_library_provider_.reset(provider);
  if (!packages_path.empty())
    provider->LoadPackagesMap(packages_path);
  RunFromLibrary(main_str);
}

void Engine::RunFromBundle(const mojo::String& script_uri,
                           const mojo::String& path) {
  TRACE_EVENT0("flutter", "Engine::RunFromBundle");

  ConfigureZipAssetBundle(path);

  root_bundle_->GetAsStream(
      blink::kSnapshotAssetKey,
      base::Bind(&Engine::RunFromSnapshotStream, weak_factory_.GetWeakPtr(),
                 script_uri));
}

void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
                                      const mojo::String& bundle_path,
                                      const mojo::String& snapshot_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromBundleAndSnapshot");

  ConfigureZipAssetBundle(bundle_path);

  std::string snapshot_path_str = snapshot_path;
  zip_asset_bundle_->AddOverlayFile(blink::kSnapshotAssetKey,
                                    base::FilePath(snapshot_path_str));

  root_bundle_->GetAsStream(
      blink::kSnapshotAssetKey,
      base::Bind(&Engine::RunFromSnapshotStream, weak_factory_.GetWeakPtr(),
                 script_uri));
}

void Engine::PushRoute(const mojo::String& route) {
  if (sky_view_)
    sky_view_->PushRoute(route);
  else
    initial_route_ = route;
}

void Engine::PopRoute() {
  if (sky_view_)
    sky_view_->PopRoute();
}

void Engine::OnAppLifecycleStateChanged(sky::AppLifecycleState state) {
  switch (state) {
    case sky::AppLifecycleState::PAUSED:
      activity_running_ = false;
      StopAnimator();
      break;

    case sky::AppLifecycleState::RESUMED:
      activity_running_ = true;
      StartAnimatorIfPossible();
      break;
  }

  if (sky_view_)
    sky_view_->OnAppLifecycleStateChanged(state);
}

void Engine::DidCreateMainIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
  service_provider_bindings_.AddBinding(
      &service_provider_impl_, mojo::GetProxy(&services_from_embedder));

  blink::MojoServices::Create(
      isolate, services_.Pass(), services_from_embedder.Pass(),
      root_bundle_.Pass());

  if (zip_asset_bundle_) {
    FlutterFontSelector::install(zip_asset_bundle_);
  }
}

void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
  mojo::InterfaceRequest<mojo::ServiceProvider> request =
      mojo::GetProxy(&services_from_embedder);
  blink::Platform::current()->GetUITaskRunner()->PostTask(FROM_HERE,
      base::Bind(&Engine::BindToServiceProvider,
                 weak_factory_.GetWeakPtr(),
                 base::Passed(&request)));

  blink::MojoServices::Create(
      isolate, nullptr, services_from_embedder.Pass(), nullptr);
}

void Engine::BindToServiceProvider(
    mojo::InterfaceRequest<mojo::ServiceProvider> request) {
  service_provider_bindings_.AddBinding(&service_provider_impl_,
                                        request.Pass());
}

void Engine::StopAnimator() {
  animator_->Stop();
}

void Engine::StartAnimatorIfPossible() {
  if (activity_running_ && have_surface_)
    animator_->Start();
}

void Engine::ScheduleFrame() {
  animator_->RequestFrame();
}

void Engine::FlushRealTimeEvents() {
  animator_->FlushRealTimeEvents();
}

void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {}

}  // namespace shell
}  // namespace sky
<commit_msg>Fix Mozart crash<commit_after>// Copyright 2015 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 "sky/shell/ui/engine.h"

#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/threading/worker_pool.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "mojo/data_pipe_utils/data_pipe_utils.h"
#include "mojo/public/cpp/application/connect.h"
#include "services/asset_bundle/zip_asset_bundle.h"
#include "sky/engine/bindings/mojo_services.h"
#include "sky/engine/core/script/dart_init.h"
#include "sky/engine/core/script/ui_dart_state.h"
#include "sky/engine/public/platform/WebInputEvent.h"
#include "sky/engine/public/web/Sky.h"
#include "sky/shell/dart/dart_library_provider_files.h"
#include "sky/shell/shell.h"
#include "sky/shell/ui/animator.h"
#include "sky/shell/ui/flutter_font_selector.h"
#include "sky/shell/ui/platform_impl.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"

namespace sky {
namespace shell {
namespace {

PlatformImpl* g_platform_impl = nullptr;

}  // namespace

using mojo::asset_bundle::ZipAssetBundle;
using mojo::asset_bundle::ZipAssetService;

Engine::Config::Config() {}

Engine::Config::~Config() {}

Engine::Engine(const Config& config, rasterizer::RasterizerPtr rasterizer)
    : config_(config),
      animator_(new Animator(config, rasterizer.Pass(), this)),
      binding_(this),
      activity_running_(false),
      have_surface_(false),
      weak_factory_(this) {}

Engine::~Engine() {}

base::WeakPtr<Engine> Engine::GetWeakPtr() {
  return weak_factory_.GetWeakPtr();
}

void Engine::Init() {
  TRACE_EVENT0("flutter", "Engine::Init");

  DCHECK(!g_platform_impl);
  g_platform_impl = new PlatformImpl();
  blink::initialize(g_platform_impl);
}

std::unique_ptr<flow::LayerTree> Engine::BeginFrame(
    base::TimeTicks frame_time) {
  TRACE_EVENT0("flutter", "Engine::BeginFrame");

  if (!sky_view_)
    return nullptr;

  auto begin_time = base::TimeTicks::Now();
  std::unique_ptr<flow::LayerTree> layer_tree =
      sky_view_->BeginFrame(frame_time);
  if (layer_tree) {
    if (viewport_metrics_) {
      layer_tree->set_scene_version(viewport_metrics_->scene_version);
      layer_tree->set_frame_size(SkISize::Make(viewport_metrics_->physical_width,
                                               viewport_metrics_->physical_height));
    } else {
      layer_tree->set_scene_version(0);
      layer_tree->set_frame_size(SkISize::Make(0, 0));
    }
    layer_tree->set_construction_time(base::TimeTicks::Now() - begin_time);
  }
  return layer_tree;
}

void Engine::ConnectToEngine(mojo::InterfaceRequest<SkyEngine> request) {
  binding_.Bind(request.Pass());
}

void Engine::OnOutputSurfaceCreated(const base::Closure& gpu_continuation) {
  config_.gpu_task_runner->PostTask(FROM_HERE, gpu_continuation);
  have_surface_ = true;
  StartAnimatorIfPossible();
  if (sky_view_)
    ScheduleFrame();
}

void Engine::OnOutputSurfaceDestroyed(const base::Closure& gpu_continuation) {
  have_surface_ = false;
  StopAnimator();
  config_.gpu_task_runner->PostTask(FROM_HERE, gpu_continuation);
}

void Engine::SetServices(ServicesDataPtr services) {
  services_ = services.Pass();

  if (services_->incoming_services) {
    incoming_services_ = mojo::ServiceProviderPtr::Create(
        services_->incoming_services.Pass());
    service_provider_impl_.set_fallback_service_provider(
        incoming_services_.get());
  }

  if (services_->scene_scheduler) {
    animator_->Reset();
    animator_->set_scene_scheduler(services_->scene_scheduler.Pass());
  } else {
#if defined(OS_ANDROID) || defined(OS_IOS)
    vsync::VSyncProviderPtr vsync_provider;
    if (services_->shell) {
      // We bind and unbind our Shell here, since this is the only place we use
      // it in this class.
      auto shell = mojo::ShellPtr::Create(services_->shell.Pass());
      mojo::ConnectToService(shell.get(), "mojo:vsync", &vsync_provider);
      services_->shell = shell.Pass();
    } else {
      mojo::ConnectToService(incoming_services_.get(), &vsync_provider);
    }
    animator_->Reset();
    animator_->set_vsync_provider(vsync_provider.Pass());
#endif
  }
}

void Engine::OnViewportMetricsChanged(ViewportMetricsPtr metrics) {
  viewport_metrics_ = metrics.Pass();
  if (sky_view_)
    sky_view_->SetViewportMetrics(viewport_metrics_);
}

void Engine::OnLocaleChanged(const mojo::String& language_code,
                             const mojo::String& country_code) {
  language_code_ = language_code;
  country_code_ = country_code;
  if (sky_view_)
    sky_view_->SetLocale(language_code_, country_code_);
}

void Engine::OnPointerPacket(pointer::PointerPacketPtr packet) {
  TRACE_EVENT0("flutter", "Engine::OnPointerPacket");

  // Convert the pointers' x and y coordinates to logical pixels.
  for (auto it = packet->pointers.begin(); it != packet->pointers.end(); ++it) {
    (*it)->x /= viewport_metrics_->device_pixel_ratio;
    (*it)->y /= viewport_metrics_->device_pixel_ratio;
  }

  if (sky_view_)
    sky_view_->HandlePointerPacket(packet);
}

void Engine::RunFromLibrary(const std::string& name) {
  TRACE_EVENT0("flutter", "Engine::RunFromLibrary");
  sky_view_ = blink::SkyView::Create(this);
  sky_view_->CreateView(name);
  sky_view_->RunFromLibrary(name, dart_library_provider_.get());
  sky_view_->SetViewportMetrics(viewport_metrics_);
  sky_view_->SetLocale(language_code_, country_code_);
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
}

void Engine::RunFromSnapshotStream(
    const std::string& script_uri,
    mojo::ScopedDataPipeConsumerHandle snapshot) {
  TRACE_EVENT0("flutter", "Engine::RunFromSnapshotStream");
  sky_view_ = blink::SkyView::Create(this);
  sky_view_->CreateView(script_uri);
  sky_view_->RunFromSnapshot(snapshot.Pass());
  sky_view_->SetViewportMetrics(viewport_metrics_);
  sky_view_->SetLocale(language_code_, country_code_);
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
}

void Engine::ConfigureZipAssetBundle(const mojo::String& path) {
  zip_asset_bundle_ = new ZipAssetBundle(base::FilePath(std::string{path}),
                                         base::WorkerPool::GetTaskRunner(true));
  ZipAssetService::Create(mojo::GetProxy(&root_bundle_), zip_asset_bundle_);
}

void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot");

  ConfigureZipAssetBundle(bundle_path);

  sky_view_ = blink::SkyView::Create(this);
  sky_view_->CreateView("http://localhost");
  sky_view_->RunFromPrecompiledSnapshot();
  sky_view_->SetViewportMetrics(viewport_metrics_);
  sky_view_->SetLocale(language_code_, country_code_);
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
}

void Engine::RunFromFile(const mojo::String& main,
                         const mojo::String& packages,
                         const mojo::String& bundle) {
  TRACE_EVENT0("flutter", "Engine::RunFromFile");
  std::string main_str(main);
  if (bundle.size() != 0) {
    // The specification of an FLX bundle is optional.
    ConfigureZipAssetBundle(bundle);
  }
  base::FilePath packages_path = base::FilePath(std::string(packages));
  if (packages_path.empty()) {
    base::FilePath main_dir = base::FilePath(main_str).DirName();
    packages_path = main_dir.Append(FILE_PATH_LITERAL(".packages"));
    if (!base::PathExists(packages_path)) {
      packages_path = main_dir
          .Append(base::FilePath::kParentDirectory)
          .Append(FILE_PATH_LITERAL(".packages"));
      if (!base::PathExists(packages_path))
        packages_path = base::FilePath();
    }
  }
  DartLibraryProviderFiles* provider = new DartLibraryProviderFiles();
  dart_library_provider_.reset(provider);
  if (!packages_path.empty())
    provider->LoadPackagesMap(packages_path);
  RunFromLibrary(main_str);
}

void Engine::RunFromBundle(const mojo::String& script_uri,
                           const mojo::String& path) {
  TRACE_EVENT0("flutter", "Engine::RunFromBundle");

  ConfigureZipAssetBundle(path);

  root_bundle_->GetAsStream(
      blink::kSnapshotAssetKey,
      base::Bind(&Engine::RunFromSnapshotStream, weak_factory_.GetWeakPtr(),
                 script_uri));
}

void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
                                      const mojo::String& bundle_path,
                                      const mojo::String& snapshot_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromBundleAndSnapshot");

  ConfigureZipAssetBundle(bundle_path);

  std::string snapshot_path_str = snapshot_path;
  zip_asset_bundle_->AddOverlayFile(blink::kSnapshotAssetKey,
                                    base::FilePath(snapshot_path_str));

  root_bundle_->GetAsStream(
      blink::kSnapshotAssetKey,
      base::Bind(&Engine::RunFromSnapshotStream, weak_factory_.GetWeakPtr(),
                 script_uri));
}

void Engine::PushRoute(const mojo::String& route) {
  if (sky_view_)
    sky_view_->PushRoute(route);
  else
    initial_route_ = route;
}

void Engine::PopRoute() {
  if (sky_view_)
    sky_view_->PopRoute();
}

void Engine::OnAppLifecycleStateChanged(sky::AppLifecycleState state) {
  switch (state) {
    case sky::AppLifecycleState::PAUSED:
      activity_running_ = false;
      StopAnimator();
      break;

    case sky::AppLifecycleState::RESUMED:
      activity_running_ = true;
      StartAnimatorIfPossible();
      break;
  }

  if (sky_view_)
    sky_view_->OnAppLifecycleStateChanged(state);
}

void Engine::DidCreateMainIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
  service_provider_bindings_.AddBinding(
      &service_provider_impl_, mojo::GetProxy(&services_from_embedder));

  blink::MojoServices::Create(
      isolate, services_.Pass(), services_from_embedder.Pass(),
      root_bundle_.Pass());

  if (zip_asset_bundle_) {
    FlutterFontSelector::install(zip_asset_bundle_);
  }
}

void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
  mojo::InterfaceRequest<mojo::ServiceProvider> request =
      mojo::GetProxy(&services_from_embedder);
  blink::Platform::current()->GetUITaskRunner()->PostTask(FROM_HERE,
      base::Bind(&Engine::BindToServiceProvider,
                 weak_factory_.GetWeakPtr(),
                 base::Passed(&request)));

  blink::MojoServices::Create(
      isolate, nullptr, services_from_embedder.Pass(), nullptr);
}

void Engine::BindToServiceProvider(
    mojo::InterfaceRequest<mojo::ServiceProvider> request) {
  service_provider_bindings_.AddBinding(&service_provider_impl_,
                                        request.Pass());
}

void Engine::StopAnimator() {
  animator_->Stop();
}

void Engine::StartAnimatorIfPossible() {
  if (activity_running_ && have_surface_)
    animator_->Start();
}

void Engine::ScheduleFrame() {
  animator_->RequestFrame();
}

void Engine::FlushRealTimeEvents() {
  animator_->FlushRealTimeEvents();
}

void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {}

}  // namespace shell
}  // namespace sky
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Google 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.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 "resource_cache.h"

#include <memory>

#include "core/cc/assert.h"
#include "replay_connection.h"

namespace gapir {

ResourceCache::ResourceCache(std::unique_ptr<ResourceProvider> fallbackProvider)
    : mFallbackProvider(std::move(fallbackProvider)) {}

bool ResourceCache::get(const Resource* resources, size_t count,
                        ReplayConnection* conn, void* target, size_t size) {
  uint8_t* dst = reinterpret_cast<uint8_t*>(target);
  Batch batch(dst, size);
  for (size_t i = 0; i < count; i++) {
    const Resource& resource = resources[i];
    if (size < resource.size) {
      return false;  // Not enough space
    }
    // Try fetching the resource from the cache.
    if (getCache(resource, dst)) {
      // In cache. Flush the pending requests.
      // Note: This implementation can result in many round trips to the
      // GAPIS, because whenever a cache hit happens, all the pending
      // resources accumulated before this resource must be fetched and
      // loaded prior to the cached resource to be loaded. The original
      // design was based around the idea that we could load the resource
      // directly into the destination buffer without temporary copies.
      // As gRPC forces us to have temporary copies, this implementation
      // should be changed to have a single fetch.
      // TODO: Update this batching logic to reduce the number of resource
      // fetching calls.
      if (!batch.flush(*this, conn)) {
        return false;  // Failed to get resources from fallback provider.
      }
      batch = Batch(dst, size);
    } else {
      // Not in cache.
      // Add this to the batch we need to request from the fallback provider.
      batch.append(resource);
    }
    dst += resource.size;
    size -= resource.size;
  }
  return batch.flush(*this, conn);
}

ResourceCache::Batch::Batch(void* target, size_t size)
    : mTarget(reinterpret_cast<uint8_t*>(target)), mSize(0), mSpace(size) {
  GAPID_ASSERT(target != nullptr);
}

bool ResourceCache::Batch::append(const Resource& resource) {
  if (mTarget == nullptr) {
    GAPID_FATAL("Cannot append after flush.");
  }
  if (mSpace < resource.size) {
    return false;
  }
  mResources.push_back(resource);
  mSize += resource.size;
  mSpace -= resource.size;
  return true;
}

bool ResourceCache::Batch::flush(ResourceCache& cache, ReplayConnection* conn) {
  uint8_t* ptr = mTarget;
  mTarget = nullptr;  // nullptr is used for detecting append-after-flush.
  size_t count = mResources.size();
  if (count == 0) {
    return true;
  }
  if (!cache.mFallbackProvider) {
    return false;
  }
  if (!cache.mFallbackProvider->get(mResources.data(), count, conn, ptr,
                                    mSize)) {
    return false;
  }
  for (auto resource : mResources) {
    cache.putCache(resource, ptr);
    ptr += resource.size;
  }
  return true;
}

}  // namespace gapir
<commit_msg>Limit the size of replay resource data chunks to reduce memory usage (#2171)<commit_after>/*
 * Copyright (C) 2017 Google 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.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 "resource_cache.h"

#include <memory>

#include "core/cc/assert.h"
#include "replay_connection.h"

namespace gapir {

ResourceCache::ResourceCache(std::unique_ptr<ResourceProvider> fallbackProvider)
    : mFallbackProvider(std::move(fallbackProvider)) {}

bool ResourceCache::get(const Resource* resources, size_t count,
                        ReplayConnection* conn, void* target, size_t size) {
  uint8_t* dst = reinterpret_cast<uint8_t*>(target);
  Batch batch(dst, size);
  for (size_t i = 0; i < count; i++) {
    const Resource& resource = resources[i];
    if (size < resource.size) {
      return false;  // Not enough space
    }
    // Try fetching the resource from the cache.
    if (getCache(resource, dst)) {
      // In cache. Flush the pending requests.
      // Note: This implementation can result in many round trips to the
      // GAPIS, because whenever a cache hit happens, all the pending
      // resources accumulated before this resource must be fetched and
      // loaded prior to the cached resource to be loaded. The original
      // design was based around the idea that we could load the resource
      // directly into the destination buffer without temporary copies.
      // As gRPC forces us to have temporary copies, this implementation
      // should be changed to have a single fetch.
      // TODO: Update this batching logic to reduce the number of resource
      // fetching calls.
      if (!batch.flush(*this, conn)) {
        return false;  // Failed to get resources from fallback provider.
      }
      batch = Batch(dst, size);
    } else {
      // Not in cache.
      // Add this to the batch we need to request from the fallback provider.
      batch.append(resource);
    }
    dst += resource.size;
    size -= resource.size;
  }
  return batch.flush(*this, conn);
}

ResourceCache::Batch::Batch(void* target, size_t size)
    : mTarget(reinterpret_cast<uint8_t*>(target)), mSize(0), mSpace(size) {
  GAPID_ASSERT(target != nullptr);
}

bool ResourceCache::Batch::append(const Resource& resource) {
  if (mTarget == nullptr) {
    GAPID_FATAL("Cannot append after flush.");
  }
  if (mSpace < resource.size) {
    return false;
  }
  mResources.push_back(resource);
  mSize += resource.size;
  mSpace -= resource.size;
  return true;
}

bool ResourceCache::Batch::flush(ResourceCache& cache, ReplayConnection* conn) {
  uint8_t* ptr = mTarget;
  mTarget = nullptr;  // nullptr is used for detecting append-after-flush.
  size_t count = mResources.size();
  if (count == 0) {
    return true;
  }
  if (!cache.mFallbackProvider) {
    return false;
  }
  size_t one_req_limit =
      100 * 1024 * 1024;  // limit 100MB unless there is only resource
  size_t i = 0;
  size_t j = 0;
  size_t one_req_size = 0;
  while (i < count) {
    if (((i != j) && (one_req_size + mResources[j].size > one_req_limit)) ||
        (j == mResources.size())) {
      if (!cache.mFallbackProvider->get(&mResources[i], j - i, conn, ptr,
                                        one_req_size)) {
        return false;
      }
      while (i < j) {
        cache.putCache(mResources[i], ptr);
        ptr += mResources[i].size;
        i++;
      }
      one_req_size = 0;
    }
    if (j < mResources.size()) {
      one_req_size += mResources[j].size;
      j++;
    }
  }
  return true;
}

}  // namespace gapir
<|endoftext|>