<commit_before>// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/VirtualDirectory.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <algorithm>
#include <cassert>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	inline VirtualDirectory::VirtualDirectory(std::weak_ptr<VirtualDirectory> parentDirectory) :
	m_parent(std::move(parentDirectory))
	{
	}

	inline VirtualDirectory::VirtualDirectory(std::filesystem::path physicalPath, std::weak_ptr<VirtualDirectory> parentDirectory) :
	m_physicalPath(std::move(physicalPath)),
	m_parent(std::move(parentDirectory))
	{
	}

	inline bool VirtualDirectory::Exists(std::string_view path)
	{
		return GetEntry(path, [](const auto&) {});
	}

	template<typename F>
	void VirtualDirectory::Foreach(F&& callback, bool includeDots)
	{
		if (includeDots)
		{
			Entry ourselves = DirectoryEntry{ shared_from_this() };
			callback(std::string_view("."), ourselves);
			if (VirtualDirectoryPtr parent = m_parent.lock())
			{
				Entry parentEntry = DirectoryEntry{ parent };
				if (!CallbackReturn(callback, std::string_view(".."), parentEntry))
					return;
			}
			else if (!CallbackReturn(callback, std::string_view(".."), ourselves))
					return;
		}

		for (auto&& entry : m_content)
		{
			if (!CallbackReturn(callback, std::string_view(entry.name), std::as_const(entry.entry)))
				return;
		}

		if (m_physicalPath)
		{
			for (auto&& physicalEntry : std::filesystem::directory_iterator(*m_physicalPath))
			{
				std::string filename = physicalEntry.path().filename().generic_u8string();

				// Check if physical file/directory has been overridden by a virtual one
				auto it = std::lower_bound(m_content.begin(), m_content.end(), filename, [](const ContentEntry& entry, std::string_view name)
				{
					return entry.name < name;
				});
				if (it != m_content.end() && it->name == filename)
					continue;

				std::filesystem::file_status status = physicalEntry.status();

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ physicalEntry.path() };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ physicalEntry.path() };
				else
					continue;

				if (!CallbackReturn(callback, std::string_view(filename), entry))
					return;
			}
		}
	}

	template<typename F> bool VirtualDirectory::GetEntry(std::string_view path, F&& callback)
	{
		assert(!path.empty());

		VirtualDirectoryPtr currentDir = shared_from_this();
		std::vector<std::string> physicalDirectoryParts;
		return SplitPath(path, [&](std::string_view dirName)
		{
			assert(!dirName.empty());

			if (!physicalDirectoryParts.empty())
			{
				// Special case when traversing directory
				if (dirName == "..")
				{
					// Don't allow to escape virtual directory
					if (!physicalDirectoryParts.empty())
						physicalDirectoryParts.pop_back();
				}
				else if (dirName != ".")
					physicalDirectoryParts.emplace_back(dirName);

				return true;
			}

			return currentDir->GetEntryInternal(dirName, [&](const Entry& entry)
			{
				if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
				{
					currentDir = dirEntry->directory;
					return true;
				}
				else if (auto physDirEntry = std::get_if<PhysicalDirectoryEntry>(&entry))
				{
					// We're traversing a physical directory
					physicalDirectoryParts.emplace_back(dirName);
					return true;
				}

				return false;
			});
		},
		[&](std::string_view name)
		{
			if (!physicalDirectoryParts.empty())
			{
				assert(m_physicalPath);
				std::filesystem::path filePath = *m_physicalPath;
				for (const auto& part : physicalDirectoryParts)
					filePath /= part;

				filePath /= name;

				std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ std::move(filePath) };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ std::move(filePath) };
				else
					return false; //< either not known or of a special type

				return CallbackReturn(callback, entry);
			}
			else
				return currentDir->GetEntryInternal(name, callback);
		});
	}

	inline auto VirtualDirectory::StoreDirectory(std::string_view path, VirtualDirectoryPtr directory) -> DirectoryEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), DirectoryEntry{ std::move(directory) });
	}

	inline auto VirtualDirectory::StoreDirectory(std::string_view path, std::filesystem::path directoryPath) -> PhysicalDirectoryEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), PhysicalDirectoryEntry{ std::move(directoryPath) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, std::vector<UInt8> file) -> FileContentEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), FileContentEntry{ std::move(file) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, std::filesystem::path filePath) -> PhysicalFileEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), PhysicalFileEntry{ std::move(filePath) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, const void* data, std::size_t size) -> DataPointerEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), DataPointerEntry{ data, size });
	}

	template<typename F> bool VirtualDirectory::GetEntryInternal(std::string_view name, F&& callback)
	{
		if (name == ".")
		{
			Entry entry{ DirectoryEntry{ shared_from_this() } };
			return CallbackReturn(callback, entry);
		}
		else if (name == "..")
		{
			Entry entry;
			if (VirtualDirectoryPtr parent = m_parent.lock())
				entry = DirectoryEntry{ std::move(parent) };
			else
				entry = DirectoryEntry{ shared_from_this() };

			return CallbackReturn(callback, entry);
		}
		else
		{
			auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
			{
				return entry.name < name;
			});
			if (it == m_content.end() || it->name != name)
			{
				// Virtual file not found, check if it has a physical one
				if (m_physicalPath)
				{
					std::filesystem::path filePath = *m_physicalPath / name;
					std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)

					Entry entry;
					if (std::filesystem::is_regular_file(status))
						entry = PhysicalFileEntry{ std::move(filePath) };
					else if (std::filesystem::is_directory(status))
						entry = PhysicalDirectoryEntry{ std::move(filePath) };
					else
						return false; //< either not known or of a special type

					return CallbackReturn(callback, entry);
				}

				return false;
			}

			return CallbackReturn(callback, it->entry);
		}
	}

	inline bool VirtualDirectory::CreateOrRetrieveDirectory(std::string_view path, std::shared_ptr<VirtualDirectory>& directory, std::string_view& entryName)
{
		directory = shared_from_this();

		bool allowCreation = true;
		return SplitPath(path, [&](std::string_view dirName)
		{
			assert(!dirName.empty());

			bool dirFound = directory->GetEntryInternal(dirName, [&](const Entry& entry)
			{
				if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
					directory = dirEntry->directory;
				else
					allowCreation = false; //< does exist but is not a directory
			});

			if (dirFound)
				return true;

			// Try to create a new directory
			if (!allowCreation)
				return false;

			auto newDirectory = std::make_shared<VirtualDirectory>(directory);
			directory->StoreDirectory(dirName, newDirectory);

			directory = std::move(newDirectory);
			return true;
		},
		[&](std::string_view name)
		{
			if (name.empty())
				return false;

			entryName = name;
			return true;
		});
	}

	template<typename T>
	T& VirtualDirectory::StoreInternal(std::string name, T value)
	{
		assert(!name.empty());

		auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
		{
			return entry.name < name;
		});

		ContentEntry* entryPtr;
		if (it == m_content.end() || it->name != name)
			entryPtr = &*m_content.emplace(it);
		else
			entryPtr = &*it;

		entryPtr->entry = std::move(value);
		entryPtr->name = std::move(name);

		return std::get<T>(entryPtr->entry);
	}

	template<typename F, typename... Args>
	bool VirtualDirectory::CallbackReturn(F&& callback, Args&& ...args)
	{
		using Ret = decltype(callback(std::forward<Args>(args)...));
		if constexpr (std::is_void_v<Ret>)
		{
			callback(std::forward<Args>(args)...);
			return true;
		}
		else
		{
			static_assert(std::is_same_v<Ret, bool>, "callback must either return a boolean or nothing");
			return callback(std::forward<Args>(args)...);
		}
	}

	template<typename F1, typename F2>
	bool VirtualDirectory::SplitPath(std::string_view path, F1&& dirCB, F2&& lastCB)
	{
		std::string_view nextPart;
		auto HandlePart = [&](std::string_view part)
		{
			if (part.empty())
				return true; //< "a//b" == "a/b"

			if (!nextPart.empty() && !CallbackReturn(dirCB, nextPart))
				return false;

			nextPart = part;
			return true;
		};

		return SplitStringAny(path, R"(\/:)", HandlePart) && CallbackReturn(lastCB, nextPart);
	}
}

#include <Nazara/Core/DebugOff.hpp>
<commit_msg>Core/VirtualDirectory: Fix physical path traversal<commit_after>// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/VirtualDirectory.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <algorithm>
#include <cassert>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	inline VirtualDirectory::VirtualDirectory(std::weak_ptr<VirtualDirectory> parentDirectory) :
	m_parent(std::move(parentDirectory))
	{
	}

	inline VirtualDirectory::VirtualDirectory(std::filesystem::path physicalPath, std::weak_ptr<VirtualDirectory> parentDirectory) :
	m_physicalPath(std::move(physicalPath)),
	m_parent(std::move(parentDirectory))
	{
	}

	inline bool VirtualDirectory::Exists(std::string_view path)
	{
		return GetEntry(path, [](const auto&) {});
	}

	template<typename F>
	void VirtualDirectory::Foreach(F&& callback, bool includeDots)
	{
		if (includeDots)
		{
			Entry ourselves = DirectoryEntry{ shared_from_this() };
			callback(std::string_view("."), ourselves);
			if (VirtualDirectoryPtr parent = m_parent.lock())
			{
				Entry parentEntry = DirectoryEntry{ parent };
				if (!CallbackReturn(callback, std::string_view(".."), parentEntry))
					return;
			}
			else if (!CallbackReturn(callback, std::string_view(".."), ourselves))
					return;
		}

		for (auto&& entry : m_content)
		{
			if (!CallbackReturn(callback, std::string_view(entry.name), std::as_const(entry.entry)))
				return;
		}

		if (m_physicalPath)
		{
			for (auto&& physicalEntry : std::filesystem::directory_iterator(*m_physicalPath))
			{
				std::string filename = physicalEntry.path().filename().generic_u8string();

				// Check if physical file/directory has been overridden by a virtual one
				auto it = std::lower_bound(m_content.begin(), m_content.end(), filename, [](const ContentEntry& entry, std::string_view name)
				{
					return entry.name < name;
				});
				if (it != m_content.end() && it->name == filename)
					continue;

				std::filesystem::file_status status = physicalEntry.status();

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ physicalEntry.path() };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ physicalEntry.path() };
				else
					continue;

				if (!CallbackReturn(callback, std::string_view(filename), entry))
					return;
			}
		}
	}

	template<typename F> bool VirtualDirectory::GetEntry(std::string_view path, F&& callback)
	{
		assert(!path.empty());

		VirtualDirectoryPtr currentDir = shared_from_this();
		std::optional<std::filesystem::path> physicalPathBase;
		std::vector<std::string> physicalDirectoryParts;
		return SplitPath(path, [&](std::string_view dirName)
		{
			assert(!dirName.empty());

			if (physicalPathBase)
			{
				// Special case when traversing directory
				if (dirName == "..")
				{
					// Don't allow to escape virtual directory
					if (!physicalDirectoryParts.empty())
						physicalDirectoryParts.pop_back();
					else
						physicalPathBase.reset();
				}
				else if (dirName != ".")
					physicalDirectoryParts.emplace_back(dirName);

				return true;
			}

			return currentDir->GetEntryInternal(dirName, [&](const Entry& entry)
			{
				if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
				{
					currentDir = dirEntry->directory;
					return true;
				}
				else if (auto physDirEntry = std::get_if<PhysicalDirectoryEntry>(&entry))
				{
					assert(!physicalPathBase);

					// We're traversing a physical directory
					physicalPathBase = physDirEntry->filePath;
					return true;
				}

				return false;
			});
		},
		[&](std::string_view name)
		{
			if (physicalPathBase)
			{
				std::filesystem::path filePath = *physicalPathBase;
				for (const auto& part : physicalDirectoryParts)
					filePath /= part;

				filePath /= name;

				std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ std::move(filePath) };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ std::move(filePath) };
				else
					return false; //< either not known or of a special type

				return CallbackReturn(callback, entry);
			}
			else
				return currentDir->GetEntryInternal(name, callback);
		});
	}

	inline auto VirtualDirectory::StoreDirectory(std::string_view path, VirtualDirectoryPtr directory) -> DirectoryEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), DirectoryEntry{ std::move(directory) });
	}

	inline auto VirtualDirectory::StoreDirectory(std::string_view path, std::filesystem::path directoryPath) -> PhysicalDirectoryEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), PhysicalDirectoryEntry{ std::move(directoryPath) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, std::vector<UInt8> file) -> FileContentEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), FileContentEntry{ std::move(file) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, std::filesystem::path filePath) -> PhysicalFileEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), PhysicalFileEntry{ std::move(filePath) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, const void* data, std::size_t size) -> DataPointerEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), DataPointerEntry{ data, size });
	}

	template<typename F> bool VirtualDirectory::GetEntryInternal(std::string_view name, F&& callback)
	{
		if (name == ".")
		{
			Entry entry{ DirectoryEntry{ shared_from_this() } };
			return CallbackReturn(callback, entry);
		}
		else if (name == "..")
		{
			Entry entry;
			if (VirtualDirectoryPtr parent = m_parent.lock())
				entry = DirectoryEntry{ std::move(parent) };
			else
				entry = DirectoryEntry{ shared_from_this() };

			return CallbackReturn(callback, entry);
		}
		else
		{
			auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
			{
				return entry.name < name;
			});
			if (it == m_content.end() || it->name != name)
			{
				// Virtual file not found, check if it has a physical one
				if (m_physicalPath)
				{
					std::filesystem::path filePath = *m_physicalPath / name;
					std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)

					Entry entry;
					if (std::filesystem::is_regular_file(status))
						entry = PhysicalFileEntry{ std::move(filePath) };
					else if (std::filesystem::is_directory(status))
						entry = PhysicalDirectoryEntry{ std::move(filePath) };
					else
						return false; //< either not known or of a special type

					return CallbackReturn(callback, entry);
				}

				return false;
			}

			return CallbackReturn(callback, it->entry);
		}
	}

	inline bool VirtualDirectory::CreateOrRetrieveDirectory(std::string_view path, std::shared_ptr<VirtualDirectory>& directory, std::string_view& entryName)
{
		directory = shared_from_this();

		bool allowCreation = true;
		return SplitPath(path, [&](std::string_view dirName)
		{
			assert(!dirName.empty());

			bool dirFound = directory->GetEntryInternal(dirName, [&](const Entry& entry)
			{
				if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
					directory = dirEntry->directory;
				else
					allowCreation = false; //< does exist but is not a directory
			});

			if (dirFound)
				return true;

			// Try to create a new directory
			if (!allowCreation)
				return false;

			auto newDirectory = std::make_shared<VirtualDirectory>(directory);
			directory->StoreDirectory(dirName, newDirectory);

			directory = std::move(newDirectory);
			return true;
		},
		[&](std::string_view name)
		{
			if (name.empty())
				return false;

			entryName = name;
			return true;
		});
	}

	template<typename T>
	T& VirtualDirectory::StoreInternal(std::string name, T value)
	{
		assert(!name.empty());

		auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
		{
			return entry.name < name;
		});

		ContentEntry* entryPtr;
		if (it == m_content.end() || it->name != name)
			entryPtr = &*m_content.emplace(it);
		else
			entryPtr = &*it;

		entryPtr->entry = std::move(value);
		entryPtr->name = std::move(name);

		return std::get<T>(entryPtr->entry);
	}

	template<typename F, typename... Args>
	bool VirtualDirectory::CallbackReturn(F&& callback, Args&& ...args)
	{
		using Ret = decltype(callback(std::forward<Args>(args)...));
		if constexpr (std::is_void_v<Ret>)
		{
			callback(std::forward<Args>(args)...);
			return true;
		}
		else
		{
			static_assert(std::is_same_v<Ret, bool>, "callback must either return a boolean or nothing");
			return callback(std::forward<Args>(args)...);
		}
	}

	template<typename F1, typename F2>
	bool VirtualDirectory::SplitPath(std::string_view path, F1&& dirCB, F2&& lastCB)
	{
		std::string_view nextPart;
		auto HandlePart = [&](std::string_view part)
		{
			if (part.empty())
				return true; //< "a//b" == "a/b"

			if (!nextPart.empty() && !CallbackReturn(dirCB, nextPart))
				return false;

			nextPart = part;
			return true;
		};

		return SplitStringAny(path, R"(\/:)", HandlePart) && CallbackReturn(lastCB, nextPart);
	}
}

#include <Nazara/Core/DebugOff.hpp>
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          svn.cpp
* Purpose:       Implementation of wxExSVN class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/extension/svn.h>
#include <wx/extension/configdlg.h>
#include <wx/extension/defs.h>
#include <wx/extension/log.h>
#include <wx/extension/stc.h>

#if wxUSE_GUI

wxExSTCEntryDialog* wxExSVN::m_STCEntryDialog = NULL;

wxExSVN::wxExSVN(int command_id, const wxString& fullpath)
  : m_Type(GetType(command_id))
  , m_FullPath(fullpath)
{
  Initialize();
}

wxExSVN::wxExSVN(wxExSVNType type, const wxString& fullpath)
  : m_Type(type)
  , m_FullPath(fullpath)
{
  Initialize();
}

void wxExSVN::Cleanup()
{
  delete m_STCEntryDialog;
}

bool wxExSVN::DirExists(const wxFileName& filename)
{
  wxFileName path(filename);
  path.AppendDir(".svn");
  return path.DirExists();
}

wxStandardID wxExSVN::Execute(wxWindow* parent)
{
  const wxString svn_flags_name = wxString::Format("svn/flags%d", m_Type);
  const wxString svn_flags_contents = wxConfigBase::Get()->Read(svn_flags_name);

  if (parent != NULL)
  {
    std::vector<wxExConfigItem> v;

    if (m_Type == SVN_COMMIT)
    {
      v.push_back(wxExConfigItem(
        _("Revision comment"),
        CONFIG_COMBOBOX,
        wxEmptyString,
        true)); // required
    }

    if (m_FullPath.empty() && m_Type != SVN_HELP)
    {
      v.push_back(wxExConfigItem(
        _("Base folder"),
        CONFIG_COMBOBOXDIR,
        wxEmptyString,
        true)); // required
    }

    // SVN_UPDATE and SVN_HELP have no flags to ask for.
    if (m_Type != SVN_UPDATE && m_Type != SVN_HELP)
    {
      wxConfigBase::Get()->Write(_("Flags"), svn_flags_contents);
      v.push_back(wxExConfigItem(_("Flags")));
    }

    // Instead, SVN_HELP has an extra subcommand.
    if (m_Type == SVN_HELP)
    {
      v.push_back(wxExConfigItem(_("Subcommand")));
    }

    m_ReturnCode = (wxStandardID)wxExConfigDialog(parent,
      v,
      m_Caption).ShowModal();

    if (m_ReturnCode == wxID_CANCEL)
    {
      return m_ReturnCode;
    }
  }

  const wxString cwd = wxGetCwd();

  wxString file;

  if (m_FullPath.empty())
  {
    wxSetWorkingDirectory(wxConfigBase::Get()->Read(_("Base folder")));
  }
  else
  {
    file = " \"" + m_FullPath + "\"";
  }

  wxString comment;

  if (m_Type == SVN_COMMIT)
  {
    comment = " -m \"" + wxConfigBase::Get()->Read(_("Revision comment")) + "\"";
  }

  wxString flags;
  wxString subcommand;

  if (m_Type == SVN_HELP)
  {
    subcommand = wxConfigBase::Get()->Read(_("Subcommand"));

    if (!subcommand.empty())
    {
      subcommand = " " + subcommand;
    }
  }
  else
  {
    flags = wxConfigBase::Get()->Read(_("Flags"));

    wxConfigBase::Get()->Write(svn_flags_name, flags);

    m_CommandWithFlags = m_Command + " " + flags;

    if (!flags.empty())
    {
      flags += " ";
    }
  }

  const wxString command =
    "svn " + flags + m_Command + subcommand + comment + file;

  wxArrayString output;
  wxArrayString errors;
  m_Output.clear();

  if (wxExecute(
    command,
    output,
    errors) == -1)
  {
    if (m_Output.empty())
    {
      m_Output = "Could not execute: " + command;
    }

    m_ReturnCode = wxID_ABORT;
    return m_ReturnCode;
  }

  wxExLog::Get()->Log(command);

  if (m_FullPath.empty())
  {
    wxSetWorkingDirectory(cwd);
  }

  // First output the errors.
  for (size_t i = 0; i < errors.GetCount(); i++)
  {
    m_Output += errors[i] + "\n";
  }

  // Then the normal output, will be empty if there are errors.
  for (size_t j = 0; j < output.GetCount(); j++)
  {
    m_Output += output[j] + "\n";
  }

  return wxID_OK;
}

wxStandardID wxExSVN::ExecuteAndShowOutput(wxWindow* parent)
{
  // If an error occurred, already shown by wxExecute itself.
  if (Execute(parent) == wxID_OK)
  {
    ShowOutput(parent);
  }

  return m_ReturnCode;
}

wxExSVNType wxExSVN::GetType(int command_id) const
{
  switch (command_id)
  {
    case ID_EDIT_SVN_BLAME: return SVN_BLAME; break;
    case ID_EDIT_SVN_CAT: return SVN_CAT; break;
    case ID_EDIT_SVN_COMMIT: return SVN_COMMIT; break;
    case ID_EDIT_SVN_DIFF: return SVN_DIFF; break;
    case ID_EDIT_SVN_HELP: return SVN_HELP; break;
    case ID_EDIT_SVN_INFO: return SVN_INFO; break;
    case ID_EDIT_SVN_LOG: return SVN_LOG; break;
    case ID_EDIT_SVN_REVERT: return SVN_REVERT; break;
    case ID_EDIT_SVN_STAT: return SVN_STAT; break;
    case ID_EDIT_SVN_UPDATE: return SVN_UPDATE; break;
    default:
      wxFAIL;
      return SVN_STAT;
      break;
  }
}

void wxExSVN::Initialize()
{
  switch (m_Type)
  {
    case SVN_BLAME:  m_Caption = "SVN Blame"; break;
    case SVN_CAT:    m_Caption = "SVN Cat"; break;
    case SVN_COMMIT: m_Caption = "SVN Commit"; break;
    case SVN_DIFF:   m_Caption = "SVN Diff"; break;
    case SVN_HELP:   m_Caption = "SVN Help"; break;
    case SVN_INFO:   m_Caption = "SVN Info"; break;
    case SVN_LOG:    m_Caption = "SVN Log"; break;
    case SVN_REVERT: m_Caption = "SVN Revert"; break;
    case SVN_STAT:   m_Caption = "SVN Stat"; break;
    case SVN_UPDATE: m_Caption = "SVN Update"; break;
    default:
      wxFAIL;
      break;
  }

  m_Command = m_Caption.AfterFirst(' ').Lower();

  // Currently no flags, as no command was executed.
  m_CommandWithFlags = m_Command;

  m_Output.clear();
  m_ReturnCode = wxID_NONE;
}

void wxExSVN::ShowOutput(wxWindow* parent) const
{
  switch (m_ReturnCode)
  {
    case wxID_CANCEL:
      break;

    case wxID_ABORT:
      wxMessageBox(m_Output);
      break;

    case wxID_OK:
    {
      const wxString caption = m_Caption +
        (!m_FullPath.empty() ? " " + wxFileName(m_FullPath).GetFullName(): wxString(wxEmptyString));

      // Create a dialog for contents.
      if (m_STCEntryDialog == NULL)
      {
        m_STCEntryDialog = new wxExSTCEntryDialog(
          parent,
          caption,
          m_Output,
          wxEmptyString,
          wxOK,
          wxID_ANY,
          wxDefaultPosition, wxSize(575, 250));
      }
      else
      {
        m_STCEntryDialog->SetText(m_Output);
        m_STCEntryDialog->SetTitle(caption);

        // Reset a previous lexer.
        if (!m_STCEntryDialog->GetLexer().empty())
        {
          m_STCEntryDialog->SetLexer(wxEmptyString);
        }
      }

      // Add a lexer if we specified a path, asked for cat or blame
      // and there is a lexer.
      if (
        !m_FullPath.empty() &&
        (m_Type == SVN_CAT || m_Type == SVN_BLAME))
      {
        const wxExFileName fn(m_FullPath);

        if (!fn.GetLexer().GetScintillaLexer().empty())
        {
          m_STCEntryDialog->SetLexer(fn.GetLexer().GetScintillaLexer());
        }
      }

      m_STCEntryDialog->Show();
    }
    break;

    default:
      wxFAIL;
      break;
  }
}

#endif
<commit_msg>fixed svn update, it has no flags<commit_after>/******************************************************************************\
* File:          svn.cpp
* Purpose:       Implementation of wxExSVN class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/extension/svn.h>
#include <wx/extension/configdlg.h>
#include <wx/extension/defs.h>
#include <wx/extension/log.h>
#include <wx/extension/stc.h>

#if wxUSE_GUI

wxExSTCEntryDialog* wxExSVN::m_STCEntryDialog = NULL;

wxExSVN::wxExSVN(int command_id, const wxString& fullpath)
  : m_Type(GetType(command_id))
  , m_FullPath(fullpath)
{
  Initialize();
}

wxExSVN::wxExSVN(wxExSVNType type, const wxString& fullpath)
  : m_Type(type)
  , m_FullPath(fullpath)
{
  Initialize();
}

void wxExSVN::Cleanup()
{
  delete m_STCEntryDialog;
}

bool wxExSVN::DirExists(const wxFileName& filename)
{
  wxFileName path(filename);
  path.AppendDir(".svn");
  return path.DirExists();
}

wxStandardID wxExSVN::Execute(wxWindow* parent)
{
  const wxString svn_flags_name = wxString::Format("svn/flags%d", m_Type);
  const wxString svn_flags_contents = wxConfigBase::Get()->Read(svn_flags_name);

  if (parent != NULL)
  {
    std::vector<wxExConfigItem> v;

    if (m_Type == SVN_COMMIT)
    {
      v.push_back(wxExConfigItem(
        _("Revision comment"),
        CONFIG_COMBOBOX,
        wxEmptyString,
        true)); // required
    }

    if (m_FullPath.empty() && m_Type != SVN_HELP)
    {
      v.push_back(wxExConfigItem(
        _("Base folder"),
        CONFIG_COMBOBOXDIR,
        wxEmptyString,
        true)); // required
    }

    // SVN_UPDATE and SVN_HELP have no flags to ask for.
    if (m_Type != SVN_UPDATE && m_Type != SVN_HELP)
    {
      wxConfigBase::Get()->Write(_("Flags"), svn_flags_contents);
      v.push_back(wxExConfigItem(_("Flags")));
    }

    // Instead, SVN_HELP has an extra subcommand.
    if (m_Type == SVN_HELP)
    {
      v.push_back(wxExConfigItem(_("Subcommand")));
    }

    m_ReturnCode = (wxStandardID)wxExConfigDialog(parent,
      v,
      m_Caption).ShowModal();

    if (m_ReturnCode == wxID_CANCEL)
    {
      return m_ReturnCode;
    }
  }

  const wxString cwd = wxGetCwd();

  wxString file;

  if (m_FullPath.empty())
  {
    wxSetWorkingDirectory(wxConfigBase::Get()->Read(_("Base folder")));
  }
  else
  {
    file = " \"" + m_FullPath + "\"";
  }

  wxString comment;

  if (m_Type == SVN_COMMIT)
  {
    comment =
      " -m \"" + wxConfigBase::Get()->Read(_("Revision comment"))
      + "\"";
  }

  wxString flags;
  wxString subcommand;

  // SVN_UPDATE and SVN_HELP have no flags to ask for.
  if (m_Type == SVN_UPDATE || m_Type == SVN_HELP)
  {
    if (m_Type == SVN_HELP)
    {
      subcommand = wxConfigBase::Get()->Read(_("Subcommand"));

      if (!subcommand.empty())
      {
        subcommand = " " + subcommand;
      }
    }
  }
  else
  {
    flags = wxConfigBase::Get()->Read(_("Flags"));

    wxConfigBase::Get()->Write(svn_flags_name, flags);

    m_CommandWithFlags = m_Command + " " + flags;

    if (!flags.empty())
    {
      flags += " ";
    }
  }

  const wxString command =
    "svn " + flags + m_Command + subcommand + comment + file;

  wxArrayString output;
  wxArrayString errors;
  m_Output.clear();

  if (wxExecute(
    command,
    output,
    errors) == -1)
  {
    if (m_Output.empty())
    {
      m_Output = "Could not execute: " + command;
    }

    m_ReturnCode = wxID_ABORT;
    return m_ReturnCode;
  }

  wxExLog::Get()->Log(command);

  if (m_FullPath.empty())
  {
    wxSetWorkingDirectory(cwd);
  }

  // First output the errors.
  for (size_t i = 0; i < errors.GetCount(); i++)
  {
    m_Output += errors[i] + "\n";
  }

  // Then the normal output, will be empty if there are errors.
  for (size_t j = 0; j < output.GetCount(); j++)
  {
    m_Output += output[j] + "\n";
  }

  return wxID_OK;
}

wxStandardID wxExSVN::ExecuteAndShowOutput(wxWindow* parent)
{
  // If an error occurred, already shown by wxExecute itself.
  if (Execute(parent) == wxID_OK)
  {
    ShowOutput(parent);
  }

  return m_ReturnCode;
}

wxExSVNType wxExSVN::GetType(int command_id) const
{
  switch (command_id)
  {
    case ID_EDIT_SVN_BLAME: return SVN_BLAME; break;
    case ID_EDIT_SVN_CAT: return SVN_CAT; break;
    case ID_EDIT_SVN_COMMIT: return SVN_COMMIT; break;
    case ID_EDIT_SVN_DIFF: return SVN_DIFF; break;
    case ID_EDIT_SVN_HELP: return SVN_HELP; break;
    case ID_EDIT_SVN_INFO: return SVN_INFO; break;
    case ID_EDIT_SVN_LOG: return SVN_LOG; break;
    case ID_EDIT_SVN_REVERT: return SVN_REVERT; break;
    case ID_EDIT_SVN_STAT: return SVN_STAT; break;
    case ID_EDIT_SVN_UPDATE: return SVN_UPDATE; break;
    default:
      wxFAIL;
      return SVN_STAT;
      break;
  }
}

void wxExSVN::Initialize()
{
  switch (m_Type)
  {
    case SVN_BLAME:  m_Caption = "SVN Blame"; break;
    case SVN_CAT:    m_Caption = "SVN Cat"; break;
    case SVN_COMMIT: m_Caption = "SVN Commit"; break;
    case SVN_DIFF:   m_Caption = "SVN Diff"; break;
    case SVN_HELP:   m_Caption = "SVN Help"; break;
    case SVN_INFO:   m_Caption = "SVN Info"; break;
    case SVN_LOG:    m_Caption = "SVN Log"; break;
    case SVN_REVERT: m_Caption = "SVN Revert"; break;
    case SVN_STAT:   m_Caption = "SVN Stat"; break;
    case SVN_UPDATE: m_Caption = "SVN Update"; break;
    default:
      wxFAIL;
      break;
  }

  m_Command = m_Caption.AfterFirst(' ').Lower();

  // Currently no flags, as no command was executed.
  m_CommandWithFlags = m_Command;

  m_Output.clear();
  m_ReturnCode = wxID_NONE;
}

void wxExSVN::ShowOutput(wxWindow* parent) const
{
  switch (m_ReturnCode)
  {
    case wxID_CANCEL:
      break;

    case wxID_ABORT:
      wxMessageBox(m_Output);
      break;

    case wxID_OK:
    {
      const wxString caption = m_Caption +
        (!m_FullPath.empty() ? " " +
            wxFileName(m_FullPath).GetFullName():
            wxString(wxEmptyString));

      // Create a dialog for contents.
      if (m_STCEntryDialog == NULL)
      {
        m_STCEntryDialog = new wxExSTCEntryDialog(
          parent,
          caption,
          m_Output,
          wxEmptyString,
          wxOK,
          wxID_ANY,
          wxDefaultPosition, wxSize(575, 250));
      }
      else
      {
        m_STCEntryDialog->SetText(m_Output);
        m_STCEntryDialog->SetTitle(caption);

        // Reset a previous lexer.
        if (!m_STCEntryDialog->GetLexer().empty())
        {
          m_STCEntryDialog->SetLexer(wxEmptyString);
        }
      }

      // Add a lexer if we specified a path, asked for cat or blame
      // and there is a lexer.
      if (
        !m_FullPath.empty() &&
        (m_Type == SVN_CAT || m_Type == SVN_BLAME))
      {
        const wxExFileName fn(m_FullPath);

        if (!fn.GetLexer().GetScintillaLexer().empty())
        {
          m_STCEntryDialog->SetLexer(fn.GetLexer().GetScintillaLexer());
        }
      }

      m_STCEntryDialog->Show();
    }
    break;

    default:
      wxFAIL;
      break;
  }
}

#endif
<|endoftext|>


<commit_before>#pragma once

#include <cstdint>
#include <cmath>

#include <Eigen/Sparse>
#include <Eigen/Dense>

#include <crest/geometry/indexed_mesh.hpp>
#include <crest/util/eigen_extensions.hpp>
#include <crest/quadrature/triquad.hpp>
#include <crest/basis/basis.hpp>

namespace crest
{
    /**
     * A standard linear Lagrangian basis
     */
    template <typename Scalar>
    class LagrangeBasis2d : public Basis<Scalar, LagrangeBasis2d<Scalar>>
    {
    public:
        explicit LagrangeBasis2d(const IndexedMesh<Scalar, int> & mesh) : _mesh(mesh) {}

        virtual std::vector<int> boundary_nodes() const override { return _mesh.boundary_vertices(); }
        virtual std::vector<int> interior_nodes() const override { return _mesh.compute_interior_vertices(); }

        virtual Assembly<Scalar> assemble() const override;

        virtual int num_dof() const override { return _mesh.num_vertices(); }

        template <typename Function2d>
        VectorX<Scalar> interpolate(const Function2d &f) const;

        template <int QuadStrength, typename Function2d>
        VectorX<Scalar> load(const Function2d &f) const;

        template <int QuadStrength, typename Function2d>
        Scalar error_l2(const Function2d &f, const VectorX<Scalar> & weights) const;

        template <int QuadStrength, typename Function2d_x, typename Function2d_y>
        Scalar error_h1_semi(const Function2d_x & f_x,
                             const Function2d_y & f_y,
                             const VectorX<Scalar> & weights) const;

    private:
        const IndexedMesh<double, int> & _mesh;
    };

    namespace detail
    {
        template <typename Scalar>
        struct assembly_triplets {
            std::vector<Eigen::Triplet<Scalar>> stiffness_triplets;
            std::vector<Eigen::Triplet<Scalar>> mass_triplets;
        };

        template <typename Scalar>
        assembly_triplets<Scalar> assemble_linear_lagrangian_stiffness_triplets(
                const crest::IndexedMesh<Scalar, int> &mesh);
    }

    /*
     * IMPLEMENTATION BELOW
     */

    template <typename Scalar>
    detail::assembly_triplets<Scalar> detail::assemble_linear_lagrangian_stiffness_triplets(
            const crest::IndexedMesh<Scalar, int> &mesh)
    {
        const static Eigen::Matrix<Scalar, 3, 3> M_LOCAL_REF = (1.0 / 24.0) * (Eigen::Matrix3d()
                <<
                2.0, 1.0, 1.0,
                1.0, 2.0, 1.0,
                1.0, 1.0, 2.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A11 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                1.0, 0.0, -1.0,
                0.0, 0.0, 0.0,
                -1.0, 0.0, 1.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A12 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                0.0, 1.0, -1.0,
                1.0, 0.0, -1.0,
                -1.0, -1.0, 2.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A22 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                0.0, 0.0, 0.0,
                0.0, 1.0, -1.0,
                0.0, -1.0, 1.0
        ).finished().cast<Scalar>();

        std::vector<Eigen::Triplet<Scalar>> mass_triplets;
        std::vector<Eigen::Triplet<Scalar>> stiffness_triplets;
        mass_triplets.reserve(3 * mesh.num_elements());
        stiffness_triplets.reserve(3 * mesh.num_elements());

        for (const auto & element : mesh.elements())
        {
            const auto a = mesh.vertices()[element.vertex_indices[0]];
            const auto b = mesh.vertices()[element.vertex_indices[1]];
            const auto c = mesh.vertices()[element.vertex_indices[2]];

            const auto v1 = a - c;
            const auto v2 = b - c;

            const Eigen::Matrix2d jacobian = (Eigen::Matrix2d() << v1.x, v2.x, v1.y, v2.y).finished();
            const Eigen::Matrix2d jacobian_inverse = jacobian.inverse();
            const Eigen::Matrix2d C = jacobian_inverse * jacobian_inverse.transpose();
            const auto abs_det_jacobian = std::abs(jacobian.determinant());

            const Eigen::Matrix<Scalar, 3, 3> A_local = abs_det_jacobian * (C(0, 0) * A11 + C(0, 1) * A12 + C(1, 1) * A22);
            const Eigen::Matrix<Scalar, 3, 3> M_local = abs_det_jacobian * M_LOCAL_REF;

            typedef Eigen::Triplet<Scalar> T;
            for (size_t i = 0; i < 3; ++i)
            {
                for (size_t j = 0; j < 3; ++j)
                {
                    const auto I = element.vertex_indices[i];
                    const auto J = element.vertex_indices[j];
                    mass_triplets.emplace_back(T(I, J, M_local(i, j)));
                    stiffness_triplets.emplace_back(T(I, J, A_local(i, j)));
                }
            }
        }

        return detail::assembly_triplets<Scalar> {
                std::move(stiffness_triplets),
                std::move(mass_triplets)
        };
    }

    template <typename Scalar>
    Assembly<Scalar> LagrangeBasis2d<Scalar>::assemble() const
    {
        const auto triplets = detail::assemble_linear_lagrangian_stiffness_triplets(_mesh);

        Assembly<Scalar> assembly;

        // Stiffness
        assembly.stiffness = Eigen::SparseMatrix<Scalar>(num_dof(), num_dof());
        assembly.stiffness.setFromTriplets(triplets.stiffness_triplets.cbegin(), triplets.stiffness_triplets.cend());

        // Mass
        assembly.mass = Eigen::SparseMatrix<Scalar>(num_dof(), num_dof());
        assembly.mass.setFromTriplets(triplets.mass_triplets.cbegin(), triplets.mass_triplets.cend());

        return assembly;
    }

    template <typename Scalar>
    template <int QuadStrength, typename Function2d>
    VectorX<Scalar> LagrangeBasis2d<Scalar>::load(const Function2d & f) const
    {
        Eigen::VectorXd load(_mesh.num_vertices());
        load.setZero();

        // See triquad.hpp for the mapping used here
        const auto a_basis = [] (auto x, auto  ) { return Scalar(0.5) * x + Scalar(0.5); };
        const auto b_basis = [] (auto  , auto y) { return Scalar(0.5) * y + Scalar(0.5); };
        const auto c_basis = [] (auto x, auto y) { return Scalar(0.5) * (-x - y); };

        for (const auto element : _mesh.elements())
        {
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);
            const auto transformed_f = [&f, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                return f(coords.x, coords.y);
            };

            const auto absdet = transform.absolute_determinant();

            load(z0) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * a_basis(x, y); }
            );
            load(z1) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * b_basis(x, y); }
            );
            load(z2) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * c_basis(x, y); }
            );
        }

        return load;
    }

    template <typename Scalar>
    template <typename Function2d>
    VectorX<Scalar> LagrangeBasis2d<Scalar>::interpolate(const Function2d & f) const
    {
        // Simple nodal interpolation
        auto result = VectorX<Scalar>(_mesh.num_vertices());
        for (int i = 0; i < _mesh.num_vertices(); ++i)
        {
            const auto vertex = _mesh.vertices()[i];
            result(i) = f(vertex.x, vertex.y);
        }
        return result;
    }

    template <typename Scalar>
    template <int QuadStrength, typename Function2d>
    Scalar LagrangeBasis2d<Scalar>::error_l2(const Function2d &f, const VectorX<Scalar> & weights) const
    {
        Scalar error_squared = Scalar(0);

        // See triquad.hpp for the mapping used here
        const auto basis0 = [] (auto x, auto  ) { return Scalar(0.5) * x + Scalar(0.5); };
        const auto basis1 = [] (auto  , auto y) { return Scalar(0.5) * y + Scalar(0.5); };
        const auto basis2 = [] (auto x, auto y) { return Scalar(0.5) * (-x - y); };

        for (const auto element : _mesh.elements())
        {
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto w0 = weights(z0);
            const auto w1 = weights(z1);
            const auto w2 = weights(z2);

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);
            const auto f_ref = [&f, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                return f(coords.x, coords.y);
            };

            // Computes the square of the difference of f and f_h in the reference triangle
            const auto diff_ref_squared = [&] (auto x, auto y)
            {
                const auto f_h_ref = w0 * basis0(x, y) +
                                     w1 * basis1(x, y) +
                                     w2 * basis2(x, y);

                const auto diff = f_ref(x, y) - f_h_ref;
                return diff * diff;
            };

            const auto absdet = transform.absolute_determinant();
            error_squared += absdet * triquad_ref<QuadStrength, Scalar>(diff_ref_squared);
        }

        return std::sqrt(error_squared);
    };

    template <typename Scalar>
    template <int QuadStrength, typename Function2d_x, typename Function2d_y>
    Scalar LagrangeBasis2d<Scalar>::error_h1_semi(const Function2d_x & f_x,
                                                  const Function2d_y & f_y,
                                                  const VectorX<Scalar> & weights) const
    {
        Scalar error_squared = Scalar(0);

        // See triquad.hpp for the mapping used here
        const auto basis0_x = Scalar(0.5);
        const auto basis0_y = Scalar(0.0);
        const auto basis1_x = Scalar(0.0);
        const auto basis1_y = Scalar(0.5);
        const auto basis2_x = Scalar(-0.5);
        const auto basis2_y = Scalar(-0.5);

        for (const auto element : _mesh.elements())
        {
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto w0 = weights(z0);
            const auto w1 = weights(z1);
            const auto w2 = weights(z2);

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);

            const auto f_grad_ref = [&f_x, &f_y, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                Eigen::Matrix<Scalar, 2, 1> grad;
                grad(0) = f_x(coords.x, coords.y);
                grad(1) = f_y(coords.x, coords.y);
                return grad;
            };

            // Since we have linear elements, the gradients are constants
            Eigen::Matrix<Scalar, 2, 1> f_h_grad_ref;
            f_h_grad_ref(0) = w0 * basis0_x +
                              w1 * basis1_x +
                              w2 * basis2_x;
            f_h_grad_ref(1) = w0 * basis0_y +
                              w1 * basis1_y +
                              w2 * basis2_y;

            // Due to change of variables, we have to left-apply J^-T
            const auto J_inv_t = transform.jacobian().inverse().transpose();
            const Eigen::Matrix<Scalar, 2, 1> f_h_grad_ref_transformed = J_inv_t * f_h_grad_ref;

            // Computes the square of the difference of grad(f) and grad(f_h)
            // in the reference triangle
            const auto diff_squared = [&] (auto x, auto y)
            {
                // Note that J_inv_t cancels with J_t for f_grad_ref
                const auto diff = f_grad_ref(x, y) - f_h_grad_ref_transformed;
                return diff.dot(diff);
            };

            const auto absdet = transform.absolute_determinant();
            error_squared += absdet * triquad_ref<QuadStrength, Scalar>(diff_squared);

        }

        return std::sqrt(error_squared);
    };
}
<commit_msg>Fix error due to self-applying an Eigen expression<commit_after>#pragma once

#include <cstdint>
#include <cmath>

#include <Eigen/Sparse>
#include <Eigen/Dense>

#include <crest/geometry/indexed_mesh.hpp>
#include <crest/util/eigen_extensions.hpp>
#include <crest/quadrature/triquad.hpp>
#include <crest/basis/basis.hpp>

namespace crest
{
    /**
     * A standard linear Lagrangian basis
     */
    template <typename Scalar>
    class LagrangeBasis2d : public Basis<Scalar, LagrangeBasis2d<Scalar>>
    {
    public:
        explicit LagrangeBasis2d(const IndexedMesh<Scalar, int> & mesh) : _mesh(mesh) {}

        virtual std::vector<int> boundary_nodes() const override { return _mesh.boundary_vertices(); }
        virtual std::vector<int> interior_nodes() const override { return _mesh.compute_interior_vertices(); }

        virtual Assembly<Scalar> assemble() const override;

        virtual int num_dof() const override { return _mesh.num_vertices(); }

        template <typename Function2d>
        VectorX<Scalar> interpolate(const Function2d &f) const;

        template <int QuadStrength, typename Function2d>
        VectorX<Scalar> load(const Function2d &f) const;

        template <int QuadStrength, typename Function2d>
        Scalar error_l2(const Function2d &f, const VectorX<Scalar> & weights) const;

        template <int QuadStrength, typename Function2d_x, typename Function2d_y>
        Scalar error_h1_semi(const Function2d_x & f_x,
                             const Function2d_y & f_y,
                             const VectorX<Scalar> & weights) const;

    private:
        const IndexedMesh<double, int> & _mesh;
    };

    namespace detail
    {
        template <typename Scalar>
        struct assembly_triplets {
            std::vector<Eigen::Triplet<Scalar>> stiffness_triplets;
            std::vector<Eigen::Triplet<Scalar>> mass_triplets;
        };

        template <typename Scalar>
        assembly_triplets<Scalar> assemble_linear_lagrangian_stiffness_triplets(
                const crest::IndexedMesh<Scalar, int> &mesh);
    }

    /*
     * IMPLEMENTATION BELOW
     */

    template <typename Scalar>
    detail::assembly_triplets<Scalar> detail::assemble_linear_lagrangian_stiffness_triplets(
            const crest::IndexedMesh<Scalar, int> &mesh)
    {
        const static Eigen::Matrix<Scalar, 3, 3> M_LOCAL_REF = (1.0 / 24.0) * (Eigen::Matrix3d()
                <<
                2.0, 1.0, 1.0,
                1.0, 2.0, 1.0,
                1.0, 1.0, 2.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A11 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                1.0, 0.0, -1.0,
                0.0, 0.0, 0.0,
                -1.0, 0.0, 1.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A12 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                0.0, 1.0, -1.0,
                1.0, 0.0, -1.0,
                -1.0, -1.0, 2.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A22 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                0.0, 0.0, 0.0,
                0.0, 1.0, -1.0,
                0.0, -1.0, 1.0
        ).finished().cast<Scalar>();

        std::vector<Eigen::Triplet<Scalar>> mass_triplets;
        std::vector<Eigen::Triplet<Scalar>> stiffness_triplets;
        mass_triplets.reserve(3 * mesh.num_elements());
        stiffness_triplets.reserve(3 * mesh.num_elements());

        for (const auto & element : mesh.elements())
        {
            const auto a = mesh.vertices()[element.vertex_indices[0]];
            const auto b = mesh.vertices()[element.vertex_indices[1]];
            const auto c = mesh.vertices()[element.vertex_indices[2]];

            const auto v1 = a - c;
            const auto v2 = b - c;

            const Eigen::Matrix2d jacobian = (Eigen::Matrix2d() << v1.x, v2.x, v1.y, v2.y).finished();
            const Eigen::Matrix2d jacobian_inverse = jacobian.inverse();
            const Eigen::Matrix2d C = jacobian_inverse * jacobian_inverse.transpose();
            const auto abs_det_jacobian = std::abs(jacobian.determinant());

            const Eigen::Matrix<Scalar, 3, 3> A_local = abs_det_jacobian * (C(0, 0) * A11 + C(0, 1) * A12 + C(1, 1) * A22);
            const Eigen::Matrix<Scalar, 3, 3> M_local = abs_det_jacobian * M_LOCAL_REF;

            typedef Eigen::Triplet<Scalar> T;
            for (size_t i = 0; i < 3; ++i)
            {
                for (size_t j = 0; j < 3; ++j)
                {
                    const auto I = element.vertex_indices[i];
                    const auto J = element.vertex_indices[j];
                    mass_triplets.emplace_back(T(I, J, M_local(i, j)));
                    stiffness_triplets.emplace_back(T(I, J, A_local(i, j)));
                }
            }
        }

        return detail::assembly_triplets<Scalar> {
                std::move(stiffness_triplets),
                std::move(mass_triplets)
        };
    }

    template <typename Scalar>
    Assembly<Scalar> LagrangeBasis2d<Scalar>::assemble() const
    {
        const auto triplets = detail::assemble_linear_lagrangian_stiffness_triplets(_mesh);

        Assembly<Scalar> assembly;

        // Stiffness
        assembly.stiffness = Eigen::SparseMatrix<Scalar>(num_dof(), num_dof());
        assembly.stiffness.setFromTriplets(triplets.stiffness_triplets.cbegin(), triplets.stiffness_triplets.cend());

        // Mass
        assembly.mass = Eigen::SparseMatrix<Scalar>(num_dof(), num_dof());
        assembly.mass.setFromTriplets(triplets.mass_triplets.cbegin(), triplets.mass_triplets.cend());

        return assembly;
    }

    template <typename Scalar>
    template <int QuadStrength, typename Function2d>
    VectorX<Scalar> LagrangeBasis2d<Scalar>::load(const Function2d & f) const
    {
        Eigen::VectorXd load(_mesh.num_vertices());
        load.setZero();

        // See triquad.hpp for the mapping used here
        const auto a_basis = [] (auto x, auto  ) { return Scalar(0.5) * x + Scalar(0.5); };
        const auto b_basis = [] (auto  , auto y) { return Scalar(0.5) * y + Scalar(0.5); };
        const auto c_basis = [] (auto x, auto y) { return Scalar(0.5) * (-x - y); };

        for (const auto element : _mesh.elements())
        {
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);
            const auto transformed_f = [&f, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                return f(coords.x, coords.y);
            };

            const auto absdet = transform.absolute_determinant();

            load(z0) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * a_basis(x, y); }
            );
            load(z1) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * b_basis(x, y); }
            );
            load(z2) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * c_basis(x, y); }
            );
        }

        return load;
    }

    template <typename Scalar>
    template <typename Function2d>
    VectorX<Scalar> LagrangeBasis2d<Scalar>::interpolate(const Function2d & f) const
    {
        // Simple nodal interpolation
        auto result = VectorX<Scalar>(_mesh.num_vertices());
        for (int i = 0; i < _mesh.num_vertices(); ++i)
        {
            const auto vertex = _mesh.vertices()[i];
            result(i) = f(vertex.x, vertex.y);
        }
        return result;
    }

    template <typename Scalar>
    template <int QuadStrength, typename Function2d>
    Scalar LagrangeBasis2d<Scalar>::error_l2(const Function2d &f, const VectorX<Scalar> & weights) const
    {
        Scalar error_squared = Scalar(0);

        // See triquad.hpp for the mapping used here
        const auto basis0 = [] (auto x, auto  ) { return Scalar(0.5) * x + Scalar(0.5); };
        const auto basis1 = [] (auto  , auto y) { return Scalar(0.5) * y + Scalar(0.5); };
        const auto basis2 = [] (auto x, auto y) { return Scalar(0.5) * (-x - y); };

        for (const auto element : _mesh.elements())
        {
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto w0 = weights(z0);
            const auto w1 = weights(z1);
            const auto w2 = weights(z2);

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);
            const auto f_ref = [&f, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                return f(coords.x, coords.y);
            };

            // Computes the square of the difference of f and f_h in the reference triangle
            const auto diff_ref_squared = [&] (auto x, auto y)
            {
                const auto f_h_ref = w0 * basis0(x, y) +
                                     w1 * basis1(x, y) +
                                     w2 * basis2(x, y);

                const auto diff = f_ref(x, y) - f_h_ref;
                return diff * diff;
            };

            const auto absdet = transform.absolute_determinant();
            error_squared += absdet * triquad_ref<QuadStrength, Scalar>(diff_ref_squared);
        }

        return std::sqrt(error_squared);
    };

    template <typename Scalar>
    template <int QuadStrength, typename Function2d_x, typename Function2d_y>
    Scalar LagrangeBasis2d<Scalar>::error_h1_semi(const Function2d_x & f_x,
                                                  const Function2d_y & f_y,
                                                  const VectorX<Scalar> & weights) const
    {
        Scalar error_squared = Scalar(0);

        // See triquad.hpp for the mapping used here
        const auto basis0_x = Scalar(0.5);
        const auto basis0_y = Scalar(0.0);
        const auto basis1_x = Scalar(0.0);
        const auto basis1_y = Scalar(0.5);
        const auto basis2_x = Scalar(-0.5);
        const auto basis2_y = Scalar(-0.5);

        for (const auto element : _mesh.elements())
        {
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto w0 = weights(z0);
            const auto w1 = weights(z1);
            const auto w2 = weights(z2);

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);

            const auto f_grad_ref = [&f_x, &f_y, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                Eigen::Matrix<Scalar, 2, 1> grad;
                grad(0) = f_x(coords.x, coords.y);
                grad(1) = f_y(coords.x, coords.y);
                return grad;
            };

            // Since we have linear elements, the gradients are constants
            Eigen::Matrix<Scalar, 2, 1> f_h_grad_ref;
            f_h_grad_ref(0) = w0 * basis0_x +
                              w1 * basis1_x +
                              w2 * basis2_x;
            f_h_grad_ref(1) = w0 * basis0_y +
                              w1 * basis1_y +
                              w2 * basis2_y;

            // Due to change of variables, we have to left-apply J^-T
            const auto J_inv_t = transform.jacobian().inverse().transpose();
            const Eigen::Matrix<Scalar, 2, 1> f_h_grad_ref_transformed = J_inv_t * f_h_grad_ref;

            // Computes the square of the difference of grad(f) and grad(f_h)
            // in the reference triangle
            const auto diff_squared = [&] (auto x, auto y)
            {
                // Note that J_inv_t cancels with J_t for f_grad_ref
                const Eigen::Matrix<Scalar, 2, 1> diff = f_grad_ref(x, y) - f_h_grad_ref_transformed;
                return diff.dot(diff);
            };

            const auto absdet = transform.absolute_determinant();
            error_squared += absdet * triquad_ref<QuadStrength, Scalar>(diff_squared);

        }

        return std::sqrt(error_squared);
    };
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "transform_layer.hpp"

namespace dll {

/*!
 * \brief Simple thresholding binarize layer
 */
template <typename Desc>
struct binarize_layer : transform_layer<binarize_layer<Desc>> {
    using desc = Desc; ///< The descriptor type

    static constexpr const std::size_t Threshold = desc::T;

    binarize_layer() = default;

    /*!
     * \brief Returns a string representation of the layer
     */
    static std::string to_short_string() {
        return "Binarize";
    }

    /*!
     * \brief Apply the layer to the input
     * \param output The output
     * \param input The input to apply the layer to
     */
    template <typename Input, typename Output>
    static void activate_hidden(Output& output, const Input& input) {
        output = input;

        for (auto& value : output) {
            value = value > Threshold ? 1 : 0;
        }
    }

    /*!
     * \brief Apply the layer to the batch of input
     * \param output The batch of output
     * \param input The batch of input to apply the layer to
     */
    template <typename Input, typename Output>
    static void batch_activate_hidden(Output& output, const Input& input) {
        output = input;

        for (auto& value : output) {
            value = value > Threshold ? 1 : 0;
        }
    }
};

//Allow odr-use of the constexpr static members

template <typename Desc>
const std::size_t binarize_layer<Desc>::Threshold;

} //end of dll namespace
<commit_msg>Support for binarize layer<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "transform_layer.hpp"

namespace dll {

/*!
 * \brief Simple thresholding binarize layer
 *
 * Note: This is only supported at the beginning of the network, no
 * backpropagation is possible for now.
 */
template <typename Desc>
struct binarize_layer : transform_layer<binarize_layer<Desc>> {
    using desc = Desc; ///< The descriptor type

    static constexpr const std::size_t Threshold = desc::T;

    binarize_layer() = default;

    /*!
     * \brief Returns a string representation of the layer
     */
    static std::string to_short_string() {
        return "Binarize";
    }

    /*!
     * \brief Apply the layer to the input
     * \param output The output
     * \param input The input to apply the layer to
     */
    template <typename Input, typename Output>
    static void activate_hidden(Output& output, const Input& input) {
        output = input;

        for (auto& value : output) {
            value = value > Threshold ? 1 : 0;
        }
    }

    /*!
     * \brief Apply the layer to the batch of input
     * \param output The batch of output
     * \param input The batch of input to apply the layer to
     */
    template <typename Input, typename Output>
    static void batch_activate_hidden(Output& output, const Input& input) {
        output = input;

        for (auto& value : output) {
            value = value > Threshold ? 1 : 0;
        }
    }

    template<typename C>
    void adapt_errors(C& context) const {
        cpp_unused(context);
    }

    template<typename H, typename C>
    void backward_batch(H&& output, C& context) const {
        cpp_unused(output);
        cpp_unused(context);
    }

    template<typename C>
    void compute_gradients(C& context) const {
        cpp_unused(context);
    }
};

//Allow odr-use of the constexpr static members

template <typename Desc>
const std::size_t binarize_layer<Desc>::Threshold;

} //end of dll namespace
<|endoftext|>


<commit_before>//
//  basic_iostream.hpp
//  fibio
//
//  Created by Chen Xu on 14-3-8.
//  Copyright (c) 2014 0d0a.com. All rights reserved.
//

#ifndef fibio_basic_iostream_hpp
#define fibio_basic_iostream_hpp

#include <streambuf>
#include <iostream>
#include <chrono>
#include <fibio/fibers/fiber.hpp>

namespace fibio { namespace stream {
    template<typename StreamDescriptor>
    class basic_streambuf : public std::streambuf {
    public:
        basic_streambuf()
        : sd_(fibio::fibers::this_fiber::detail::get_io_service())
        { init_buffers(); }

        basic_streambuf(StreamDescriptor &&sd)
        : sd_(std::move(sd))
        { init_buffers(); }

        basic_streambuf(asio::io_service &iosvc)
        : sd_(iosvc)
        { init_buffers(); }

        /// Destructor flushes buffered data.
        ~basic_streambuf() {
            if (pptr() != pbase())
                overflow(traits_type::eof());
        }

        template <typename... T>
        std::error_code open(T... x) {
            return fibio::io::open(sd_, x...);
        }

        template <typename... T>
        std::error_code connect(T... x) {
            sd_.close();
            typename StreamDescriptor::protocol_type::resolver::query q(x...);
            typename StreamDescriptor::protocol_type::endpoint ep=fibio::io::resolve(q);
            typedef typename StreamDescriptor::protocol_type::endpoint endpoint_t;
            return fibio::io::connect(sd_, ep, endpoint_t(), connect_timeout_);
        }

        inline bool is_open() const
        { return sd_.is_open(); }

        inline void close() {
            if(sd_.is_open()) {
                std::error_code ec;
                sd_.close(ec);
            }
        }

        typename StreamDescriptor::native_handle_type release()
        { return sd_.release(); }

        inline StreamDescriptor &stream_descriptor()
        { return sd_; }

        template<typename Rep, typename Period>
        void set_connect_timeout(const std::chrono::duration<Rep, Period>& timeout_duration)
        { connect_timeout_=std::chrono::duration_cast<std::chrono::microseconds>(timeout_duration).count(); }

        template<typename Rep, typename Period>
        void set_read_timeout(const std::chrono::duration<Rep, Period>& timeout_duration)
        { read_timeout_=std::chrono::duration_cast<std::chrono::microseconds>(timeout_duration).count(); }

        template<typename Rep, typename Period>
        void set_write_timeout(const std::chrono::duration<Rep, Period>& timeout_duration)
        { write_timeout_=std::chrono::duration_cast<std::chrono::microseconds>(timeout_duration).count(); }

    protected:
        virtual std::streamsize showmanyc() override {
            if ( gptr() == egptr() ) {
                // Getting area is empty, fetch something
                if (traits_type::eq_int_type(underflow(), traits_type::eof())) {
                    // underflow() hits eof
                    return -1;
                }
            }
            return egptr()-gptr();
        }

        int_type underflow() {
            if (gptr() == egptr()) {
                std::error_code ec;
                size_t bytes_transferred_=io::read_some(sd_,
                                                        &get_buffer_[0]+ putback_max,
                                                        putback_max,
                                                        read_timeout_,
                                                        ec);
                if (ec) {
                    return traits_type::eof();
                }
                setg(&get_buffer_[0],
                     &get_buffer_[0] + putback_max,
                     &get_buffer_[0] + putback_max + bytes_transferred_);
                return traits_type::to_int_type(*gptr());
            } else {
                return traits_type::eof();
            }
        }

        int_type overflow(int_type c) {
            std::error_code ec;
            if (unbuffered_) {
                if (traits_type::eq_int_type(c, traits_type::eof())) {
                    // Nothing to do.
                    return traits_type::not_eof(c);
                } else {
                    char c_=c;
                    fibio::io::write_some(sd_, &c_, 1, write_timeout_, ec);
                    if (ec)
                        return traits_type::eof();
                    return c;
                }
            } else {
                char *ptr=pbase();
                size_t size=pptr() - pbase();
                while (size > 0)
                {
                    size_t bytes_transferred=fibio::io::write_some(sd_,
                                                                   ptr,
                                                                   size,
                                                                   write_timeout_,
                                                                   ec);
                    ptr+=bytes_transferred;
                    size-=bytes_transferred;
                    if (ec)
                        return traits_type::eof();
                }
                setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());

                // If the new character is eof then our work here is done.
                if (traits_type::eq_int_type(c, traits_type::eof()))
                    return traits_type::not_eof(c);

                // Add the new character to the output buffer.
                *pptr() = traits_type::to_char_type(c);
                pbump(1);
                return c;
            }
        }

        int sync()
        {
            return overflow(traits_type::eof());
        }

        std::streambuf* setbuf(char_type* s, std::streamsize n)
        {
            if (pptr() == pbase() && s == 0 && n == 0)
            {
                unbuffered_ = true;
                setp(0, 0);
                return this;
            }

            return 0;
        }

    private:
        void init_buffers()
        {
            setg(&get_buffer_[0],
                 &get_buffer_[0] + putback_max,
                 &get_buffer_[0] + putback_max);
            if (unbuffered_)
                setp(0, 0);
            else
                setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
        }

        enum { putback_max = 8 };
        enum { buffer_size = 10 };

        StreamDescriptor sd_;
        asio::detail::array<char, buffer_size> get_buffer_;
        asio::detail::array<char, buffer_size> put_buffer_;
        int connect_timeout_=0;
        int read_timeout_=0;
        int write_timeout_=0;
        bool unbuffered_=false;
    };

    template<typename StreamDescriptor>
    using streambuf=basic_streambuf<StreamDescriptor>;
}}  // End of namespace fibio::stream

#endif
<commit_msg>eof condition<commit_after>//
//  basic_iostream.hpp
//  fibio
//
//  Created by Chen Xu on 14-3-8.
//  Copyright (c) 2014 0d0a.com. All rights reserved.
//

#ifndef fibio_basic_iostream_hpp
#define fibio_basic_iostream_hpp

#include <streambuf>
#include <iostream>
#include <chrono>
#include <fibio/fibers/fiber.hpp>

namespace fibio { namespace stream {
    template<typename StreamDescriptor>
    class basic_streambuf : public std::streambuf {
    public:
        basic_streambuf()
        : sd_(fibio::fibers::this_fiber::detail::get_io_service())
        { init_buffers(); }

        basic_streambuf(StreamDescriptor &&sd)
        : sd_(std::move(sd))
        { init_buffers(); }

        basic_streambuf(asio::io_service &iosvc)
        : sd_(iosvc)
        { init_buffers(); }

        /// Destructor flushes buffered data.
        ~basic_streambuf() {
            if (pptr() != pbase())
                overflow(traits_type::eof());
        }

        template <typename... T>
        std::error_code open(T... x) {
            return fibio::io::open(sd_, x...);
        }

        template <typename... T>
        std::error_code connect(T... x) {
            sd_.close();
            typename StreamDescriptor::protocol_type::resolver::query q(x...);
            typename StreamDescriptor::protocol_type::endpoint ep=fibio::io::resolve(q);
            typedef typename StreamDescriptor::protocol_type::endpoint endpoint_t;
            return fibio::io::connect(sd_, ep, endpoint_t(), connect_timeout_);
        }

        inline bool is_open() const
        { return sd_.is_open(); }

        inline void close() {
            if(sd_.is_open()) {
                std::error_code ec;
                sd_.close(ec);
            }
        }

        typename StreamDescriptor::native_handle_type release()
        { return sd_.release(); }

        inline StreamDescriptor &stream_descriptor()
        { return sd_; }

        template<typename Rep, typename Period>
        void set_connect_timeout(const std::chrono::duration<Rep, Period>& timeout_duration)
        { connect_timeout_=std::chrono::duration_cast<std::chrono::microseconds>(timeout_duration).count(); }

        template<typename Rep, typename Period>
        void set_read_timeout(const std::chrono::duration<Rep, Period>& timeout_duration)
        { read_timeout_=std::chrono::duration_cast<std::chrono::microseconds>(timeout_duration).count(); }

        template<typename Rep, typename Period>
        void set_write_timeout(const std::chrono::duration<Rep, Period>& timeout_duration)
        { write_timeout_=std::chrono::duration_cast<std::chrono::microseconds>(timeout_duration).count(); }

    protected:
        virtual std::streamsize showmanyc() override {
            if ( gptr() == egptr() ) {
                underflow();
            }
            return egptr()-gptr();
        }

        int_type underflow() {
            if (gptr() == egptr()) {
                std::error_code ec;
                size_t bytes_transferred=io::read_some(sd_,
                                                        &get_buffer_[0]+ putback_max,
                                                        buffer_size-putback_max,
                                                        read_timeout_,
                                                        ec);
                if (ec || bytes_transferred==0) {
                    return traits_type::eof();
                }
                setg(&get_buffer_[0],
                     &get_buffer_[0] + putback_max,
                     &get_buffer_[0] + putback_max + bytes_transferred);
                return traits_type::to_int_type(*gptr());
            } else {
                return traits_type::eof();
            }
        }

        int_type overflow(int_type c) {
            std::error_code ec;
            if (unbuffered_) {
                if (traits_type::eq_int_type(c, traits_type::eof())) {
                    // Nothing to do.
                    return traits_type::not_eof(c);
                } else {
                    char c_=c;
                    fibio::io::write_some(sd_, &c_, 1, write_timeout_, ec);
                    if (ec)
                        return traits_type::eof();
                    return c;
                }
            } else {
                char *ptr=pbase();
                size_t size=pptr() - pbase();
                while (size > 0)
                {
                    size_t bytes_transferred=fibio::io::write_some(sd_,
                                                                   ptr,
                                                                   size,
                                                                   write_timeout_,
                                                                   ec);
                    ptr+=bytes_transferred;
                    size-=bytes_transferred;
                    if (ec)
                        return traits_type::eof();
                }
                setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());

                // If the new character is eof then our work here is done.
                if (traits_type::eq_int_type(c, traits_type::eof()))
                    return traits_type::not_eof(c);

                // Add the new character to the output buffer.
                *pptr() = traits_type::to_char_type(c);
                pbump(1);
                return c;
            }
        }

        int sync()
        {
            return overflow(traits_type::eof());
        }

        std::streambuf* setbuf(char_type* s, std::streamsize n)
        {
            if (pptr() == pbase() && s == 0 && n == 0)
            {
                unbuffered_ = true;
                setp(0, 0);
                return this;
            }

            return 0;
        }

    private:
        void init_buffers()
        {
            setg(&get_buffer_[0],
                 &get_buffer_[0] + putback_max,
                 &get_buffer_[0] + putback_max);
            if (unbuffered_)
                setp(0, 0);
            else
                setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
        }

        enum { putback_max = 8 };
        enum { buffer_size = 10 };

        StreamDescriptor sd_;
        asio::detail::array<char, buffer_size> get_buffer_;
        asio::detail::array<char, buffer_size> put_buffer_;
        int connect_timeout_=0;
        int read_timeout_=0;
        int write_timeout_=0;
        bool unbuffered_=false;
    };

    template<typename StreamDescriptor>
    using streambuf=basic_streambuf<StreamDescriptor>;
}}  // End of namespace fibio::stream

#endif
<|endoftext|>


<commit_before>/**
 * @file llplacesinventorypanel.cpp
 * @brief LLPlacesInventoryPanel  class definition
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * 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
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llscrollcontainer.h"

#include "llplacesinventorypanel.h"

#include "llfolderviewmodel.h"
#include "llplacesfolderview.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llpanellandmarks.h"
#include "llplacesinventorybridge.h"
#include "llviewerfoldertype.h"

static LLDefaultChildRegistry::Register<LLPlacesInventoryPanel> r("places_inventory_panel");

static const LLPlacesInventoryBridgeBuilder PLACES_INVENTORY_BUILDER;

LLPlacesInventoryPanel::LLPlacesInventoryPanel(const Params& p) :
	LLInventoryPanel(p),
	mSavedFolderState(NULL)

{
	mInvFVBridgeBuilder = &PLACES_INVENTORY_BUILDER;
	mSavedFolderState = new LLSaveFolderState();
	mSavedFolderState->setApply(FALSE);
}

LLPlacesInventoryPanel::~LLPlacesInventoryPanel()
{
	delete mSavedFolderState;
}

LLFolderView * LLPlacesInventoryPanel::createFolderRoot(LLUUID root_id )
{
    LLPlacesFolderView::Params p;

    p.name = getName();
    p.title = getLabel();
    p.rect = LLRect(0, 0, getRect().getWidth(), 0);
    p.parent_panel = this;
    p.tool_tip = p.name;
    p.listener = mInvFVBridgeBuilder->createBridge(	LLAssetType::AT_CATEGORY,
        LLAssetType::AT_CATEGORY,
        LLInventoryType::IT_CATEGORY,
        this,
        &mInventoryViewModel,
        NULL,
        root_id);
    p.view_model = &mInventoryViewModel;
    p.use_label_suffix = mParams.use_label_suffix;
    p.allow_multiselect = mAllowMultiSelect;
    p.show_empty_message = mShowEmptyMessage;
    p.show_item_link_overlays = mShowItemLinkOverlays;
    p.root = NULL;
    p.use_ellipses = mParams.folder_view.use_ellipses;

    return LLUICtrlFactory::create<LLPlacesFolderView>(p);
}

// save current folder open state
void LLPlacesInventoryPanel::saveFolderState()
{
	mSavedFolderState->setApply(FALSE);
	mFolderRoot->applyFunctorRecursively(*mSavedFolderState);
}

// re-open folders which state was saved
void LLPlacesInventoryPanel::restoreFolderState()
{
	mSavedFolderState->setApply(TRUE);
	mFolderRoot->applyFunctorRecursively(*mSavedFolderState);
	LLOpenFoldersWithSelection opener;
	mFolderRoot->applyFunctorRecursively(opener);
	mFolderRoot->scrollToShowSelection();
}

S32	LLPlacesInventoryPanel::notify(const LLSD& info)
{
	if(info.has("action"))
	{
		std::string str_action = info["action"];
		if(str_action == "select_first")
		{
			return mFolderRoot->notify(info);
		}
		else if(str_action == "select_last")
		{
			return mFolderRoot->notify(info);
		}
	}
	return 0;
}
<commit_msg>merging<commit_after>/**
 * @file llplacesinventorypanel.cpp
 * @brief LLPlacesInventoryPanel  class definition
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * 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
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llscrollcontainer.h"

#include "llplacesinventorypanel.h"

#include "llfolderviewmodel.h"
#include "llplacesfolderview.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llpanellandmarks.h"
#include "llplacesinventorybridge.h"
#include "llviewerfoldertype.h"

static LLDefaultChildRegistry::Register<LLPlacesInventoryPanel> r("places_inventory_panel");

static const LLPlacesInventoryBridgeBuilder PLACES_INVENTORY_BUILDER;

LLPlacesInventoryPanel::LLPlacesInventoryPanel(const Params& p) :
	LLInventoryPanel(p),
	mSavedFolderState(NULL)

{
	mInvFVBridgeBuilder = &PLACES_INVENTORY_BUILDER;
	mSavedFolderState = new LLSaveFolderState();
	mSavedFolderState->setApply(FALSE);
}

LLPlacesInventoryPanel::~LLPlacesInventoryPanel()
{
	delete mSavedFolderState;
}

LLFolderView * LLPlacesInventoryPanel::createFolderRoot(LLUUID root_id )
{
    LLPlacesFolderView::Params p;

    p.name = getName();
    p.title = getLabel();
    p.rect = LLRect(0, 0, getRect().getWidth(), 0);
    p.parent_panel = this;
    p.tool_tip = p.name;
    p.listener = mInvFVBridgeBuilder->createBridge(	LLAssetType::AT_CATEGORY,
        LLAssetType::AT_CATEGORY,
        LLInventoryType::IT_CATEGORY,
        this,
        &mInventoryViewModel,
        NULL,
        root_id);
    p.view_model = &mInventoryViewModel;
    p.use_label_suffix = mParams.use_label_suffix;
    p.allow_multiselect = mAllowMultiSelect;
    p.show_empty_message = mShowEmptyMessage;
    p.show_item_link_overlays = mShowItemLinkOverlays;
    p.root = NULL;
    p.use_ellipses = mParams.folder_view.use_ellipses;
    p.options_menu = "menu_inventory.xml";

    return LLUICtrlFactory::create<LLPlacesFolderView>(p);
}

// save current folder open state
void LLPlacesInventoryPanel::saveFolderState()
{
	mSavedFolderState->setApply(FALSE);
	mFolderRoot->applyFunctorRecursively(*mSavedFolderState);
}

// re-open folders which state was saved
void LLPlacesInventoryPanel::restoreFolderState()
{
	mSavedFolderState->setApply(TRUE);
	mFolderRoot->applyFunctorRecursively(*mSavedFolderState);
	LLOpenFoldersWithSelection opener;
	mFolderRoot->applyFunctorRecursively(opener);
	mFolderRoot->scrollToShowSelection();
}

S32	LLPlacesInventoryPanel::notify(const LLSD& info)
{
	if(info.has("action"))
	{
		std::string str_action = info["action"];
		if(str_action == "select_first")
		{
			return mFolderRoot->notify(info);
		}
		else if(str_action == "select_last")
		{
			return mFolderRoot->notify(info);
		}
	}
	return 0;
}
<|endoftext|>