<commit_before>//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "platform/platform.h"
#include "platform/platformFileMonitor.h"
#include "collection/vector.h"
#include "console/console.h"
#include "string/stringTable.h"
#include "io/resource/resourceManager.h"

//-----------------------------------------------------------------------------

struct PlatformFileMonitor
{
   bool                       firstRun;
   StringTableEntry           path;
   StringTableEntry           fileName;
   PlatformFileChangeDelegate callback;
   FileTime                   createTime;
   FileTime                   modifyTime;
};

typedef Vector<PlatformFileMonitor> PlatformDirectoryMonitor;
typedef HashMap<StringTableEntry, PlatformDirectoryMonitor> PlatformDirectoryMonitorTable;
PlatformDirectoryMonitorTable dirMonitorMap;

bool addFileMonitor(StringTableEntry path, PlatformFileChangeDelegate callback)
{
   StringTableEntry dirName = Platform::stripFileName(path);
   StringTableEntry fileName = Platform::stripDirectory(path);

   PlatformFileMonitor fileMonitor;
   fileMonitor.firstRun = true;
   fileMonitor.fileName = fileName;
   fileMonitor.path = path;
   fileMonitor.callback = callback;

   PlatformDirectoryMonitorTable::iterator itr = dirMonitorMap.find(dirName);
   if (itr != dirMonitorMap.end())
   {
      PlatformDirectoryMonitor* dirMonitor = &dirMonitorMap[dirName];
      for (U32 n = 0; n < dirMonitor->size(); ++n)
      {
         PlatformFileMonitor* fileMonitor = &dirMonitor->at(n);
         if (dStrcmp(fileMonitor->fileName, fileName) == 0)
            return false;
      }
      dirMonitor->push_back(fileMonitor);
      onDirectoryChanged(dirName);
      return true;
   }
   else {
      PlatformDirectoryMonitor dirMonitor;
      dirMonitor.push_back(fileMonitor);
      dirMonitorMap.insert(dirName, dirMonitor);
      addDirectoryMonitor(dirName);
      onDirectoryChanged(dirName);
      return true;
   }

   return false;
}

bool removeFileMonitor(StringTableEntry path)
{
   StringTableEntry dirName = Platform::stripFileName(path);
   removeDirectoryMonitor(dirName);
   return true;
}

void onDirectoryChanged(StringTableEntry path)
{
   PlatformDirectoryMonitorTable::iterator itr = dirMonitorMap.find(path);
   if (itr == dirMonitorMap.end())
      return;

   PlatformDirectoryMonitor* dirMonitor = &dirMonitorMap[path];
   Vector < Platform::FileInfo > fileInfoVec;
   Platform::dumpPath(path, fileInfoVec);

   //Con::printf("Dir: %s, Size: %d", path, dirMonitor->size());

   for (U32 n = 0; n < dirMonitor->size(); ++n)
   {
      PlatformFileMonitor* fileMonitor = &dirMonitor->at(n);
      for (U32 i = 0; i < fileInfoVec.size(); ++i)
      {
         if (dStrcmp(fileMonitor->fileName, fileInfoVec[i].pFileName) == 0 && dStrlen(fileMonitor->fileName) == dStrlen(fileInfoVec[i].pFileName))
         {
            FileTime createTime;
            FileTime modifyTime;
            //Con::printf("Getting file times: %s %s", fileInfoVec[i].pFullPath, fileInfoVec[i].pFileName);
            Platform::getFileTimes(fileMonitor->path, &createTime, &modifyTime);

            //Con::printf("COMPARING [n=%d, i=%d]: %s %s", n, i, fileMonitor->fileName, fileInfoVec[i].pFileName);
            if (fileMonitor->firstRun ||
               fileMonitor->createTime.v1 != createTime.v1 || fileMonitor->createTime.v2 != createTime.v2 ||
               fileMonitor->modifyTime.v1 != modifyTime.v1 || fileMonitor->modifyTime.v2 != modifyTime.v2)
            {
               fileMonitor->createTime.v1 = createTime.v1;
               fileMonitor->createTime.v2 = createTime.v2;
               fileMonitor->modifyTime.v1 = modifyTime.v1;
               fileMonitor->modifyTime.v2 = modifyTime.v2;

               if (fileMonitor->firstRun)
                  fileMonitor->firstRun = false;
               else
                  fileMonitor->callback(fileMonitor->path);
            }
         }
      }
   }
}<commit_msg>Linux build fix.<commit_after>//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "platform/platform.h"
#include "platform/platformFileMonitor.h"
#include "collection/vector.h"
#include "console/console.h"
#include "string/stringTable.h"
#include "io/resource/resourceManager.h"

//-----------------------------------------------------------------------------

struct PlatformFileMonitor
{
   bool                       firstRun;
   StringTableEntry           path;
   StringTableEntry           fileName;
   PlatformFileChangeDelegate callback;
   FileTime                   createTime;
   FileTime                   modifyTime;
};

typedef Vector<PlatformFileMonitor> PlatformDirectoryMonitor;
typedef HashMap<StringTableEntry, PlatformDirectoryMonitor> PlatformDirectoryMonitorTable;
PlatformDirectoryMonitorTable dirMonitorMap;

bool addFileMonitor(StringTableEntry path, PlatformFileChangeDelegate callback)
{
   StringTableEntry dirName = Platform::stripFileName(path);
   StringTableEntry fileName = Platform::stripDirectory(path);

   PlatformFileMonitor fileMonitor;
   fileMonitor.firstRun = true;
   fileMonitor.fileName = fileName;
   fileMonitor.path = path;
   fileMonitor.callback = callback;

   PlatformDirectoryMonitorTable::iterator itr = dirMonitorMap.find(dirName);
   if (itr != dirMonitorMap.end())
   {
      PlatformDirectoryMonitor* dirMonitor = &dirMonitorMap[dirName];
      for (U32 n = 0; n < dirMonitor->size(); ++n)
      {
         PlatformFileMonitor* fileMonitor = &dirMonitor->at(n);
         if (dStrcmp(fileMonitor->fileName, fileName) == 0)
            return false;
      }
      dirMonitor->push_back(fileMonitor);
      onDirectoryChanged(dirName);
      return true;
   }
   else {
      PlatformDirectoryMonitor dirMonitor;
      dirMonitor.push_back(fileMonitor);
      dirMonitorMap.insert(dirName, dirMonitor);
      addDirectoryMonitor(dirName);
      onDirectoryChanged(dirName);
      return true;
   }

   return false;
}

bool removeFileMonitor(StringTableEntry path)
{
   StringTableEntry dirName = Platform::stripFileName(path);
   removeDirectoryMonitor(dirName);
   return true;
}

void onDirectoryChanged(StringTableEntry path)
{
   PlatformDirectoryMonitorTable::iterator itr = dirMonitorMap.find(path);
   if (itr == dirMonitorMap.end())
      return;

   PlatformDirectoryMonitor* dirMonitor = &dirMonitorMap[path];
   Vector < Platform::FileInfo > fileInfoVec;
   Platform::dumpPath(path, fileInfoVec);

   //Con::printf("Dir: %s, Size: %d", path, dirMonitor->size());

   for (U32 n = 0; n < dirMonitor->size(); ++n)
   {
      PlatformFileMonitor* fileMonitor = &dirMonitor->at(n);
      for (U32 i = 0; i < fileInfoVec.size(); ++i)
      {
         if (dStrcmp(fileMonitor->fileName, fileInfoVec[i].pFileName) == 0 && dStrlen(fileMonitor->fileName) == dStrlen(fileInfoVec[i].pFileName))
         {
#ifdef TORQUE_OS_WIN32
            FileTime createTime;
            FileTime modifyTime;
            //Con::printf("Getting file times: %s %s", fileInfoVec[i].pFullPath, fileInfoVec[i].pFileName);
            Platform::getFileTimes(fileMonitor->path, &createTime, &modifyTime);

            //Con::printf("COMPARING [n=%d, i=%d]: %s %s", n, i, fileMonitor->fileName, fileInfoVec[i].pFileName);
            if (fileMonitor->firstRun ||
               fileMonitor->createTime.v1 != createTime.v1 || fileMonitor->createTime.v2 != createTime.v2 ||
               fileMonitor->modifyTime.v1 != modifyTime.v1 || fileMonitor->modifyTime.v2 != modifyTime.v2)
            {
               fileMonitor->createTime.v1 = createTime.v1;
               fileMonitor->createTime.v2 = createTime.v2;
               fileMonitor->modifyTime.v1 = modifyTime.v1;
               fileMonitor->modifyTime.v2 = modifyTime.v2;

               if (fileMonitor->firstRun)
                  fileMonitor->firstRun = false;
               else
                  fileMonitor->callback(fileMonitor->path);
            }
#endif
         }
      }
   }
}<|endoftext|>


<commit_before>/*
Copyright (c), Helios
All rights reserved.

Distributed under a permissive license. See COPYING.txt for details.
*/

#include "PluginCoreState.h"
#include "../LoadedImage.h"
#include "../MainWindow.h"
#include <QFile>
#include <QFileInfo>
#include <QMessageBox>
#include <QDir>
#ifdef WIN32
#include <Windows.h>
#endif

const char * const accepted_cpp_extensions[] = {
	"cpp",
	"c",
	"cc",
	"cxx",
	"c++",
};
const size_t accepted_cpp_extensions_size = sizeof(accepted_cpp_extensions) / sizeof(*accepted_cpp_extensions);

bool is_cpp_path(const QString &path){
	auto file_extension = QFileInfo(path).suffix();
	for (auto &ext : accepted_cpp_extensions)
		if (!file_extension.compare(QString(ext), Qt::CaseInsensitive))
			return true;
	return false;
}

bool is_lua_path(const QString &path){
	auto file_extension = QFileInfo(path).suffix().toLower();
	return file_extension == "lua";
}

PluginCoreState::PluginCoreState(){
}

void PluginCoreState::execute(const QString &path){
	if (!QFile::exists(path))
		throw std::exception("File not found.");
	if (is_cpp_path(path))
		this->execute_cpp(path);
	if (is_lua_path(path))
		this->execute_lua(path);
}

#define RESOLVE_FUNCTION(lib, x) auto x = (x##_f)lib.resolve(#x)

void PluginCoreState::execute_lua(const QString &path){
	if (!this->lua_library.isLoaded()){
		this->lua_library.setFileName("LuaInterpreter");
		this->lua_library.load();
	}
	this->caller_image_handle = -1;
	QFile file(path);
	file.open(QFile::ReadOnly);
	if (!file.isOpen())
		throw std::exception("Unknown error while reading file.");
	auto data = file.readAll();

	auto filename = QFileInfo(path).fileName();

	RESOLVE_FUNCTION(this->lua_library, new_LuaInterpreter);
	RESOLVE_FUNCTION(this->lua_library, delete_LuaInterpreter);
	RESOLVE_FUNCTION(this->lua_library, LuaInterpreter_execute);
	RESOLVE_FUNCTION(this->lua_library, delete_LuaCallResult);

	auto params = this->construct_LuaInterpreterParameters();
	std::shared_ptr<LuaInterpreter> interpreter(new_LuaInterpreter(&params), [=](LuaInterpreter *i){ delete_LuaInterpreter(i); });

	CallResult result;
	LuaInterpreter_execute(&result, interpreter.get(), filename.toUtf8().toStdString().c_str(), data.data(), data.size());
	delete_LuaCallResult(&result);
}

int PluginCoreState::get_caller_image_handle(){
	if (this->caller_image_handle >= 0)
		return this->caller_image_handle;
	return this->caller_image_handle = this->image_store.store(this->latest_caller->get_image());
}

void PluginCoreState::display_in_caller(int handle){
	auto image = this->get_store().get_image(handle);
	if (image)
		this->latest_caller->display_filtered_image(std::make_shared<LoadedImage>(image->get_bitmap()));
}

char *clone_string(const char *s){
	if (!s)
		return nullptr;
	auto n = strlen(s);
	auto ret = new char[n + 1];
	memcpy(ret, s, n);
	ret[n] = 0;
	return ret;
}

char *clone_string(const std::string &s){
	auto n = s.size();
	if (!n)
		return nullptr;
	auto ret = new char[n + 1];
	memcpy(ret, &s[0], n);
	ret[n] = 0;
	return ret;
}

ImageOperationResultExternal to_ImageOperationResultExternal(const ImageOperationResult &src){
	ImageOperationResultExternal ret;
	ret.success = src.success;
	static_assert(sizeof(ret.results) == sizeof(src.results), "Inconsistent struct definitions!");
	memcpy(ret.results, src.results, sizeof(ret.results));
	ret.message = clone_string(src.message);
	return ret;
}

namespace lua_implementations{
#define LUA_FUNCTION_SIGNATURE(rt, x, ...) rt x(external_state state, __VA_ARGS__)

LUA_FUNCTION_SIGNATURE(void, release_returned_string, char *s){
	delete[] s;
}

LUA_FUNCTION_SIGNATURE(void, show_message_box, const char *title, const char *message, bool is_error){
	QMessageBox msgbox;
	if (title)
		msgbox.setWindowTitle(QString::fromUtf8(title));
	msgbox.setText(QString::fromUtf8(message));
	if (is_error)
		msgbox.setIcon(QMessageBox::Critical);
	msgbox.exec();
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, get_image_info, int handle, image_info *info){
	ImageOperationResultExternal ret;
	auto This = (PluginCoreState *)state;
	auto image = This->get_store().get_image(handle);
	if (!image){
		ret.success = false;
		ret.message = clone_string(HANDLE_NOT_FOUND_MSG);
		return ret;
	}
	info->handle = handle;
	unsigned stride, pitch;
	info->pixels = image->get_pixels_pointer(stride, pitch);
	info->stride = stride;
	info->pitch = pitch;
	auto temp = image->get_dimensions();
	info->w = temp.results[0];
	info->h = temp.results[1];
	ret.success = true;
	return ret;
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, load_image, const char *path){
	auto This = (PluginCoreState *)state;
	return to_ImageOperationResultExternal(This->get_store().load(path));
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, unload_image, int handle){
	auto This = (PluginCoreState *)state;
	return to_ImageOperationResultExternal(This->get_store().unload(handle));
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, allocate_image, int w, int h){
	auto This = (PluginCoreState *)state;
	return to_ImageOperationResultExternal(This->get_store().allocate(w, h));
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, save_image, int handle, const char *path, int compression, const char *format){
	auto This = (PluginCoreState *)state;
	SaveOptions opt;
	opt.compression = compression;
	if (format)
		opt.format = format;
	return to_ImageOperationResultExternal(This->get_store().save(handle, QString::fromUtf8(path), opt));
}

LUA_FUNCTION_SIGNATURE(int, get_caller_image){
	auto This = (PluginCoreState *)state;
	return This->get_caller_image_handle();
}

LUA_FUNCTION_SIGNATURE(void, display_in_current_window, int handle){
	auto This = (PluginCoreState *)state;
	This->display_in_caller(handle);
}

LUA_FUNCTION_SIGNATURE(void, debug_print, const char *string){
#ifdef WIN32
	auto temp = QString::fromUtf8(string);
	OutputDebugStringW(temp.toStdWString().c_str());
#endif
}

}

LuaInterpreterParameters PluginCoreState::construct_LuaInterpreterParameters(){
	LuaInterpreterParameters ret;
	ret.state = this;
#define PASS_FUNCTION_TO_LUA(x) ret.x = lua_implementations::x
	PASS_FUNCTION_TO_LUA(release_returned_string);
	PASS_FUNCTION_TO_LUA(show_message_box);
	PASS_FUNCTION_TO_LUA(get_image_info);
	PASS_FUNCTION_TO_LUA(load_image);
	PASS_FUNCTION_TO_LUA(unload_image);
	PASS_FUNCTION_TO_LUA(allocate_image);
	PASS_FUNCTION_TO_LUA(save_image);
	PASS_FUNCTION_TO_LUA(get_caller_image);
	PASS_FUNCTION_TO_LUA(display_in_current_window);
	PASS_FUNCTION_TO_LUA(debug_print);

	return ret;
}

namespace cpp_implementations{

QThreadStorage<void *> tls;

#define CPP_FUNCTION_SIGNATURE(rt, x, ...) rt x(external_state state, __VA_ARGS__)

CPP_FUNCTION_SIGNATURE(void, release_returned_string, char *s){
	delete[] s;
}

CPP_FUNCTION_SIGNATURE(void, store_tls, void *s){
	auto This = (PluginCoreState *)tls.localData();
	This->store_tls(s);
}

CPP_FUNCTION_SIGNATURE(void *, retrieve_tls){
	auto This = (PluginCoreState *)tls.localData();
	return This->retrieve_tls();
}

}

CppInterpreterParameters PluginCoreState::construct_CppInterpreterParameters(){
	CppInterpreterParameters ret;
	ret.state = this;
	ret.caller_image = this->get_caller_image_handle();
#define PASS_FUNCTION_TO_CPP(x) ret.x = cpp_implementations::x
	PASS_FUNCTION_TO_CPP(release_returned_string);
	PASS_FUNCTION_TO_CPP(store_tls);
	PASS_FUNCTION_TO_CPP(retrieve_tls);

	return ret;
}

void PluginCoreState::execute_cpp(const QString &path){
	if (!this->cpp_library.isLoaded()){
		this->cpp_library.setFileName("CppInterpreter");
		this->cpp_library.load();
	}
	this->caller_image_handle = -1;
	{
		QFile file(path);
		file.open(QFile::ReadOnly);
		if (!file.isOpen())
			throw std::exception("Unknown error while reading file.");
	}

	RESOLVE_FUNCTION(this->cpp_library, new_CppInterpreter);
	RESOLVE_FUNCTION(this->cpp_library, delete_CppInterpreter);
	RESOLVE_FUNCTION(this->cpp_library, CppInterpreter_execute);
	RESOLVE_FUNCTION(this->cpp_library, delete_CppCallResult);

	auto params = this->construct_CppInterpreterParameters();
	std::shared_ptr<CppInterpreter> interpreter(new_CppInterpreter(&params), [=](CppInterpreter *i){ delete_CppInterpreter(i); });

	auto old_tls = cpp_implementations::tls.localData();
	cpp_implementations::tls.setLocalData(this);
	auto old_size = this->cpp_tls_size;
	this->cpp_tls_size = this->cpp_tls.size();

	CallResult result;
	auto parameter = QDir::toNativeSeparators(path).toUtf8().toStdString();
	CppInterpreter_execute(&result, interpreter.get(), parameter.c_str());
	delete_CppCallResult(&result);

	this->cpp_tls.resize(this->cpp_tls_size);
	this->cpp_tls_size = old_size;
	cpp_implementations::tls.setLocalData(old_tls);
}

void PluginCoreState::store_tls(void *p){
	if (this->cpp_tls_size == this->cpp_tls.size())
		this->cpp_tls.push_back(p);
	else
		this->cpp_tls.back() = p;
}

void *PluginCoreState::retrieve_tls(){
	if (this->cpp_tls_size == this->cpp_tls.size())
		return nullptr;
	return this->cpp_tls.back();
}
<commit_msg>Fixed QThreadStorage usage to accommodate lousy Qt implementation.<commit_after>/*
Copyright (c), Helios
All rights reserved.

Distributed under a permissive license. See COPYING.txt for details.
*/

#include "PluginCoreState.h"
#include "../LoadedImage.h"
#include "../MainWindow.h"
#include <QFile>
#include <QFileInfo>
#include <QMessageBox>
#include <QDir>
#ifdef WIN32
#include <Windows.h>
#endif

const char * const accepted_cpp_extensions[] = {
	"cpp",
	"c",
	"cc",
	"cxx",
	"c++",
};
const size_t accepted_cpp_extensions_size = sizeof(accepted_cpp_extensions) / sizeof(*accepted_cpp_extensions);

bool is_cpp_path(const QString &path){
	auto file_extension = QFileInfo(path).suffix();
	for (auto &ext : accepted_cpp_extensions)
		if (!file_extension.compare(QString(ext), Qt::CaseInsensitive))
			return true;
	return false;
}

bool is_lua_path(const QString &path){
	auto file_extension = QFileInfo(path).suffix().toLower();
	return file_extension == "lua";
}

PluginCoreState::PluginCoreState(){
}

void PluginCoreState::execute(const QString &path){
	if (!QFile::exists(path))
		throw std::exception("File not found.");
	if (is_cpp_path(path))
		this->execute_cpp(path);
	if (is_lua_path(path))
		this->execute_lua(path);
}

#define RESOLVE_FUNCTION(lib, x) auto x = (x##_f)lib.resolve(#x)

void PluginCoreState::execute_lua(const QString &path){
	if (!this->lua_library.isLoaded()){
		this->lua_library.setFileName("LuaInterpreter");
		this->lua_library.load();
	}
	this->caller_image_handle = -1;
	QFile file(path);
	file.open(QFile::ReadOnly);
	if (!file.isOpen())
		throw std::exception("Unknown error while reading file.");
	auto data = file.readAll();

	auto filename = QFileInfo(path).fileName();

	RESOLVE_FUNCTION(this->lua_library, new_LuaInterpreter);
	RESOLVE_FUNCTION(this->lua_library, delete_LuaInterpreter);
	RESOLVE_FUNCTION(this->lua_library, LuaInterpreter_execute);
	RESOLVE_FUNCTION(this->lua_library, delete_LuaCallResult);

	auto params = this->construct_LuaInterpreterParameters();
	std::shared_ptr<LuaInterpreter> interpreter(new_LuaInterpreter(&params), [=](LuaInterpreter *i){ delete_LuaInterpreter(i); });

	CallResult result;
	LuaInterpreter_execute(&result, interpreter.get(), filename.toUtf8().toStdString().c_str(), data.data(), data.size());
	delete_LuaCallResult(&result);
}

int PluginCoreState::get_caller_image_handle(){
	if (this->caller_image_handle >= 0)
		return this->caller_image_handle;
	return this->caller_image_handle = this->image_store.store(this->latest_caller->get_image());
}

void PluginCoreState::display_in_caller(int handle){
	auto image = this->get_store().get_image(handle);
	if (image)
		this->latest_caller->display_filtered_image(std::make_shared<LoadedImage>(image->get_bitmap()));
}

char *clone_string(const char *s){
	if (!s)
		return nullptr;
	auto n = strlen(s);
	auto ret = new char[n + 1];
	memcpy(ret, s, n);
	ret[n] = 0;
	return ret;
}

char *clone_string(const std::string &s){
	auto n = s.size();
	if (!n)
		return nullptr;
	auto ret = new char[n + 1];
	memcpy(ret, &s[0], n);
	ret[n] = 0;
	return ret;
}

ImageOperationResultExternal to_ImageOperationResultExternal(const ImageOperationResult &src){
	ImageOperationResultExternal ret;
	ret.success = src.success;
	static_assert(sizeof(ret.results) == sizeof(src.results), "Inconsistent struct definitions!");
	memcpy(ret.results, src.results, sizeof(ret.results));
	ret.message = clone_string(src.message);
	return ret;
}

namespace lua_implementations{
#define LUA_FUNCTION_SIGNATURE(rt, x, ...) rt x(external_state state, __VA_ARGS__)

LUA_FUNCTION_SIGNATURE(void, release_returned_string, char *s){
	delete[] s;
}

LUA_FUNCTION_SIGNATURE(void, show_message_box, const char *title, const char *message, bool is_error){
	QMessageBox msgbox;
	if (title)
		msgbox.setWindowTitle(QString::fromUtf8(title));
	msgbox.setText(QString::fromUtf8(message));
	if (is_error)
		msgbox.setIcon(QMessageBox::Critical);
	msgbox.exec();
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, get_image_info, int handle, image_info *info){
	ImageOperationResultExternal ret;
	auto This = (PluginCoreState *)state;
	auto image = This->get_store().get_image(handle);
	if (!image){
		ret.success = false;
		ret.message = clone_string(HANDLE_NOT_FOUND_MSG);
		return ret;
	}
	info->handle = handle;
	unsigned stride, pitch;
	info->pixels = image->get_pixels_pointer(stride, pitch);
	info->stride = stride;
	info->pitch = pitch;
	auto temp = image->get_dimensions();
	info->w = temp.results[0];
	info->h = temp.results[1];
	ret.success = true;
	return ret;
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, load_image, const char *path){
	auto This = (PluginCoreState *)state;
	return to_ImageOperationResultExternal(This->get_store().load(path));
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, unload_image, int handle){
	auto This = (PluginCoreState *)state;
	return to_ImageOperationResultExternal(This->get_store().unload(handle));
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, allocate_image, int w, int h){
	auto This = (PluginCoreState *)state;
	return to_ImageOperationResultExternal(This->get_store().allocate(w, h));
}

LUA_FUNCTION_SIGNATURE(ImageOperationResultExternal, save_image, int handle, const char *path, int compression, const char *format){
	auto This = (PluginCoreState *)state;
	SaveOptions opt;
	opt.compression = compression;
	if (format)
		opt.format = format;
	return to_ImageOperationResultExternal(This->get_store().save(handle, QString::fromUtf8(path), opt));
}

LUA_FUNCTION_SIGNATURE(int, get_caller_image){
	auto This = (PluginCoreState *)state;
	return This->get_caller_image_handle();
}

LUA_FUNCTION_SIGNATURE(void, display_in_current_window, int handle){
	auto This = (PluginCoreState *)state;
	This->display_in_caller(handle);
}

LUA_FUNCTION_SIGNATURE(void, debug_print, const char *string){
#ifdef WIN32
	auto temp = QString::fromUtf8(string);
	OutputDebugStringW(temp.toStdWString().c_str());
#endif
}

}

LuaInterpreterParameters PluginCoreState::construct_LuaInterpreterParameters(){
	LuaInterpreterParameters ret;
	ret.state = this;
#define PASS_FUNCTION_TO_LUA(x) ret.x = lua_implementations::x
	PASS_FUNCTION_TO_LUA(release_returned_string);
	PASS_FUNCTION_TO_LUA(show_message_box);
	PASS_FUNCTION_TO_LUA(get_image_info);
	PASS_FUNCTION_TO_LUA(load_image);
	PASS_FUNCTION_TO_LUA(unload_image);
	PASS_FUNCTION_TO_LUA(allocate_image);
	PASS_FUNCTION_TO_LUA(save_image);
	PASS_FUNCTION_TO_LUA(get_caller_image);
	PASS_FUNCTION_TO_LUA(display_in_current_window);
	PASS_FUNCTION_TO_LUA(debug_print);

	return ret;
}

namespace cpp_implementations{

QThreadStorage<uintptr_t> tls;

#define CPP_FUNCTION_SIGNATURE(rt, x, ...) rt x(external_state state, __VA_ARGS__)

CPP_FUNCTION_SIGNATURE(void, release_returned_string, char *s){
	delete[] s;
}

CPP_FUNCTION_SIGNATURE(void, store_tls, void *s){
	auto This = (PluginCoreState *)tls.localData();
	This->store_tls(s);
}

CPP_FUNCTION_SIGNATURE(void *, retrieve_tls){
	auto This = (PluginCoreState *)tls.localData();
	return This->retrieve_tls();
}

}

CppInterpreterParameters PluginCoreState::construct_CppInterpreterParameters(){
	CppInterpreterParameters ret;
	ret.state = this;
	ret.caller_image = this->get_caller_image_handle();
#define PASS_FUNCTION_TO_CPP(x) ret.x = cpp_implementations::x
	PASS_FUNCTION_TO_CPP(release_returned_string);
	PASS_FUNCTION_TO_CPP(store_tls);
	PASS_FUNCTION_TO_CPP(retrieve_tls);

	return ret;
}

void PluginCoreState::execute_cpp(const QString &path){
	if (!this->cpp_library.isLoaded()){
		this->cpp_library.setFileName("CppInterpreter");
		this->cpp_library.load();
	}
	this->caller_image_handle = -1;
	{
		QFile file(path);
		file.open(QFile::ReadOnly);
		if (!file.isOpen())
			throw std::exception("Unknown error while reading file.");
	}

	RESOLVE_FUNCTION(this->cpp_library, new_CppInterpreter);
	RESOLVE_FUNCTION(this->cpp_library, delete_CppInterpreter);
	RESOLVE_FUNCTION(this->cpp_library, CppInterpreter_execute);
	RESOLVE_FUNCTION(this->cpp_library, delete_CppCallResult);

	auto params = this->construct_CppInterpreterParameters();
	std::shared_ptr<CppInterpreter> interpreter(new_CppInterpreter(&params), [=](CppInterpreter *i){ delete_CppInterpreter(i); });

	auto old_tls = cpp_implementations::tls.localData();
	cpp_implementations::tls.setLocalData((uintptr_t)this);
	auto old_size = this->cpp_tls_size;
	this->cpp_tls_size = this->cpp_tls.size();

	CallResult result;
	auto parameter = QDir::toNativeSeparators(path).toUtf8().toStdString();
	CppInterpreter_execute(&result, interpreter.get(), parameter.c_str());
	delete_CppCallResult(&result);

	this->cpp_tls.resize(this->cpp_tls_size);
	this->cpp_tls_size = old_size;
	cpp_implementations::tls.setLocalData(old_tls);
}

void PluginCoreState::store_tls(void *p){
	if (this->cpp_tls_size == this->cpp_tls.size())
		this->cpp_tls.push_back(p);
	else
		this->cpp_tls.back() = p;
}

void *PluginCoreState::retrieve_tls(){
	if (this->cpp_tls_size == this->cpp_tls.size())
		return nullptr;
	return this->cpp_tls.back();
}
<|endoftext|>


<commit_before>#include <fstream>
#include <sstream>

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/alert_types.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::create_directory;
using namespace libtorrent;

void print_alerts(libtorrent::session& ses, char const* name, bool allow_disconnects, bool allow_no_torrents)
{
	std::vector<torrent_handle> handles = ses.get_torrents();
	TEST_CHECK(!handles.empty() || allow_no_torrents);
	torrent_handle h;
	if (!handles.empty()) h = handles[0];
	std::auto_ptr<alert> a;
	a = ses.pop_alert();
	while (a.get())
	{
		std::cerr << name << ": " << a->msg() << "\n";
		TEST_CHECK(dynamic_cast<peer_error_alert*>(a.get()) == 0
			|| (!handles.empty() && h.is_seed())
			|| a->msg() == "connecting to peer"
			|| a->msg() == "closing connection to ourself"
			|| a->msg() == "duplicate connection"
			|| (allow_disconnects && a->msg() == "End of file."));
		a = ses.pop_alert();
	}
}

void test_sleep(int millisec)
{
	boost::xtime xt;
	boost::xtime_get(&xt, boost::TIME_UTC);
	boost::uint64_t nanosec = (millisec % 1000) * 1000000 + xt.nsec;
	int sec = millisec / 1000;
	if (nanosec > 1000000000)
	{
		nanosec -= 1000000000;
		sec++;
	}
	xt.nsec = nanosec;
	xt.sec += sec;
	boost::thread::sleep(xt);
}

void stop_web_server(int port)
{
	std::stringstream cmd;
	cmd << "kill `cat ./lighty" << port << ".pid` >/dev/null";
	system(cmd.str().c_str());
}

void start_web_server(int port)
{
	stop_web_server(port);
	std::ofstream f("./lighty_config");
	f << "server.modules = (\"mod_access\")\n"
		"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
		"server.range-requests = \"enable\"\n"
		"server.port = " << port << "\n"
		"server.pid-file = \"./lighty" << port << ".pid\"\n";
	f.close();

	system("lighttpd -f lighty_config &");
	test_sleep(1000);
}

void stop_proxy(int port)
{
	std::stringstream cmd;
	cmd << "delegated -P" << port << " -Fkill";
	system(cmd.str().c_str());
}

void start_proxy(int port, int proxy_type)
{
	using namespace libtorrent;

	stop_proxy(port);
	std::stringstream cmd;
	// we need to echo n since dg will ask us to configure it
	cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com";
	switch (proxy_type)
	{
		case proxy_settings::socks4:
			cmd << " SERVER=socks4";
			break;
		case proxy_settings::socks5:
			cmd << " SERVER=socks5";
			break;
		case proxy_settings::socks5_pw:
			cmd << " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
			break;
		case proxy_settings::http:
			cmd << " SERVER=http";
			break;
		case proxy_settings::http_pw:
			cmd << " SERVER=http AUTHORIZER=-list{testuser:testpass}";
			break;
	}
	system(cmd.str().c_str());
}

using namespace libtorrent;

template <class T>
boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
{
	return boost::intrusive_ptr<T>(new T(*ptr));
}

boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file)
{
	char const* tracker_url = "http://non-existent-name.com/announce";

	using namespace boost::filesystem;

	boost::intrusive_ptr<torrent_info> t(new torrent_info);
	int total_size = 2 * 1024 * 1024;
	t->add_file(path("temporary"), total_size);
	t->set_piece_size(16 * 1024);
	t->add_tracker(tracker_url);

	std::vector<char> piece(16 * 1024);
	for (int i = 0; i < int(piece.size()); ++i)
		piece[i] = (i % 26) + 'A';

	// calculate the hash for all pieces
	int num = t->num_pieces();
	sha1_hash ph = hasher(&piece[0], piece.size()).final();
	for (int i = 0; i < num; ++i)
		t->set_hash(i, ph);
	t->create_torrent();

	if (file)
	{
		while (total_size > 0)
		{
			file->write(&piece[0], (std::min)(int(piece.size()), total_size));
			total_size -= piece.size();
		}
	}

	return t;
}

boost::tuple<torrent_handle, torrent_handle, torrent_handle>
setup_transfer(session* ses1, session* ses2, session* ses3
	, bool clear_files, bool use_metadata_transfer, bool connect_peers
	, std::string suffix)
{
	using namespace boost::filesystem;

	assert(ses1);
	assert(ses2);

	assert(ses1->id() != ses2->id());
	if (ses3)
		assert(ses3->id() != ses2->id());

	create_directory("./tmp1" + suffix);
	std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = create_torrent(&file);
	file.close();
	if (clear_files)
	{
		remove_all("./tmp2" + suffix + "/temporary");
		remove_all("./tmp3" + suffix + "/temporary");
	}

	std::cerr << "generated torrent: " << t->info_hash() << std::endl;

	ses1->set_severity_level(alert::debug);
	ses2->set_severity_level(alert::debug);

	// they should not use the same save dir, because the
	// file pool will complain if two torrents are trying to
	// use the same files
	sha1_hash info_hash = t->info_hash();
	torrent_handle tor1 = ses1->add_torrent(clone_ptr(t), "./tmp1" + suffix);
	TEST_CHECK(!ses1->get_torrents().empty());
	torrent_handle tor2;
	torrent_handle tor3;
	if (ses3)
	{
		tor3 = ses3->add_torrent(clone_ptr(t), "./tmp3" + suffix);
		TEST_CHECK(!ses3->get_torrents().empty());
	}

  	if (use_metadata_transfer)
		tor2 = ses2->add_torrent("http://non-existent-name.com/announce"
		, t->info_hash(), 0, "./tmp2" + suffix);
	else
		tor2 = ses2->add_torrent(clone_ptr(t), "./tmp2" + suffix);
	TEST_CHECK(!ses2->get_torrents().empty());

	assert(ses1->get_torrents().size() == 1);
	assert(ses2->get_torrents().size() == 1);

	test_sleep(100);

	if (connect_peers)
	{
		std::cerr << "connecting peer\n";
		tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
			, ses2->listen_port()));

		if (ses3)
		{
			// give the other peers some time to get an initial
			// set of pieces before they start sharing with each-other
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses2->listen_port()));
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses1->listen_port()));
		}
	}

	return boost::make_tuple(tor1, tor2, tor3);
}

<commit_msg>updated tests<commit_after>#include <fstream>
#include <sstream>

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/alert_types.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::create_directory;
using namespace libtorrent;

void print_alerts(libtorrent::session& ses, char const* name, bool allow_disconnects, bool allow_no_torrents)
{
	std::vector<torrent_handle> handles = ses.get_torrents();
	TEST_CHECK(!handles.empty() || allow_no_torrents);
	torrent_handle h;
	if (!handles.empty()) h = handles[0];
	std::auto_ptr<alert> a;
	a = ses.pop_alert();
	while (a.get())
	{
		if (a->msg() != "block downloading"
			&& a->msg() != "block finished"
			&& a->msg() != "piece finished")
			std::cerr << name << ": " << a->msg() << "\n";
		TEST_CHECK(dynamic_cast<peer_error_alert*>(a.get()) == 0
			|| (!handles.empty() && h.is_seed())
			|| a->msg() == "connecting to peer"
			|| a->msg() == "closing connection to ourself"
			|| a->msg() == "duplicate connection"
			|| (allow_disconnects && a->msg() == "End of file."));
		a = ses.pop_alert();
	}
}

void test_sleep(int millisec)
{
	boost::xtime xt;
	boost::xtime_get(&xt, boost::TIME_UTC);
	boost::uint64_t nanosec = (millisec % 1000) * 1000000 + xt.nsec;
	int sec = millisec / 1000;
	if (nanosec > 1000000000)
	{
		nanosec -= 1000000000;
		sec++;
	}
	xt.nsec = nanosec;
	xt.sec += sec;
	boost::thread::sleep(xt);
}

void stop_web_server(int port)
{
	std::stringstream cmd;
	cmd << "kill `cat ./lighty" << port << ".pid` >/dev/null";
	system(cmd.str().c_str());
}

void start_web_server(int port)
{
	stop_web_server(port);
	std::ofstream f("./lighty_config");
	f << "server.modules = (\"mod_access\")\n"
		"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
		"server.range-requests = \"enable\"\n"
		"server.port = " << port << "\n"
		"server.pid-file = \"./lighty" << port << ".pid\"\n";
	f.close();

	system("lighttpd -f lighty_config &");
	test_sleep(1000);
}

void stop_proxy(int port)
{
	std::stringstream cmd;
	cmd << "delegated -P" << port << " -Fkill";
	system(cmd.str().c_str());
}

void start_proxy(int port, int proxy_type)
{
	using namespace libtorrent;

	stop_proxy(port);
	std::stringstream cmd;
	// we need to echo n since dg will ask us to configure it
	cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com";
	switch (proxy_type)
	{
		case proxy_settings::socks4:
			cmd << " SERVER=socks4";
			break;
		case proxy_settings::socks5:
			cmd << " SERVER=socks5";
			break;
		case proxy_settings::socks5_pw:
			cmd << " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
			break;
		case proxy_settings::http:
			cmd << " SERVER=http";
			break;
		case proxy_settings::http_pw:
			cmd << " SERVER=http AUTHORIZER=-list{testuser:testpass}";
			break;
	}
	system(cmd.str().c_str());
}

using namespace libtorrent;

template <class T>
boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
{
	return boost::intrusive_ptr<T>(new T(*ptr));
}

boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file)
{
	char const* tracker_url = "http://non-existent-name.com/announce";

	using namespace boost::filesystem;

	boost::intrusive_ptr<torrent_info> t(new torrent_info);
	int total_size = 2 * 1024 * 1024;
	t->add_file(path("temporary"), total_size);
	t->set_piece_size(16 * 1024);
	t->add_tracker(tracker_url);

	std::vector<char> piece(16 * 1024);
	for (int i = 0; i < int(piece.size()); ++i)
		piece[i] = (i % 26) + 'A';

	// calculate the hash for all pieces
	int num = t->num_pieces();
	sha1_hash ph = hasher(&piece[0], piece.size()).final();
	for (int i = 0; i < num; ++i)
		t->set_hash(i, ph);
	t->create_torrent();

	if (file)
	{
		while (total_size > 0)
		{
			file->write(&piece[0], (std::min)(int(piece.size()), total_size));
			total_size -= piece.size();
		}
	}

	return t;
}

boost::tuple<torrent_handle, torrent_handle, torrent_handle>
setup_transfer(session* ses1, session* ses2, session* ses3
	, bool clear_files, bool use_metadata_transfer, bool connect_peers
	, std::string suffix)
{
	using namespace boost::filesystem;

	assert(ses1);
	assert(ses2);

	assert(ses1->id() != ses2->id());
	if (ses3)
		assert(ses3->id() != ses2->id());

	create_directory("./tmp1" + suffix);
	std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = create_torrent(&file);
	file.close();
	if (clear_files)
	{
		remove_all("./tmp2" + suffix + "/temporary");
		remove_all("./tmp3" + suffix + "/temporary");
	}

	std::cerr << "generated torrent: " << t->info_hash() << std::endl;

	ses1->set_severity_level(alert::debug);
	ses2->set_severity_level(alert::debug);

	// they should not use the same save dir, because the
	// file pool will complain if two torrents are trying to
	// use the same files
	sha1_hash info_hash = t->info_hash();
	torrent_handle tor1 = ses1->add_torrent(clone_ptr(t), "./tmp1" + suffix);
	TEST_CHECK(!ses1->get_torrents().empty());
	torrent_handle tor2;
	torrent_handle tor3;
	if (ses3)
	{
		tor3 = ses3->add_torrent(clone_ptr(t), "./tmp3" + suffix);
		TEST_CHECK(!ses3->get_torrents().empty());
	}

  	if (use_metadata_transfer)
		tor2 = ses2->add_torrent("http://non-existent-name.com/announce"
		, t->info_hash(), 0, "./tmp2" + suffix);
	else
		tor2 = ses2->add_torrent(clone_ptr(t), "./tmp2" + suffix);
	TEST_CHECK(!ses2->get_torrents().empty());

	assert(ses1->get_torrents().size() == 1);
	assert(ses2->get_torrents().size() == 1);

	test_sleep(100);

	if (connect_peers)
	{
		std::cerr << "connecting peer\n";
		tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
			, ses2->listen_port()));

		if (ses3)
		{
			// give the other peers some time to get an initial
			// set of pieces before they start sharing with each-other
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses2->listen_port()));
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses1->listen_port()));
		}
	}

	return boost::make_tuple(tor1, tor2, tor3);
}

<|endoftext|>


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

  Copyright 2013 Scientific Computation Research Center,
      Rensselaer Polytechnic Institute. All rights reserved.

  The LICENSE file included with this distribution describes the terms
  of the SCOREC Non-Commercial License this program is distributed under.

*******************************************************************************/
#include "maCollapse.h"
#include "maAdapt.h"
#include "maShape.h"
#include <apfCavityOp.h>
#include <cassert>

namespace ma {

void Collapse::Init(Adapt* a)
{
  adapt = a;
  cavity.init(a);
}

bool Collapse::requestLocality(apf::CavityOp* o)
{
/* get vertices again since this is sometimes used
   before setVerts can work */
  Entity* v[2];
  Mesh* m = adapt->mesh;
  m->getDownward(edge,0,v);
  return o->requestLocality(v,2);
}

bool Collapse::tryThisDirection(double qualityToBeat)
{
  assert( ! adapt->mesh->isShared(vertToCollapse));
  rebuildElements();
  if ( ! checkValidity(qualityToBeat))
    return false;
  if ((adapt->mesh->getDimension()==2)
    &&( ! isGood2DMesh()))
  {
    cancel();
    return false;
  }
  return true;
}

bool Collapse::tryBothDirections(double qualityToBeat)
{
  computeElementSets();
  if (tryThisDirection(qualityToBeat))
    return true;
  if ( ! getFlag(adapt,vertToKeep,COLLAPSE))
    return false;
  std::swap(vertToKeep,vertToCollapse);
  computeElementSets();
  return tryThisDirection(qualityToBeat);
}

bool Collapse::setEdge(Entity* e)
{
  if (getFlag(adapt,e,DONT_COLLAPSE))
    return false;
  edge = e;
  vertToCollapse = 0;
  vertToKeep = 0;
  elementsToCollapse.clear();
  elementsToKeep.clear();
  return true;
}

/* this routine ensures we have "mesh material" to pull from
   on at least one side of a collapsing entity.
   "a side (edge or tri) adjacent to a vertex to collapse must have the same classification
    as the center entity (tri or tet) being collapsed" */
static bool checkRingSide(Adapt* a, Entity* side, Entity* vert, Model* centerModel)
{
  Mesh* m = a->mesh;
  if (getFlag(a,vert,COLLAPSE)) {
    if (m->toModel(side)==centerModel)
      return true;
    else {
/* this function is responsible for disabling collapse of a
   vertex that has no material to pull from ! */
      clearFlag(a,vert,COLLAPSE);
      return false;
    }
  }
  else
    return false;
}

/* if there exists a ring of three edges containing
   the collapsing edge, those edges must bound a triangle */
bool checkEdgeCollapseEdgeRings(Adapt* a, Entity* edge)
{
  Mesh* m = a->mesh;
  Entity* v[2];
  m->getDownward(edge,0,v);
  assert( ! m->isShared(v[0]));
  assert( ! m->isShared(v[1]));
  apf::Up ve[2];
  m->getUp(v[0],ve[0]);
  m->getUp(v[1],ve[1]);
  Entity* ring[3];
  ring[2] = edge;
  for (int i=0; i < ve[0].n; ++i)
  {
    ring[0] = ve[0].e[i];
    Entity* midv = getEdgeVertOppositeVert(m,ring[0],v[0]);
    for (int j=0; j < ve[1].n; ++j)
    {
      ring[1] = ve[1].e[j];
      if (midv != getEdgeVertOppositeVert(m,ring[1],v[1]))
        continue;
      //at this point a ring is found
      Entity* face = findUpward(m, apf::Mesh::TRIANGLE, ring);
      if (!face) return false; //the ring doesn't bound a face
      Model* c = m->toModel(face);
/* the face must have the same classification
   as one edge adjacent to a collapsing vertex.
   explicit booleans because checkRingSide has side
   effects and should be run on both vertices. */
      bool ok0 = checkRingSide(a,ring[0],v[0],c);
      bool ok1 = checkRingSide(a,ring[1],v[1],c);
      if ( ! (ok0 || ok1))
        return false;
    }
  }
  return true;
}

/* if there exist two edge-adjacent faces connecting the vertices,
   those faces and the edge must bound a tet */
bool checkEdgeCollapseFaceRings(Adapt* a, Entity* edge)
{
  Mesh* m = a->mesh;
  Entity* v[2];
  m->getDownward(edge,0,v);
  Upward vf[2];
  m->getAdjacent(v[0],2,vf[0]);
  m->getAdjacent(v[1],2,vf[1]);
/* this is here to speed up what would otherwise be an n^2 operation
   where n is the number of faces per vertex, n=~30 on average */
  std::map<Entity*,Entity*> oppositeEdgesToFaces;
  Entity* f[2];
  for (size_t i=0; i < vf[0].getSize(); ++i)
  {
    f[0] = vf[0][i];
/* we filter out non-tri faces; collapses involving the boundary
   layer should ensure topological correctness by other methods */
    if (( m->getType(f[0]) == apf::Mesh::TRIANGLE)
      &&( ! isInClosure(m,f[0],edge)))
    {
      Entity* oppositeEdge = getTriEdgeOppositeVert(m,f[0],v[0]);
      oppositeEdgesToFaces[oppositeEdge]=f[0];
    }
  }
  for (size_t i=0; i < vf[1].getSize(); ++i)
  {
    f[1] = vf[1][i];
    if ((m->getType(f[1]) != apf::Mesh::TRIANGLE)||
        (isInClosure(m, f[1], edge)))
      continue;
    Entity* oppositeEdge = getTriEdgeOppositeVert(m,f[1],v[1]);
    std::map<Entity*,Entity*>::iterator found =
      oppositeEdgesToFaces.find(oppositeEdge);
    if (found==oppositeEdgesToFaces.end()) continue;
    //at this point a ring is found
    f[0] = found->second;
    Entity* tet = findTetByTwoTris(m,f);
    if (!tet) return false;
    Model* c = m->toModel(tet);
/* at least one face adjacent to a collapsing vertex
   must have the same classification as the tet.
   explicit booleans because checkRingSide has side
   effects and should be run on both vertices. */
    bool ok0 = checkRingSide(a,f[0],v[0],c);
    bool ok1 = checkRingSide(a,f[1],v[1],c);
    if ( ! (ok0 || ok1))
      return false;
  }
  return true;
}

bool checkEdgeCollapseTopology(Adapt* a, Entity* edge)
{
  if ( ! checkEdgeCollapseEdgeRings(a,edge))
    return false;
  if ( ! checkEdgeCollapseFaceRings(a,edge))
    return false;
  return true;
}

static bool setVertexToCollapse(Adapt* a, Entity* v)
{
  if (getFlag(a,v,DONT_COLLAPSE))
    return false;
  setFlag(a,v,COLLAPSE);
  return true;
}

/* this function checks the geometric classification
   requirements on an edge collapse
   and marks vertices with the COLLAPSE flag */
bool checkEdgeCollapseClassification(Adapt* a, Entity* edge)
{
  Mesh* m = a->mesh;
  Entity* v[2];
  m->getDownward(edge,0,v);
  Model* c[3];
  c[0] = m->toModel(v[0]);
  c[1] = m->toModel(edge);
  c[2] = m->toModel(v[1]);
  int cd[3];
  cd[0] = m->getModelType(c[0]);
  cd[1] = m->getModelType(c[1]);
  cd[2] = m->getModelType(c[2]);
  /* if the vertices are classified on equal-order model entities,
     then both vertices and the edge must have the same classification */
  if (cd[0] == cd[2])
  {
    if ( ! ((c[0]==c[1])&&(c[1]==c[2])))
      return false;
    bool ok[2];
    ok[0] = setVertexToCollapse(a,v[0]);
    ok[1] = setVertexToCollapse(a,v[1]);
    return ok[0] || ok[1];
  }
  //by now cd[2] != cd[0]
  if (cd[2] > cd[0])
  {
    std::swap(cd[0],cd[2]);
    std::swap(c[0],c[2]);
    std::swap(v[0],v[1]);
  }
  //now cd[0] > cd[2]
  /* if the vertices are classified on different orders, then the
     vertex to be collapsed and the edge must be classified on
     the higher-order model entity */
  if (c[0]!=c[1])
    return false;
  return setVertexToCollapse(a,v[0]);
}

bool Collapse::checkClass()
{
  if (checkEdgeCollapseClassification(adapt,edge))
    return true;
  clearFlag(adapt,edge,COLLAPSE);
  return false;
}

bool Collapse::checkTopo()
{
  if (checkEdgeCollapseTopology(adapt,edge))
  {
    setVerts();
    return true;
  }
  unmark();
  return false;
}

void Collapse::unmark()
{ /* flags must be properly cleared to prevent misinterpretation
     later in the algorithms */
  clearFlag(adapt,edge,COLLAPSE);
  Entity* v[2];
  Mesh* m = adapt->mesh;
  m->getDownward(edge,0,v);
  for (int i=0; i < 2; ++i)
    if ( ! isRequiredForAnEdgeCollapse(adapt,v[i]))
      clearFlag(adapt,v[i],COLLAPSE);
}

void Collapse::setVerts()
{
  Entity* v[2];
  Mesh* m = adapt->mesh;
  m->getDownward(edge,0,v);
  if (getFlag(adapt,v[0],COLLAPSE))
    vertToCollapse = v[0];
  else
    vertToCollapse = v[1];
  assert(getFlag(adapt,vertToCollapse,COLLAPSE));
  vertToKeep = getEdgeVertOppositeVert(m,edge,vertToCollapse);
}

void Collapse::computeElementSets()
{
  Upward adjacent;
  Mesh* m = adapt->mesh;
  m->getAdjacent(edge,m->getDimension(),adjacent);
  elementsToCollapse.clear();
  APF_ITERATE(Upward,adjacent,it)
    elementsToCollapse.insert(*it);
  m->getAdjacent(vertToCollapse,m->getDimension(),adjacent);
  elementsToKeep.clear();
  APF_ITERATE(Upward,adjacent,it)
    if ( ! elementsToCollapse.count(*it))
      elementsToKeep.insert(*it);
  assert(elementsToKeep.size());
}

void Collapse::rebuildElements()
{
  assert(elementsToKeep.size());
  newElements.setSize(elementsToKeep.size());
  cavity.beforeBuilding();
  size_t ni=0;
  APF_ITERATE(EntitySet,elementsToKeep,it)
    newElements[ni++]=
        rebuildElement(adapt,*it,vertToCollapse,vertToKeep);
  cavity.afterBuilding();
  if (cavity.shouldFit) {
    EntityArray oldElements;
    getOldElements(oldElements);
    cavity.fit(oldElements);
  }
}

bool Collapse::checkValidity(double qualityToBeat)
{
  double quality = getWorstQuality(adapt,newElements);
  if (quality > qualityToBeat)
    return true;
  cancel();
  return false;
}

bool Collapse::isGood2DMesh()
{
  /* in 2D we want to prevent "inverted" triangles
     we check that each rebuilt triangle has not had
     its normal changed by more than 90 degrees. */
  Mesh* m = adapt->mesh;
  size_t i=0;
  APF_ITERATE(EntitySet,elementsToKeep,it)
    if ( ! isTwoTriAngleAcute(m,*it,newElements[i++]))
      return false;
  return true;
}

void Collapse::cancel()
{
  for (size_t i=0; i < newElements.getSize(); ++i)
    destroyElement(adapt,newElements[i]);
  unmark();
}

void Collapse::getOldElements(EntityArray& oldElements)
{
  EntitySet& toCollapse = elementsToCollapse;
  assert(toCollapse.size());
  EntitySet& toKeep = elementsToKeep;
  assert(toKeep.size());
  oldElements.setSize(toCollapse.size() + toKeep.size());
  size_t k=0;
  APF_ITERATE(EntitySet,toCollapse,it)
    oldElements[k++] = *it;
  APF_ITERATE(EntitySet,toKeep,it)
    oldElements[k++] = *it;
  assert(k==oldElements.getSize());
}

double Collapse::getOldQuality()
{
  EntityArray oldElements;
  getOldElements(oldElements);
  return getWorstQuality(adapt,oldElements);
}

void Collapse::destroyOldElements()
{
  EntityArray oldElements;
  getOldElements(oldElements);
  cavity.transfer(oldElements);
  for (size_t i=0; i < oldElements.getSize(); ++i)
    destroyElement(adapt,oldElements[i]);
}

bool isRequiredForAnEdgeCollapse(Adapt* adapt, Entity* vertex)
{
  Mesh* m = adapt->mesh;
  Model* c = m->toModel(vertex);
  apf::Up ve;
  m->getUp(vertex,ve);
  for (int i=0; i < ve.n; ++i)
  {
    Entity* edge = ve.e[i];
    /* we collapse one model dimension at a time, so
       only edges on the same model entity as the
       vertex being collapsed are relevant */
    if (c != m->toModel(edge))
      continue;
    if (getFlag(adapt,edge,COLLAPSE))
    {
      Entity* v2 = getEdgeVertOppositeVert(m,edge,vertex);
      if ( ! getFlag(adapt,v2,COLLAPSE))
        return true;
    }
  }
  return false;
}

bool setupCollapse(Collapse& collapse, Entity* edge, Entity* vert)
{
  Adapt* adapter = collapse.adapt;
  assert(adapter->mesh->getType(edge) == apf::Mesh::EDGE);
  assert(adapter->mesh->getType(vert) == apf::Mesh::VERTEX);
  if ( ! collapse.setEdge(edge))
    return false;
  if ( ! collapse.checkClass())
    return false;
  if ( ! collapse.checkTopo())
    return false;
  if ( ! getFlag(adapter, vert, COLLAPSE)) {
    collapse.unmark();
    return false;
  }
  if (collapse.vertToCollapse != vert)
    std::swap(collapse.vertToCollapse, collapse.vertToKeep);
  assert(collapse.vertToCollapse == vert);
  collapse.computeElementSets();
  return true;
}

}
<commit_msg>deallocate newElements after destroying them<commit_after>/******************************************************************************

  Copyright 2013 Scientific Computation Research Center,
      Rensselaer Polytechnic Institute. All rights reserved.

  The LICENSE file included with this distribution describes the terms
  of the SCOREC Non-Commercial License this program is distributed under.

*******************************************************************************/
#include "maCollapse.h"
#include "maAdapt.h"
#include "maShape.h"
#include <apfCavityOp.h>
#include <cassert>

namespace ma {

void Collapse::Init(Adapt* a)
{
  adapt = a;
  cavity.init(a);
}

bool Collapse::requestLocality(apf::CavityOp* o)
{
/* get vertices again since this is sometimes used
   before setVerts can work */
  Entity* v[2];
  Mesh* m = adapt->mesh;
  m->getDownward(edge,0,v);
  return o->requestLocality(v,2);
}

bool Collapse::tryThisDirection(double qualityToBeat)
{
  assert( ! adapt->mesh->isShared(vertToCollapse));
  rebuildElements();
  if ( ! checkValidity(qualityToBeat))
    return false;
  if ((adapt->mesh->getDimension()==2)
    &&( ! isGood2DMesh()))
  {
    cancel();
    return false;
  }
  return true;
}

bool Collapse::tryBothDirections(double qualityToBeat)
{
  computeElementSets();
  if (tryThisDirection(qualityToBeat))
    return true;
  if ( ! getFlag(adapt,vertToKeep,COLLAPSE))
    return false;
  std::swap(vertToKeep,vertToCollapse);
  computeElementSets();
  return tryThisDirection(qualityToBeat);
}

bool Collapse::setEdge(Entity* e)
{
  if (getFlag(adapt,e,DONT_COLLAPSE))
    return false;
  edge = e;
  vertToCollapse = 0;
  vertToKeep = 0;
  elementsToCollapse.clear();
  elementsToKeep.clear();
  return true;
}

/* this routine ensures we have "mesh material" to pull from
   on at least one side of a collapsing entity.
   "a side (edge or tri) adjacent to a vertex to collapse must have the same classification
    as the center entity (tri or tet) being collapsed" */
static bool checkRingSide(Adapt* a, Entity* side, Entity* vert, Model* centerModel)
{
  Mesh* m = a->mesh;
  if (getFlag(a,vert,COLLAPSE)) {
    if (m->toModel(side)==centerModel)
      return true;
    else {
/* this function is responsible for disabling collapse of a
   vertex that has no material to pull from ! */
      clearFlag(a,vert,COLLAPSE);
      return false;
    }
  }
  else
    return false;
}

/* if there exists a ring of three edges containing
   the collapsing edge, those edges must bound a triangle */
bool checkEdgeCollapseEdgeRings(Adapt* a, Entity* edge)
{
  Mesh* m = a->mesh;
  Entity* v[2];
  m->getDownward(edge,0,v);
  assert( ! m->isShared(v[0]));
  assert( ! m->isShared(v[1]));
  apf::Up ve[2];
  m->getUp(v[0],ve[0]);
  m->getUp(v[1],ve[1]);
  Entity* ring[3];
  ring[2] = edge;
  for (int i=0; i < ve[0].n; ++i)
  {
    ring[0] = ve[0].e[i];
    Entity* midv = getEdgeVertOppositeVert(m,ring[0],v[0]);
    for (int j=0; j < ve[1].n; ++j)
    {
      ring[1] = ve[1].e[j];
      if (midv != getEdgeVertOppositeVert(m,ring[1],v[1]))
        continue;
      //at this point a ring is found
      Entity* face = findUpward(m, apf::Mesh::TRIANGLE, ring);
      if (!face) return false; //the ring doesn't bound a face
      Model* c = m->toModel(face);
/* the face must have the same classification
   as one edge adjacent to a collapsing vertex.
   explicit booleans because checkRingSide has side
   effects and should be run on both vertices. */
      bool ok0 = checkRingSide(a,ring[0],v[0],c);
      bool ok1 = checkRingSide(a,ring[1],v[1],c);
      if ( ! (ok0 || ok1))
        return false;
    }
  }
  return true;
}

/* if there exist two edge-adjacent faces connecting the vertices,
   those faces and the edge must bound a tet */
bool checkEdgeCollapseFaceRings(Adapt* a, Entity* edge)
{
  Mesh* m = a->mesh;
  Entity* v[2];
  m->getDownward(edge,0,v);
  Upward vf[2];
  m->getAdjacent(v[0],2,vf[0]);
  m->getAdjacent(v[1],2,vf[1]);
/* this is here to speed up what would otherwise be an n^2 operation
   where n is the number of faces per vertex, n=~30 on average */
  std::map<Entity*,Entity*> oppositeEdgesToFaces;
  Entity* f[2];
  for (size_t i=0; i < vf[0].getSize(); ++i)
  {
    f[0] = vf[0][i];
/* we filter out non-tri faces; collapses involving the boundary
   layer should ensure topological correctness by other methods */
    if (( m->getType(f[0]) == apf::Mesh::TRIANGLE)
      &&( ! isInClosure(m,f[0],edge)))
    {
      Entity* oppositeEdge = getTriEdgeOppositeVert(m,f[0],v[0]);
      oppositeEdgesToFaces[oppositeEdge]=f[0];
    }
  }
  for (size_t i=0; i < vf[1].getSize(); ++i)
  {
    f[1] = vf[1][i];
    if ((m->getType(f[1]) != apf::Mesh::TRIANGLE)||
        (isInClosure(m, f[1], edge)))
      continue;
    Entity* oppositeEdge = getTriEdgeOppositeVert(m,f[1],v[1]);
    std::map<Entity*,Entity*>::iterator found =
      oppositeEdgesToFaces.find(oppositeEdge);
    if (found==oppositeEdgesToFaces.end()) continue;
    //at this point a ring is found
    f[0] = found->second;
    Entity* tet = findTetByTwoTris(m,f);
    if (!tet) return false;
    Model* c = m->toModel(tet);
/* at least one face adjacent to a collapsing vertex
   must have the same classification as the tet.
   explicit booleans because checkRingSide has side
   effects and should be run on both vertices. */
    bool ok0 = checkRingSide(a,f[0],v[0],c);
    bool ok1 = checkRingSide(a,f[1],v[1],c);
    if ( ! (ok0 || ok1))
      return false;
  }
  return true;
}

bool checkEdgeCollapseTopology(Adapt* a, Entity* edge)
{
  if ( ! checkEdgeCollapseEdgeRings(a,edge))
    return false;
  if ( ! checkEdgeCollapseFaceRings(a,edge))
    return false;
  return true;
}

static bool setVertexToCollapse(Adapt* a, Entity* v)
{
  if (getFlag(a,v,DONT_COLLAPSE))
    return false;
  setFlag(a,v,COLLAPSE);
  return true;
}

/* this function checks the geometric classification
   requirements on an edge collapse
   and marks vertices with the COLLAPSE flag */
bool checkEdgeCollapseClassification(Adapt* a, Entity* edge)
{
  Mesh* m = a->mesh;
  Entity* v[2];
  m->getDownward(edge,0,v);
  Model* c[3];
  c[0] = m->toModel(v[0]);
  c[1] = m->toModel(edge);
  c[2] = m->toModel(v[1]);
  int cd[3];
  cd[0] = m->getModelType(c[0]);
  cd[1] = m->getModelType(c[1]);
  cd[2] = m->getModelType(c[2]);
  /* if the vertices are classified on equal-order model entities,
     then both vertices and the edge must have the same classification */
  if (cd[0] == cd[2])
  {
    if ( ! ((c[0]==c[1])&&(c[1]==c[2])))
      return false;
    bool ok[2];
    ok[0] = setVertexToCollapse(a,v[0]);
    ok[1] = setVertexToCollapse(a,v[1]);
    return ok[0] || ok[1];
  }
  //by now cd[2] != cd[0]
  if (cd[2] > cd[0])
  {
    std::swap(cd[0],cd[2]);
    std::swap(c[0],c[2]);
    std::swap(v[0],v[1]);
  }
  //now cd[0] > cd[2]
  /* if the vertices are classified on different orders, then the
     vertex to be collapsed and the edge must be classified on
     the higher-order model entity */
  if (c[0]!=c[1])
    return false;
  return setVertexToCollapse(a,v[0]);
}

bool Collapse::checkClass()
{
  if (checkEdgeCollapseClassification(adapt,edge))
    return true;
  clearFlag(adapt,edge,COLLAPSE);
  return false;
}

bool Collapse::checkTopo()
{
  if (checkEdgeCollapseTopology(adapt,edge))
  {
    setVerts();
    return true;
  }
  unmark();
  return false;
}

void Collapse::unmark()
{ /* flags must be properly cleared to prevent misinterpretation
     later in the algorithms */
  clearFlag(adapt,edge,COLLAPSE);
  Entity* v[2];
  Mesh* m = adapt->mesh;
  m->getDownward(edge,0,v);
  for (int i=0; i < 2; ++i)
    if ( ! isRequiredForAnEdgeCollapse(adapt,v[i]))
      clearFlag(adapt,v[i],COLLAPSE);
}

void Collapse::setVerts()
{
  Entity* v[2];
  Mesh* m = adapt->mesh;
  m->getDownward(edge,0,v);
  if (getFlag(adapt,v[0],COLLAPSE))
    vertToCollapse = v[0];
  else
    vertToCollapse = v[1];
  assert(getFlag(adapt,vertToCollapse,COLLAPSE));
  vertToKeep = getEdgeVertOppositeVert(m,edge,vertToCollapse);
}

void Collapse::computeElementSets()
{
  Upward adjacent;
  Mesh* m = adapt->mesh;
  m->getAdjacent(edge,m->getDimension(),adjacent);
  elementsToCollapse.clear();
  APF_ITERATE(Upward,adjacent,it)
    elementsToCollapse.insert(*it);
  m->getAdjacent(vertToCollapse,m->getDimension(),adjacent);
  elementsToKeep.clear();
  APF_ITERATE(Upward,adjacent,it)
    if ( ! elementsToCollapse.count(*it))
      elementsToKeep.insert(*it);
  assert(elementsToKeep.size());
}

void Collapse::rebuildElements()
{
  assert(elementsToKeep.size());
  newElements.setSize(elementsToKeep.size());
  cavity.beforeBuilding();
  size_t ni=0;
  APF_ITERATE(EntitySet,elementsToKeep,it)
    newElements[ni++]=
        rebuildElement(adapt,*it,vertToCollapse,vertToKeep);
  cavity.afterBuilding();
  if (cavity.shouldFit) {
    EntityArray oldElements;
    getOldElements(oldElements);
    cavity.fit(oldElements);
  }
}

bool Collapse::checkValidity(double qualityToBeat)
{
  double quality = getWorstQuality(adapt,newElements);
  if (quality > qualityToBeat)
    return true;
  cancel();
  return false;
}

bool Collapse::isGood2DMesh()
{
  /* in 2D we want to prevent "inverted" triangles
     we check that each rebuilt triangle has not had
     its normal changed by more than 90 degrees. */
  Mesh* m = adapt->mesh;
  size_t i=0;
  APF_ITERATE(EntitySet,elementsToKeep,it)
    if ( ! isTwoTriAngleAcute(m,*it,newElements[i++]))
      return false;
  return true;
}

void Collapse::cancel()
{
  for (size_t i=0; i < newElements.getSize(); ++i)
    destroyElement(adapt,newElements[i]);
  newElements.setSize(0);
  unmark();
}

void Collapse::getOldElements(EntityArray& oldElements)
{
  EntitySet& toCollapse = elementsToCollapse;
  assert(toCollapse.size());
  EntitySet& toKeep = elementsToKeep;
  assert(toKeep.size());
  oldElements.setSize(toCollapse.size() + toKeep.size());
  size_t k=0;
  APF_ITERATE(EntitySet,toCollapse,it)
    oldElements[k++] = *it;
  APF_ITERATE(EntitySet,toKeep,it)
    oldElements[k++] = *it;
  assert(k==oldElements.getSize());
}

double Collapse::getOldQuality()
{
  EntityArray oldElements;
  getOldElements(oldElements);
  return getWorstQuality(adapt,oldElements);
}

void Collapse::destroyOldElements()
{
  EntityArray oldElements;
  getOldElements(oldElements);
  cavity.transfer(oldElements);
  for (size_t i=0; i < oldElements.getSize(); ++i)
    destroyElement(adapt,oldElements[i]);
}

bool isRequiredForAnEdgeCollapse(Adapt* adapt, Entity* vertex)
{
  Mesh* m = adapt->mesh;
  Model* c = m->toModel(vertex);
  apf::Up ve;
  m->getUp(vertex,ve);
  for (int i=0; i < ve.n; ++i)
  {
    Entity* edge = ve.e[i];
    /* we collapse one model dimension at a time, so
       only edges on the same model entity as the
       vertex being collapsed are relevant */
    if (c != m->toModel(edge))
      continue;
    if (getFlag(adapt,edge,COLLAPSE))
    {
      Entity* v2 = getEdgeVertOppositeVert(m,edge,vertex);
      if ( ! getFlag(adapt,v2,COLLAPSE))
        return true;
    }
  }
  return false;
}

bool setupCollapse(Collapse& collapse, Entity* edge, Entity* vert)
{
  Adapt* adapter = collapse.adapt;
  assert(adapter->mesh->getType(edge) == apf::Mesh::EDGE);
  assert(adapter->mesh->getType(vert) == apf::Mesh::VERTEX);
  if ( ! collapse.setEdge(edge))
    return false;
  if ( ! collapse.checkClass())
    return false;
  if ( ! collapse.checkTopo())
    return false;
  if ( ! getFlag(adapter, vert, COLLAPSE)) {
    collapse.unmark();
    return false;
  }
  if (collapse.vertToCollapse != vert)
    std::swap(collapse.vertToCollapse, collapse.vertToKeep);
  assert(collapse.vertToCollapse == vert);
  collapse.computeElementSets();
  return true;
}

}
<|endoftext|>


<commit_before>#include <SDL.h>
#include "SDLUtils.hpp"
#include "InitScreen.hpp"

using namespace rd;

int main()
{
    if( ! initSDL() )
        return 1;

    InitScreen screen;
    if( ! screen.init() )
        return 1;

    for (int i = 0; i < 200; i++)
    {
        if( ! screen.show() )
            return 1;
        SDL_Delay(20); //Wait a bit :)
    }
    if( ! screen.cleanup() )
        return 1;

    if( ! cleanupSDL() )
        return 1;

    return 0;
}
<commit_msg>Update testInitScreen to work with new RdScreen API<commit_after>/***
 * testInitScreen
 *
 * Testing InitScreen class, which shows the splash screen and a message to press any key.
 * This test requires a SDLScreenManager
 *
 * This test is NOT AUTOMATIC, not suitable for running it with a CI server
 *
 ***/

#include "ScreenManager.hpp"
#include "SDLScreenManager.hpp"
#include "RdScreen.hpp"
#include "InitScreen.hpp"

#include <yarp/os/Time.h>

using namespace rd;

int main()
{
    //-- Start SDL, Create SDLScreen Manager
    SDLScreenManager::RegisterManager();
    ScreenManager * screenManager = ScreenManager::getScreenManager("SDL");
    screenManager->start();

    RdScreen * screen = new InitScreen();

    if(!screen->init())
        return 1;
    screenManager->setCurrentScreen(screen);

    for (int i = 0; i < 200; i++)
    {
        if(!screen->show())
            return 1;
        yarp::os::Time::delay(0.002);
    }

    if(!screenManager->stop())
        return 1;

    if(!screen->cleanup() )
        return 1;

    delete screen;
    screen = NULL;

    SDLScreenManager::destroyScreenManager();

    return 0;
}
<|endoftext|>


<commit_before>// Copyright © 2018 Dmitriy Khaustov
//
// 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.
//
// Author: Dmitriy Khaustov aka xDimon
// Contacts: khaustov.dm@gmail.com
// File created on: 2018.10.21

// Random.cpp

#include "Random.hpp"

#include <random>
#include <chrono>

#if __cplusplus >= 201703L
std::string Random::generateSequence(const std::string_view& lookUpTable, size_t length)
#else
std::string Random::generateSequence(const std::string& lookUpTable, size_t length)
#endif
{
	std::string sequence;

	std::default_random_engine generator(static_cast<uint64_t>(std::chrono::system_clock::now().time_since_epoch().count()));

	for (;;)
	{
		auto rnd = static_cast<uint64_t>(
			std::generate_canonical<long double, std::numeric_limits<long double>::digits>(generator) * std::numeric_limits<uint64_t>::max()
		);
		for (auto symbol = 0; symbol < 5; symbol++)
		{
			sequence.push_back(lookUpTable[rnd % 62]);
			if (sequence.length() >= length)
			{
				break;
			}
			rnd /= 62;
		}
	}

	return nullptr;
}
<commit_msg>Fix random sequence generator<commit_after>// Copyright © 2018 Dmitriy Khaustov
//
// 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.
//
// Author: Dmitriy Khaustov aka xDimon
// Contacts: khaustov.dm@gmail.com
// File created on: 2018.10.21

// Random.cpp

#include "Random.hpp"

#include <random>
#include <chrono>

#if __cplusplus >= 201703L
std::string Random::generateSequence(const std::string_view& lookUpTable, size_t length)
#else
std::string Random::generateSequence(const std::string& lookUpTable, size_t length)
#endif
{
	std::string sequence;

	std::default_random_engine generator(static_cast<uint64_t>(std::chrono::system_clock::now().time_since_epoch().count()));

	for (;;)
	{
		auto rnd = static_cast<uint64_t>(
			std::generate_canonical<long double, std::numeric_limits<long double>::digits>(generator) * std::numeric_limits<uint64_t>::max()
		);
		for (;;)
		{
			sequence.push_back(lookUpTable[rnd % 62]);
			if (sequence.length() >= length)
			{
				return sequence;
			}
			rnd /= 62;
			if (rnd < lookUpTable.length())
			{
				break;
			}
		}
	}

	return sequence;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <cstdio>
#include <fstream>
#include <iostream>
#include "MccAssembler.h"
#include "MccRobot.h"
using namespace std;

extern int yyparse();
extern FILE *yyin;

int main(int args, char** argv)
{
	MccRobot &robot = theMccRobot();
	string output_filename;
	string input_filename;
	string input_path;

#ifdef DEBUG_MODE
	// Test selection.
	int select_input;
	cout << "Input 1 or 2 to select input file, 1 select 'test', 2 select 'correct'\n"
		"Your select: ";
	cin >> select_input;
	if (1 == select_input) {
		output_filename = input_filename = "test";
	} else if (2 == select_input) {
		output_filename = input_filename = "correct";
	} else {
		cout << "Wrong selection.\n";
		exit(0);
	}
#endif

	// Deal with main arguments.
	// args[1]: input file name.
	if (args > 1) {
		string argv1 = string(argv[1]);
		// Split argv1 into input_path and input_filename.
		int pos = argv1.find_last_of('\\');
		if (string::npos != pos) {
			input_filename = argv1.substr(pos + 1);
			input_path = argv1.substr(0, pos + 1);
		} else {
			input_filename = argv1;
		}
		output_filename = input_filename;
		pos = input_filename.find('.');
		if (string::npos != pos) {
			output_filename = input_filename.substr(0, pos);
		}
	} else if (input_filename.empty()) {
		cout << "No input file.\n";
		exit(0);
	}

	// Open input file as yyin, the input of flex.
	yyin = fopen((input_path + input_filename).c_str(), "r");
	if (nullptr == yyin) {
		cout << "Open file failed.\n";
		exit(1);
	}

	// Parse.
	if (0 != yyparse()) {
		cout << "Parse error.\n";
		exit(1);
	}

	// After parsing, do more thing.
	if (robot.check_semantic_error()) {
		robot.generate_code();

		// Deal with conflict between input filename and output filename.
		if (input_filename == output_filename) {
			output_filename += ".out";
		}

		// Output generated code.
		ofstream out_stream(output_filename);
		out_stream << robot.get_global_var_code_buffer() << robot.get_code_buffer();

		// Generate machine code by using assembler.
		MccAssembler mcca(robot.get_codes());
		mcca.scan();
		mcca.output_coes();
	} else {
		cout << "Found error.\n";
	}

	return 0;
}<commit_msg>Add support for both unix and windows intput path<commit_after>#include <stdio.h>
#include <cstdio>
#include <fstream>
#include <iostream>
#include "MccAssembler.h"
#include "MccRobot.h"
using namespace std;

extern int yyparse();
extern FILE *yyin;

int main(int args, char** argv)
{
	MccRobot &robot = theMccRobot();
	string output_filename;
	string input_filename;
	string input_path;

#ifdef DEBUG_MODE
	// Test selection.
	int select_input;
	cout << "Input 1 or 2 to select input file, 1 select 'test', 2 select 'correct'\n"
		"Your select: ";
	cin >> select_input;
	if (1 == select_input) {
		output_filename = input_filename = "test";
	} else if (2 == select_input) {
		output_filename = input_filename = "correct";
	} else {
		cout << "Wrong selection.\n";
		exit(0);
	}
#endif

	// Deal with main arguments.
	// args[1]: input file name.
	if (args > 1) {
		string argv1 = string(argv[1]);
		// Split argv1 into input_path and input_filename.
		// Check windows path.
		int pos = argv1.find_last_of('\\');
		if (string::npos == pos) {
			// Check unix path.
			pos = argv1.find_last_of('/');
		}
		if (string::npos != pos) {
			input_filename = argv1.substr(pos + 1);
			input_path = argv1.substr(0, pos + 1);
		} else {
			input_filename = argv1;
		}
		output_filename = input_filename;
		pos = input_filename.find('.');
		if (string::npos != pos) {
			output_filename = input_filename.substr(0, pos);
		}
	} else if (input_filename.empty()) {
		cout << "No input file.\n";
		exit(0);
	}

	// Open input file as yyin, the input of flex.
	yyin = fopen((input_path + input_filename).c_str(), "r");
	if (nullptr == yyin) {
		cout << "Open file failed.\n";
		exit(1);
	}

	// Parse.
	if (0 != yyparse()) {
		cout << "Parse error.\n";
		exit(1);
	}

	// After parsing, do more thing.
	if (robot.check_semantic_error()) {
		robot.generate_code();

		// Deal with conflict between input filename and output filename.
		if (input_filename == output_filename) {
			output_filename += ".out";
		}

		// Output generated code.
		ofstream out_stream(output_filename);
		out_stream << robot.get_global_var_code_buffer() << robot.get_code_buffer();
		out_stream.close();

		// Generate machine code by using assembler.
		MccAssembler mcca(robot.get_codes());
		mcca.scan();
		mcca.output_coes();
	} else {
		cout << "Found error.\n";
	}

	return 0;
}<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id: memory.cc,v 1.53 2006/03/28 16:53:02 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  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; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

#include "bochs.h"
#include "cpu/cpu.h"
#include "iodev/iodev.h"
#define LOG_THIS BX_MEM_THIS

#if BX_PROVIDE_CPU_MEMORY

//
// Memory map inside the 1st megabyte:
//
// 0x00000 - 0x7ffff    DOS area (512K)
// 0x80000 - 0x9ffff    Optional fixed memory hole (128K)
// 0xa0000 - 0xbffff    Standard PCI/ISA Video Mem / SMMRAM (128K)
// 0xc0000 - 0xdffff    Expansion Card BIOS and Buffer Area (128K)
// 0xe0000 - 0xeffff    Lower BIOS Area (64K)
// 0xf0000 - 0xfffff    Upper BIOS Area (64K)
//

  void BX_CPP_AttrRegparmN(3)
BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  Bit8u *data_ptr;
  bx_phy_address a20addr = A20ADDR(addr);

  // Note: accesses should always be contained within a single page now

  if (cpu != NULL) {
#if BX_SUPPORT_IODEBUG
    bx_iodebug_c::mem_write(cpu, a20addr, len, data);
#endif

    BX_INSTR_PHY_WRITE(cpu->which_cpu(), a20addr, len);

#if BX_DEBUGGER
    // (mch) Check for physical write break points, TODO
    // (bbd) Each breakpoint should have an associated CPU#, TODO
    for (int i = 0; i < num_write_watchpoints; i++) {
      if (write_watchpoint[i] == a20addr) {
        BX_CPU(0)->watchpoint = a20addr;
        BX_CPU(0)->break_point = BREAK_POINT_WRITE;
        break;
      }
    }
#endif

#if BX_SUPPORT_APIC
    bx_generic_apic_c *local_apic = &cpu->local_apic;
    if (local_apic->is_selected(a20addr, len)) {
      local_apic->write(a20addr, (Bit32u *)data, len);
      return;
    }
#endif

    if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
    {
      // SMRAM memory space
      if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
        goto mem_write;
    }
  }

  struct memory_handler_struct *memory_handler = memory_handlers[a20addr >> 20];
  while (memory_handler) {
    if (memory_handler->begin <= a20addr &&
          memory_handler->end >= a20addr &&
          memory_handler->write_handler(a20addr, len, data, memory_handler->param))
    {
      return;
    }
    memory_handler = memory_handler->next;
  }

mem_write:

#if BX_SUPPORT_ICACHE
  if (a20addr < BX_MEM_THIS len)
    pageWriteStampTable.decWriteStamp(a20addr);
#endif

  // all memory access feets in single 4K page
  if (a20addr <= BX_MEM_THIS len) {
    // all of data is within limits of physical memory
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      if (len == 8) {
        WriteHostQWordToLittleEndian(&vector[a20addr], *(Bit64u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 4) {
        WriteHostDWordToLittleEndian(&vector[a20addr], *(Bit32u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 2) {
        WriteHostWordToLittleEndian(&vector[a20addr], *(Bit16u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 1) {
        * ((Bit8u *) (&vector[a20addr])) = * (Bit8u *) data;
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      // len == other, just fall thru to special cases handling
    }

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

write_one:
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      // addr *not* in range 000A0000 .. 000FFFFF
      vector[a20addr] = *data_ptr;
      BX_DBG_DIRTY_PAGE(a20addr >> 12);
inc_one:
      if (len == 1) return;
      len--;
      a20addr++;
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
      goto write_one;
    }

    // addr must be in range 000A0000 .. 000FFFFF

    // SMMRAM
    if (a20addr <= 0x000bffff) {
      // devices are not allowed to access SMMRAM under VGA memory
      if (cpu) {
        vector[a20addr] = *data_ptr;
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
      }
      goto inc_one;
    }

    // adapter ROM     C0000 .. DFFFF
    // ROM BIOS memory E0000 .. FFFFF
#if BX_SUPPORT_PCI == 0
    // ignore write to ROM
#else
    // Write Based on 440fx Programming
    if (pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
    {
      switch (DEV_pci_wr_memtype(a20addr & 0xFC000)) {
        case 0x1:   // Writes to ShadowRAM
          BX_DEBUG(("Writing to ShadowRAM: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
          vector[a20addr] = *data_ptr;
          BX_DBG_DIRTY_PAGE(a20addr >> 12);
          goto inc_one;

        case 0x0:   // Writes to ROM, Inhibit
          BX_DEBUG(("Write to ROM ignored: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
          goto inc_one;

        default:
          BX_PANIC(("writePhysicalPage: default case"));
          goto inc_one;
      }
    }
#endif
    goto inc_one;
  }
  else {
    // access outside limits of physical memory, ignore
    BX_DEBUG(("Write outside the limits of physical memory (ignore)"));
  }
}

  void BX_CPP_AttrRegparmN(3)
BX_MEM_C::readPhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  Bit8u *data_ptr;
  bx_phy_address a20addr = A20ADDR(addr);

  // Note: accesses should always be contained within a single page now

  if (cpu != NULL) {
#if BX_SUPPORT_IODEBUG
    bx_iodebug_c::mem_read(cpu, a20addr, len, data);
#endif

    BX_INSTR_PHY_READ(cpu->which_cpu(), a20addr, len);

#if BX_DEBUGGER
    // (mch) Check for physical read break points, TODO
    // (bbd) Each breakpoint should have an associated CPU#, TODO
    for (int i = 0; i < num_read_watchpoints; i++) {
      if (read_watchpoint[i] == a20addr) {
         BX_CPU(0)->watchpoint = a20addr;
         BX_CPU(0)->break_point = BREAK_POINT_READ;
         break;
      }
    }
#endif

#if BX_SUPPORT_APIC
    bx_generic_apic_c *local_apic = &cpu->local_apic;
    if (local_apic->is_selected (a20addr, len)) {
      local_apic->read(a20addr, data, len);
      return;
    }
#endif

    if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
    {
      // SMRAM memory space
      if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
        goto mem_read;
    }
  }

  struct memory_handler_struct *memory_handler = memory_handlers[a20addr >> 20];
  while (memory_handler) {
    if (memory_handler->begin <= a20addr &&
          memory_handler->end >= a20addr &&
          memory_handler->read_handler(a20addr, len, data, memory_handler->param))
    {
      return;
    }
    memory_handler = memory_handler->next;
  }

mem_read:

  if (a20addr <= BX_MEM_THIS len) {
    // all of data is within limits of physical memory
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      if (len == 8) {
        ReadHostQWordFromLittleEndian(&vector[a20addr], * (Bit64u*) data);
        return;
      }
      if (len == 4) {
        ReadHostDWordFromLittleEndian(&vector[a20addr], * (Bit32u*) data);
        return;
      }
      if (len == 2) {
        ReadHostWordFromLittleEndian(&vector[a20addr], * (Bit16u*) data);
        return;
      }
      if (len == 1) {
        * (Bit8u *) data = * ((Bit8u *) (&vector[a20addr]));
        return;
      }
      // len == other case can just fall thru to special cases handling
    }

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

read_one:
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      // addr *not* in range 00080000 .. 000FFFFF
      *data_ptr = vector[a20addr];
inc_one:
      if (len == 1) return;
      len--;
      a20addr++;
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
      goto read_one;
    }

    // addr must be in range 000A0000 .. 000FFFFF

    // SMMRAM
    if (a20addr <= 0x000bffff) {
      // devices are not allowed to access SMMRAM under VGA memory
      if (cpu) *data_ptr = vector[a20addr];
      goto inc_one;
    }

#if BX_SUPPORT_PCI
    if (pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
    {
      switch (DEV_pci_rd_memtype (a20addr)) {
        case 0x0:  // Read from ROM
          if ( (a20addr & 0xfffe0000) == 0x000e0000 )
          {
            *data_ptr = rom[a20addr & BIOS_MASK];
          }
          else
          {
            *data_ptr = rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
          }
          goto inc_one;
        case 0x1:  // Read from ShadowRAM
          *data_ptr = vector[a20addr];
          goto inc_one;
        default:
          BX_PANIC(("readPhysicalPage: default case"));
      }
      goto inc_one;
    }
    else
#endif  // #if BX_SUPPORT_PCI
    {
      if ((a20addr & 0xfffc0000) != 0x000c0000) {
        *data_ptr = vector[a20addr];
      }
      else if ((a20addr & 0xfffe0000) == 0x000e0000)
      {
        *data_ptr = rom[a20addr & BIOS_MASK];
      }
      else
      {
        *data_ptr = rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
      }
      goto inc_one;
    }
  }
  else
  {  // access outside limits of physical memory

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

    for (unsigned i = 0; i < len; i++) {
      if (a20addr >= (bx_phy_address)~BIOS_MASK)
        *data_ptr = rom[a20addr & BIOS_MASK];
      else
        *data_ptr = 0xff;
      addr++;
      a20addr = (addr);
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
    }
  }
}

#endif // #if BX_PROVIDE_CPU_MEMORY
<commit_msg>Fixed compilaion problem on Linux gcc 3.3.4<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id: memory.cc,v 1.54 2006/03/28 21:09:04 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  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; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

#include "bochs.h"
#include "cpu/cpu.h"
#include "iodev/iodev.h"
#define LOG_THIS BX_MEM_THIS

#if BX_PROVIDE_CPU_MEMORY

//
// Memory map inside the 1st megabyte:
//
// 0x00000 - 0x7ffff    DOS area (512K)
// 0x80000 - 0x9ffff    Optional fixed memory hole (128K)
// 0xa0000 - 0xbffff    Standard PCI/ISA Video Mem / SMMRAM (128K)
// 0xc0000 - 0xdffff    Expansion Card BIOS and Buffer Area (128K)
// 0xe0000 - 0xeffff    Lower BIOS Area (64K)
// 0xf0000 - 0xfffff    Upper BIOS Area (64K)
//

  void BX_CPP_AttrRegparmN(3)
BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  Bit8u *data_ptr;
  bx_phy_address a20addr = A20ADDR(addr);
  struct memory_handler_struct *memory_handler = NULL;

  // Note: accesses should always be contained within a single page now

  if (cpu != NULL) {
#if BX_SUPPORT_IODEBUG
    bx_iodebug_c::mem_write(cpu, a20addr, len, data);
#endif

    BX_INSTR_PHY_WRITE(cpu->which_cpu(), a20addr, len);

#if BX_DEBUGGER
    // (mch) Check for physical write break points, TODO
    // (bbd) Each breakpoint should have an associated CPU#, TODO
    for (int i = 0; i < num_write_watchpoints; i++) {
      if (write_watchpoint[i] == a20addr) {
        BX_CPU(0)->watchpoint = a20addr;
        BX_CPU(0)->break_point = BREAK_POINT_WRITE;
        break;
      }
    }
#endif

#if BX_SUPPORT_APIC
    bx_generic_apic_c *local_apic = &cpu->local_apic;
    if (local_apic->is_selected(a20addr, len)) {
      local_apic->write(a20addr, (Bit32u *)data, len);
      return;
    }
#endif

    if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
    {
      // SMRAM memory space
      if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
        goto mem_write;
    }
  }

  memory_handler = memory_handlers[a20addr >> 20];
  while (memory_handler) {
    if (memory_handler->begin <= a20addr &&
          memory_handler->end >= a20addr &&
          memory_handler->write_handler(a20addr, len, data, memory_handler->param))
    {
      return;
    }
    memory_handler = memory_handler->next;
  }

mem_write:

#if BX_SUPPORT_ICACHE
  if (a20addr < BX_MEM_THIS len)
    pageWriteStampTable.decWriteStamp(a20addr);
#endif

  // all memory access feets in single 4K page
  if (a20addr <= BX_MEM_THIS len) {
    // all of data is within limits of physical memory
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      if (len == 8) {
        WriteHostQWordToLittleEndian(&vector[a20addr], *(Bit64u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 4) {
        WriteHostDWordToLittleEndian(&vector[a20addr], *(Bit32u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 2) {
        WriteHostWordToLittleEndian(&vector[a20addr], *(Bit16u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 1) {
        * ((Bit8u *) (&vector[a20addr])) = * (Bit8u *) data;
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      // len == other, just fall thru to special cases handling
    }

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

write_one:
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      // addr *not* in range 000A0000 .. 000FFFFF
      vector[a20addr] = *data_ptr;
      BX_DBG_DIRTY_PAGE(a20addr >> 12);
inc_one:
      if (len == 1) return;
      len--;
      a20addr++;
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
      goto write_one;
    }

    // addr must be in range 000A0000 .. 000FFFFF

    // SMMRAM
    if (a20addr <= 0x000bffff) {
      // devices are not allowed to access SMMRAM under VGA memory
      if (cpu) {
        vector[a20addr] = *data_ptr;
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
      }
      goto inc_one;
    }

    // adapter ROM     C0000 .. DFFFF
    // ROM BIOS memory E0000 .. FFFFF
#if BX_SUPPORT_PCI == 0
    // ignore write to ROM
#else
    // Write Based on 440fx Programming
    if (pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
    {
      switch (DEV_pci_wr_memtype(a20addr & 0xFC000)) {
        case 0x1:   // Writes to ShadowRAM
          BX_DEBUG(("Writing to ShadowRAM: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
          vector[a20addr] = *data_ptr;
          BX_DBG_DIRTY_PAGE(a20addr >> 12);
          goto inc_one;

        case 0x0:   // Writes to ROM, Inhibit
          BX_DEBUG(("Write to ROM ignored: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
          goto inc_one;

        default:
          BX_PANIC(("writePhysicalPage: default case"));
          goto inc_one;
      }
    }
#endif
    goto inc_one;
  }
  else {
    // access outside limits of physical memory, ignore
    BX_DEBUG(("Write outside the limits of physical memory (ignore)"));
  }
}

  void BX_CPP_AttrRegparmN(3)
BX_MEM_C::readPhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  Bit8u *data_ptr;
  bx_phy_address a20addr = A20ADDR(addr);
  struct memory_handler_struct *memory_handler = NULL;

  // Note: accesses should always be contained within a single page now

  if (cpu != NULL) {
#if BX_SUPPORT_IODEBUG
    bx_iodebug_c::mem_read(cpu, a20addr, len, data);
#endif

    BX_INSTR_PHY_READ(cpu->which_cpu(), a20addr, len);

#if BX_DEBUGGER
    // (mch) Check for physical read break points, TODO
    // (bbd) Each breakpoint should have an associated CPU#, TODO
    for (int i = 0; i < num_read_watchpoints; i++) {
      if (read_watchpoint[i] == a20addr) {
         BX_CPU(0)->watchpoint = a20addr;
         BX_CPU(0)->break_point = BREAK_POINT_READ;
         break;
      }
    }
#endif

#if BX_SUPPORT_APIC
    bx_generic_apic_c *local_apic = &cpu->local_apic;
    if (local_apic->is_selected (a20addr, len)) {
      local_apic->read(a20addr, data, len);
      return;
    }
#endif

    if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
    {
      // SMRAM memory space
      if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
        goto mem_read;
    }
  }

  memory_handler = memory_handlers[a20addr >> 20];
  while (memory_handler) {
    if (memory_handler->begin <= a20addr &&
          memory_handler->end >= a20addr &&
          memory_handler->read_handler(a20addr, len, data, memory_handler->param))
    {
      return;
    }
    memory_handler = memory_handler->next;
  }

mem_read:

  if (a20addr <= BX_MEM_THIS len) {
    // all of data is within limits of physical memory
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      if (len == 8) {
        ReadHostQWordFromLittleEndian(&vector[a20addr], * (Bit64u*) data);
        return;
      }
      if (len == 4) {
        ReadHostDWordFromLittleEndian(&vector[a20addr], * (Bit32u*) data);
        return;
      }
      if (len == 2) {
        ReadHostWordFromLittleEndian(&vector[a20addr], * (Bit16u*) data);
        return;
      }
      if (len == 1) {
        * (Bit8u *) data = * ((Bit8u *) (&vector[a20addr]));
        return;
      }
      // len == other case can just fall thru to special cases handling
    }

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

read_one:
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      // addr *not* in range 00080000 .. 000FFFFF
      *data_ptr = vector[a20addr];
inc_one:
      if (len == 1) return;
      len--;
      a20addr++;
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
      goto read_one;
    }

    // addr must be in range 000A0000 .. 000FFFFF

    // SMMRAM
    if (a20addr <= 0x000bffff) {
      // devices are not allowed to access SMMRAM under VGA memory
      if (cpu) *data_ptr = vector[a20addr];
      goto inc_one;
    }

#if BX_SUPPORT_PCI
    if (pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
    {
      switch (DEV_pci_rd_memtype (a20addr)) {
        case 0x0:  // Read from ROM
          if ( (a20addr & 0xfffe0000) == 0x000e0000 )
          {
            *data_ptr = rom[a20addr & BIOS_MASK];
          }
          else
          {
            *data_ptr = rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
          }
          goto inc_one;
        case 0x1:  // Read from ShadowRAM
          *data_ptr = vector[a20addr];
          goto inc_one;
        default:
          BX_PANIC(("readPhysicalPage: default case"));
      }
      goto inc_one;
    }
    else
#endif  // #if BX_SUPPORT_PCI
    {
      if ((a20addr & 0xfffc0000) != 0x000c0000) {
        *data_ptr = vector[a20addr];
      }
      else if ((a20addr & 0xfffe0000) == 0x000e0000)
      {
        *data_ptr = rom[a20addr & BIOS_MASK];
      }
      else
      {
        *data_ptr = rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
      }
      goto inc_one;
    }
  }
  else
  {  // access outside limits of physical memory

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

    for (unsigned i = 0; i < len; i++) {
      if (a20addr >= (bx_phy_address)~BIOS_MASK)
        *data_ptr = rom[a20addr & BIOS_MASK];
      else
        *data_ptr = 0xff;
      addr++;
      a20addr = (addr);
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
    }
  }
}

#endif // #if BX_PROVIDE_CPU_MEMORY
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio and Hazza Alkaabi
 * All rights reserved.
 */
#include "radial_algorithm.h"
namespace game { namespace strat
{
  // This function could be run alone.
  void Radial_Algorithm::gen(Grid_Map& map) noexcept
  {
    osn_context* osn = nullptr;
    auto noise_init = Noise_Raii{this->seed, &osn};

    for(int i = 0; i < map.extents.y; ++i)
    {
      for(int j = 0; j < map.extents.x; ++j)
      {
        // Point from the continent origin to here.
        Vec<float> to_here = Vec<int>{j, i} - this->origin;
        auto to_here_dir = normalize(to_here);

        // Angle is not used or passed into the noise function because at 2pi
        // radians it goes from +pi to -pi causing a discontinuity in the land
        // mass.

        // Get a small delta from the angle. We will use this to modify the
        auto delta = 0.0f;
        auto cur_amplitude = this->amplitude;
        auto cur_frequency = this->frequency;
        for(int octave_i = 0; octave_i < this->octaves; ++octave_i)
        {
          delta += open_simplex_noise2(osn, to_here_dir.y * cur_frequency,
                                       to_here_dir.x * cur_frequency) *
                   cur_amplitude;
          cur_amplitude *= this->persistence;
          cur_frequency *= this->lacunarity;
        }

        auto modified_radius = radius + delta;

        // This tile is land.
        if(length(to_here) < modified_radius)
        {
          map.values[i * map.extents.x + j].type = this->type;
        }
      }
    }
  }
} }
<commit_msg>Optimize the Radial_Algorithm to use a smaller volume<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio and Hazza Alkaabi
 * All rights reserved.
 */
#include "radial_algorithm.h"
#include "../common/volume.h"
namespace game { namespace strat
{
  // This function could be run alone.
  void Radial_Algorithm::gen(Grid_Map& map) noexcept
  {
    osn_context* osn = nullptr;
    auto noise_init = Noise_Raii{this->seed, &osn};

    // Figure out what area we actually *could* modify. I think technically it
    // could be big larger if we are dealing with multiple octaves, but
    // whatever.
    Volume<int> active_area;
    active_area.pos.x = std::ceil(origin.x - radius - amplitude);
    active_area.pos.y = std::ceil(origin.y - radius - amplitude);
    active_area.width = (radius + amplitude) * 2;
    active_area.height = (radius + amplitude) * 2;

    active_area = contain_inside_extents(active_area, map.extents);

    auto& aa = active_area;
    for(int i = aa.pos.y; i < aa.height + aa.pos.y; ++i)
    {
      for(int j = aa.pos.x; j < aa.width + aa.pos.x; ++j)
      {
        // Point from the continent origin to here.
        Vec<float> to_here = Vec<int>{j, i} - this->origin;
        auto to_here_dir = normalize(to_here);

        // Angle is not used or passed into the noise function because at 2pi
        // radians it goes from +pi to -pi causing a discontinuity in the land
        // mass.

        // Get a small delta from the angle. We will use this to modify the
        auto delta = 0.0f;
        auto cur_amplitude = this->amplitude;
        auto cur_frequency = this->frequency;
        for(int octave_i = 0; octave_i < this->octaves; ++octave_i)
        {
          delta += open_simplex_noise2(osn, to_here_dir.y * cur_frequency,
                                       to_here_dir.x * cur_frequency) *
                   cur_amplitude;
          cur_amplitude *= this->persistence;
          cur_frequency *= this->lacunarity;
        }

        auto modified_radius = radius + delta;

        // This tile is land.
        if(length(to_here) < modified_radius)
        {
          map.values[i * map.extents.x + j].type = this->type;
        }
      }
    }
  }
} }
<|endoftext|>