<commit_before>#include <BALL/PLUGIN/pluginManager.h>
#include <BALL/PLUGIN/BALLPlugin.h>
#include <BALL/PLUGIN/pluginHandler.h>

#include <QtCore/QPluginLoader>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QReadLocker>
#include <QtCore/QWriteLocker>
#include <BALL/COMMON/logStream.h>

namespace BALL
{
	const char* PluginManager::BETWEEN_PLUGINDIR_SEPERATOR  = "?";
	boost::shared_ptr<PluginManager> PluginManager::manager_;

	QMutex PluginManager::mutex_;

	PluginManager::PluginManager()
		: PreferencesObject()
	{
		setObjectName("PluginManager");
	}

	PluginManager::~PluginManager()
	{
		unloadAllPlugins();

		std::list<PluginHandler*>::iterator ht = handlers_.begin();
		for (; ht != handlers_.end(); ++ht)
		{
			delete *ht;
		}
		//unregisterThis();
	}

	PluginManager& PluginManager::instance()
	{
		//Make the PluginManager creation thread safe
		if (!manager_)
		{
			//Another thread could have taken over control right now
			//so lock a mutex to ensure the PluginManager is created only once.
			mutex_.lock();
			//Check that the manager has not been created by a concurring thread
			if(!manager_)
			{
				manager_ = boost::shared_ptr<PluginManager>(new PluginManager());
			}
			mutex_.unlock();
		}

		return *manager_;
	}

	void PluginManager::addPluginDirectory(const QString& dir, bool autoactivate)
	{
		std::map<QString, vector<BALLPlugin*> >::iterator to_load_it = loaded_plugin_dirs_.find(dir);
		if (to_load_it == loaded_plugin_dirs_.end())
		{
			vector<BALLPlugin*> loaded_plugins;
#if defined(BALL_OS_WINDOWS)
			QDir plugin_dir(dir, "plugin*.dll", QDir::Name | QDir::IgnoreCase, QDir::Files);
#elif defined(BALL_OS_DARWIN)
			QDir plugin_dir(dir, "plugin*.dylib", QDir::Name | QDir::IgnoreCase, QDir::Files);
#else
			QDir plugin_dir(dir, "plugin*.so", QDir::Name | QDir::IgnoreCase, QDir::Files);
#endif

			// collect the loaded plugins in this dir
			foreach(QString it, plugin_dir.entryList())
			{
				BALLPlugin* new_plugin = loadPlugin(plugin_dir.absoluteFilePath(it));
				if (new_plugin)
				{
					loaded_plugins.push_back(new_plugin);
					if (autoactivate)
						startPlugin(new_plugin);
				}
			}

			// and store the entry
			loaded_plugin_dirs_[dir]=loaded_plugins;
		}
	}

	bool PluginManager::removePluginDirectory(const QString& dir)
	{
		std::map<QString, vector<BALLPlugin*> >::iterator to_unload_it = loaded_plugin_dirs_.find(dir);

		if (to_unload_it != loaded_plugin_dirs_.end())
		{
			// remove the corresponding plugins
			vector<BALLPlugin*> to_unload = to_unload_it->second;
			for (Size i=0; i<to_unload.size(); i++)
			{
				unloadPlugin(to_unload[i]->getName());
			}

			// and the directory itself
			loaded_plugin_dirs_.erase(to_unload_it);
		}
		else
		{
			return false;
		}
		return true;
	}

	vector<QString> PluginManager::getPluginDirectories() const
	{
		vector<QString> result;

		std::map<QString, vector<BALLPlugin*> >::const_iterator it = loaded_plugin_dirs_.begin();
		for (; it!=loaded_plugin_dirs_.end(); ++it)
		 	result.push_back(it->first);

		return result;
	}

	BALLPlugin* PluginManager::loadPlugin(const QString& plugin_name)
	{
		BALLPlugin* plugin = 0;
		QPluginLoader* loader = new QPluginLoader(plugin_name);

		qDebug() << "Trying to load plugin: " << plugin_name;
		if (loader->load())
		{
			plugin = qobject_cast<BALLPlugin*>(loader->instance());
		}
		else
		{
			qDebug() << "Error:" << loader->errorString();
		}

		if (plugin)
		{
			qDebug() << "Loaded plugin " << plugin_name << ".";
			loader_mutex_.lockForWrite();
			loaders_.insert(plugin->getName(), loader);
			loader_mutex_.unlock();
		}

		return plugin;
	}

	bool PluginManager::unloadPlugin(const QString& plugin)
	{
		QWriteLocker locker(&loader_mutex_);
		QHash<QString, QPluginLoader*>::iterator it = loaders_.find(plugin);

		if (it != loaders_.end())
		{
			//Shutdown the plugin
			stopPlugin(qobject_cast<BALLPlugin*>(it.value()->instance()));
			//Delete the loader
			it.value()->unload();
			delete it.value();
			loaders_.erase(it);

			return true;
		}

		return false;
	}

	void PluginManager::unloadAllPlugins()
	{
		QHash<QString, QPluginLoader*>::iterator it = loaders_.begin();
		for (; it != loaders_.end(); ++it)
		{
			stopPlugin(qobject_cast<BALLPlugin*>(it.value()->instance()));
			//Delete the loader
			it.value()->unload();
			delete it.value();
		}
		loaders_.clear();
	}

	QObject* PluginManager::getPluginInstance(const QString& plugin)
	{
		QReadLocker locker(&loader_mutex_);
		QHash<QString, QPluginLoader*>::iterator it = loaders_.find(plugin);

		if(it != loaders_.end())
		{
			return (it.value()->instance());
		}

		return NULL;
	}

	QObject* PluginManager::getPluginInstance(int pos)
	{
		QReadLocker locker(&loader_mutex_);
		if(pos < 0 || pos >= getPluginCount())
		{
			return NULL;
		}

		QHash<QString, QPluginLoader*>::const_iterator it = loaders_.begin();
		for(int i = 0; i < pos; ++i, ++it)
		{}

		return it.value()->instance();
	}

	void PluginManager::registerHandler(PluginHandler* h)
	{
		handler_mutex_.lockForWrite();
		handlers_.push_back(h);
		handler_mutex_.unlock();
	}

	bool PluginManager::startPlugin(int plugin)
	{
		return startPlugin(qobject_cast<BALLPlugin*>(getPluginInstance(plugin)));
	}

	bool PluginManager::startPlugin(const QString& plugin)
	{
		return startPlugin(qobject_cast<BALLPlugin*>(getPluginInstance(plugin)));
	}

	bool PluginManager::startPlugin(BALLPlugin* plugin)
	{
		if (!plugin)
		{
			return true;
		}

		bool started = false;
		handler_mutex_.lockForRead();
		std::list<PluginHandler*>::iterator it = handlers_.begin();
		for (; it != handlers_.end(); ++it)
		{
			if ((*it)->canHandle(plugin))
			{
				started = (*it)->startPlugin(plugin) && !started;
			}
		}
		handler_mutex_.unlock();

		return started;
	}

	bool PluginManager::stopPlugin(int plugin)
	{
		return stopPlugin(qobject_cast<BALLPlugin*>(getPluginInstance(plugin)));
	}

	bool PluginManager::stopPlugin(const QString& plugin)
	{
		return stopPlugin(qobject_cast<BALLPlugin*>(getPluginInstance(plugin)));
	}

	bool PluginManager::stopPlugin(BALLPlugin* plugin)
	{
		if (!plugin)
		{
			return true;
		}

		bool all_stopped = true;
		handler_mutex_.lockForRead();
		std::list<PluginHandler*>::iterator it = handlers_.begin();
		for (; it != handlers_.end(); ++it)
		{
			if ((*it)->isRunning(plugin))
			{
				all_stopped = (*it)->stopPlugin(plugin) && all_stopped;
			}
		}
		handler_mutex_.unlock();

		return all_stopped;
	}

	int PluginManager::getPluginCount() const
	{
		QReadLocker locker(&loader_mutex_);
		return loaders_.size();
	}

	bool PluginManager::getValue(String& value) const
	{
		if (!loaded_plugin_dirs_.empty())
		{
			std::map<QString, vector<BALLPlugin*> >::const_iterator it = loaded_plugin_dirs_.begin();

			if ( it != loaded_plugin_dirs_.end())
			{

			value += it->first.toAscii().toPercentEncoding().data();

			for (++it; it != loaded_plugin_dirs_.end(); ++it)
			{
				value += BETWEEN_PLUGINDIR_SEPERATOR;
				value += it->first.toAscii().toPercentEncoding().data();
			}
			}
		}
		return true;
	}

	bool PluginManager::setValue(const String& value)
	{
		std::vector<String> plugin_directories;

		String tmp(QByteArray::fromPercentEncoding(QByteArray(value.c_str())).data());
		tmp.split(plugin_directories, BETWEEN_PLUGINDIR_SEPERATOR, 0);

		for (size_t i = 0; i < plugin_directories.size(); ++i)
		{
 			addPluginDirectory(plugin_directories[i].c_str());
		}

		return true;
	}
}

<commit_msg>Whitespace & indentation fixes for pluginManager.C<commit_after>#include <BALL/PLUGIN/pluginManager.h>
#include <BALL/PLUGIN/BALLPlugin.h>
#include <BALL/PLUGIN/pluginHandler.h>

#include <QtCore/QPluginLoader>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QReadLocker>
#include <QtCore/QWriteLocker>
#include <BALL/COMMON/logStream.h>

namespace BALL
{
	const char* PluginManager::BETWEEN_PLUGINDIR_SEPERATOR  = "?";
	boost::shared_ptr<PluginManager> PluginManager::manager_;

	QMutex PluginManager::mutex_;

	PluginManager::PluginManager()
		: PreferencesObject()
	{
		setObjectName("PluginManager");
	}

	PluginManager::~PluginManager()
	{
		unloadAllPlugins();

		std::list<PluginHandler*>::iterator ht = handlers_.begin();
		for (; ht != handlers_.end(); ++ht)
		{
			delete *ht;
		}
		//unregisterThis();
	}

	PluginManager& PluginManager::instance()
	{
		//Make the PluginManager creation thread safe
		if (!manager_)
		{
			//Another thread could have taken over control right now
			//so lock a mutex to ensure the PluginManager is created only once.
			mutex_.lock();
			//Check that the manager has not been created by a concurring thread
			if(!manager_)
			{
				manager_ = boost::shared_ptr<PluginManager>(new PluginManager());
			}
			mutex_.unlock();
		}

		return *manager_;
	}

	void PluginManager::addPluginDirectory(const QString& dir, bool autoactivate)
	{
		std::map<QString, vector<BALLPlugin*> >::iterator to_load_it = loaded_plugin_dirs_.find(dir);
		if (to_load_it == loaded_plugin_dirs_.end())
		{
			vector<BALLPlugin*> loaded_plugins;
#if defined(BALL_OS_WINDOWS)
			QDir plugin_dir(dir, "plugin*.dll", QDir::Name | QDir::IgnoreCase, QDir::Files);
#elif defined(BALL_OS_DARWIN)
			QDir plugin_dir(dir, "plugin*.dylib", QDir::Name | QDir::IgnoreCase, QDir::Files);
#else
			QDir plugin_dir(dir, "plugin*.so", QDir::Name | QDir::IgnoreCase, QDir::Files);
#endif

			// collect the loaded plugins in this dir
			foreach(QString it, plugin_dir.entryList())
			{
				BALLPlugin* new_plugin = loadPlugin(plugin_dir.absoluteFilePath(it));
				if (new_plugin)
				{
					loaded_plugins.push_back(new_plugin);
					if (autoactivate)
						startPlugin(new_plugin);
				}
			}

			// and store the entry
			loaded_plugin_dirs_[dir]=loaded_plugins;
		}
	}

	bool PluginManager::removePluginDirectory(const QString& dir)
	{
		std::map<QString, vector<BALLPlugin*> >::iterator to_unload_it = loaded_plugin_dirs_.find(dir);

		if (to_unload_it != loaded_plugin_dirs_.end())
		{
			// remove the corresponding plugins
			vector<BALLPlugin*> to_unload = to_unload_it->second;
			for (Size i=0; i<to_unload.size(); i++)
			{
				unloadPlugin(to_unload[i]->getName());
			}

			// and the directory itself
			loaded_plugin_dirs_.erase(to_unload_it);
		}
		else
		{
			return false;
		}
		return true;
	}

	vector<QString> PluginManager::getPluginDirectories() const
	{
		vector<QString> result;

		std::map<QString, vector<BALLPlugin*> >::const_iterator it = loaded_plugin_dirs_.begin();
		for (; it!=loaded_plugin_dirs_.end(); ++it)
			result.push_back(it->first);

		return result;
	}

	BALLPlugin* PluginManager::loadPlugin(const QString& plugin_name)
	{
		BALLPlugin* plugin = 0;
		QPluginLoader* loader = new QPluginLoader(plugin_name);

		qDebug() << "Trying to load plugin: " << plugin_name;
		if (loader->load())
		{
			plugin = qobject_cast<BALLPlugin*>(loader->instance());
		}
		else
		{
			qDebug() << "Error:" << loader->errorString();
		}

		if (plugin)
		{
			qDebug() << "Loaded plugin " << plugin_name << ".";
			loader_mutex_.lockForWrite();
			loaders_.insert(plugin->getName(), loader);
			loader_mutex_.unlock();
		}

		return plugin;
	}

	bool PluginManager::unloadPlugin(const QString& plugin)
	{
		QWriteLocker locker(&loader_mutex_);
		QHash<QString, QPluginLoader*>::iterator it = loaders_.find(plugin);

		if (it != loaders_.end())
		{
			//Shutdown the plugin
			stopPlugin(qobject_cast<BALLPlugin*>(it.value()->instance()));
			//Delete the loader
			it.value()->unload();
			delete it.value();
			loaders_.erase(it);

			return true;
		}

		return false;
	}

	void PluginManager::unloadAllPlugins()
	{
		QHash<QString, QPluginLoader*>::iterator it = loaders_.begin();
		for (; it != loaders_.end(); ++it)
		{
			stopPlugin(qobject_cast<BALLPlugin*>(it.value()->instance()));
			//Delete the loader
			it.value()->unload();
			delete it.value();
		}
		loaders_.clear();
	}

	QObject* PluginManager::getPluginInstance(const QString& plugin)
	{
		QReadLocker locker(&loader_mutex_);
		QHash<QString, QPluginLoader*>::iterator it = loaders_.find(plugin);

		if(it != loaders_.end())
		{
			return (it.value()->instance());
		}

		return NULL;
	}

	QObject* PluginManager::getPluginInstance(int pos)
	{
		QReadLocker locker(&loader_mutex_);
		if(pos < 0 || pos >= getPluginCount())
		{
			return NULL;
		}

		QHash<QString, QPluginLoader*>::const_iterator it = loaders_.begin();
		for(int i = 0; i < pos; ++i, ++it) {}

		return it.value()->instance();
	}

	void PluginManager::registerHandler(PluginHandler* h)
	{
		handler_mutex_.lockForWrite();
		handlers_.push_back(h);
		handler_mutex_.unlock();
	}

	bool PluginManager::startPlugin(int plugin)
	{
		return startPlugin(qobject_cast<BALLPlugin*>(getPluginInstance(plugin)));
	}

	bool PluginManager::startPlugin(const QString& plugin)
	{
		return startPlugin(qobject_cast<BALLPlugin*>(getPluginInstance(plugin)));
	}

	bool PluginManager::startPlugin(BALLPlugin* plugin)
	{
		if (!plugin)
		{
			return true;
		}

		bool started = false;
		handler_mutex_.lockForRead();
		std::list<PluginHandler*>::iterator it = handlers_.begin();
		for (; it != handlers_.end(); ++it)
		{
			if ((*it)->canHandle(plugin))
			{
				started = (*it)->startPlugin(plugin) && !started;
			}
		}
		handler_mutex_.unlock();

		return started;
	}

	bool PluginManager::stopPlugin(int plugin)
	{
		return stopPlugin(qobject_cast<BALLPlugin*>(getPluginInstance(plugin)));
	}

	bool PluginManager::stopPlugin(const QString& plugin)
	{
		return stopPlugin(qobject_cast<BALLPlugin*>(getPluginInstance(plugin)));
	}

	bool PluginManager::stopPlugin(BALLPlugin* plugin)
	{
		if (!plugin)
		{
			return true;
		}

		bool all_stopped = true;
		handler_mutex_.lockForRead();
		std::list<PluginHandler*>::iterator it = handlers_.begin();
		for (; it != handlers_.end(); ++it)
		{
			if ((*it)->isRunning(plugin))
			{
				all_stopped = (*it)->stopPlugin(plugin) && all_stopped;
			}
		}
		handler_mutex_.unlock();

		return all_stopped;
	}

	int PluginManager::getPluginCount() const
	{
		QReadLocker locker(&loader_mutex_);
		return loaders_.size();
	}

	bool PluginManager::getValue(String& value) const
	{
		if (!loaded_plugin_dirs_.empty())
		{
			std::map<QString, vector<BALLPlugin*> >::const_iterator it = loaded_plugin_dirs_.begin();

			if ( it != loaded_plugin_dirs_.end())
			{

				value += it->first.toAscii().toPercentEncoding().data();

				for (++it; it != loaded_plugin_dirs_.end(); ++it)
				{
					value += BETWEEN_PLUGINDIR_SEPERATOR;
					value += it->first.toAscii().toPercentEncoding().data();
				}
			}
		}
		return true;
	}

	bool PluginManager::setValue(const String& value)
	{
		std::vector<String> plugin_directories;

		String tmp(QByteArray::fromPercentEncoding(QByteArray(value.c_str())).data());
		tmp.split(plugin_directories, BETWEEN_PLUGINDIR_SEPERATOR, 0);

		for (size_t i = 0; i < plugin_directories.size(); ++i)
		{
			addPluginDirectory(plugin_directories[i].c_str());
		}

		return true;
	}
}
<|endoftext|>


<commit_before>//===-- sanitizer_linux_s390.cc -------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements s390-linux-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"

#if SANITIZER_LINUX && SANITIZER_S390

#include "sanitizer_libc.h"
#include "sanitizer_linux.h"

#include <errno.h>
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <unistd.h>

namespace __sanitizer {

// --------------- sanitizer_libc.h
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
                   OFF_T offset) {
  struct s390_mmap_params {
    unsigned long addr;
    unsigned long length;
    unsigned long prot;
    unsigned long flags;
    unsigned long fd;
    unsigned long offset;
  } params = {
    (unsigned long)addr,
    (unsigned long)length,
    (unsigned long)prot,
    (unsigned long)flags,
    (unsigned long)fd,
# ifdef __s390x__
    (unsigned long)offset,
# else
    (unsigned long)(offset / 4096),
# endif
  };
# ifdef __s390x__
  return syscall(__NR_mmap, &params);
# else
  return syscall(__NR_mmap2, &params);
# endif
}

uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                    int *parent_tidptr, void *newtls, int *child_tidptr) {
  if (!fn || !child_stack)
    return -EINVAL;
  CHECK_EQ(0, (uptr)child_stack % 16);
  // Minimum frame size.
#ifdef __s390x__
  child_stack = (char *)child_stack - 160;
#else
  child_stack = (char *)child_stack - 96;
#endif
  // Terminate unwind chain.
  ((unsigned long *)child_stack)[0] = 0;
  // And pass parameters.
  ((unsigned long *)child_stack)[1] = (uptr)fn;
  ((unsigned long *)child_stack)[2] = (uptr)arg;
  register long res __asm__("r2");
  register void *__cstack      __asm__("r2") = child_stack;
  register int __flags         __asm__("r3") = flags;
  register int * __ptidptr     __asm__("r4") = parent_tidptr;
  register int * __ctidptr     __asm__("r5") = child_tidptr;
  register void * __newtls     __asm__("r6") = newtls;

  __asm__ __volatile__(
                       /* Clone. */
                       "svc    %1\n"

                       /* if (%r2 != 0)
                        *   return;
                        */
#ifdef __s390x__
                       "cghi   %%r2, 0\n"
#else
                       "chi    %%r2, 0\n"
#endif
                       "jne    1f\n"

                       /* Call "fn(arg)". */
#ifdef __s390x__
                       "lmg    %%r1, %%r2, 8(%%r15)\n"
#else
                       "lm     %%r1, %%r2, 4(%%r15)\n"
#endif
                       "basr   %%r14, %%r1\n"

                       /* Call _exit(%r2). */
                       "svc %2\n"

                       /* Return to parent. */
                     "1:\n"
                       : "=r" (res)
                       : "i"(__NR_clone), "i"(__NR_exit),
                         "r"(__cstack),
                         "r"(__flags),
                         "r"(__ptidptr),
                         "r"(__ctidptr),
                         "r"(__newtls)
                       : "memory", "cc");
  return res;
}

#if SANITIZER_S390_64
static bool FixedCVE_2016_2143() {
  // Try to determine if the running kernel has a fix for CVE-2016-2143,
  // return false if in doubt (better safe than sorry).  Distros may want to
  // adjust this for their own kernels.
  struct utsname buf;
  unsigned int major, minor, patch = 0;
  // This should never fail, but just in case...
  if (uname(&buf))
    return false;
  char *ptr = buf.release;
  major = internal_simple_strtoll(ptr, &ptr, 10);
  // At least first 2 should be matched.
  if (ptr[0] != '.')
    return false;
  minor = internal_simple_strtoll(ptr+1, &ptr, 10);
  // Third is optional.
  if (ptr[0] == '.')
    patch = internal_simple_strtoll(ptr+1, &ptr, 10);
  if (major < 3) {
    // <3.0 is bad.
    return false;
  } else if (major == 3) {
    // 3.2.79+ is OK.
    if (minor == 2 && patch >= 79)
      return true;
    // 3.12.58+ is OK.
    if (minor == 12 && patch >= 58)
      return true;
    // Otherwise, bad.
    return false;
  } else if (major == 4) {
    // 4.1.21+ is OK.
    if (minor == 1 && patch >= 21)
      return true;
    // 4.4.6+ is OK.
    if (minor == 4 && patch >= 6)
      return true;
    // Otherwise, OK if 4.5+.
    return minor >= 5;
  } else {
    // Linux 5 and up are fine.
    return true;
  }
}

void AvoidCVE_2016_2143() {
  // Older kernels are affected by CVE-2016-2143 - they will crash hard
  // if someone uses 4-level page tables (ie. virtual addresses >= 4TB)
  // and fork() in the same process.  Unfortunately, sanitizers tend to
  // require such addresses.  Since this is very likely to crash the whole
  // machine (sanitizers themselves use fork() for llvm-symbolizer, for one),
  // abort the process at initialization instead.
  if (FixedCVE_2016_2143())
    return;
  if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143"))
    return;
  Report(
    "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143.  Using ASan,\n"
    "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
    "machine, or worse.\n"
    "\n"
    "If you are certain your kernel is not vulnerable (you have compiled it\n"
    "yourself, or are using an unrecognized distribution kernel), you can\n"
    "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
    "with any value.\n");
  Die();
}
#endif

} // namespace __sanitizer

#endif // SANITIZER_LINUX && SANITIZER_S390
<commit_msg>s390 CVE-2016-2143 whitelist for RHEL kernels<commit_after>//===-- sanitizer_linux_s390.cc -------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements s390-linux-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"

#if SANITIZER_LINUX && SANITIZER_S390

#include "sanitizer_libc.h"
#include "sanitizer_linux.h"

#include <errno.h>
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <unistd.h>

namespace __sanitizer {

// --------------- sanitizer_libc.h
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
                   OFF_T offset) {
  struct s390_mmap_params {
    unsigned long addr;
    unsigned long length;
    unsigned long prot;
    unsigned long flags;
    unsigned long fd;
    unsigned long offset;
  } params = {
    (unsigned long)addr,
    (unsigned long)length,
    (unsigned long)prot,
    (unsigned long)flags,
    (unsigned long)fd,
# ifdef __s390x__
    (unsigned long)offset,
# else
    (unsigned long)(offset / 4096),
# endif
  };
# ifdef __s390x__
  return syscall(__NR_mmap, &params);
# else
  return syscall(__NR_mmap2, &params);
# endif
}

uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                    int *parent_tidptr, void *newtls, int *child_tidptr) {
  if (!fn || !child_stack)
    return -EINVAL;
  CHECK_EQ(0, (uptr)child_stack % 16);
  // Minimum frame size.
#ifdef __s390x__
  child_stack = (char *)child_stack - 160;
#else
  child_stack = (char *)child_stack - 96;
#endif
  // Terminate unwind chain.
  ((unsigned long *)child_stack)[0] = 0;
  // And pass parameters.
  ((unsigned long *)child_stack)[1] = (uptr)fn;
  ((unsigned long *)child_stack)[2] = (uptr)arg;
  register long res __asm__("r2");
  register void *__cstack      __asm__("r2") = child_stack;
  register int __flags         __asm__("r3") = flags;
  register int * __ptidptr     __asm__("r4") = parent_tidptr;
  register int * __ctidptr     __asm__("r5") = child_tidptr;
  register void * __newtls     __asm__("r6") = newtls;

  __asm__ __volatile__(
                       /* Clone. */
                       "svc    %1\n"

                       /* if (%r2 != 0)
                        *   return;
                        */
#ifdef __s390x__
                       "cghi   %%r2, 0\n"
#else
                       "chi    %%r2, 0\n"
#endif
                       "jne    1f\n"

                       /* Call "fn(arg)". */
#ifdef __s390x__
                       "lmg    %%r1, %%r2, 8(%%r15)\n"
#else
                       "lm     %%r1, %%r2, 4(%%r15)\n"
#endif
                       "basr   %%r14, %%r1\n"

                       /* Call _exit(%r2). */
                       "svc %2\n"

                       /* Return to parent. */
                     "1:\n"
                       : "=r" (res)
                       : "i"(__NR_clone), "i"(__NR_exit),
                         "r"(__cstack),
                         "r"(__flags),
                         "r"(__ptidptr),
                         "r"(__ctidptr),
                         "r"(__newtls)
                       : "memory", "cc");
  return res;
}

#if SANITIZER_S390_64
static bool FixedCVE_2016_2143() {
  // Try to determine if the running kernel has a fix for CVE-2016-2143,
  // return false if in doubt (better safe than sorry).  Distros may want to
  // adjust this for their own kernels.
  struct utsname buf;
  unsigned int major, minor, patch = 0;
  // This should never fail, but just in case...
  if (uname(&buf))
    return false;
  char *ptr = buf.release;
  major = internal_simple_strtoll(ptr, &ptr, 10);
  // At least first 2 should be matched.
  if (ptr[0] != '.')
    return false;
  minor = internal_simple_strtoll(ptr+1, &ptr, 10);
  // Third is optional.
  if (ptr[0] == '.')
    patch = internal_simple_strtoll(ptr+1, &ptr, 10);
  if (major < 3) {
    if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' &&
        internal_strstr(ptr, ".el6")) {
      // Check RHEL6
      int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
      if (r1 >= 657) // 2.6.32-657.el6 or later
        return true;
      if (r1 == 642 && ptr[0] == '.') {
        int r2 = internal_simple_strtoll(ptr+1, &ptr, 10);
        if (r2 >= 9) // 2.6.32-642.9.1.el6 or later
          return true;
      }
    }
    // <3.0 is bad.
    return false;
  } else if (major == 3) {
    // 3.2.79+ is OK.
    if (minor == 2 && patch >= 79)
      return true;
    // 3.12.58+ is OK.
    if (minor == 12 && patch >= 58)
      return true;
    if (minor == 10 && patch == 0 && ptr[0] == '-' &&
        internal_strstr(ptr, ".el7")) {
      // Check RHEL7
      int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
      if (r1 >= 426) // 3.10.0-426.el7 or later
        return true;
      if (r1 == 327 && ptr[0] == '.') {
        int r2 = internal_simple_strtoll(ptr+1, &ptr, 10);
        if (r2 >= 27) // 3.10.0-327.27.1.el7 or later
          return true;
      }
    }
    // Otherwise, bad.
    return false;
  } else if (major == 4) {
    // 4.1.21+ is OK.
    if (minor == 1 && patch >= 21)
      return true;
    // 4.4.6+ is OK.
    if (minor == 4 && patch >= 6)
      return true;
    // Otherwise, OK if 4.5+.
    return minor >= 5;
  } else {
    // Linux 5 and up are fine.
    return true;
  }
}

void AvoidCVE_2016_2143() {
  // Older kernels are affected by CVE-2016-2143 - they will crash hard
  // if someone uses 4-level page tables (ie. virtual addresses >= 4TB)
  // and fork() in the same process.  Unfortunately, sanitizers tend to
  // require such addresses.  Since this is very likely to crash the whole
  // machine (sanitizers themselves use fork() for llvm-symbolizer, for one),
  // abort the process at initialization instead.
  if (FixedCVE_2016_2143())
    return;
  if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143"))
    return;
  Report(
    "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143.  Using ASan,\n"
    "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
    "machine, or worse.\n"
    "\n"
    "If you are certain your kernel is not vulnerable (you have compiled it\n"
    "yourself, or are using an unrecognized distribution kernel), you can\n"
    "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
    "with any value.\n");
  Die();
}
#endif

} // namespace __sanitizer

#endif // SANITIZER_LINUX && SANITIZER_S390
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#pragma once

#include <chrono>
#include <ctime>
#include <cstring>

#include <date/date.h>

#include "vast/access.hpp"
#include "vast/time.hpp"
#include "vast/concept/parseable/core.hpp"
#include "vast/concept/parseable/numeric/real.hpp"
#include "vast/concept/parseable/string/char_class.hpp"

namespace vast {

// TODO: replace with Howard Hinnant's TZ stuff and then move into
// vast/concept/parseable/std/chrono.

template <class Rep, class Period>
struct duration_parser : parser<duration_parser<Rep, Period>> {
  using duration_type = std::chrono::duration<Rep, Period>;
  using attribute = duration_type;

  template <class Duration>
  static auto cast(Duration d) {
    return std::chrono::duration_cast<duration_type>(d);
  }

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, const Iterator& l, Attribute& a) const {
    using namespace parsers;
    using namespace parser_literals;
    auto save = f;
    Rep i;
    if (!make_parser<Rep>{}(f, l, i))
      return false;
    static auto whitespace = *space;
    if (!whitespace(f, l, unused)) {
      f = save;
      return false;
    }
    using namespace std::chrono;
    static auto unit
      = "nsecs"_p ->* [] { return cast(nanoseconds(1)); }
      | "nsec"_p  ->* [] { return cast(nanoseconds(1)); }
      | "ns"_p    ->* [] { return cast(nanoseconds(1)); }
      | "usecs"_p ->* [] { return cast(microseconds(1)); }
      | "usec"_p  ->* [] { return cast(microseconds(1)); }
      | "us"_p    ->* [] { return cast(microseconds(1)); }
      | "msecs"_p ->* [] { return cast(milliseconds(1)); }
      | "msec"_p  ->* [] { return cast(milliseconds(1)); }
      | "ms"_p    ->* [] { return cast(milliseconds(1)); }
      | "secs"_p  ->* [] { return cast(seconds(1)); }
      | "sec"_p   ->* [] { return cast(seconds(1)); }
      | "s"_p     ->* [] { return cast(seconds(1)); }
      | "mins"_p  ->* [] { return cast(minutes(1)); }
      | "min"_p   ->* [] { return cast(minutes(1)); }
      | "m"_p     ->* [] { return cast(minutes(1)); }
      | "hrs"_p   ->* [] { return cast(hours(1)); }
      | "hours"_p ->* [] { return cast(hours(1)); }
      | "hour"_p  ->* [] { return cast(hours(1)); }
      | "h"_p     ->* [] { return cast(hours(1)); }
      | "days"_p  ->* [] { return cast(hours(24)); }
      | "day"_p   ->* [] { return cast(hours(24)); }
      | "d"_p     ->* [] { return cast(hours(24)); }
      | "weeks"_p ->* [] { return cast(hours(24 * 7)); }
      | "week"_p  ->* [] { return cast(hours(24 * 7)); }
      | "w"_p     ->* [] { return cast(hours(24 * 7)); }
      | "years"_p ->* [] { return cast(hours(24 * 365)); }
      | "year"_p  ->* [] { return cast(hours(24 * 365)); }
      | "y"_p     ->* [] { return cast(hours(24 * 365)); }
      ;
    if (!unit(f, l, a)) {
      f = save;
      return false;
    }
    a *= i;
    return true;
  }
};

template <class Rep, class Period>
struct parser_registry<std::chrono::duration<Rep, Period>> {
  using type = duration_parser<Rep, Period>;
};

namespace parsers {

template <class Rep, class Period>
auto const duration = duration_parser<Rep, Period>{};

auto const timespan = duration<vast::timespan::rep, vast::timespan::period>;

} // namespace parsers

struct ymdhms_parser : vast::parser<ymdhms_parser> {
  using attribute = timestamp;

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, const Iterator& l, Attribute& x) const {
    using namespace std::chrono;
    auto year = integral_parser<int, 4, 4>{}
                  .with([](auto x) { return x >= 1900; });
    auto mon = integral_parser<int, 2, 2>{}
                 .with([](auto x) { return x >= 1 && x <= 12; });
    auto day = integral_parser<int, 2, 2>{}
                 .with([](auto x) { return x >= 1 && x <= 31; });
    auto hour = integral_parser<int, 2, 2>{}
                 .with([](auto x) { return x >= 0 && x <= 23; });
    auto min = integral_parser<int, 2, 2>{}
                 .with([](auto x) { return x >= 0 && x <= 59; });
    auto sec = parsers::real_opt_dot
                 .with([](auto x) { return x >= 0.0 && x <= 60.0; });
    auto p = year >> '-' >> mon
        >> ~('-' >> day >> ~('+' >> hour >> ~(':' >> min >> ~(':' >> sec))));
    if constexpr (std::is_same_v<Attribute, unused_type>) {
      return p(f, l, unused);
    } else {
      auto secs = 0.0;
      auto mins = 0;
      auto hrs = 0;
      auto dys = 1;
      auto mons = 1;
      auto yrs = 0;
      // Compose to match parser attribute.
      auto ms = std::tie(mins, secs);
      auto hms = std::tie(hrs, ms);
      auto dhms = std::tie(dys, hms);
      if (!p(f, l, yrs, mons, dhms))
        return false;
      date::sys_days ymd = date::year{yrs} / mons / dys;
      auto delta = hours{hrs} + minutes{mins} + double_seconds{secs};
      x = timestamp{ymd} + duration_cast<timespan>(delta);
      return true;
    }
  }
};

namespace parsers {

auto const ymdhms = ymdhms_parser{};

/// Parses a fractional seconds-timestamp as UNIX epoch.
auto const unix_ts = real_opt_dot
  ->* [](double d) {
    using std::chrono::duration_cast;
    return timestamp{duration_cast<vast::timespan>(double_seconds{d})};
  };

} // namespace parsers

struct timestamp_parser : parser<timestamp_parser> {
  using attribute = timestamp;

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, const Iterator& l, Attribute& a) const {
    using namespace parser_literals;
    auto plus = [](timespan t) { return timestamp::clock::now() + t; };
    auto minus = [](timespan t) { return timestamp::clock::now() - t; };
    auto ws = ignore(*parsers::space);
    auto p
      = parsers::ymdhms
      | '@' >> parsers::unix_ts
      | "now" >> ws >> ( '+' >> ws >> parsers::timespan ->* plus
                       | '-' >> ws >> parsers::timespan ->* minus )
      | "now"_p ->* []() { return timestamp::clock::now(); }
      | "in" >> ws >> parsers::timespan ->* plus
      | (parsers::timespan ->* minus) >> ws >> "ago"
      ;
    return p(f, l, a);
  }
};

template <>
struct parser_registry<timestamp> {
  using type = timestamp_parser;
};

namespace parsers {

auto const timestamp = timestamp_parser{};

} // namespace parsers
} // namespace vast
<commit_msg>Allow fractional durations in parser<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#pragma once

#include <chrono>
#include <ctime>
#include <cstring>

#include <date/date.h>

#include "vast/access.hpp"
#include "vast/time.hpp"
#include "vast/concept/parseable/core.hpp"
#include "vast/concept/parseable/numeric/real.hpp"
#include "vast/concept/parseable/string/char_class.hpp"

namespace vast {

// TODO: replace with Howard Hinnant's TZ stuff and then move into
// vast/concept/parseable/std/chrono.

template <class Rep, class Period>
struct duration_parser : parser<duration_parser<Rep, Period>> {
  using attribute = std::chrono::duration<Rep, Period>;

  template <class T>
  static attribute cast(T x) {
    return std::chrono::duration_cast<attribute>(x);
  }

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, const Iterator& l, Attribute& x) const {
    using namespace parsers;
    using namespace parser_literals;
    using namespace std::chrono;
    auto unit
      = "nsecs"_p ->* [] { return cast(nanoseconds(1)); }
      | "nsec"_p  ->* [] { return cast(nanoseconds(1)); }
      | "ns"_p    ->* [] { return cast(nanoseconds(1)); }
      | "usecs"_p ->* [] { return cast(microseconds(1)); }
      | "usec"_p  ->* [] { return cast(microseconds(1)); }
      | "us"_p    ->* [] { return cast(microseconds(1)); }
      | "msecs"_p ->* [] { return cast(milliseconds(1)); }
      | "msec"_p  ->* [] { return cast(milliseconds(1)); }
      | "ms"_p    ->* [] { return cast(milliseconds(1)); }
      | "secs"_p  ->* [] { return cast(seconds(1)); }
      | "sec"_p   ->* [] { return cast(seconds(1)); }
      | "s"_p     ->* [] { return cast(seconds(1)); }
      | "mins"_p  ->* [] { return cast(minutes(1)); }
      | "min"_p   ->* [] { return cast(minutes(1)); }
      | "m"_p     ->* [] { return cast(minutes(1)); }
      | "hrs"_p   ->* [] { return cast(hours(1)); }
      | "hours"_p ->* [] { return cast(hours(1)); }
      | "hour"_p  ->* [] { return cast(hours(1)); }
      | "h"_p     ->* [] { return cast(hours(1)); }
      | "days"_p  ->* [] { return cast(hours(24)); }
      | "day"_p   ->* [] { return cast(hours(24)); }
      | "d"_p     ->* [] { return cast(hours(24)); }
      | "weeks"_p ->* [] { return cast(hours(24 * 7)); }
      | "week"_p  ->* [] { return cast(hours(24 * 7)); }
      | "w"_p     ->* [] { return cast(hours(24 * 7)); }
      | "years"_p ->* [] { return cast(hours(24 * 365)); }
      | "year"_p  ->* [] { return cast(hours(24 * 365)); }
      | "y"_p     ->* [] { return cast(hours(24 * 365)); }
      ;
    double scale;
    auto multiply = [&](attribute dur) {
      auto result = duration_cast<duration<double, Period>>(dur) * scale;
      return cast(result);
    };
    auto p = real_opt_dot >> ignore(*space) >> unit ->* multiply;
    return p(f, l, scale, x);
  }
};

template <class Rep, class Period>
struct parser_registry<std::chrono::duration<Rep, Period>> {
  using type = duration_parser<Rep, Period>;
};

namespace parsers {

template <class Rep, class Period>
auto const duration = duration_parser<Rep, Period>{};

auto const timespan = duration<vast::timespan::rep, vast::timespan::period>;

} // namespace parsers

struct ymdhms_parser : vast::parser<ymdhms_parser> {
  using attribute = timestamp;

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, const Iterator& l, Attribute& x) const {
    using namespace std::chrono;
    auto year = integral_parser<int, 4, 4>{}
                  .with([](auto x) { return x >= 1900; });
    auto mon = integral_parser<int, 2, 2>{}
                 .with([](auto x) { return x >= 1 && x <= 12; });
    auto day = integral_parser<int, 2, 2>{}
                 .with([](auto x) { return x >= 1 && x <= 31; });
    auto hour = integral_parser<int, 2, 2>{}
                 .with([](auto x) { return x >= 0 && x <= 23; });
    auto min = integral_parser<int, 2, 2>{}
                 .with([](auto x) { return x >= 0 && x <= 59; });
    auto sec = parsers::real_opt_dot
                 .with([](auto x) { return x >= 0.0 && x <= 60.0; });
    auto p = year >> '-' >> mon
        >> ~('-' >> day >> ~('+' >> hour >> ~(':' >> min >> ~(':' >> sec))));
    if constexpr (std::is_same_v<Attribute, unused_type>) {
      return p(f, l, unused);
    } else {
      auto secs = 0.0;
      auto mins = 0;
      auto hrs = 0;
      auto dys = 1;
      auto mons = 1;
      auto yrs = 0;
      // Compose to match parser attribute.
      auto ms = std::tie(mins, secs);
      auto hms = std::tie(hrs, ms);
      auto dhms = std::tie(dys, hms);
      if (!p(f, l, yrs, mons, dhms))
        return false;
      date::sys_days ymd = date::year{yrs} / mons / dys;
      auto delta = hours{hrs} + minutes{mins} + double_seconds{secs};
      x = timestamp{ymd} + duration_cast<timespan>(delta);
      return true;
    }
  }
};

namespace parsers {

auto const ymdhms = ymdhms_parser{};

/// Parses a fractional seconds-timestamp as UNIX epoch.
auto const unix_ts = real_opt_dot
  ->* [](double d) {
    using std::chrono::duration_cast;
    return timestamp{duration_cast<vast::timespan>(double_seconds{d})};
  };

} // namespace parsers

struct timestamp_parser : parser<timestamp_parser> {
  using attribute = timestamp;

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, const Iterator& l, Attribute& a) const {
    using namespace parser_literals;
    auto plus = [](timespan t) { return timestamp::clock::now() + t; };
    auto minus = [](timespan t) { return timestamp::clock::now() - t; };
    auto ws = ignore(*parsers::space);
    auto p
      = parsers::ymdhms
      | '@' >> parsers::unix_ts
      | "now" >> ws >> ( '+' >> ws >> parsers::timespan ->* plus
                       | '-' >> ws >> parsers::timespan ->* minus )
      | "now"_p ->* []() { return timestamp::clock::now(); }
      | "in" >> ws >> parsers::timespan ->* plus
      | (parsers::timespan ->* minus) >> ws >> "ago"
      ;
    return p(f, l, a);
  }
};

template <>
struct parser_registry<timestamp> {
  using type = timestamp_parser;
};

namespace parsers {

auto const timestamp = timestamp_parser{};

} // namespace parsers
} // namespace vast
<|endoftext|>


<commit_before>#ifndef VAST_CONCEPT_PRINTABLE_VAST_JSON_HPP
#define VAST_CONCEPT_PRINTABLE_VAST_JSON_HPP

#include "vast/concept/printable/print.hpp"
#include "vast/concept/printable/string.hpp"
#include "vast/concept/printable/core/printer.hpp"
#include "vast/detail/string.hpp"
#include "vast/json.hpp"

namespace vast {

//struct json_type_printer : printer<json_type_printer> {
//  using attribute = json::type;
//
//  template <typename Iterator>
//  bool print(Iterator& out, json::type const& t) {
//    using namespace printers;
//    switch (t) {
//      default:
//        return str.print(out, "<invalid>");
//      case json::type::null:
//        return str.print(out, "null");
//      case json::type::boolean:
//        return str.print(out, "bool");
//      case json::type::number:
//        return str.print(out, "number");
//      case json::type::string:
//        return str.print(out, "string");
//      case json::type::array:
//        return str.print(out, "array");
//      case json::type::object:
//        return str.print(out, "object");
//    }
//  }
//};

namespace policy {

struct tree {};
struct oneline {};

} // namespace policy

template <typename TreePolicy, int Indent = 2, int Padding = 0>
struct json_printer : printer<json_printer<TreePolicy, Indent, Padding>> {
  using attribute = json;

  static constexpr auto tree = std::is_same<TreePolicy, policy::tree>{};

  static_assert(Padding >= 0, "padding must not be negative");

  template <typename Iterator>
  struct print_visitor {
    print_visitor(Iterator& out) : out_{out} {}

    bool operator()(none const&) {
      return printers::str.print(out_, "null");
    }

    bool operator()(bool b) {
      return printers::str.print(out_, b ? "true" : "false");
    }

    bool operator()(json::number n) {
      auto str = std::to_string(n);
      json::number i;
      if (std::modf(n, &i) == 0.0)
        // Do not show 0 as 0.0.
        str.erase(str.find('.'), std::string::npos);
      else
        // Avoid no trailing zeros.
        str.erase(str.find_last_not_of('0') + 1, std::string::npos);
      return printers::str.print(out_, str);
    }

    bool operator()(std::string const& str) {
      return printers::str.print(out_, detail::json_escape(str));
    }

    bool operator()(json::array const& a) {
      using namespace printers;
      if (depth_ == 0 && !pad())
        return false;
      if (!any.print(out_, '['))
        return false;
      if (!a.empty() && tree) {
        ++depth_;
        any.print(out_, '\n');
      }
      auto begin = a.begin();
      auto end = a.end();
      while (begin != end) {
        if (!indent())
          return false;
        if (!visit(*this, *begin))
          return false;
        ;
        ++begin;
        if (begin != end)
          if (!str.print(out_, tree ? ",\n" : ", "))
            return false;
      }
      if (!a.empty() && tree) {
        --depth_;
        any.print(out_, '\n');
        if (!indent())
          return false;
      }
      return any.print(out_, ']');
    }

    bool operator()(json::object const& o) {
      using namespace printers;
      if (depth_ == 0 && !pad())
        return false;
      if (!any.print(out_, '{'))
        return false;
      if (!o.empty() && tree) {
        ++depth_;
        if (!any.print(out_, '\n'))
          return false;
      }
      auto begin = o.begin();
      auto end = o.end();
      while (begin != end) {
        if (!indent())
          return false;
        if (!(*this)(begin->first))
          return false;
        if (!str.print(out_, ": "))
          return false;
        if (!visit(*this, begin->second))
          return false;
        ++begin;
        if (begin != end)
          if (!str.print(out_, tree ? ",\n" : ", "))
            return false;
      }
      if (!o.empty() && tree) {
        --depth_;
        if (!any.print(out_, '\n'))
          return false;
        if (!indent())
          return false;
      }
      return any.print(out_, '}');
    }

    bool pad() {
      if (Padding > 0)
        for (auto i = 0; i < Padding; ++i)
          if (!printers::any.print(out_, ' '))
            return false;
      return true;
    }

    bool indent() {
      if (!pad())
        return false;
      if (!tree)
        return true;
      for (auto i = 0; i < depth_ * Indent; ++i)
        if (!printers::any.print(out_, ' '))
          return false;
      return true;
    }

    Iterator& out_;
    int depth_ = 0;
  };

  template <typename Iterator, typename T>
  auto print(Iterator& out, T const& x) const
  -> std::enable_if_t<!std::is_same<json::jsonize<T>,
                                    std::false_type>::value> {
    return print_visitor<Iterator>{out}(x);
  }

  template <typename Iterator>
  bool print(Iterator& out, json const& j) const {
    return visit(print_visitor<Iterator>{out}, j);
  }
};

//template <>
//struct printer_registry<json::type> {
//  using type = json_type_printer;
//};

template <>
struct printer_registry<json::array> {
  using type = json_printer<policy::tree, 2>;
};

template <>
struct printer_registry<json::object> {
  using type = json_printer<policy::tree, 2>;
};

template <>
struct printer_registry<json> {
  using type = json_printer<policy::tree, 2>;
};

namespace printers {

template <typename Policy>
json_printer<Policy> json;

} // namespace printers
} // namespace vast

#endif
<commit_msg>Fix invalid return type<commit_after>#ifndef VAST_CONCEPT_PRINTABLE_VAST_JSON_HPP
#define VAST_CONCEPT_PRINTABLE_VAST_JSON_HPP

#include "vast/concept/printable/print.hpp"
#include "vast/concept/printable/string.hpp"
#include "vast/concept/printable/core/printer.hpp"
#include "vast/detail/string.hpp"
#include "vast/json.hpp"

namespace vast {

//struct json_type_printer : printer<json_type_printer> {
//  using attribute = json::type;
//
//  template <typename Iterator>
//  bool print(Iterator& out, json::type const& t) {
//    using namespace printers;
//    switch (t) {
//      default:
//        return str.print(out, "<invalid>");
//      case json::type::null:
//        return str.print(out, "null");
//      case json::type::boolean:
//        return str.print(out, "bool");
//      case json::type::number:
//        return str.print(out, "number");
//      case json::type::string:
//        return str.print(out, "string");
//      case json::type::array:
//        return str.print(out, "array");
//      case json::type::object:
//        return str.print(out, "object");
//    }
//  }
//};

namespace policy {

struct tree {};
struct oneline {};

} // namespace policy

template <typename TreePolicy, int Indent = 2, int Padding = 0>
struct json_printer : printer<json_printer<TreePolicy, Indent, Padding>> {
  using attribute = json;

  static constexpr auto tree = std::is_same<TreePolicy, policy::tree>{};

  static_assert(Padding >= 0, "padding must not be negative");

  template <typename Iterator>
  struct print_visitor {
    print_visitor(Iterator& out) : out_{out} {}

    bool operator()(none const&) {
      return printers::str.print(out_, "null");
    }

    bool operator()(bool b) {
      return printers::str.print(out_, b ? "true" : "false");
    }

    bool operator()(json::number n) {
      auto str = std::to_string(n);
      json::number i;
      if (std::modf(n, &i) == 0.0)
        // Do not show 0 as 0.0.
        str.erase(str.find('.'), std::string::npos);
      else
        // Avoid no trailing zeros.
        str.erase(str.find_last_not_of('0') + 1, std::string::npos);
      return printers::str.print(out_, str);
    }

    bool operator()(std::string const& str) {
      return printers::str.print(out_, detail::json_escape(str));
    }

    bool operator()(json::array const& a) {
      using namespace printers;
      if (depth_ == 0 && !pad())
        return false;
      if (!any.print(out_, '['))
        return false;
      if (!a.empty() && tree) {
        ++depth_;
        any.print(out_, '\n');
      }
      auto begin = a.begin();
      auto end = a.end();
      while (begin != end) {
        if (!indent())
          return false;
        if (!visit(*this, *begin))
          return false;
        ;
        ++begin;
        if (begin != end)
          if (!str.print(out_, tree ? ",\n" : ", "))
            return false;
      }
      if (!a.empty() && tree) {
        --depth_;
        any.print(out_, '\n');
        if (!indent())
          return false;
      }
      return any.print(out_, ']');
    }

    bool operator()(json::object const& o) {
      using namespace printers;
      if (depth_ == 0 && !pad())
        return false;
      if (!any.print(out_, '{'))
        return false;
      if (!o.empty() && tree) {
        ++depth_;
        if (!any.print(out_, '\n'))
          return false;
      }
      auto begin = o.begin();
      auto end = o.end();
      while (begin != end) {
        if (!indent())
          return false;
        if (!(*this)(begin->first))
          return false;
        if (!str.print(out_, ": "))
          return false;
        if (!visit(*this, begin->second))
          return false;
        ++begin;
        if (begin != end)
          if (!str.print(out_, tree ? ",\n" : ", "))
            return false;
      }
      if (!o.empty() && tree) {
        --depth_;
        if (!any.print(out_, '\n'))
          return false;
        if (!indent())
          return false;
      }
      return any.print(out_, '}');
    }

    bool pad() {
      if (Padding > 0)
        for (auto i = 0; i < Padding; ++i)
          if (!printers::any.print(out_, ' '))
            return false;
      return true;
    }

    bool indent() {
      if (!pad())
        return false;
      if (!tree)
        return true;
      for (auto i = 0; i < depth_ * Indent; ++i)
        if (!printers::any.print(out_, ' '))
          return false;
      return true;
    }

    Iterator& out_;
    int depth_ = 0;
  };

  template <typename Iterator, typename T>
  auto print(Iterator& out, T const& x) const
  -> std::enable_if_t<
    !std::is_same<json::jsonize<T>, std::false_type>::value,
    bool
  > {
    return print_visitor<Iterator>{out}(x);
  }

  template <typename Iterator>
  bool print(Iterator& out, json const& j) const {
    return visit(print_visitor<Iterator>{out}, j);
  }
};

//template <>
//struct printer_registry<json::type> {
//  using type = json_type_printer;
//};

template <>
struct printer_registry<json::array> {
  using type = json_printer<policy::tree, 2>;
};

template <>
struct printer_registry<json::object> {
  using type = json_printer<policy::tree, 2>;
};

template <>
struct printer_registry<json> {
  using type = json_printer<policy::tree, 2>;
};

namespace printers {

template <typename Policy>
json_printer<Policy> json;

} // namespace printers
} // namespace vast

#endif
<|endoftext|>


<commit_before>#include "pixelboost/graphics/components/rectangle.h"
#include "pixelboost/graphics/renderer/primitive/primitiveRenderer.h"
#include "pixelboost/logic/component/transform/basic.h"

#include "core/selection.h"
#include "core/uidHelpers.h"
#include "project/entity.h"
#include "project/schema.h"
#include "view/entity/property/property.h"
#include "view/entity/property/sprite.h"
#include "view/entity/entity.h"
#include "core.h"
#include "view.h"

using namespace pixeleditor;

ViewEntity::ViewEntity(pb::Scene* scene, Uid uid, pixeleditor::Entity* entity)
    : pb::Entity(scene, uid)
    , _BoundsComponent(0)
    , _Entity(entity)
{
    AddComponent(new pb::BasicTransformComponent(this));

    ParseProperties();

    ResetTransform();

    _Entity->propertyChanged.Connect(this, &ViewEntity::OnPropertyChanged);

    Core::Instance()->GetSelection().selectionChanged.Connect(this, &ViewEntity::OnSelectionChanged);

    OnSelectionChanged(&Core::Instance()->GetSelection());
}

ViewEntity::~ViewEntity()
{
    Core::Instance()->GetSelection().selectionChanged.Disconnect(this, &ViewEntity::OnSelectionChanged);

    _Entity->propertyChanged.Disconnect(this, &ViewEntity::OnPropertyChanged);
}

void ViewEntity::Update(float time)
{
    for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
    {
        it->second->Update(time);
    }
}

void ViewEntity::Render(int layer)
{
    UpdateBounds();

    /*
    View::Instance()->GetPrimitiveRenderer()->AttachBox(layer, Vec2(_Position.x, _Position.y), Vec2(0.1,0.1));
    View::Instance()->GetPrimitiveRenderer()->AttachLine(layer, Vec2(_Position.x, _Position.y), Vec2(_Position.x, _Position.y+1));
    View::Instance()->GetPrimitiveRenderer()->AttachLine(layer, Vec2(_Position.x, _Position.y), Vec2(_Position.x+1, _Position.y));
    */

    for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
    {
        it->second->Render(layer);
    }

    if (Core::Instance()->GetSelection().IsSelected(GenerateSelectionUid(GetUid())))
    {
        glm::vec3 boxCenter = _BoundingBox.GetCenter();
        glm::vec3 boxSize = _BoundingBox.GetSize();
        /*
        View::Instance()->GetPrimitiveRenderer()->AttachBox(layer, Vec2(boxCenter.x, boxCenter.y), Vec2(boxSize.x, boxSize.y), Vec3(0,0,0), Vec4(0.2,0.2,0.4,0.3));
        View::Instance()->GetPrimitiveRenderer()->AttachBox(layer, Vec2(boxCenter.x, boxCenter.y), Vec2(boxSize.x, boxSize.y), Vec3(0,0,0), Vec4(0.4,0.2,0.2,0.5), false);
        */
    }
}

Entity* ViewEntity::GetEntity()
{
    return _Entity;
}

glm::vec3 ViewEntity::GetPosition()
{
    return GetComponentByType<pb::TransformComponent>()->GetPosition();
}

glm::vec3 ViewEntity::GetRotation()
{
    return GetComponentByType<pb::TransformComponent>()->GetRotation();
}

glm::vec3 ViewEntity::GetScale()
{
    return GetComponentByType<pb::TransformComponent>()->GetScale();
}

void ViewEntity::SetPosition(glm::vec3 position)
{
    GetComponentByType<pb::TransformComponent>()->SetPosition(position);
    DirtyBounds();
}

void ViewEntity::SetRotation(glm::vec3 rotation)
{
    GetComponentByType<pb::TransformComponent>()->SetRotation(rotation);
    DirtyBounds();
}

void ViewEntity::SetScale(glm::vec3 scale)
{
    GetComponentByType<pb::TransformComponent>()->SetScale(scale);
    DirtyBounds();
}

void ViewEntity::Transform(glm::vec3 positionOffset, glm::vec3 rotationOffset, glm::vec3 scaleOffset)
{
    GetComponentByType<pb::TransformComponent>()->SetTransform(GetPosition()+positionOffset, GetRotation()+rotationOffset, GetScale()*scaleOffset);
    DirtyBounds();
}

void ViewEntity::CommitTransform()
{
    _Entity->SetPosition(GetPosition());
    _Entity->SetRotation(GetRotation().z);
    _Entity->SetScale(GetScale());
}

void ViewEntity::ResetTransform()
{
    GetComponentByType<pb::TransformComponent>()->SetTransform(_Entity->GetPosition(), glm::vec3(0,0,_Entity->GetRotation()), _Entity->GetScale());
    DirtyBounds();
}

pb::BoundingBox ViewEntity::GetBoundingBox()
{
    if (_BoundsDirty)
        UpdateBounds();

    return _BoundingBox;
}

Uid ViewEntity::GetPropertyIdByPath(const std::string& path)
{
    PropertyIdMap::iterator it = _PropertyIdMap.find(path);

    if (it != _PropertyIdMap.end())
    {
        return it->second;
    }

    return 0;
}

ViewProperty* ViewEntity::GetPropertyByPath(const std::string& path)
{
    PropertyIdMap::iterator it = _PropertyIdMap.find(path);

    if (it != _PropertyIdMap.end())
    {
        return GetPropertyById(it->second);
    }

    return 0;
}

ViewProperty* ViewEntity::GetPropertyById(Uid uid)
{
    PropertyMap::iterator it = _Properties.find(uid);
    if (it != _Properties.end())
    {
        return it->second;
    }

    return 0;
}

void ViewEntity::RemoveProperty(ViewProperty* property)
{
    RemovePropertyById(property->GetPropertyId());
}

void ViewEntity::RemovePropertyById(Uid uid)
{
    PropertyMap::iterator it = _Properties.find(uid);
    if (it != _Properties.end())
    {
        delete it->second;
        _Properties.erase(it);
    }
}

Uid ViewEntity::GeneratePropertyId(const std::string& path)
{
    Uid uid;

    do {
        uid = (rand()%((1<<12)-2))+1;
    } while (_Properties.find(uid) != _Properties.end());

    _PropertyIdMap[path] = uid;

    return uid;
}

void ViewEntity::OnSelectionChanged(const pixeleditor::Selection* selection)
{
    if (selection->IsSelected(GenerateSelectionUid(GetUid())))
    {
        UpdateBounds();

        if (!_BoundsComponent)
        {
            _BoundsComponent = new pb::RectangleComponent(this);
            _BoundsComponent->SetColor(glm::vec4(0.2, 0.2, 0.4, 0.3));
            _BoundsComponent->SetSolid(true);
            _BoundsComponent->SetLayer(1);
            _BoundsComponent->SetSize(glm::vec2(_BoundingBox.GetSize().x, _BoundingBox.GetSize().y)/glm::vec2(GetScale().x, GetScale().y));
            AddComponent(_BoundsComponent);
        }
    } else {
        if (_BoundsComponent)
        {
            DestroyComponent(_BoundsComponent);
            _BoundsComponent = 0;
        }
    }
}

Uid ViewEntity::AddProperty(ViewProperty* property)
{
    ViewProperty* other = GetPropertyByPath(property->GetPath());

    if (other)
    {
        RemoveProperty(other);
    }

    Uid uid = GeneratePropertyId(property->GetPath());

    _Properties[uid] = property;

    return uid;
}

void ViewEntity::ParseProperties()
{
    const SchemaStruct* schemaStruct = _Entity->GetType();

    ParseItem("/", schemaStruct);
    ParseStruct("/", schemaStruct);
}

void ViewEntity::ParseStruct(const std::string& path, const SchemaStruct* schemaStruct)
{
    for (SchemaStruct::PropertyMap::const_iterator it = schemaStruct->GetProperties().begin(); it != schemaStruct->GetProperties().end(); ++it)
    {
        std::string propertyPath = path + it->second->GetName() + "/";

        ParseItem(propertyPath, it->second);

        switch (it->second->GetPropertyType())
        {
            case SchemaProperty::kSchemaPropertyAtom:
            {
                break;
            }
            case SchemaProperty::kSchemaPropertyArray:
            {
                break;
            }
            case SchemaProperty::kSchemaPropertyStruct:
            {
                SchemaPropertyStruct* propertyStruct = static_cast<SchemaPropertyStruct*>(it->second);
                ParseStruct(propertyPath, propertyStruct->GetSchemaStruct());
                break;
            }
            case SchemaProperty::kSchemaPropertyPointer:
            {
                break;
            }
        }
    }
}

void ViewEntity::ParseItem(const std::string& path, const SchemaItem* item)
{
    if (const SchemaAttribute* visualisation = item->GetAttribute("Visualisation"))
    {
        std::string type = visualisation->GetParamValue("type");

        if (type == "sprite")
        {
            new SpriteViewProperty(this, path, item);
        }
    }
}

void ViewEntity::OnPropertyChanged(pixeleditor::Struct* structure)
{
    for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
    {
        it->second->Refresh();
    }
}

void ViewEntity::DirtyBounds()
{
    _BoundsDirty = true;

    for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
    {
        it->second->DirtyBounds();
    }
}

void ViewEntity::UpdateBounds()
{
    if (_BoundsDirty)
    {
        _BoundingBox.Invalidate();

        _BoundingBox.Expand(GetPosition());
        _BoundingBox.Expand(GetPosition() + glm::vec3(1,1,0));

        for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
        {
            _BoundingBox.Expand(it->second->GetBoundingBox());
        }

        _BoundsDirty = false;
    }
}
<commit_msg>Remove old code<commit_after>#include "pixelboost/graphics/components/rectangle.h"
#include "pixelboost/graphics/renderer/primitive/primitiveRenderer.h"
#include "pixelboost/logic/component/transform/basic.h"

#include "core/selection.h"
#include "core/uidHelpers.h"
#include "project/entity.h"
#include "project/schema.h"
#include "view/entity/property/property.h"
#include "view/entity/property/sprite.h"
#include "view/entity/entity.h"
#include "core.h"
#include "view.h"

using namespace pixeleditor;

ViewEntity::ViewEntity(pb::Scene* scene, Uid uid, pixeleditor::Entity* entity)
    : pb::Entity(scene, uid)
    , _BoundsComponent(0)
    , _Entity(entity)
{
    AddComponent(new pb::BasicTransformComponent(this));

    ParseProperties();

    ResetTransform();

    _Entity->propertyChanged.Connect(this, &ViewEntity::OnPropertyChanged);

    Core::Instance()->GetSelection().selectionChanged.Connect(this, &ViewEntity::OnSelectionChanged);

    OnSelectionChanged(&Core::Instance()->GetSelection());
}

ViewEntity::~ViewEntity()
{
    Core::Instance()->GetSelection().selectionChanged.Disconnect(this, &ViewEntity::OnSelectionChanged);

    _Entity->propertyChanged.Disconnect(this, &ViewEntity::OnPropertyChanged);
}

void ViewEntity::Update(float time)
{
    for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
    {
        it->second->Update(time);
    }
}

void ViewEntity::Render(int layer)
{

}

Entity* ViewEntity::GetEntity()
{
    return _Entity;
}

glm::vec3 ViewEntity::GetPosition()
{
    return GetComponentByType<pb::TransformComponent>()->GetPosition();
}

glm::vec3 ViewEntity::GetRotation()
{
    return GetComponentByType<pb::TransformComponent>()->GetRotation();
}

glm::vec3 ViewEntity::GetScale()
{
    return GetComponentByType<pb::TransformComponent>()->GetScale();
}

void ViewEntity::SetPosition(glm::vec3 position)
{
    GetComponentByType<pb::TransformComponent>()->SetPosition(position);
    DirtyBounds();
}

void ViewEntity::SetRotation(glm::vec3 rotation)
{
    GetComponentByType<pb::TransformComponent>()->SetRotation(rotation);
    DirtyBounds();
}

void ViewEntity::SetScale(glm::vec3 scale)
{
    GetComponentByType<pb::TransformComponent>()->SetScale(scale);
    DirtyBounds();
}

void ViewEntity::Transform(glm::vec3 positionOffset, glm::vec3 rotationOffset, glm::vec3 scaleOffset)
{
    GetComponentByType<pb::TransformComponent>()->SetTransform(GetPosition()+positionOffset, GetRotation()+rotationOffset, GetScale()*scaleOffset);
    DirtyBounds();
}

void ViewEntity::CommitTransform()
{
    _Entity->SetPosition(GetPosition());
    _Entity->SetRotation(GetRotation().z);
    _Entity->SetScale(GetScale());
}

void ViewEntity::ResetTransform()
{
    GetComponentByType<pb::TransformComponent>()->SetTransform(_Entity->GetPosition(), glm::vec3(0,0,_Entity->GetRotation()), _Entity->GetScale());
    DirtyBounds();
}

pb::BoundingBox ViewEntity::GetBoundingBox()
{
    if (_BoundsDirty)
        UpdateBounds();

    return _BoundingBox;
}

Uid ViewEntity::GetPropertyIdByPath(const std::string& path)
{
    PropertyIdMap::iterator it = _PropertyIdMap.find(path);

    if (it != _PropertyIdMap.end())
    {
        return it->second;
    }

    return 0;
}

ViewProperty* ViewEntity::GetPropertyByPath(const std::string& path)
{
    PropertyIdMap::iterator it = _PropertyIdMap.find(path);

    if (it != _PropertyIdMap.end())
    {
        return GetPropertyById(it->second);
    }

    return 0;
}

ViewProperty* ViewEntity::GetPropertyById(Uid uid)
{
    PropertyMap::iterator it = _Properties.find(uid);
    if (it != _Properties.end())
    {
        return it->second;
    }

    return 0;
}

void ViewEntity::RemoveProperty(ViewProperty* property)
{
    RemovePropertyById(property->GetPropertyId());
}

void ViewEntity::RemovePropertyById(Uid uid)
{
    PropertyMap::iterator it = _Properties.find(uid);
    if (it != _Properties.end())
    {
        delete it->second;
        _Properties.erase(it);
    }
}

Uid ViewEntity::GeneratePropertyId(const std::string& path)
{
    Uid uid;

    do {
        uid = (rand()%((1<<12)-2))+1;
    } while (_Properties.find(uid) != _Properties.end());

    _PropertyIdMap[path] = uid;

    return uid;
}

void ViewEntity::OnSelectionChanged(const pixeleditor::Selection* selection)
{
    if (selection->IsSelected(GenerateSelectionUid(GetUid())))
    {
        UpdateBounds();

        if (!_BoundsComponent)
        {
            _BoundsComponent = new pb::RectangleComponent(this);
            _BoundsComponent->SetColor(glm::vec4(0.2, 0.2, 0.4, 0.3));
            _BoundsComponent->SetSolid(true);
            _BoundsComponent->SetLayer(1);
            _BoundsComponent->SetSize(glm::vec2(_BoundingBox.GetSize().x, _BoundingBox.GetSize().y)/glm::vec2(GetScale().x, GetScale().y));
            AddComponent(_BoundsComponent);
        }
    } else {
        if (_BoundsComponent)
        {
            DestroyComponent(_BoundsComponent);
            _BoundsComponent = 0;
        }
    }
}

Uid ViewEntity::AddProperty(ViewProperty* property)
{
    ViewProperty* other = GetPropertyByPath(property->GetPath());

    if (other)
    {
        RemoveProperty(other);
    }

    Uid uid = GeneratePropertyId(property->GetPath());

    _Properties[uid] = property;

    return uid;
}

void ViewEntity::ParseProperties()
{
    const SchemaStruct* schemaStruct = _Entity->GetType();

    ParseItem("/", schemaStruct);
    ParseStruct("/", schemaStruct);
}

void ViewEntity::ParseStruct(const std::string& path, const SchemaStruct* schemaStruct)
{
    for (SchemaStruct::PropertyMap::const_iterator it = schemaStruct->GetProperties().begin(); it != schemaStruct->GetProperties().end(); ++it)
    {
        std::string propertyPath = path + it->second->GetName() + "/";

        ParseItem(propertyPath, it->second);

        switch (it->second->GetPropertyType())
        {
            case SchemaProperty::kSchemaPropertyAtom:
            {
                break;
            }
            case SchemaProperty::kSchemaPropertyArray:
            {
                break;
            }
            case SchemaProperty::kSchemaPropertyStruct:
            {
                SchemaPropertyStruct* propertyStruct = static_cast<SchemaPropertyStruct*>(it->second);
                ParseStruct(propertyPath, propertyStruct->GetSchemaStruct());
                break;
            }
            case SchemaProperty::kSchemaPropertyPointer:
            {
                break;
            }
        }
    }
}

void ViewEntity::ParseItem(const std::string& path, const SchemaItem* item)
{
    if (const SchemaAttribute* visualisation = item->GetAttribute("Visualisation"))
    {
        std::string type = visualisation->GetParamValue("type");

        if (type == "sprite")
        {
            new SpriteViewProperty(this, path, item);
        }
    }
}

void ViewEntity::OnPropertyChanged(pixeleditor::Struct* structure)
{
    for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
    {
        it->second->Refresh();
    }
}

void ViewEntity::DirtyBounds()
{
    _BoundsDirty = true;

    for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
    {
        it->second->DirtyBounds();
    }
}

void ViewEntity::UpdateBounds()
{
    if (_BoundsDirty)
    {
        _BoundingBox.Invalidate();

        _BoundingBox.Expand(GetPosition());
        _BoundingBox.Expand(GetPosition() + glm::vec3(1,1,0));

        for (PropertyMap::iterator it = _Properties.begin(); it != _Properties.end(); ++it)
        {
            _BoundingBox.Expand(it->second->GetBoundingBox());
        }

        _BoundsDirty = false;
    }
}
<|endoftext|>


<commit_before><commit_msg>esn : tests : AdpativeFilter : ReferenceFilter : produce scalar output<commit_after><|endoftext|>


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

/*
 * $Id$
 */

#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/ruby/config/RubyConfig.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/profiler/Profiler.hh"
#include "mem/ruby/system/System.hh"
#include "mem/gems_common/PrioHeap.hh"
#include "mem/ruby/eventqueue/RubyEventQueueNode.hh"

// Class public method definitions

RubyEventQueue::RubyEventQueue()
{
  m_prio_heap_ptr = NULL;
  init();
}

RubyEventQueue::~RubyEventQueue()
{
  delete m_prio_heap_ptr;
}

void RubyEventQueue::init()
{
  m_globalTime = 1;
  m_timeOfLastRecovery = 1;
  m_prio_heap_ptr = new PrioHeap<RubyEventQueueNode>;
  m_prio_heap_ptr->init();
}

bool RubyEventQueue::isEmpty() const
{
  return (m_prio_heap_ptr->size() == 0);
}

void RubyEventQueue::scheduleEventAbsolute(Consumer* consumer, Time timeAbs)
{
  // Check to see if this is a redundant wakeup
  //  Time time = timeDelta + m_globalTime;
  ASSERT(consumer != NULL);
  if (consumer->getLastScheduledWakeup() != timeAbs) {
    // This wakeup is not redundant
    RubyEventQueueNode thisNode;
    thisNode.m_consumer_ptr = consumer;
    assert(timeAbs > m_globalTime);
    thisNode.m_time = timeAbs;
    m_prio_heap_ptr->insert(thisNode);
    consumer->setLastScheduledWakeup(timeAbs);
  }
}

void RubyEventQueue::triggerEvents(Time t)
{
  RubyEventQueueNode thisNode;

  while(m_prio_heap_ptr->size() > 0 && m_prio_heap_ptr->peekMin().m_time <= t) {
    m_globalTime = m_prio_heap_ptr->peekMin().m_time;
    thisNode = m_prio_heap_ptr->extractMin();
    assert(thisNode.m_consumer_ptr != NULL);
    DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,*(thisNode.m_consumer_ptr));
    DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,thisNode.m_time);
    thisNode.m_consumer_ptr->triggerWakeup();
  }
  m_globalTime = t;
}

void RubyEventQueue::triggerAllEvents()
{
  // FIXME - avoid repeated code
  RubyEventQueueNode thisNode;

  while(m_prio_heap_ptr->size() > 0) {
    m_globalTime = m_prio_heap_ptr->peekMin().m_time;
    thisNode = m_prio_heap_ptr->extractMin();
    assert(thisNode.m_consumer_ptr != NULL);
    DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,*(thisNode.m_consumer_ptr));
    DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,thisNode.m_time);
    thisNode.m_consumer_ptr->triggerWakeup();
  }
}

// Class private method definitions

void
RubyEventQueue::print(ostream& out) const
{
  out << "[Event Queue: " << *m_prio_heap_ptr << "]";
}
<commit_msg>ruby: Disabled RubyEventQueue's deletion of its home-grown priority heap. Temporarily to fix unusual memory problem.<commit_after>
/*
 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * $Id$
 */

#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/ruby/config/RubyConfig.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/profiler/Profiler.hh"
#include "mem/ruby/system/System.hh"
#include "mem/gems_common/PrioHeap.hh"
#include "mem/ruby/eventqueue/RubyEventQueueNode.hh"

// Class public method definitions

RubyEventQueue::RubyEventQueue()
{
  m_prio_heap_ptr = NULL;
  init();
}

RubyEventQueue::~RubyEventQueue()
{
  // delete m_prio_heap_ptr;
}

void RubyEventQueue::init()
{
  m_globalTime = 1;
  m_timeOfLastRecovery = 1;
  m_prio_heap_ptr = new PrioHeap<RubyEventQueueNode>;
  m_prio_heap_ptr->init();
}

bool RubyEventQueue::isEmpty() const
{
  return (m_prio_heap_ptr->size() == 0);
}

void RubyEventQueue::scheduleEventAbsolute(Consumer* consumer, Time timeAbs)
{
  // Check to see if this is a redundant wakeup
  //  Time time = timeDelta + m_globalTime;
  ASSERT(consumer != NULL);
  if (consumer->getLastScheduledWakeup() != timeAbs) {
    // This wakeup is not redundant
    RubyEventQueueNode thisNode;
    thisNode.m_consumer_ptr = consumer;
    assert(timeAbs > m_globalTime);
    thisNode.m_time = timeAbs;
    m_prio_heap_ptr->insert(thisNode);
    consumer->setLastScheduledWakeup(timeAbs);
  }
}

void RubyEventQueue::triggerEvents(Time t)
{
  RubyEventQueueNode thisNode;

  while(m_prio_heap_ptr->size() > 0 && m_prio_heap_ptr->peekMin().m_time <= t) {
    m_globalTime = m_prio_heap_ptr->peekMin().m_time;
    thisNode = m_prio_heap_ptr->extractMin();
    assert(thisNode.m_consumer_ptr != NULL);
    DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,*(thisNode.m_consumer_ptr));
    DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,thisNode.m_time);
    thisNode.m_consumer_ptr->triggerWakeup();
  }
  m_globalTime = t;
}

void RubyEventQueue::triggerAllEvents()
{
  // FIXME - avoid repeated code
  RubyEventQueueNode thisNode;

  while(m_prio_heap_ptr->size() > 0) {
    m_globalTime = m_prio_heap_ptr->peekMin().m_time;
    thisNode = m_prio_heap_ptr->extractMin();
    assert(thisNode.m_consumer_ptr != NULL);
    DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,*(thisNode.m_consumer_ptr));
    DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,thisNode.m_time);
    thisNode.m_consumer_ptr->triggerWakeup();
  }
}

// Class private method definitions

void
RubyEventQueue::print(ostream& out) const
{
  out << "[Event Queue: " << *m_prio_heap_ptr << "]";
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmessageid.h"
#include <qhash.h>
#include <messagingutil_p.h>

QTM_BEGIN_NAMESPACE

class QMessageIdPrivate
{
public:
    QString _id;
};

QMessageId::QMessageId()
 : d_ptr(0)
{
}

QMessageId::QMessageId(const QMessageId& other)
 : d_ptr(0)
{
	this->operator=(other);
}

QMessageId::QMessageId(const QString& id)
{
    d_ptr = new QMessageIdPrivate;
    d_ptr->_id = id;
}

QMessageId::~QMessageId()
{
	delete d_ptr;
}

QMessageId& QMessageId::operator=(const QMessageId& other)
{
    if (!other.d_ptr) {
        delete d_ptr;
        return *this;
    }

    if (!d_ptr)
        d_ptr = new QMessageIdPrivate;

    d_ptr->_id = other.d_ptr->_id;

    return *this;
}

bool QMessageId::operator==(const QMessageId& other) const
{
    if (!other.d_ptr && !d_ptr)
        return true;

    if (!other.d_ptr || !d_ptr)
        return false;

    return (d_ptr->_id == other.d_ptr->_id);
}

bool QMessageId::operator<(const QMessageId& other) const
{
    long left = 0;
    long right = 0;
    if (d_ptr) {
        //left = SymbianHelpers::stripIdPrefix(d_ptr->_id).toLong();
        left = d_ptr->_id.toLong();
    }
    if (other.d_ptr) {
        //right = SymbianHelpers::stripIdPrefix(other.d_ptr->_id).toLong();
        right = other.d_ptr->_id.toLong();
    }

    return (left < right);
}

QString QMessageId::toString() const
{
    return d_ptr ? d_ptr->_id : QString();
}

bool QMessageId::isValid() const
{
    return d_ptr ? true : false;
}

uint qHash(const QMessageId &id)
{
    return qHash(id.toString());
}

QTM_END_NAMESPACE
<commit_msg>Strip prefixes when comparing message ids<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmessageid.h"
#include <qhash.h>
#include <messagingutil_p.h>

QTM_BEGIN_NAMESPACE

class QMessageIdPrivate
{
public:
    QString _id;
};

QMessageId::QMessageId()
 : d_ptr(0)
{
}

QMessageId::QMessageId(const QMessageId& other)
 : d_ptr(0)
{
	this->operator=(other);
}

QMessageId::QMessageId(const QString& id)
{
    d_ptr = new QMessageIdPrivate;
    d_ptr->_id = id;
}

QMessageId::~QMessageId()
{
	delete d_ptr;
}

QMessageId& QMessageId::operator=(const QMessageId& other)
{
    if (!other.d_ptr) {
        delete d_ptr;
        return *this;
    }

    if (!d_ptr)
        d_ptr = new QMessageIdPrivate;

    d_ptr->_id = other.d_ptr->_id;

    return *this;
}

bool QMessageId::operator==(const QMessageId& other) const
{
    if (!other.d_ptr && !d_ptr)
        return true;

    if (!other.d_ptr || !d_ptr)
        return false;

    return (d_ptr->_id == other.d_ptr->_id);
}

bool QMessageId::operator<(const QMessageId& other) const
{
    long left = 0;
    long right = 0;
    if (d_ptr) {
        left = SymbianHelpers::stripIdPrefix(d_ptr->_id).toLong();
        //left = d_ptr->_id.toLong();
    }
    if (other.d_ptr) {
        right = SymbianHelpers::stripIdPrefix(other.d_ptr->_id).toLong();
        //right = other.d_ptr->_id.toLong();
    }

    return (left < right);
}

QString QMessageId::toString() const
{
    return d_ptr ? d_ptr->_id : QString();
}

bool QMessageId::isValid() const
{
    return d_ptr ? true : false;
}

uint qHash(const QMessageId &id)
{
    return qHash(id.toString());
}

QTM_END_NAMESPACE
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2020 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/openglqt/canvasqopenglwidget.h>
#include <inviwo/core/datastructures/image/layerram.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <modules/opengl/openglcapabilities.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QApplication>
#include <QOpenGLContext>
#include <QResizeEvent>
#include <warn/pop>

namespace inviwo {

CanvasQOpenGLWidget::CanvasQOpenGLWidget(QWidget* parent, size2_t dim)
    : QOpenGLWidget(parent), CanvasGL(dim) {

    setFocusPolicy(Qt::StrongFocus);

    grabGesture(Qt::PanGesture);
    grabGesture(Qt::PinchGesture);
}

void CanvasQOpenGLWidget::activate() { makeCurrent(); }

void CanvasQOpenGLWidget::initializeGL() {
    OpenGLCapabilities::initializeGLEW();
    // QOpenGLWidget docs:
    // There is no need to call makeCurrent() because this has already been done
    // when this function is called.
    // Note however that the framebuffer is not yet available at this stage,
    // so do not issue draw calls from here.
    // Defer such calls to paintGL() instead.
    QOpenGLWidget::initializeGL();
}

void CanvasQOpenGLWidget::glSwapBuffers() {
    // Do nothing:
    // QOpenGLWidget will swap buffers after paintGL and we are calling this from CanvasGL::update()
    // QOpenGLWidget docs:
    // triggering a buffer swap just for the QOpenGLWidget is not possible since there is no real,
    // onscreen native surface for it.
    // Instead, it is up to the widget stack to manage composition and buffer swaps on the gui
    // thread. When a thread is done updating the framebuffer, call update() on the GUI/main thread
    // to schedule composition.
}

void CanvasQOpenGLWidget::update() {
    QOpenGLWidget::update();  // this will trigger a paint event.
}

void CanvasQOpenGLWidget::paintGL() { CanvasGL::update(); }

void CanvasQOpenGLWidget::resize(size2_t size) {
    // this should trigger a resize event.
    QOpenGLWidget::resize(static_cast<int>(size.x), static_cast<int>(size.y));
}

Canvas::ContextID CanvasQOpenGLWidget::activeContext() const {
    return static_cast<ContextID>(QOpenGLContext::currentContext());
}
Canvas::ContextID CanvasQOpenGLWidget::contextId() const {
    return static_cast<ContextID>(context());
}

void CanvasQOpenGLWidget::resizeEvent(QResizeEvent* event) {
    if (event->spontaneous()) {
        return;
    }
    setUpdatesEnabled(false);
    util::OnScopeExit enable([&]() { setUpdatesEnabled(true); });
    QOpenGLWidget::resizeEvent(event);
    // CanvasGL::resize may switch to default context so call this last
    CanvasGL::resize(uvec2(event->size().width(), event->size().height()));
}

void CanvasQOpenGLWidget::releaseContext() {
    doneCurrent();
    context()->moveToThread(QApplication::instance()->thread());
}

}  // namespace inviwo<commit_msg>OpenGLQT: canvas fix<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2020 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/openglqt/canvasqopenglwidget.h>
#include <inviwo/core/datastructures/image/layerram.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <modules/opengl/openglcapabilities.h>
#include <modules/qtwidgets/inviwoqtutils.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QApplication>
#include <QOpenGLContext>
#include <QResizeEvent>
#include <warn/pop>

namespace inviwo {

CanvasQOpenGLWidget::CanvasQOpenGLWidget(QWidget* parent, size2_t dim)
    : QOpenGLWidget(parent), CanvasGL(dim) {

    setFocusPolicy(Qt::StrongFocus);

    grabGesture(Qt::PanGesture);
    grabGesture(Qt::PinchGesture);
    installEventFilter(new utilqt::WidgetCloseEventFilter(this));
}

void CanvasQOpenGLWidget::activate() { makeCurrent(); }

void CanvasQOpenGLWidget::initializeGL() {
    OpenGLCapabilities::initializeGLEW();
    // QOpenGLWidget docs:
    // There is no need to call makeCurrent() because this has already been done
    // when this function is called.
    // Note however that the framebuffer is not yet available at this stage,
    // so do not issue draw calls from here.
    // Defer such calls to paintGL() instead.
    QOpenGLWidget::initializeGL();
}

void CanvasQOpenGLWidget::glSwapBuffers() {
    // Do nothing:
    // QOpenGLWidget will swap buffers after paintGL and we are calling this from CanvasGL::update()
    // QOpenGLWidget docs:
    // triggering a buffer swap just for the QOpenGLWidget is not possible since there is no real,
    // onscreen native surface for it.
    // Instead, it is up to the widget stack to manage composition and buffer swaps on the gui
    // thread. When a thread is done updating the framebuffer, call update() on the GUI/main thread
    // to schedule composition.
}

void CanvasQOpenGLWidget::update() {
    QOpenGLWidget::update();  // this will trigger a paint event.
}

void CanvasQOpenGLWidget::paintGL() { CanvasGL::update(); }

void CanvasQOpenGLWidget::resize(size2_t size) {
    // this should trigger a resize event.
    QOpenGLWidget::resize(static_cast<int>(size.x), static_cast<int>(size.y));
}

Canvas::ContextID CanvasQOpenGLWidget::activeContext() const {
    return static_cast<ContextID>(QOpenGLContext::currentContext());
}
Canvas::ContextID CanvasQOpenGLWidget::contextId() const {
    return static_cast<ContextID>(context());
}

void CanvasQOpenGLWidget::resizeEvent(QResizeEvent* event) {
    if (event->spontaneous()) {
        return;
    }
    setUpdatesEnabled(false);
    util::OnScopeExit enable([&]() { setUpdatesEnabled(true); });
    QOpenGLWidget::resizeEvent(event);
    // CanvasGL::resize may switch to default context so call this last
    CanvasGL::resize(uvec2(event->size().width(), event->size().height()));
}

void CanvasQOpenGLWidget::releaseContext() {
    doneCurrent();
    context()->moveToThread(QApplication::instance()->thread());
}

}  // namespace inviwo<|endoftext|>