<commit_before>#include "qrautorun.h"

#include <QtWidgets/qapplication.h>
#include <QtCore/qsettings.h>
#include <QtCore/qdir.h>

NS_QRCOMMON_BEGIN

class QrAutoRunPrivate{
public:
    QString appName;

#ifdef Q_OS_WIN32
    const QString regKey = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
#endif
};

NS_QRCOMMON_END

////////////////////////////////////////////////////

USING_NS_QRCOMMON;

QrAutoRun::QrAutoRun(const QString& appName)
    : d_ptr(new QrAutoRunPrivate())
{
    Q_D(QrAutoRun);
    d->appName = appName;
}

bool QrAutoRun::isAutoRun() const
{
    Q_D(const QrAutoRun);
#ifdef Q_OS_WIN32
    QSettings reg(d->regKey, QSettings::NativeFormat);
    return reg.contains(d->appName);
#elif Q_OS_MAC

#endif
    return false;
}

void QrAutoRun::autoRun(bool _auto)
{
    Q_D(QrAutoRun);
#ifdef Q_OS_WIN32
        QSettings reg(d->regKey, QSettings::NativeFormat);
        if(_auto) {
            reg.setValue(d->appName, QDir::toNativeSeparators(qApp->applicationFilePath()));
        } else {
            reg.remove(d->appName);
        }
#elif Q_OS_MAC

#endif
}
<commit_msg>auto run on mac<commit_after>#include "qrautorun.h"

#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
#include <QtWidgets/qapplication.h>

#ifdef Q_OS_WIN32
#include <QtCore/qsettings.h>
#elif Q_OS_MAC
#include <QtCore/qfile.h>
#include <QtCore/qtextstream.h>
#endif

NS_QRCOMMON_BEGIN

class QrAutoRunPrivate{
public:
    QString appName;
    QString appPath;

#ifdef Q_OS_WIN32
    const QString regKey = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
#endif

public:
#ifdef Q_OS_MAC
    void writePlist();
    QString plistPath();
#endif
};

#ifdef Q_OS_MAC
bool QrAutoRunPrivate::writePlist()
{
    QFile file(plistPath());
    if(! file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDbug() << "auto run, fail to write plist.";
        return false;
    }

    QTextStream txtOutput(&file);
    txtOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
    txtOutput << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" << endl;
    txtOutput << "<plist version=\"1.0\">" << endl;
    txtOutput << "<dict>" << endl;
    txtOutput << "	<key>Label</key>" << endl;
    txtOutput << QString("	<string>%1</string>").arg(appName) << endl;
    txtOutput << "	<key>ProgramArguments</key>" << endl;
    txtOutput << "	<array>" << endl;
    txtOutput << QString("		<string>%1</string>").arg(appPath) << endl;
    txtOutput << "	</array>" << endl;
    txtOutput << "	<key>ProcessType</key>" << endl;
    txtOutput << "	<string>Interactive</string>" << endl;
    txtOutput << "	<key>RunAtLoad</key>" << endl;
    txtOutput << "	<true/>" << endl;
    txtOutput << "	<key>KeepAlive</key>" << endl;
    txtOutput << "	<false/>" << endl;
    txtOutput << "</dict>" << endl;
    txtOutput << "</plist>" << endl;
    file.close();

    return true;
}

QString QrAutoRunPrivate::plistPath()
{
    return QString("%1/Library/LaunchAgents/%2.plist")
            .arg(QDir::homePath())
            .arg(appName);
}
#endif

NS_QRCOMMON_END

////////////////////////////////////////////////////

USING_NS_QRCOMMON;

QrAutoRun::QrAutoRun(const QString& appName)
    : d_ptr(new QrAutoRunPrivate())
{
    Q_D(QrAutoRun);
    d->appName = appName;
    d->appPath = qApp->applicationFilePath();
}

bool QrAutoRun::isAutoRun() const
{
    Q_D(const QrAutoRun);

#ifdef Q_OS_WIN32
    QSettings reg(d->regKey, QSettings::NativeFormat);
    return reg.contains(d->appName);
#elif Q_OS_MAC
    return QFile::exists(d->plistPath());
#endif

    return false;
}

void QrAutoRun::autoRun(bool isAuto)
{
    Q_D(QrAutoRun);
#ifdef Q_OS_WIN32
    QSettings registry(d->regKey, QSettings::NativeFormat);
    if(isAuto) {
        registry.setValue(d->appName, QDir::toNativeSeparators(d->appPath));
    } else {
        registry.remove(d->appName);
    }
    registry.sync();
#elif Q_OS_MAC
    if(isAuto) {
        d->writePlist();
    } else {
        QFile::remove(d->plistPath());
    }
#endif
}

void QrAutoRun::resetAppPath(const QString &path)
{
    Q_D(QrAutoRun);
    d->appPath = path;
}
<|endoftext|>


<commit_before>/* vim: ts=2:sw=2:expandtab
 *
 * VHDE - The VHDL Diagram Editor
 * Copyright (C) 2009-2017  Maurice van der Pot <griffon26@kfk4ever.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <iostream>
#include "project_treeview_updater.h"

ProjectTreeViewUpdater::ProjectTreeViewUpdater():
  m_pProject(nullptr),
  m_pTreeView(nullptr)
{
  std::cout << "ProjectTreeViewUpdater::ProjectTreeViewUpdater\n";
}

ProjectTreeViewUpdater::~ProjectTreeViewUpdater()
{
  std::cout << "ProjectTreeViewUpdater::~ProjectTreeViewUpdater\n";
  m_projectChangedConnection.disconnect();
  m_treeViewRowActivatedConnection.disconnect();
}

void ProjectTreeViewUpdater::onProjectChanged()
{
  repopulateTreeView();
}

void ProjectTreeViewUpdater::setProject(Project *pProject)
{
  m_pProject = pProject;
  m_projectChangedConnection = m_pProject->changed.connect(sigc::mem_fun(*this, &ProjectTreeViewUpdater::onProjectChanged));
}

void ProjectTreeViewUpdater::onRowActivated(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *pColumn)
{
  if(path.size() == 2)
  {
    auto fileNames = m_pProject->getFileNames();
    item_activated.emit(fileNames[path[0]], path[1]);
  }
}

void ProjectTreeViewUpdater::setTreeView(Gtk::TreeView *pTreeView)
{
  g_assert(m_pProject);

  m_pTreeView = pTreeView;

  m_pTreeStore = Gtk::TreeStore::create(m_treeStoreColumns);
  m_pTreeView->set_model(m_pTreeStore);
  m_pTreeView->append_column("Name", m_treeStoreColumns.name);

  m_treeViewRowActivatedConnection = m_pTreeView->signal_row_activated().connect(sigc::mem_fun(*this, &ProjectTreeViewUpdater::onRowActivated));

  repopulateTreeView();
}

void ProjectTreeViewUpdater::repopulateTreeView()
{
  m_pTreeStore->clear();

  auto fileNames = m_pProject->getFileNames();
  for(auto &pFileName: fileNames)
  {
    auto parentRow = *m_pTreeStore->append();
    parentRow[m_treeStoreColumns.name] = pFileName;

    auto childRow = *m_pTreeStore->append(parentRow.children());
    auto pLayoutFile = m_pProject->getLayoutFile(pFileName);

    auto name = pLayoutFile->getComponent()->getName();
    childRow[m_treeStoreColumns.name] = name;

    for(auto &pArch: pLayoutFile->getArchitectures())
    {
      childRow = *m_pTreeStore->append(parentRow.children());
      name = pArch->getName();
      childRow[m_treeStoreColumns.name] = name;
    }
  }

  m_pTreeView->expand_all();
}

<commit_msg>Show the entity of the first file by default after opening a project<commit_after>/* vim: ts=2:sw=2:expandtab
 *
 * VHDE - The VHDL Diagram Editor
 * Copyright (C) 2009-2017  Maurice van der Pot <griffon26@kfk4ever.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <iostream>
#include "project_treeview_updater.h"

ProjectTreeViewUpdater::ProjectTreeViewUpdater():
  m_pProject(nullptr),
  m_pTreeView(nullptr)
{
  std::cout << "ProjectTreeViewUpdater::ProjectTreeViewUpdater\n";
}

ProjectTreeViewUpdater::~ProjectTreeViewUpdater()
{
  std::cout << "ProjectTreeViewUpdater::~ProjectTreeViewUpdater\n";
  m_projectChangedConnection.disconnect();
  m_treeViewRowActivatedConnection.disconnect();
}

void ProjectTreeViewUpdater::onProjectChanged()
{
  repopulateTreeView();
}

void ProjectTreeViewUpdater::setProject(Project *pProject)
{
  m_pProject = pProject;
  m_projectChangedConnection = m_pProject->changed.connect(sigc::mem_fun(*this, &ProjectTreeViewUpdater::onProjectChanged));
}

void ProjectTreeViewUpdater::onRowActivated(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *pColumn)
{
  if(path.size() == 2)
  {
    auto fileNames = m_pProject->getFileNames();
    item_activated.emit(fileNames[path[0]], path[1]);
  }
}

void ProjectTreeViewUpdater::setTreeView(Gtk::TreeView *pTreeView)
{
  g_assert(m_pProject);

  m_pTreeView = pTreeView;

  m_pTreeStore = Gtk::TreeStore::create(m_treeStoreColumns);
  m_pTreeView->set_model(m_pTreeStore);
  m_pTreeView->append_column("Name", m_treeStoreColumns.name);

  m_treeViewRowActivatedConnection = m_pTreeView->signal_row_activated().connect(sigc::mem_fun(*this, &ProjectTreeViewUpdater::onRowActivated));

  repopulateTreeView();
}

void ProjectTreeViewUpdater::repopulateTreeView()
{
  m_pTreeStore->clear();

  auto fileNames = m_pProject->getFileNames();
  for(auto &pFileName: fileNames)
  {
    auto parentRow = *m_pTreeStore->append();
    parentRow[m_treeStoreColumns.name] = pFileName;

    auto childRow = *m_pTreeStore->append(parentRow.children());
    auto pLayoutFile = m_pProject->getLayoutFile(pFileName);

    auto name = pLayoutFile->getComponent()->getName();
    childRow[m_treeStoreColumns.name] = name;

    for(auto &pArch: pLayoutFile->getArchitectures())
    {
      childRow = *m_pTreeStore->append(parentRow.children());
      name = pArch->getName();
      childRow[m_treeStoreColumns.name] = name;
    }
  }

  m_pTreeView->expand_all();

  if(fileNames.size() != 0)
  {
    item_activated.emit(fileNames[0], 0);
  }
}

<|endoftext|>


<commit_before>#include "JsArgToArrayConverter.h"
#include <limits>
#include <sstream>
#include <assert.h>
#include "ObjectManager.h"
#include "NativeScriptAssert.h"
#include "ArgConverter.h"
#include "JniLocalRef.h"
#include "Util.h"
#include "V8GlobalHelpers.h"
#include "V8StringConstants.h"
#include "JavaObjectArrayCache.h"
#include "JType.h"

using namespace v8;
using namespace std;
using namespace tns;

JsArgToArrayConverter::JsArgToArrayConverter(const v8::Handle<Value>& arg, bool isImplementationObject, int classReturnType) :
		m_arr(nullptr), m_argsAsObject(nullptr), m_argsLen(0), m_isValid(false), m_error(Error()), m_return_type(classReturnType)
{
	if (!isImplementationObject)
	{
		m_argsLen = 1;
		m_argsAsObject = new jobject[m_argsLen];
		memset(m_argsAsObject, 0, m_argsLen * sizeof(jobject));

		m_isValid = ConvertArg(arg, 0);
	}
}

JsArgToArrayConverter::JsArgToArrayConverter(const v8::FunctionCallbackInfo<Value>& args, bool hasImplementationObject, const Handle<Object>& outerThis) :
		m_arr(nullptr), m_argsAsObject(nullptr), m_argsLen(0), m_isValid(false), m_error(Error())
{
	auto isInnerClass = !outerThis.IsEmpty();
	if (isInnerClass)
	{
		m_argsLen = args.Length() + 1;
	}
	else
	{
		m_argsLen = !hasImplementationObject ? args.Length() : args.Length() - 2;
	}

	bool success = true;

	if (m_argsLen > 0)
	{
		m_argsAsObject = new jobject[m_argsLen];
		memset(m_argsAsObject, 0, m_argsLen * sizeof(jobject));

		for (int i = 0; i < m_argsLen; i++)
		{
			if (isInnerClass)
			{
				if (i == 0)
				{
					success = ConvertArg(outerThis, i);
				}
				else
				{
					success = ConvertArg(args[i - 1], i);
				}
			}
			else
			{
				success = ConvertArg(args[i], i);
			}

			if (!success)
			{
				break;
			}
		}
	}

	m_isValid = success;
}

bool JsArgToArrayConverter::ConvertArg(const Handle<Value>& arg, int index)
{
	bool success = false;
	stringstream s;

	JEnv env;

	Type returnType = JType::getClassType(m_return_type);

	if (arg.IsEmpty())
	{
		s << "Cannot convert empty JavaScript object";
		success = false;
	}
	else if (arg->IsInt32() && (returnType == Type::Int))
	{
		jint value = arg->Int32Value();
		JniLocalRef javaObject(JType::NewInt(env, value));
		SetConvertedObject(env, index, javaObject);

		success = true;
	}
	else if (arg->IsNumber() || arg->IsNumberObject())
	{
		double d = arg->NumberValue();
		int64_t i = (int64_t)d;
		bool isInteger = d == i;

		if (isInteger)
		{
			jobject obj;
			if ((INT_MIN <= i) && (i < INT_MAX) && (returnType == Type::Int))
			{
				obj = JType::NewInt(env, (jint)d);
			}
			else
			{
				obj = JType::NewLong(env, (jlong)d);
			}

			JniLocalRef javaObject(obj);
			SetConvertedObject(env, index, javaObject);

			success = true;
		}
		else
		{
			JniLocalRef javaObject(JType::NewDouble(env, (jdouble)d));
			SetConvertedObject(env, index, javaObject);

			success = true;
		}
	}
	else if (arg->IsBoolean())
	{
		jboolean value = arg->BooleanValue();
		JniLocalRef javaObject(JType::NewBoolean(env, value));
		SetConvertedObject(env, index, javaObject);
		success = true;
	}
	else if (arg->IsBooleanObject())
	{
		auto boolObj = Handle<BooleanObject>::Cast(arg);
		jboolean value = boolObj->BooleanValue() ? JNI_TRUE : JNI_FALSE;
		JniLocalRef javaObject(JType::NewBoolean(env, value));
		SetConvertedObject(env, index, javaObject);

		success = true;
	}
	else if (arg->IsString() || arg->IsStringObject())
	{
		JniLocalRef stringObject(ConvertToJavaString(arg));
		SetConvertedObject(env, index, stringObject);

		success = true;
	}
	else if (arg->IsObject())
	{
		Local<Object> objectWithHiddenID = arg->ToObject();

		auto hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsLong());
		if (!hidden.IsEmpty())
		{
			jlong value = 0;
			if (hidden->IsString())
			{
				auto strValue = ConvertToString(hidden->ToString());
				value = atoll(strValue.c_str());
			}
			else if (hidden->IsInt32())
			{
				value = hidden->ToInt32()->Int32Value();
			}

			JniLocalRef javaObject(JType::NewLong(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsByte());
		if (!hidden.IsEmpty())
		{
			jbyte value = 0;
			if (hidden->IsString())
			{
				string value = ConvertToString(hidden->ToString());
				int byteArg = atoi(value.c_str());
				value = (jbyte)byteArg;
			}
			else if (hidden->IsInt32())
			{
				int byteArg = hidden->ToInt32()->Int32Value();
				value = (jbyte)byteArg;
			}

			JniLocalRef javaObject(JType::NewByte(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsShort());
		if (!hidden.IsEmpty())
		{
			jshort value = 0;
			if (hidden->IsString())
			{
				string value = ConvertToString(hidden->ToString());
				int shortArg = atoi(value.c_str());
				value = (jshort)shortArg;
			}
			else if (hidden->IsInt32())
			{
				jlong shortArg = hidden->ToInt32()->Int32Value();
				value = (jshort)shortArg;
			}

			JniLocalRef javaObject(JType::NewShort(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsDouble());
		if (!hidden.IsEmpty())
		{
			jdouble value = 0;
			if (hidden->IsNumber())
			{
				double doubleArg = hidden->ToNumber()->NumberValue();
				value = (jdouble)doubleArg;
			}

			JniLocalRef javaObject(JType::NewDouble(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsFloat());
		if (!hidden.IsEmpty())
		{
			jfloat value = 0;
			if (hidden->IsNumber())
			{
				double floatArg = hidden->ToNumber()->NumberValue();
				value = (jfloat)floatArg;
			}

			JniLocalRef javaObject(JType::NewFloat(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsChar());
		if (!hidden.IsEmpty())
		{
			jchar value = '\0';
			if (hidden->IsString())
			{
				string str = ConvertToString(hidden->ToString());
				value = (jchar)str[0];
			}

			JniLocalRef javaObject(JType::NewChar(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		jweak obj = ObjectManager::GetJavaObjectByJsObjectStatic(objectWithHiddenID);
		success = obj != nullptr;
		if (success)
		{
			SetConvertedObject(env, index, obj, true);
		}
		else
		{
			s << "Cannot convert JavaScript object with id " << objectWithHiddenID->GetIdentityHash() << " at index " << index;
		}
	}
	else if (arg->IsUndefined() || arg->IsNull())
	{
		SetConvertedObject(env, index, nullptr);
		success = true;
	}
	else
	{
		s << "Cannot convert JavaScript object at index " << index;
		success = false;
	}

	if (!success)
	{
		m_error.index = index;
		m_error.msg = s.str();
	}

	return success;
}

jobject JsArgToArrayConverter::GetConvertedArg()
{
	return (m_argsLen > 0) ? m_argsAsObject[0] : nullptr;
}

void JsArgToArrayConverter::SetConvertedObject(JEnv& env, int index, jobject obj, bool isGlobalRef)
{
	if (obj == nullptr)
	{
		m_argsAsObject[index] = obj;
	}
	else if (isGlobalRef)
	{
		m_argsAsObject[index] = obj;
	}
	else
	{
		m_storedIndexes.push_back(index);
		m_argsAsObject[index] = env.NewLocalRef(obj);
	}
}

int JsArgToArrayConverter::Length() const
{
	return m_argsLen;
}

bool JsArgToArrayConverter::IsValid() const
{
	return m_isValid;
}

JsArgToArrayConverter::Error JsArgToArrayConverter::GetError() const
{
	return m_error;
}

jobjectArray JsArgToArrayConverter::ToJavaArray()
{
	if ((m_arr == nullptr) && (m_argsLen > 0))
	{
		m_arr = JavaObjectArrayCache::GetJavaObjectArray(m_argsLen);
	}

	if (m_argsLen > 0)
	{
		JEnv env;

		for (int i = 0; i < m_argsLen; i++)
		{
			env.SetObjectArrayElement(m_arr, i, m_argsAsObject[i]);
		}
	}

	return m_arr;
}

JsArgToArrayConverter::~JsArgToArrayConverter()
{
	if (m_argsLen > 0)
	{
		JEnv env;

		int length = m_storedIndexes.size();
		for (int i = 0; i < length; i++)
		{
			int index = m_storedIndexes[i];
			env.DeleteLocalRef(m_argsAsObject[index]);
		}

		delete[] m_argsAsObject;
	}
}
<commit_msg>fixed cast to float and double in jsArgToArrayConverter<commit_after>#include "JsArgToArrayConverter.h"
#include <limits>
#include <sstream>
#include <assert.h>
#include "ObjectManager.h"
#include "NativeScriptAssert.h"
#include "ArgConverter.h"
#include "JniLocalRef.h"
#include "Util.h"
#include "V8GlobalHelpers.h"
#include "V8StringConstants.h"
#include "JavaObjectArrayCache.h"
#include "JType.h"

using namespace v8;
using namespace std;
using namespace tns;

JsArgToArrayConverter::JsArgToArrayConverter(const v8::Handle<Value>& arg, bool isImplementationObject, int classReturnType) :
		m_arr(nullptr), m_argsAsObject(nullptr), m_argsLen(0), m_isValid(false), m_error(Error()), m_return_type(classReturnType)
{
	if (!isImplementationObject)
	{
		m_argsLen = 1;
		m_argsAsObject = new jobject[m_argsLen];
		memset(m_argsAsObject, 0, m_argsLen * sizeof(jobject));

		m_isValid = ConvertArg(arg, 0);
	}
}

JsArgToArrayConverter::JsArgToArrayConverter(const v8::FunctionCallbackInfo<Value>& args, bool hasImplementationObject, const Handle<Object>& outerThis) :
		m_arr(nullptr), m_argsAsObject(nullptr), m_argsLen(0), m_isValid(false), m_error(Error())
{
	auto isInnerClass = !outerThis.IsEmpty();
	if (isInnerClass)
	{
		m_argsLen = args.Length() + 1;
	}
	else
	{
		m_argsLen = !hasImplementationObject ? args.Length() : args.Length() - 2;
	}

	bool success = true;

	if (m_argsLen > 0)
	{
		m_argsAsObject = new jobject[m_argsLen];
		memset(m_argsAsObject, 0, m_argsLen * sizeof(jobject));

		for (int i = 0; i < m_argsLen; i++)
		{
			if (isInnerClass)
			{
				if (i == 0)
				{
					success = ConvertArg(outerThis, i);
				}
				else
				{
					success = ConvertArg(args[i - 1], i);
				}
			}
			else
			{
				success = ConvertArg(args[i], i);
			}

			if (!success)
			{
				break;
			}
		}
	}

	m_isValid = success;
}

bool JsArgToArrayConverter::ConvertArg(const Handle<Value>& arg, int index)
{
	bool success = false;
	stringstream s;

	JEnv env;

	Type returnType = JType::getClassType(m_return_type);

	if (arg.IsEmpty())
	{
		s << "Cannot convert empty JavaScript object";
		success = false;
	}
	else if (arg->IsInt32() && (returnType == Type::Int))
	{
		jint value = arg->Int32Value();
		JniLocalRef javaObject(JType::NewInt(env, value));
		SetConvertedObject(env, index, javaObject);

		success = true;
	}
	else if (arg->IsNumber() || arg->IsNumberObject())
	{
		double d = arg->NumberValue();
		int64_t i = (int64_t)d;
		bool isInteger = d == i;

		if (isInteger)
		{
			jobject obj;
			if ((INT_MIN <= i) && (i < INT_MAX) && (returnType == Type::Int))
			{
				obj = JType::NewInt(env, (jint)d);
			}
			else
			{
				obj = JType::NewLong(env, (jlong)d);
			}

			JniLocalRef javaObject(obj);
			SetConvertedObject(env, index, javaObject);

			success = true;
		}
		else
		{
			float f = (float)d;
			bool isFloat = (f == d);

			jobject obj;
			if(isFloat && (f <= FLT_MAX) && (f > FLT_MIN) && (returnType == Type::Float)) {
				obj = JType::NewFloat(env, (jfloat)d);
			}
			else {/*isDouble*/
				obj = JType::NewFloat(env, (jdouble)d);
			}

			JniLocalRef javaObject(obj);
			SetConvertedObject(env, index, javaObject);

			success = true;
		}
	}
	else if (arg->IsBoolean())
	{
		jboolean value = arg->BooleanValue();
		JniLocalRef javaObject(JType::NewBoolean(env, value));
		SetConvertedObject(env, index, javaObject);
		success = true;
	}
	else if (arg->IsBooleanObject())
	{
		auto boolObj = Handle<BooleanObject>::Cast(arg);
		jboolean value = boolObj->BooleanValue() ? JNI_TRUE : JNI_FALSE;
		JniLocalRef javaObject(JType::NewBoolean(env, value));
		SetConvertedObject(env, index, javaObject);

		success = true;
	}
	else if (arg->IsString() || arg->IsStringObject())
	{
		JniLocalRef stringObject(ConvertToJavaString(arg));
		SetConvertedObject(env, index, stringObject);

		success = true;
	}
	else if (arg->IsObject())
	{
		Local<Object> objectWithHiddenID = arg->ToObject();

		auto hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsLong());
		if (!hidden.IsEmpty())
		{
			jlong value = 0;
			if (hidden->IsString())
			{
				auto strValue = ConvertToString(hidden->ToString());
				value = atoll(strValue.c_str());
			}
			else if (hidden->IsInt32())
			{
				value = hidden->ToInt32()->Int32Value();
			}

			JniLocalRef javaObject(JType::NewLong(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsByte());
		if (!hidden.IsEmpty())
		{
			jbyte value = 0;
			if (hidden->IsString())
			{
				string value = ConvertToString(hidden->ToString());
				int byteArg = atoi(value.c_str());
				value = (jbyte)byteArg;
			}
			else if (hidden->IsInt32())
			{
				int byteArg = hidden->ToInt32()->Int32Value();
				value = (jbyte)byteArg;
			}

			JniLocalRef javaObject(JType::NewByte(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsShort());
		if (!hidden.IsEmpty())
		{
			jshort value = 0;
			if (hidden->IsString())
			{
				string value = ConvertToString(hidden->ToString());
				int shortArg = atoi(value.c_str());
				value = (jshort)shortArg;
			}
			else if (hidden->IsInt32())
			{
				jlong shortArg = hidden->ToInt32()->Int32Value();
				value = (jshort)shortArg;
			}

			JniLocalRef javaObject(JType::NewShort(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsDouble());
		if (!hidden.IsEmpty())
		{
			jdouble value = 0;
			if (hidden->IsNumber())
			{
				double doubleArg = hidden->ToNumber()->NumberValue();
				value = (jdouble)doubleArg;
			}

			JniLocalRef javaObject(JType::NewDouble(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsFloat());
		if (!hidden.IsEmpty())
		{
			jfloat value = 0;
			if (hidden->IsNumber())
			{
				double floatArg = hidden->ToNumber()->NumberValue();
				value = (jfloat)floatArg;
			}

			JniLocalRef javaObject(JType::NewFloat(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		hidden = objectWithHiddenID->GetHiddenValue(V8StringConstants::GetMarkedAsChar());
		if (!hidden.IsEmpty())
		{
			jchar value = '\0';
			if (hidden->IsString())
			{
				string str = ConvertToString(hidden->ToString());
				value = (jchar)str[0];
			}

			JniLocalRef javaObject(JType::NewChar(env, value));
			SetConvertedObject(env, index, javaObject);
			return true;
		}

		jweak obj = ObjectManager::GetJavaObjectByJsObjectStatic(objectWithHiddenID);
		success = obj != nullptr;
		if (success)
		{
			SetConvertedObject(env, index, obj, true);
		}
		else
		{
			s << "Cannot convert JavaScript object with id " << objectWithHiddenID->GetIdentityHash() << " at index " << index;
		}
	}
	else if (arg->IsUndefined() || arg->IsNull())
	{
		SetConvertedObject(env, index, nullptr);
		success = true;
	}
	else
	{
		s << "Cannot convert JavaScript object at index " << index;
		success = false;
	}

	if (!success)
	{
		m_error.index = index;
		m_error.msg = s.str();
	}

	return success;
}

jobject JsArgToArrayConverter::GetConvertedArg()
{
	return (m_argsLen > 0) ? m_argsAsObject[0] : nullptr;
}

void JsArgToArrayConverter::SetConvertedObject(JEnv& env, int index, jobject obj, bool isGlobalRef)
{
	if (obj == nullptr)
	{
		m_argsAsObject[index] = obj;
	}
	else if (isGlobalRef)
	{
		m_argsAsObject[index] = obj;
	}
	else
	{
		m_storedIndexes.push_back(index);
		m_argsAsObject[index] = env.NewLocalRef(obj);
	}
}

int JsArgToArrayConverter::Length() const
{
	return m_argsLen;
}

bool JsArgToArrayConverter::IsValid() const
{
	return m_isValid;
}

JsArgToArrayConverter::Error JsArgToArrayConverter::GetError() const
{
	return m_error;
}

jobjectArray JsArgToArrayConverter::ToJavaArray()
{
	if ((m_arr == nullptr) && (m_argsLen > 0))
	{
		m_arr = JavaObjectArrayCache::GetJavaObjectArray(m_argsLen);
	}

	if (m_argsLen > 0)
	{
		JEnv env;

		for (int i = 0; i < m_argsLen; i++)
		{
			env.SetObjectArrayElement(m_arr, i, m_argsAsObject[i]);
		}
	}

	return m_arr;
}

JsArgToArrayConverter::~JsArgToArrayConverter()
{
	if (m_argsLen > 0)
	{
		JEnv env;

		int length = m_storedIndexes.size();
		for (int i = 0; i < length; i++)
		{
			int index = m_storedIndexes[i];
			env.DeleteLocalRef(m_argsAsObject[index]);
		}

		delete[] m_argsAsObject;
	}
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2015 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 <inviwo/qt/widgets/inviwoqtutils.h>
#include <inviwo/core/util/logcentral.h>

#include <QLocale>
#include <ios>
#include <exception>

namespace inviwo {

namespace utilqt {

std::locale getCurrentStdLocale() {
    std::locale loc;
    try {
        // use the system locale provided by Qt

        // need to change locale given by Qt from underscore to hyphenated ("sv_SE" to "sv-SE")
        // although std::locale should only accept locales with underscore, e.g. "sv_SE"
        std::string localeName(QLocale::system().name().replace('_', '-').toStdString());
        loc = std::locale(localeName.c_str());
    }
    catch (std::exception &e) {
        LogWarnCustom("getStdLocale", "Locale could not be set. " << e.what());
    }
    return loc;
}

std::ios_base& localizeStream(std::ios_base& stream) {
    stream.imbue(getCurrentStdLocale());
    return stream;
}

} // namespace utilqt

}  // namespace
<commit_msg>Qt: fix for OSX/Linux<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2015 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 <inviwo/qt/widgets/inviwoqtutils.h>
#include <inviwo/core/util/logcentral.h>

#include <QLocale>
#include <ios>
#include <exception>

namespace inviwo {

namespace utilqt {

std::locale getCurrentStdLocale() {
    std::locale loc;
    try {
        // use the system locale provided by Qt

#ifdef WIN32
        // need to change locale given by Qt from underscore to hyphenated ("sv_SE" to "sv-SE")
        // although std::locale should only accept locales with underscore, e.g. "sv_SE"
        std::string localeName(QLocale::system().name().replace('_', '-').toStdString());
#else
        std::string localeName(QLocale::system().name().toStdString());
#endif
        loc = std::locale(localeName);
    }
    catch (std::exception &e) {
        LogWarnCustom("getStdLocale", "Locale could not be set. " << e.what());
    }
    return loc;
}

std::ios_base& localizeStream(std::ios_base& stream) {
    stream.imbue(getCurrentStdLocale());
    return stream;
}

} // namespace utilqt

}  // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#include "../mesh/mesh_headers.hpp"
#include "fem.hpp"
#include <cmath>

namespace mfem
{

ElementTransformation::ElementTransformation()
   : IntPoint(static_cast<IntegrationPoint *>(NULL)),
     EvalState(0),
     Attribute(-1),
     ElementNo(-1)
{ }

double ElementTransformation::EvalWeight()
{
   MFEM_ASSERT((EvalState & WEIGHT_MASK) == 0, "");
   Jacobian();
   EvalState |= WEIGHT_MASK;
   return (Wght = (dFdx.Width() == 0) ? 1.0 : dFdx.Weight());
}

const DenseMatrix &ElementTransformation::EvalAdjugateJ()
{
   MFEM_ASSERT((EvalState & ADJUGATE_MASK) == 0, "");
   Jacobian();
   adjJ.SetSize(dFdx.Width(), dFdx.Height());
   if (dFdx.Width() > 0) { CalcAdjugate(dFdx, adjJ); }
   EvalState |= ADJUGATE_MASK;
   return adjJ;
}

const DenseMatrix &ElementTransformation::EvalInverseJ()
{
   // TODO: compute as invJ = / adjJ/Weight,    if J is square,
   //                         \ adjJ/Weight^2,  otherwise.
   MFEM_ASSERT((EvalState & INVERSE_MASK) == 0, "");
   Jacobian();
   invJ.SetSize(dFdx.Width(), dFdx.Height());
   if (dFdx.Width() > 0) { CalcInverse(dFdx, invJ); }
   EvalState |= INVERSE_MASK;
   return invJ;
}

void IsoparametricTransformation::SetIdentityTransformation(int GeomType)
{
   switch (GeomType)
   {
      case Geometry::POINT :       FElem = &PointFE; break;
      case Geometry::SEGMENT :     FElem = &SegmentFE; break;
      case Geometry::TRIANGLE :    FElem = &TriangleFE; break;
      case Geometry::SQUARE :      FElem = &QuadrilateralFE; break;
      case Geometry::TETRAHEDRON : FElem = &TetrahedronFE; break;
      case Geometry::CUBE :        FElem = &HexahedronFE; break;
      default:
         MFEM_ABORT("unknown Geometry::Type!");
   }
   int dim = FElem->GetDim();
   int dof = FElem->GetDof();
   const IntegrationRule &nodes = FElem->GetNodes();
   PointMat.SetSize(dim, dof);
   for (int j = 0; j < dof; j++)
   {
      nodes.IntPoint(j).Get(&PointMat(0,j), dim);
   }
}

const DenseMatrix &IsoparametricTransformation::EvalJacobian()
{
   MFEM_ASSERT((EvalState & JACOBIAN_MASK) == 0, "");

   dshape.SetSize(FElem->GetDof(), FElem->GetDim());
   dFdx.SetSize(PointMat.Height(), dshape.Width());
   if (dshape.Width() > 0)
   {
      FElem->CalcDShape(*IntPoint, dshape);
      Mult(PointMat, dshape, dFdx);
   }
   EvalState |= JACOBIAN_MASK;

   return dFdx;
}

int IsoparametricTransformation::OrderJ()
{
   switch (FElem->Space())
   {
      case FunctionSpace::Pk:
         return (FElem->GetOrder()-1);
      case FunctionSpace::Qk:
         return (FElem->GetOrder());
      default:
         mfem_error("IsoparametricTransformation::OrderJ()");
   }
   return 0;
}

int IsoparametricTransformation::OrderW()
{
   switch (FElem->Space())
   {
      case FunctionSpace::Pk:
         return (FElem->GetOrder() - 1) * FElem->GetDim();
      case FunctionSpace::Qk:
         return (FElem->GetOrder() * FElem->GetDim() - 1);
      default:
         mfem_error("IsoparametricTransformation::OrderW()");
   }
   return 0;
}

int IsoparametricTransformation::OrderGrad(const FiniteElement *fe)
{
   if (FElem->Space() == fe->Space())
   {
      int k = FElem->GetOrder();
      int d = FElem->GetDim();
      int l = fe->GetOrder();
      switch (fe->Space())
      {
         case FunctionSpace::Pk:
            return ((k-1)*(d-1)+(l-1));
         case FunctionSpace::Qk:
            return (k*(d-1)+(l-1));
      }
   }
   mfem_error("IsoparametricTransformation::OrderGrad(...)");
   return 0;
}

void IsoparametricTransformation::Transform (const IntegrationPoint &ip,
                                             Vector &trans)
{
   shape.SetSize(FElem->GetDof());
   trans.SetSize(PointMat.Height());

   FElem -> CalcShape(ip, shape);
   PointMat.Mult(shape, trans);
}

void IsoparametricTransformation::Transform (const IntegrationRule &ir,
                                             DenseMatrix &tr)
{
   int dof, n, dim, i, j, k;

   dim = PointMat.Height();
   dof = FElem->GetDof();
   n = ir.GetNPoints();

   shape.SetSize(dof);
   tr.SetSize(dim, n);

   for (j = 0; j < n; j++)
   {
      FElem -> CalcShape (ir.IntPoint(j), shape);
      for (i = 0; i < dim; i++)
      {
         tr(i, j) = 0.0;
         for (k = 0; k < dof; k++)
         {
            tr(i, j) += PointMat(i, k) * shape(k);
         }
      }
   }
}

void IsoparametricTransformation::Transform (const DenseMatrix &matrix,
                                             DenseMatrix &result)
{
   result.SetSize(PointMat.Height(), matrix.Width());

   IntegrationPoint ip;
   Vector col;

   for (int j = 0; j < matrix.Width(); j++)
   {
      ip.x = matrix(0, j);
      if (matrix.Height() > 1)
      {
         ip.y = matrix(1, j);
         if (matrix.Height() > 2)
         {
            ip.z = matrix(2, j);
         }
      }

      result.GetColumnReference(j, col);
      Transform(ip, col);
   }
}

const IntegrationPoint IsoparametricTransformation::FindClosestRefinedPoint(
   const Vector& pt, int order)
{
   const int geom = FElem->GetGeomType();

   // Deal with default and invalid values for order parameter
   int refOrder = (order < 0) ? FElem->GetOrder() : order;

   // Early return for order 0 -- simply use element center
   if (refOrder == 0)
   {
      return Geometries.GetCenter(geom);
   }

   // Otherwise, use appropriate RefinedIntRules
   const IntegrationRule* ir = &(RefinedIntRules.Get(geom, refOrder));
   Vector v;

   // Initialize distance and index of closest point
   int minIndex = -1;
   double minDist = std::numeric_limits<double>::max();

   // Check against element's refinement integration points
   const int npts = ir->GetNPoints();
   for (int i = 0; i < npts; ++i)
   {
      this->Transform(ir->IntPoint(i), v);

      double dist = v.DistanceTo(pt);
      if (dist < minDist)
      {
         minDist = dist;
         minIndex = i;
      }
   }

   // Return corresponding IntegrationPoint
   return ir->IntPoint(minIndex);
}

int IsoparametricTransformation::TransformBack(const Vector &pt,
                                               IntegrationPoint &ip,
                                               int refinementOrder)
{
   const int    max_iter = 16;
   const double  ref_tol = 1e-15;
   const double phys_tol = 1e-15*pt.Normlinf();
   const double ip_tol   = 1e-8;

   const int dim = FElem->GetDim();
   const int sdim = PointMat.Height();
   const int geom = FElem->GetGeomType();
   IntegrationPoint xip;
   double xd[3], yd[3], dxd[3], Jid[9];
   Vector x(xd, dim), y(yd, sdim), dx(dxd, dim);
   DenseMatrix Jinv(Jid, dim, sdim);

   // Use closest refinement point as initial guess
   xip = FindClosestRefinedPoint(pt, refinementOrder);
   xip.Get(xd, dim); // xip -> x

   for (int it = 0; it < max_iter; it++)
   {
      // Newton iteration:    x := x + J(x)^{-1} [pt-F(x)]
      // or when dim != sdim: x := x + [J^t.J]^{-1}.J^t [pt-F(x)]
      Transform(xip, y);
      subtract(pt, y, y); // y = pt-y
      if (y.Normlinf() < phys_tol)
      {
         ip = xip;
         return Geometry::CheckPoint(geom, ip, ip_tol ) ? 0 : 1;
      }

      SetIntPoint(&xip);
      CalcInverse(Jacobian(), Jinv);
      Jinv.Mult(y, dx);
      x += dx;
      xip.Set(xd, dim); // x -> xip
      if (dx.Normlinf() < ref_tol)
      {
         ip = xip;
         return Geometry::CheckPoint(geom, ip, ip_tol) ? 0 : 1;
      }
   }

   ip = xip;
   return 2;
}

void IntegrationPointTransformation::Transform (const IntegrationPoint &ip1,
                                                IntegrationPoint &ip2)
{
   double vec[3];
   Vector v (vec, Transf.GetPointMat().Height());

   Transf.Transform (ip1, v);
   ip2.Set(vec, v.Size());
}

void IntegrationPointTransformation::Transform (const IntegrationRule &ir1,
                                                IntegrationRule &ir2)
{
   int i, n;

   n = ir1.GetNPoints();
   for (i = 0; i < n; i++)
   {
      Transform (ir1.IntPoint(i), ir2.IntPoint(i));
   }
}

}
<commit_msg>Lowered tolerances in IsoparametricTransformation's TransformBack.<commit_after>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#include "../mesh/mesh_headers.hpp"
#include "fem.hpp"
#include <cmath>

namespace mfem
{

ElementTransformation::ElementTransformation()
   : IntPoint(static_cast<IntegrationPoint *>(NULL)),
     EvalState(0),
     Attribute(-1),
     ElementNo(-1)
{ }

double ElementTransformation::EvalWeight()
{
   MFEM_ASSERT((EvalState & WEIGHT_MASK) == 0, "");
   Jacobian();
   EvalState |= WEIGHT_MASK;
   return (Wght = (dFdx.Width() == 0) ? 1.0 : dFdx.Weight());
}

const DenseMatrix &ElementTransformation::EvalAdjugateJ()
{
   MFEM_ASSERT((EvalState & ADJUGATE_MASK) == 0, "");
   Jacobian();
   adjJ.SetSize(dFdx.Width(), dFdx.Height());
   if (dFdx.Width() > 0) { CalcAdjugate(dFdx, adjJ); }
   EvalState |= ADJUGATE_MASK;
   return adjJ;
}

const DenseMatrix &ElementTransformation::EvalInverseJ()
{
   // TODO: compute as invJ = / adjJ/Weight,    if J is square,
   //                         \ adjJ/Weight^2,  otherwise.
   MFEM_ASSERT((EvalState & INVERSE_MASK) == 0, "");
   Jacobian();
   invJ.SetSize(dFdx.Width(), dFdx.Height());
   if (dFdx.Width() > 0) { CalcInverse(dFdx, invJ); }
   EvalState |= INVERSE_MASK;
   return invJ;
}

void IsoparametricTransformation::SetIdentityTransformation(int GeomType)
{
   switch (GeomType)
   {
      case Geometry::POINT :       FElem = &PointFE; break;
      case Geometry::SEGMENT :     FElem = &SegmentFE; break;
      case Geometry::TRIANGLE :    FElem = &TriangleFE; break;
      case Geometry::SQUARE :      FElem = &QuadrilateralFE; break;
      case Geometry::TETRAHEDRON : FElem = &TetrahedronFE; break;
      case Geometry::CUBE :        FElem = &HexahedronFE; break;
      default:
         MFEM_ABORT("unknown Geometry::Type!");
   }
   int dim = FElem->GetDim();
   int dof = FElem->GetDof();
   const IntegrationRule &nodes = FElem->GetNodes();
   PointMat.SetSize(dim, dof);
   for (int j = 0; j < dof; j++)
   {
      nodes.IntPoint(j).Get(&PointMat(0,j), dim);
   }
}

const DenseMatrix &IsoparametricTransformation::EvalJacobian()
{
   MFEM_ASSERT((EvalState & JACOBIAN_MASK) == 0, "");

   dshape.SetSize(FElem->GetDof(), FElem->GetDim());
   dFdx.SetSize(PointMat.Height(), dshape.Width());
   if (dshape.Width() > 0)
   {
      FElem->CalcDShape(*IntPoint, dshape);
      Mult(PointMat, dshape, dFdx);
   }
   EvalState |= JACOBIAN_MASK;

   return dFdx;
}

int IsoparametricTransformation::OrderJ()
{
   switch (FElem->Space())
   {
      case FunctionSpace::Pk:
         return (FElem->GetOrder()-1);
      case FunctionSpace::Qk:
         return (FElem->GetOrder());
      default:
         mfem_error("IsoparametricTransformation::OrderJ()");
   }
   return 0;
}

int IsoparametricTransformation::OrderW()
{
   switch (FElem->Space())
   {
      case FunctionSpace::Pk:
         return (FElem->GetOrder() - 1) * FElem->GetDim();
      case FunctionSpace::Qk:
         return (FElem->GetOrder() * FElem->GetDim() - 1);
      default:
         mfem_error("IsoparametricTransformation::OrderW()");
   }
   return 0;
}

int IsoparametricTransformation::OrderGrad(const FiniteElement *fe)
{
   if (FElem->Space() == fe->Space())
   {
      int k = FElem->GetOrder();
      int d = FElem->GetDim();
      int l = fe->GetOrder();
      switch (fe->Space())
      {
         case FunctionSpace::Pk:
            return ((k-1)*(d-1)+(l-1));
         case FunctionSpace::Qk:
            return (k*(d-1)+(l-1));
      }
   }
   mfem_error("IsoparametricTransformation::OrderGrad(...)");
   return 0;
}

void IsoparametricTransformation::Transform (const IntegrationPoint &ip,
                                             Vector &trans)
{
   shape.SetSize(FElem->GetDof());
   trans.SetSize(PointMat.Height());

   FElem -> CalcShape(ip, shape);
   PointMat.Mult(shape, trans);
}

void IsoparametricTransformation::Transform (const IntegrationRule &ir,
                                             DenseMatrix &tr)
{
   int dof, n, dim, i, j, k;

   dim = PointMat.Height();
   dof = FElem->GetDof();
   n = ir.GetNPoints();

   shape.SetSize(dof);
   tr.SetSize(dim, n);

   for (j = 0; j < n; j++)
   {
      FElem -> CalcShape (ir.IntPoint(j), shape);
      for (i = 0; i < dim; i++)
      {
         tr(i, j) = 0.0;
         for (k = 0; k < dof; k++)
         {
            tr(i, j) += PointMat(i, k) * shape(k);
         }
      }
   }
}

void IsoparametricTransformation::Transform (const DenseMatrix &matrix,
                                             DenseMatrix &result)
{
   result.SetSize(PointMat.Height(), matrix.Width());

   IntegrationPoint ip;
   Vector col;

   for (int j = 0; j < matrix.Width(); j++)
   {
      ip.x = matrix(0, j);
      if (matrix.Height() > 1)
      {
         ip.y = matrix(1, j);
         if (matrix.Height() > 2)
         {
            ip.z = matrix(2, j);
         }
      }

      result.GetColumnReference(j, col);
      Transform(ip, col);
   }
}

const IntegrationPoint IsoparametricTransformation::FindClosestRefinedPoint(
   const Vector& pt, int order)
{
   const int geom = FElem->GetGeomType();

   // Deal with default and invalid values for order parameter
   int refOrder = (order < 0) ? FElem->GetOrder() : order;

   // Early return for order 0 -- simply use element center
   if (refOrder == 0)
   {
      return Geometries.GetCenter(geom);
   }

   // Otherwise, use appropriate RefinedIntRules
   const IntegrationRule* ir = &(RefinedIntRules.Get(geom, refOrder));
   Vector v;

   // Initialize distance and index of closest point
   int minIndex = -1;
   double minDist = std::numeric_limits<double>::max();

   // Check against element's refinement integration points
   const int npts = ir->GetNPoints();
   for (int i = 0; i < npts; ++i)
   {
      this->Transform(ir->IntPoint(i), v);

      double dist = v.DistanceTo(pt);
      if (dist < minDist)
      {
         minDist = dist;
         minIndex = i;
      }
   }

   // Return corresponding IntegrationPoint
   return ir->IntPoint(minIndex);
}

int IsoparametricTransformation::TransformBack(const Vector &pt,
                                               IntegrationPoint &ip,
                                               int refinementOrder)
{
   const int    max_iter = 16;
   const double  ref_tol = 1e-14;
   const double phys_tol = 1e-14*pt.Normlinf();
   const double ip_tol   = 1e-8;

   const int dim = FElem->GetDim();
   const int sdim = PointMat.Height();
   const int geom = FElem->GetGeomType();
   IntegrationPoint xip;
   double xd[3], yd[3], dxd[3], Jid[9];
   Vector x(xd, dim), y(yd, sdim), dx(dxd, dim);
   DenseMatrix Jinv(Jid, dim, sdim);

   // Use closest refinement point as initial guess
   xip = FindClosestRefinedPoint(pt, refinementOrder);
   xip.Get(xd, dim); // xip -> x

   for (int it = 0; it < max_iter; it++)
   {
      // Newton iteration:    x := x + J(x)^{-1} [pt-F(x)]
      // or when dim != sdim: x := x + [J^t.J]^{-1}.J^t [pt-F(x)]
      Transform(xip, y);
      subtract(pt, y, y); // y = pt-y
      if (y.Normlinf() < phys_tol)
      {
         ip = xip;
         return Geometry::CheckPoint(geom, ip, ip_tol ) ? 0 : 1;
      }

      SetIntPoint(&xip);
      CalcInverse(Jacobian(), Jinv);
      Jinv.Mult(y, dx);
      x += dx;
      xip.Set(xd, dim); // x -> xip
      if (dx.Normlinf() < ref_tol)
      {
         ip = xip;
         return Geometry::CheckPoint(geom, ip, ip_tol) ? 0 : 1;
      }
   }

   ip = xip;
   return 2;
}

void IntegrationPointTransformation::Transform (const IntegrationPoint &ip1,
                                                IntegrationPoint &ip2)
{
   double vec[3];
   Vector v (vec, Transf.GetPointMat().Height());

   Transf.Transform (ip1, v);
   ip2.Set(vec, v.Size());
}

void IntegrationPointTransformation::Transform (const IntegrationRule &ir1,
                                                IntegrationRule &ir2)
{
   int i, n;

   n = ir1.GetNPoints();
   for (i = 0; i < n; i++)
   {
      Transform (ir1.IntPoint(i), ir2.IntPoint(i));
   }
}

}
<|endoftext|>


<commit_before>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/AutoConfig.h>
#include <autowiring/AutoConfigListing.h>
#include <src/autowiring/AutoConfigParser.hpp>

class AutoConfigListingTest :
  public testing::Test
{};

struct Namespace1;
struct Namespace2;
struct XYZ;

TEST_F(AutoConfigListingTest, VerifySimpleAssignment) {
  // Set an attribute in the manager before injecting anything:
  AutoRequired<AutoConfigListing> acm;
  acm->Set("Namespace1.XYZ", 323);

  // Now inject the type which expects this value to be assigned:
  AutoConfig<int, Namespace1, XYZ> cfg;
  ASSERT_EQ(323, *cfg) << "Configurable type did not receive a value as expected";
}

struct NamespaceRoot;
struct NamespaceChild;

TEST_F(AutoConfigListingTest, VerifyNestedNamespace) {
  AutoRequired<AutoConfigListing> acm;
  acm->Set("NamespaceRoot.NamespaceChild.Namespace1.Namespace2.XYZ", 142);

  AutoConfig<int, struct NamespaceRoot, struct NamespaceChild, struct Namespace1, struct Namespace2, struct XYZ> cfg;
  ASSERT_EQ(142, *cfg);
}

struct MyBoolClass {
  AutoConfig<bool, struct bool_space, struct my_bool> m_bool;
};

TEST_F(AutoConfigListingTest, VerifyPostHocAssignment) {
  // Inject the configurable type first
  AutoConfig<int, Namespace1, XYZ> cfg;

  // Configuration manager must exist at this point as a consequence of the earlier construction
  Autowired<AutoConfigListing> acm;
  ASSERT_TRUE(acm.IsAutowired()) << "AutoConfig field did not inject a configuration manager into this context as expected";

  acm->Set("Namespace1.XYZ", 323);

  // Now inject the type which expects this value to be assigned:
  ASSERT_EQ(323, *cfg) << "Configurable type did not receive a value as expected";
}
/*
TEST_F(AutoConfigListingTest, VerifyRecursiveSearch) {
  AutoRequired<AutoConfigListing> acm;
  acm->Set("Namespace1.XYZ", 1001);

  {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);

    // Now inject an element here, and verify that it was wired up as expected:
    AutoRequired<MyConfigurableClass> mcc;
    ASSERT_TRUE(mcc->m_myName->IsConfigured()) << "A configurable value was not configured as expected";
    ASSERT_EQ(1001, *mcc->m_myName) << "Configurable value obtained from a parent scope did not have the correct value";

    // This must work as expected--a local context override will rewrite configuration values in the local scope
    AutoRequired<AutoConfigListing> sub_mcc;
    sub_mcc->Set("Namespace1.XYZ", 1002);
    ASSERT_EQ(1002, *mcc->m_myName) << "Override of a configurable value in a derived class did not take place as expected";
  }
}

struct DefaultName {
  AutoConfig<int, struct defaultname1> m_def;
};

TEST_F(AutoConfigListingTest, DefaultNamespace) {
  AutoRequired<AutoConfigListing> acm;
  acm->Set("defaultname1", 123);

  AutoRequired<DefaultName> def;

  ASSERT_EQ(123, *def->m_def);
}

TEST_F(AutoConfigListingTest, VerifyParsedAssignment) {
  // We must also be able to support implicit string-to-type conversion via the shift operator for this type
  AutoRequired<AutoConfigListing> acm;

  // Direct assignment to a string should not work, the type isn't a string it's an int
  ASSERT_ANY_THROW(acm->Set("Namespace1.XYZ", "327")) << "An attempt to assign a value to an unrelated type did not generate an exception as expected";

  ASSERT_ANY_THROW(acm->Set("Namespace1.XYZ", 3.0)) << "An attempt to assign a value to an unrelated type did not generate an exception as expected";

  // Assignment to a string type should result in an appropriate coercion to the right value
  ASSERT_TRUE(acm->SetParsed("Namespace1.XYZ", "324"));
}

TEST_F(AutoConfigListingTest, VerifyDuplicateConfigAssignment) {
  AutoRequired<AutoConfigListing> acm;
  ASSERT_TRUE(acm->SetParsed("Namespace1.XYZ", "324"));
  ASSERT_TRUE(acm->SetParsed("Namespace2.XYZ", "1111"));

  AutoRequired<MyConfigurableClass> clz1;
  AutoRequired<MyConfigurableClass2> clz2;

  ASSERT_EQ(324, *clz1->m_myName);
  ASSERT_EQ(1111, *clz2->m_myName);
}

class TypeWithoutAShiftOperator {
public:
  int foo;
};

struct NoShift {
  AutoConfig<TypeWithoutAShiftOperator, struct MyNoShift> m_noshift;
};

static_assert(has_stream<int>::value, "Stream operation not detected on a primitive type");
static_assert(!has_stream<TypeWithoutAShiftOperator>::value, "Stream operation detected on a type that should not have supported it");

TEST_F(AutoConfigListingTest, TypeWithoutAShiftOperatorTest) {
  AutoRequired<NoShift> noshift;

  AutoRequired<AutoConfigListing> mgr;

  // Indirect assignment should cause an exception
  ASSERT_ANY_THROW(mgr->Set("MyNoShift", "")) << "Expected a throw in a case where a configurable value was used which cannot be assigned";

  // Direct assignment should be supported still
  TypeWithoutAShiftOperator tasoVal;
  tasoVal.foo = 592;
  mgr->Set<TypeWithoutAShiftOperator>("MyNoShift", tasoVal);

  ASSERT_EQ(592, noshift->m_noshift->foo) << "Value assignment did not result in an update to a non-serializable configuration field";
}

TEST_F(AutoConfigListingTest, Callbacks) {
  AutoRequired<AutoConfigListing> acm;
  AutoRequired<MyConfigurableClass> mcc;

  acm->Set("Namespace1.XYZ", 4);

  mcc->m_myName += [](int val) {
    ASSERT_EQ(val, 42);
  };

  mcc->m_myName += [](int val) {
    ASSERT_EQ(val, 42);
  };

  acm->Set("Namespace1.XYZ", 42);
}

TEST_F(AutoConfigListingTest, NestedContexts) {
  // Set up contexts and members
  AutoCurrentContext ctxt_outer;
  std::shared_ptr<CoreContext> ctxt_middle = ctxt_outer->Create<void>();
  std::shared_ptr<CoreContext> ctxt_sibling = ctxt_outer->Create<void>();
  std::shared_ptr<CoreContext> ctxt_inner = ctxt_middle->Create<void>();
  std::shared_ptr<CoreContext> ctxt_no_manager = ctxt_inner->Create<void>();
  std::shared_ptr<CoreContext> ctxt_leaf = ctxt_no_manager->Create<void>();

  AutoRequired<MyConfigurableClass> mcc_outer(ctxt_outer);
  AutoRequired<MyConfigurableClass> mcc_middle(ctxt_middle);
  AutoRequired<MyConfigurableClass> mcc_sibling(ctxt_sibling);
  AutoRequired<MyConfigurableClass> mcc_inner(ctxt_inner);
  AutoRequired<MyConfigurableClass> mcc_leaf(ctxt_leaf);

  AutoRequired<AutoConfigListing> acm_outer(ctxt_outer);
  AutoRequired<AutoConfigListing> acm_middle(ctxt_middle);
  AutoRequired<AutoConfigListing> acm_leaf(ctxt_leaf);

  // Set initial value
  acm_outer->Set("Namespace1.XYZ", 42);
  ASSERT_EQ(42, *mcc_outer->m_myName) << "Config value not set";
  ASSERT_EQ(42, *mcc_middle->m_myName) << "Config value not set in descendant context";
  ASSERT_EQ(42, *mcc_sibling->m_myName) << "Config value not set in descendant context";
  ASSERT_EQ(42, *mcc_inner->m_myName) << "Config value not set in descendant context";
  ASSERT_EQ(42, *mcc_leaf->m_myName) << "Config value not set in desendant context";
  EXPECT_TRUE(acm_middle->IsInherited("Namespace1.XYZ")) << "Inherited key not marked as such";
  EXPECT_TRUE(acm_leaf->IsInherited("Namespace1.XYZ")) << "Inherited key not marked as such";

  // Set middle, inner shouldn't be able to be set from outer after this
  bool callback_hit1 = false;
  mcc_inner->m_myName += [&callback_hit1](int) {
    callback_hit1 = true;
  };
  acm_middle->Set("Namespace1.XYZ", 1337);
  ASSERT_EQ(42, *mcc_outer->m_myName) << "Config value changed in outer context";
  ASSERT_EQ(42, *mcc_sibling->m_myName) << "Config value set from sibling context";
  ASSERT_EQ(1337, *mcc_middle->m_myName) << "Config value not set";
  ASSERT_EQ(1337, *mcc_inner->m_myName) << "Config value not set in child context";
  ASSERT_EQ(1337, *mcc_leaf->m_myName) << "Config value not set in leaf context";
  ASSERT_TRUE(callback_hit1) << "Callback not hit in inner context";

  // Set from outter, inner should be shielded by middle context
  mcc_inner->m_myName += [](int) {
    FAIL() << "This callback should never be hit";
  };

  // Make sure sibling context is not shielded
  bool callback_hit2 = false;
  mcc_sibling->m_myName += [&callback_hit2](int) {
    callback_hit2 = true;
  };

  // Set from outer, shouldn't effect middle or inner contexts
  acm_outer->Set("Namespace1.XYZ", 999);
  ASSERT_EQ(999, *mcc_outer->m_myName) << "Config value not set";
  ASSERT_EQ(1337, *mcc_middle->m_myName) << "Config value overwritten when value was set in this context";
  ASSERT_EQ(1337, *mcc_inner->m_myName) << "Config value overwritten when value was set in parent context";

  // Make sure sibling hit
  ASSERT_EQ(999, *mcc_sibling->m_myName) << "Value not set on sibling of context where value was previously set";
  ASSERT_TRUE(callback_hit2) << "Callback not called on sibling of context where value was previously set";
}

struct ValidatedKey{
  static bool Validate(const int& value) {
    return value > 5;
  }
};

struct MyValidatedClass{
  AutoConfig<int, ValidatedKey> m_config;
};

TEST_F(AutoConfigListingTest, Validators) {
  AutoRequired<AutoConfigListing> acm;

  ASSERT_ANY_THROW(acm->Set("ValidatedKey", 2)) << "AutoConfigListing didn't regect invalid value";

  AutoRequired<MyValidatedClass> valid;

  acm->Set("ValidatedKey", 42);
  ASSERT_EQ(42, *valid->m_config) << "Value not set for key";

  ASSERT_ANY_THROW(acm->Set("ValidatedKey", 1)) << "AutoConfigListing didn't regect invalid value";
  ASSERT_EQ(42, *valid->m_config) << "Value not set for key";

  acm->Set("ValidatedKey", 1337);
  ASSERT_EQ(1337, *valid->m_config) << "Value not set for key";
}

TEST_F(AutoConfigListingTest, DirectAssignemnt) {
  AutoConfig<int, struct Namespace1, struct XYZ> var;
  var = 10;
  ASSERT_EQ(10, *var);

  AutoRequired<MyConfigurableClass> containsVar;

  ASSERT_EQ(10, *var);
  ASSERT_EQ(10, *containsVar->m_myName);
}

struct ComplexValue {
  int a;
  int b;
  int c;

  ComplexValue(int nA, int nB, int nC) : a(nA), b(nB), c(nC) {}
  ComplexValue(int repeated) : a(repeated), b(repeated), c(repeated) {}
};

struct MyComplexValueClass {
  AutoConfig<ComplexValue, struct Namespace1, struct MyCxValue> m_cfg;
  AutoConfig<ComplexValue, struct Namespace1, struct MyCxValue2> m_cfg2 = ComplexValue{ 10, 15, 30 };

  MyComplexValueClass() : m_cfg(ComplexValue{ 2, 20, 20 }) {}
};

TEST_F(AutoConfigListingTest, ComplexConstruction){
  AutoRequired<AutoConfigListing> mgr;
  ASSERT_FALSE(mgr->IsConfigured("Namespace1.MyCxValue"));

  AutoConfig<ComplexValue, Namespace1, MyCxValue> defaultConstructed;

  ASSERT_FALSE(mgr->IsConfigured("Namespace1.MyCxValue")) << "Improperly set config value when default constructing AutoConfig";

  AutoConfig<ComplexValue, Namespace1, MyCxValue> fancyConstructed(1, 2, 3);

  ASSERT_TRUE(mgr->IsConfigured("Namespace1.MyCxValue")) << "Initializing constructor did not set config value";
  ASSERT_EQ(fancyConstructed->a, 1) << "Initializing constructor did not set config value";
  ASSERT_EQ(fancyConstructed->b, 2) << "Initializing constructor did not set config value";
  ASSERT_EQ(fancyConstructed->c, 3) << "Initializing constructor did not set config value";

  AutoConfig<ComplexValue, Namespace1, MyCxValue> fancy2(7);
  ASSERT_EQ(fancy2->a, 1) << "Second Initalizing constructor overrode the first!";
  ASSERT_EQ(fancy2->b, 2) << "Second Initalizing constructor overrode the first!";
  ASSERT_EQ(fancy2->c, 3) << "Second Initalizing constructor overrode the first!";
}

struct OuterCtxt{};
struct MiddleCtxt{};
struct InnerCtxt{};
TEST_F(AutoConfigListingTest, ListingConfigs) {
  AutoCreateContextT<OuterCtxt> ctxt_outer;
  auto ctxt_middle = ctxt_outer->Create<MiddleCtxt>();
  auto ctxt_inner = ctxt_middle->Create<InnerCtxt>();

  AutoRequired<AutoConfigListing> acm_outer(ctxt_outer);
  AutoRequired<AutoConfigListing> acm_inner(ctxt_inner);

  AutoRequired<MyConfigurableClass> var1_inner(ctxt_inner);
  var1_inner->m_myName = 1;

  ASSERT_EQ(0, acm_outer->GetLocalKeys().size()) << "Incorrect number of keys found in outer context";
  ASSERT_EQ(1, acm_inner->GetLocalKeys().size()) << "Incorrect number of keys found in inner context";

  int callback_outer = 0;
  acm_outer->AddCallback([&callback_outer](const std::string& key, const AnySharedPointer& ptr) {
    ++callback_outer;
  });

  int callback_inner = 0;
  acm_inner->AddCallback([&callback_inner](const std::string& key, const AnySharedPointer& ptr) {
    ++callback_inner;
  });

  ASSERT_EQ(1, callback_inner) << "Callback not called on existing keys";

  AutoRequired<MyConfigurableClass2> var1_outer(ctxt_outer);
  var1_outer->m_myName = 2;

  ASSERT_EQ(1, acm_outer->GetLocalKeys().size()) << "Incorrect number of keys found in outer context";
  ASSERT_EQ(1, acm_inner->GetLocalKeys().size()) << "Incorrect number of keys found in inner context";

  AutoRequired<MyConfigurableClass> var2_outer(ctxt_outer);
  var2_outer->m_myName = 3;

  ASSERT_EQ(2, acm_outer->GetLocalKeys().size()) << "Incorrect number of keys found in outer context";
  ASSERT_EQ(1, acm_inner->GetLocalKeys().size()) << "Incorrect number of keys found in inner context";

  ASSERT_EQ(2, callback_outer) << "Outer callback called an incorrect number of times";
  ASSERT_EQ(1, callback_inner) << "Inner callback called an incorrect number of times";

  auto keys_outer = acm_outer->GetLocalKeys();
  ASSERT_EQ(var1_outer->m_myName.m_key, keys_outer[0]) << "Keys listed out of construction order";
  ASSERT_EQ(var2_outer->m_myName.m_key, keys_outer[1]) << "Keys listed out of construction order";

  auto keys_inner = acm_inner->GetLocalKeys();
  ASSERT_EQ(var1_inner->m_myName.m_key, keys_inner[0]) << "Keys listed out of construction order";
}
*/<commit_msg>Fix the remainder of the AutoConfigListingTests<commit_after>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/AutoConfig.h>
#include <autowiring/AutoConfigListing.h>
#include <src/autowiring/AutoConfigParser.hpp>

class AutoConfigListingTest :
  public testing::Test
{};

struct Namespace1;
struct Namespace2;
struct XYZ;

TEST_F(AutoConfigListingTest, VerifySimpleAssignment) {
  // Set an attribute in the manager before injecting anything:
  AutoRequired<AutoConfigListing> acm;
  acm->Set("Namespace1.XYZ", 323);

  // Now inject the type which expects this value to be assigned:
  AutoConfig<int, Namespace1, XYZ> cfg;
  ASSERT_EQ(323, *cfg) << "Configurable type did not receive a value as expected";
}

struct NamespaceRoot;
struct NamespaceChild;

TEST_F(AutoConfigListingTest, VerifyNestedNamespace) {
  AutoRequired<AutoConfigListing> acm;
  acm->Set("NamespaceRoot.NamespaceChild.Namespace1.Namespace2.XYZ", 142);

  AutoConfig<int, struct NamespaceRoot, struct NamespaceChild, struct Namespace1, struct Namespace2, struct XYZ> cfg;
  ASSERT_EQ(142, *cfg);
}

struct MyBoolClass {
  AutoConfig<bool, struct bool_space, struct my_bool> m_bool;
};

TEST_F(AutoConfigListingTest, VerifyPostHocAssignment) {
  // Inject the configurable type first
  AutoConfig<int, Namespace1, XYZ> cfg;

  // Configuration manager must exist at this point as a consequence of the earlier construction
  Autowired<AutoConfigListing> acm;
  ASSERT_TRUE(acm.IsAutowired()) << "AutoConfig field did not inject a configuration manager into this context as expected";

  acm->Set("Namespace1.XYZ", 323);

  // Now inject the type which expects this value to be assigned:
  ASSERT_EQ(323, *cfg) << "Configurable type did not receive a value as expected";
}

TEST_F(AutoConfigListingTest, VerifyRecursiveSearch) {
  AutoRequired<AutoConfigListing> acm;
  acm->Set("Namespace1.XYZ", 1001);

  {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);

    // Now inject an element here, and verify that it was wired up as expected:
    AutoConfig<int, Namespace1, XYZ> cfg;
    ASSERT_TRUE(cfg->IsConfigured()) << "A configurable value was not configured as expected";
    ASSERT_EQ(*cfg, 1001) << "Configurable value obtained from a parent scope did not have the correct value";

    // This must work as expected--a local context override will rewrite configuration values in the local scope
    AutoRequired<AutoConfigListing> sub_mcc;
    sub_mcc->Set("Namespace1.XYZ", 1002);
    ASSERT_EQ(1002, *cfg) << "Override of a configurable value in a derived class did not take place as expected";
  }
}

struct DefaultName {
  AutoConfig<int, struct defaultname1> m_def;
};

TEST_F(AutoConfigListingTest, DefaultNamespace) {
  AutoRequired<AutoConfigListing> acm;
  acm->Set("defaultname1", 123);

  AutoRequired<DefaultName> def;

  ASSERT_EQ(*def->m_def, 123);
}

TEST_F(AutoConfigListingTest, VerifyParsedAssignment) {
  // We must also be able to support implicit string-to-type conversion via the shift operator for this type
  AutoRequired<AutoConfigListing> acm;

  // Direct assignment to a string should not work, the type isn't a string it's an int
  ASSERT_ANY_THROW(acm->Set("Namespace1.XYZ", "327")) << "An attempt to assign a value to an unrelated type did not generate an exception as expected";

  ASSERT_ANY_THROW(acm->Set("Namespace1.XYZ", 3.0)) << "An attempt to assign a value to an unrelated type did not generate an exception as expected";

  // Assignment to a string type should result in an appropriate coercion to the right value
  ASSERT_TRUE(acm->SetParsed("Namespace1.XYZ", "324"));
}

TEST_F(AutoConfigListingTest, VerifyDuplicateConfigAssignment) {
  AutoRequired<AutoConfigListing> acm;
  ASSERT_TRUE(acm->SetParsed("Namespace1.XYZ", "324"));
  ASSERT_TRUE(acm->SetParsed("Namespace2.XYZ", "1111"));

  AutoConfig<int, Namespace1, XYZ> clz1;
  AutoConfig<int, Namespace2, XYZ> clz2;

  ASSERT_EQ(*clz1, 324);
  ASSERT_EQ(*clz2, 1111);
}

class TypeWithoutAShiftOperator {
public:
  int foo;
};

struct NoShift {
  AutoConfig<TypeWithoutAShiftOperator, struct MyNoShift> m_noshift;
};

static_assert(has_stream<int>::value, "Stream operation not detected on a primitive type");
static_assert(!has_stream<TypeWithoutAShiftOperator>::value, "Stream operation detected on a type that should not have supported it");

TEST_F(AutoConfigListingTest, TypeWithoutAShiftOperatorTest) {
  AutoRequired<NoShift> noshift;

  AutoRequired<AutoConfigListing> mgr;

  // Indirect assignment should cause an exception
  ASSERT_ANY_THROW(mgr->Set("MyNoShift", "")) << "Expected a throw in a case where a configurable value was used which cannot be assigned";

  // Direct assignment should be supported still
  TypeWithoutAShiftOperator tasoVal;
  tasoVal.foo = 592;
  mgr->Set<TypeWithoutAShiftOperator>("MyNoShift", tasoVal);

  ASSERT_EQ((*noshift->m_noshift)->foo, 592) << "Value assignment did not result in an update to a non-serializable configuration field";
}

TEST_F(AutoConfigListingTest, Callbacks) {
  AutoRequired<AutoConfigListing> acm;
  AutoConfig<int, Namespace1, XYZ> cfg;

  acm->Set("Namespace1.XYZ", 4);

  *cfg += [](int val) {
    ASSERT_EQ(val, 42);
  };

  *cfg += [](int val) {
    ASSERT_EQ(val, 42);
  };

  acm->Set("Namespace1.XYZ", 42);
}

struct MyConfigurableClass {
  AutoConfig<int, Namespace1, XYZ> cfg;
};
struct MyConfigurableClass2 {
  AutoConfig<int, Namespace2, XYZ> cfg;
};

TEST_F(AutoConfigListingTest, NestedContexts) {
  // Set up contexts and members
  AutoCurrentContext ctxt_outer;
  std::shared_ptr<CoreContext> ctxt_middle = ctxt_outer->Create<void>();
  std::shared_ptr<CoreContext> ctxt_sibling = ctxt_outer->Create<void>();
  std::shared_ptr<CoreContext> ctxt_inner = ctxt_middle->Create<void>();
  std::shared_ptr<CoreContext> ctxt_no_manager = ctxt_inner->Create<void>();
  std::shared_ptr<CoreContext> ctxt_leaf = ctxt_no_manager->Create<void>();

  AutoRequired<MyConfigurableClass> mcc_outer(ctxt_outer);
  AutoRequired<MyConfigurableClass> mcc_middle(ctxt_middle);
  AutoRequired<MyConfigurableClass> mcc_sibling(ctxt_sibling);
  AutoRequired<MyConfigurableClass> mcc_inner(ctxt_inner);
  AutoRequired<MyConfigurableClass> mcc_leaf(ctxt_leaf);

  AutoRequired<AutoConfigListing> acm_outer(ctxt_outer);
  AutoRequired<AutoConfigListing> acm_middle(ctxt_middle);
  AutoRequired<AutoConfigListing> acm_leaf(ctxt_leaf);

  // Set initial value
  acm_outer->Set("Namespace1.XYZ", 42);
  ASSERT_EQ(42, *mcc_outer->cfg) << "Config value not set";
  ASSERT_EQ(42, *mcc_middle->cfg) << "Config value not set in descendant context";
  ASSERT_EQ(42, *mcc_sibling->cfg) << "Config value not set in descendant context";
  ASSERT_EQ(42, *mcc_inner->cfg) << "Config value not set in descendant context";
  ASSERT_EQ(42, *mcc_leaf->cfg) << "Config value not set in desendant context";
  EXPECT_TRUE(acm_middle->IsInherited("Namespace1.XYZ")) << "Inherited key not marked as such";
  EXPECT_TRUE(acm_leaf->IsInherited("Namespace1.XYZ")) << "Inherited key not marked as such";

  // Set middle, inner shouldn't be able to be set from outer after this
  bool callback_hit1 = false;
  *mcc_inner->cfg += [&callback_hit1](int) {
    callback_hit1 = true;
  };
  acm_middle->Set("Namespace1.XYZ", 1337);
  ASSERT_EQ(42, *mcc_outer->cfg) << "Config value changed in outer context";
  ASSERT_EQ(42, *mcc_sibling->cfg) << "Config value set from sibling context";
  ASSERT_EQ(1337, *mcc_middle->cfg) << "Config value not set";
  ASSERT_EQ(1337, *mcc_inner->cfg) << "Config value not set in child context";
  ASSERT_EQ(1337, *mcc_leaf->cfg) << "Config value not set in leaf context";
  ASSERT_TRUE(callback_hit1) << "Callback not hit in inner context";

  // Set from outter, inner should be shielded by middle context
  *mcc_inner->cfg += [](int) {
    FAIL() << "This callback should never be hit";
  };

  // Make sure sibling context is not shielded
  bool callback_hit2 = false;
  *mcc_sibling->cfg += [&callback_hit2](int) {
    callback_hit2 = true;
  };

  // Set from outer, shouldn't effect middle or inner contexts
  acm_outer->Set("Namespace1.XYZ", 999);
  ASSERT_EQ(999, *mcc_outer->cfg) << "Config value not set";
  ASSERT_EQ(1337, *mcc_middle->cfg) << "Config value overwritten when value was set in this context";
  ASSERT_EQ(1337, *mcc_inner->cfg) << "Config value overwritten when value was set in parent context";

  // Make sure sibling hit
  ASSERT_EQ(999, *mcc_sibling->cfg) << "Value not set on sibling of context where value was previously set";
  ASSERT_TRUE(callback_hit2) << "Callback not called on sibling of context where value was previously set";
}

struct ValidatedKey{
  static bool Validate(const int& value) {
    return value > 5;
  }
};

struct MyValidatedClass{
  AutoConfig<int, ValidatedKey> m_config;
};

TEST_F(AutoConfigListingTest, Validators) {
  AutoRequired<AutoConfigListing> acm;

  ASSERT_ANY_THROW(acm->Set("ValidatedKey", 2)) << "AutoConfigListing didn't regect invalid value";

  AutoRequired<MyValidatedClass> valid;

  acm->Set("ValidatedKey", 42);
  ASSERT_EQ(42, *valid->m_config) << "Value not set for key";

  ASSERT_ANY_THROW(acm->Set("ValidatedKey", 1)) << "AutoConfigListing didn't regect invalid value";
  ASSERT_EQ(42, *valid->m_config) << "Value not set for key";

  acm->Set("ValidatedKey", 1337);
  ASSERT_EQ(1337, *valid->m_config) << "Value not set for key";
}

struct OuterCtxt{};
struct MiddleCtxt{};
struct InnerCtxt{};
TEST_F(AutoConfigListingTest, ListingConfigs) {
  AutoCreateContextT<OuterCtxt> ctxt_outer;
  auto ctxt_middle = ctxt_outer->Create<MiddleCtxt>();
  auto ctxt_inner = ctxt_middle->Create<InnerCtxt>();

  AutoRequired<AutoConfigListing> acm_outer(ctxt_outer);
  AutoRequired<AutoConfigListing> acm_inner(ctxt_inner);

  AutoRequired<MyConfigurableClass> var1_inner(ctxt_inner);
  *var1_inner->cfg = 1;

  ASSERT_EQ(0, acm_outer->GetLocalKeys().size()) << "Incorrect number of keys found in outer context";
  ASSERT_EQ(1, acm_inner->GetLocalKeys().size()) << "Incorrect number of keys found in inner context";

  int callback_outer = 0;
  acm_outer->AddCallback([&callback_outer](const AutoConfigVarBase& ptr) {
    ++callback_outer;
  });

  int callback_inner = 0;
  acm_inner->AddCallback([&callback_inner](const AutoConfigVarBase& ptr) {
    ++callback_inner;
  });

  ASSERT_EQ(1, callback_inner) << "Callback not called on existing keys";

  AutoRequired<MyConfigurableClass2> var1_outer(ctxt_outer);
  *var1_outer->cfg = 2;

  ASSERT_EQ(1, acm_outer->GetLocalKeys().size()) << "Incorrect number of keys found in outer context";
  ASSERT_EQ(1, acm_inner->GetLocalKeys().size()) << "Incorrect number of keys found in inner context";

  AutoRequired<MyConfigurableClass> var2_outer(ctxt_outer);
  var2_outer->cfg = 3;

  ASSERT_EQ(2, acm_outer->GetLocalKeys().size()) << "Incorrect number of keys found in outer context";
  ASSERT_EQ(1, acm_inner->GetLocalKeys().size()) << "Incorrect number of keys found in inner context";

  ASSERT_EQ(2, callback_outer) << "Outer callback called an incorrect number of times";
  ASSERT_EQ(1, callback_inner) << "Inner callback called an incorrect number of times";

  auto keys_outer = acm_outer->GetLocalKeys();
  ASSERT_EQ(var1_outer->cfg->m_key, keys_outer[0]) << "Keys listed out of construction order";
  ASSERT_EQ(var2_outer->cfg->m_key, keys_outer[1]) << "Keys listed out of construction order";

  auto keys_inner = acm_inner->GetLocalKeys();
  ASSERT_EQ(var1_inner->cfg->m_key, keys_inner[0]) << "Keys listed out of construction order";
}
<|endoftext|>


<commit_before>// rbOOmit: An implementation of the Certified Reduced Basis method.
// Copyright (C) 2009, 2010 David J. Knezevic

// This file is part of rbOOmit.

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

// rbOOmit is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh/rb_eim_theta.h"
#include "libmesh/rb_parameters.h"
#include "libmesh/rb_eim_evaluation.h"

namespace libMesh
{

RBEIMTheta::RBEIMTheta(RBEIMEvaluation & rb_eim_eval_in, unsigned int index_in)
  :
  rb_eim_eval(rb_eim_eval_in),
  index(index_in)
{
}

Number RBEIMTheta::evaluate(const RBParameters & mu)
{
  if (mu.n_parameters() > rb_eim_eval.get_n_params())
    {
      // In this case the parameters related to the EIM are a subset of
      // the parameters from the associated RB problem, hence we need to "pull out"
      // the parameters related to the EIM
      RBParameters mu_eim;
      RBParameters::const_iterator it     = rb_eim_eval.get_parameters().begin();
      RBParameters::const_iterator it_end = rb_eim_eval.get_parameters().end();
      for ( ; it != it_end; ++it)
        {
          std::string param_name = it->first;
          mu_eim.set_value(param_name, mu.get_value(param_name));
        }
      rb_eim_eval.set_parameters(mu_eim);
    }
  else
    {
      rb_eim_eval.set_parameters(mu);
    }

  rb_eim_eval.rb_solve(rb_eim_eval.get_n_basis_functions());

  return rb_eim_eval.RB_solution(index);
}

}
<commit_msg>Remove iterator boilerplate in RBEIMTheta.<commit_after>// rbOOmit: An implementation of the Certified Reduced Basis method.
// Copyright (C) 2009, 2010 David J. Knezevic

// This file is part of rbOOmit.

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

// rbOOmit is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh/rb_eim_theta.h"
#include "libmesh/rb_parameters.h"
#include "libmesh/rb_eim_evaluation.h"

namespace libMesh
{

RBEIMTheta::RBEIMTheta(RBEIMEvaluation & rb_eim_eval_in, unsigned int index_in)
  :
  rb_eim_eval(rb_eim_eval_in),
  index(index_in)
{
}

Number RBEIMTheta::evaluate(const RBParameters & mu)
{
  if (mu.n_parameters() > rb_eim_eval.get_n_params())
    {
      // In this case the parameters related to the EIM are a subset of
      // the parameters from the associated RB problem, hence we need to "pull out"
      // the parameters related to the EIM
      RBParameters mu_eim;
      for (const auto & pr : rb_eim_eval.get_parameters())
        {
          const std::string & param_name = pr.first;
          mu_eim.set_value(param_name, mu.get_value(param_name));
        }
      rb_eim_eval.set_parameters(mu_eim);
    }
  else
    {
      rb_eim_eval.set_parameters(mu);
    }

  rb_eim_eval.rb_solve(rb_eim_eval.get_n_basis_functions());

  return rb_eim_eval.RB_solution(index);
}

}
<|endoftext|>


<commit_before>#pragma once

#include <functional>
#include <memory>
#include <mutex>
#include <unordered_map>

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/is_sequence.hpp>

#include "blackhole/repository/config/formatter.hpp"
#include "blackhole/repository/config/sink.hpp"
//!@note: Must be included first to resolve circular depencencies.
#include "blackhole/repository/factory/frontend/helper.hpp"
#include "blackhole/repository/factory/frontend.hpp"
#include "blackhole/repository/factory/frontend/inserter.hpp"
#include "blackhole/repository/factory/registrator.hpp"
#include "blackhole/repository/factory/traits.hpp"

namespace blackhole {

class external_factory_t {
    typedef std::unique_ptr<base_frontend_t> return_type;
    typedef return_type(*factory_type)(const frontend_factory_t&, const formatter_config_t&, const sink_config_t&);
    typedef std::string(*extractor_type)(const dynamic_t&);

    mutable std::mutex mutex;
    std::unordered_map<std::string, factory_type> sinks;
    std::unordered_map<std::string, extractor_type> config_id_extractors;

    frontend_factory_t factory;

    std::unordered_map<
        std::type_index,
        std::unordered_map<
            std::type_index,
            std::function<std::unique_ptr<base_frontend_t>(const frontend_config_t&)>
        >
    > map;

//    typedef std::tuple<std::function<bool(const std::string&, const dynamic_t&)>, std::type_index> tup;
    typedef std::tuple<std::function<std::type_index(const std::string&, const dynamic_t&)>, std::type_index> tup;
    std::vector<tup> findex;
    std::vector<tup> sindex;

    template<class Formatter, class Sink>
    static
    std::unique_ptr<base_frontend_t>
    create_frontend(const frontend_config_t& config) {
        auto formatter = aux::util::make_unique<Formatter>(
            aux::config_mapper<Formatter>::map(config.formatter.config())
        );

        auto sink = aux::util::make_unique<Sink>(
            aux::config_mapper<Sink>::map(config.sink.config())
        );

        return aux::util::make_unique<
            frontend_t<Formatter, Sink>
        >(std::move(formatter), std::move(sink));
    }

public:
    template<class Sink, class Formatter>
    typename std::enable_if<
        boost::mpl::is_sequence<Sink>::type::value && boost::mpl::is_sequence<Formatter>::type::value
    >::type
    add() {
        // do double iterations.
        anarchy action { this };
        boost::mpl::for_each<
            Sink,
            aux::util::metaholder<boost::mpl::_, Formatter>
        >(action);
    }

    template<class Sink, class Formatter>
    typename std::enable_if<
        boost::mpl::is_sequence<Sink>::type::value && !boost::mpl::is_sequence<Formatter>::type::value
    >::type
    add() {
        // do iterations over Sink
        anarchy action { this };
        boost::mpl::for_each<
            Sink,
            aux::util::metaholder<boost::mpl::_, Formatter>
        >(action);
    }

    struct anarchy {
        external_factory_t* factory;

        template<class Sink, class Formatter>
        void operator()(aux::util::metaholder<Sink, Formatter>) const {
            factory->add<Sink, Formatter>();
        }
    };

    template<class Sink, class Formatter>
    typename std::enable_if<
        !boost::mpl::is_sequence<Sink>::type::value && boost::mpl::is_sequence<Formatter>::type::value
    >::type
    add() {
        // do iterations over Formatter
        anarchy action { this };
        boost::mpl::for_each<
            Formatter,
            aux::util::metaholder<Sink, boost::mpl::_>
        >(action);
    }

    //!@todo: Swap type parameters.
    template<class Sink, class Formatter>
    typename std::enable_if<
        !boost::mpl::is_sequence<Sink>::type::value && !boost::mpl::is_sequence<Formatter>::type::value
    >::type
    add() {
        auto fid = std::type_index(typeid(Formatter));
        findex.push_back(
            std::make_tuple(std::bind(&match_traits<Formatter>::ti, std::placeholders::_1, std::placeholders::_2), fid)
        );

        auto sid = std::type_index(typeid(Sink));
        sindex.push_back(
            std::make_tuple(std::bind(&match_traits<Sink>::ti, std::placeholders::_1, std::placeholders::_2), sid)
        );

        map[fid][sid] = std::bind(&create_frontend<Formatter, Sink>, std::placeholders::_1);
    }

    std::unique_ptr<base_frontend_t>
    create(const formatter_config_t& formatter_config, const sink_config_t& sink_config) const {
        return create(frontend_config_t { formatter_config, sink_config });
    }

    std::unique_ptr<base_frontend_t>
    create(const frontend_config_t& config) const {
        auto fid = std::find_if(findex.begin(), findex.end(), [&config](const tup& t) {
            return std::get<0>(t)(config.formatter.type(), config.formatter.config()) == std::get<1>(t);
        });

        auto sid = std::find_if(sindex.begin(), sindex.end(), [&config](const tup& t) {
            return std::get<0>(t)(config.sink.type(), config.sink.config()) == std::get<1>(t);
        });

        if (fid == findex.end()) {
            throw blackhole::error_t("formatter not registered");
        }

        if (sid == sindex.end()) {
            throw blackhole::error_t("sink not registered");
        }

        auto it = map.find(std::get<1>(*fid));
        if (it == map.end()) {
            throw blackhole::error_t("formatter not registered");
        }

        auto map2 = it->second;
        auto it2 = map2.find(std::get<1>(*sid));
        if (it2 == map2.end()) {
            throw blackhole::error_t("sink not registered");
        }

        return it2->second(config);
    }

    template<class Sink, class Formatter>
    bool has() const {
        std::lock_guard<std::mutex> lock(mutex);

        auto fid = std::find_if(findex.begin(), findex.end(), [](const tup& t) {
            return std::get<1>(t) == std::type_index(typeid(Formatter));
        });

        auto sid = std::find_if(sindex.begin(), sindex.end(), [](const tup& t) {
            return std::get<1>(t) == std::type_index(typeid(Sink));
        });

        return fid != findex.end() && sid != sindex.end();
    }

    void clear() {
        std::lock_guard<std::mutex> lock(mutex);
        sinks.clear();
        factory.clear();
    }
};

template<class Sinks, class Formatters>
struct all_sequence {
    static const bool value = boost::mpl::is_sequence<Sinks>::type::value &&
        boost::mpl::is_sequence<Formatters>::type::value;
};

template<class Sink, class Formatter>
struct external_inserter<
    Sink,
    Formatter,
    typename std::enable_if<!all_sequence<Sink, Formatter>::value>::type
> {
    static void insert(external_factory_t& factory) {
        factory.add<Sink, Formatter>();
    }
};

template<class Sinks, class Formatters>
struct external_inserter<
    Sinks,
    Formatters,
    typename std::enable_if<all_sequence<Sinks, Formatters>::value>::type
> {
    static void insert(external_factory_t& factory) {
        aux::registrator::group action { factory };
        boost::mpl::for_each<
            Sinks,
            aux::util::metaholder<boost::mpl::_, Formatters>
        >(action);
    }
};

} // namespace blackhole
<commit_msg>[Detail] Dead code elimination.<commit_after>#pragma once

#include <functional>
#include <memory>
#include <mutex>
#include <unordered_map>

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/is_sequence.hpp>

#include "blackhole/repository/config/formatter.hpp"
#include "blackhole/repository/config/sink.hpp"
//!@note: Must be included first to resolve circular depencencies.
#include "blackhole/repository/factory/frontend/helper.hpp"
#include "blackhole/repository/factory/frontend.hpp"
#include "blackhole/repository/factory/frontend/inserter.hpp"
#include "blackhole/repository/factory/registrator.hpp"
#include "blackhole/repository/factory/traits.hpp"

namespace blackhole {

class external_factory_t {
    mutable std::mutex mutex;

    std::unordered_map<
        std::type_index,
        std::unordered_map<
            std::type_index,
            std::function<std::unique_ptr<base_frontend_t>(const frontend_config_t&)>
        >
    > map;

    typedef std::tuple<std::function<std::type_index(const std::string&, const dynamic_t&)>, std::type_index> tup;
    std::vector<tup> findex;
    std::vector<tup> sindex;

    template<class Formatter, class Sink>
    static
    std::unique_ptr<base_frontend_t>
    create_frontend(const frontend_config_t& config) {
        auto formatter = aux::util::make_unique<Formatter>(
            aux::config_mapper<Formatter>::map(config.formatter.config())
        );

        auto sink = aux::util::make_unique<Sink>(
            aux::config_mapper<Sink>::map(config.sink.config())
        );

        return aux::util::make_unique<
            frontend_t<Formatter, Sink>
        >(std::move(formatter), std::move(sink));
    }

public:
    template<class Sink, class Formatter>
    typename std::enable_if<
        boost::mpl::is_sequence<Sink>::type::value && boost::mpl::is_sequence<Formatter>::type::value
    >::type
    add() {
        // do double iterations.
        anarchy action { this };
        boost::mpl::for_each<
            Sink,
            aux::util::metaholder<boost::mpl::_, Formatter>
        >(action);
    }

    template<class Sink, class Formatter>
    typename std::enable_if<
        boost::mpl::is_sequence<Sink>::type::value && !boost::mpl::is_sequence<Formatter>::type::value
    >::type
    add() {
        // do iterations over Sink
        anarchy action { this };
        boost::mpl::for_each<
            Sink,
            aux::util::metaholder<boost::mpl::_, Formatter>
        >(action);
    }

    struct anarchy {
        external_factory_t* factory;

        template<class Sink, class Formatter>
        void operator()(aux::util::metaholder<Sink, Formatter>) const {
            factory->add<Sink, Formatter>();
        }
    };

    template<class Sink, class Formatter>
    typename std::enable_if<
        !boost::mpl::is_sequence<Sink>::type::value && boost::mpl::is_sequence<Formatter>::type::value
    >::type
    add() {
        // do iterations over Formatter
        anarchy action { this };
        boost::mpl::for_each<
            Formatter,
            aux::util::metaholder<Sink, boost::mpl::_>
        >(action);
    }

    //!@todo: Swap type parameters.
    template<class Sink, class Formatter>
    typename std::enable_if<
        !boost::mpl::is_sequence<Sink>::type::value && !boost::mpl::is_sequence<Formatter>::type::value
    >::type
    add() {
        auto fid = std::type_index(typeid(Formatter));
        findex.push_back(
            std::make_tuple(std::bind(&match_traits<Formatter>::ti, std::placeholders::_1, std::placeholders::_2), fid)
        );

        auto sid = std::type_index(typeid(Sink));
        sindex.push_back(
            std::make_tuple(std::bind(&match_traits<Sink>::ti, std::placeholders::_1, std::placeholders::_2), sid)
        );

        map[fid][sid] = std::bind(&create_frontend<Formatter, Sink>, std::placeholders::_1);
    }

    std::unique_ptr<base_frontend_t>
    create(const formatter_config_t& formatter_config, const sink_config_t& sink_config) const {
        return create(frontend_config_t { formatter_config, sink_config });
    }

    std::unique_ptr<base_frontend_t>
    create(const frontend_config_t& config) const {
        auto fid = std::find_if(findex.begin(), findex.end(), [&config](const tup& t) {
            return std::get<0>(t)(config.formatter.type(), config.formatter.config()) == std::get<1>(t);
        });

        auto sid = std::find_if(sindex.begin(), sindex.end(), [&config](const tup& t) {
            return std::get<0>(t)(config.sink.type(), config.sink.config()) == std::get<1>(t);
        });

        if (fid == findex.end()) {
            throw blackhole::error_t("formatter not registered");
        }

        if (sid == sindex.end()) {
            throw blackhole::error_t("sink not registered");
        }

        auto it = map.find(std::get<1>(*fid));
        if (it == map.end()) {
            throw blackhole::error_t("formatter not registered");
        }

        auto map2 = it->second;
        auto it2 = map2.find(std::get<1>(*sid));
        if (it2 == map2.end()) {
            throw blackhole::error_t("sink not registered");
        }

        return it2->second(config);
    }

    template<class Sink, class Formatter>
    bool has() const {
        std::lock_guard<std::mutex> lock(mutex);

        auto fid = std::find_if(findex.begin(), findex.end(), [](const tup& t) {
            return std::get<1>(t) == std::type_index(typeid(Formatter));
        });

        auto sid = std::find_if(sindex.begin(), sindex.end(), [](const tup& t) {
            return std::get<1>(t) == std::type_index(typeid(Sink));
        });

        return fid != findex.end() && sid != sindex.end();
    }

    void clear() {
        std::lock_guard<std::mutex> lock(mutex);
        map.clear();
    }
};

} // namespace blackhole
<|endoftext|>


<commit_before>#pragma once

#include <functional>
#include <memory>
#include <mutex>
#include <unordered_map>

#include <boost/any.hpp>

#include "blackhole/error.hpp"
#include "blackhole/repository/config/formatter.hpp"
#include "blackhole/repository/config/sink.hpp"
#include "blackhole/repository/factory/frontend/keeper.hpp"
#include "blackhole/repository/factory/frontend/traits.hpp"

namespace blackhole {

class frontend_factory_t {
    mutable std::mutex mutex;
    std::unordered_map<std::string, function_keeper_t> factories;
public:
    template<class Sink, class Formatter>
    void add() {
        std::lock_guard<std::mutex> lock(mutex);

        auto it = factories.find(Formatter::name());
        if (it != factories.end()) {
            function_keeper_t& keeper = it->second;
            keeper.add<Sink, Formatter>();
        } else {
            function_keeper_t keeper;
            keeper.add<Sink, Formatter>();
            factories[Formatter::name()] = keeper;
        }
    }

    template<class Sink, class Formatter>
    bool has() const {
        std::lock_guard<std::mutex> lock(mutex);
        auto it = factories.find(Formatter::name());
        return it != factories.end() && it->second.template has<Sink>();
    }

    template<class Sink>
    typename frontend::traits<Sink>::return_type
    create(const formatter_config_t& formatter_config, std::unique_ptr<Sink> sink) const {
        typedef typename frontend::traits<Sink>::return_type return_type;

        try {
            std::lock_guard<std::mutex> lock(mutex);
            const function_keeper_t& keeper = factories.at(formatter_config.type);
            auto factory = keeper.get<Sink>();
            return factory(formatter_config, std::move(sink));
        } catch (const std::exception&) {
            throw error_t("there are no registered formatter '%s' for sink '%s", formatter_config.type, Sink::name());
        }

        return return_type();
    }

    void clear() {
        std::lock_guard<std::mutex> lock(mutex);
        factories.clear();
    }
};

} // namespace blackhole
<commit_msg>[Bug Fix] Fixed misleading error message when failed to instantiate formatter.<commit_after>#pragma once

#include <functional>
#include <memory>
#include <mutex>
#include <unordered_map>

#include <boost/any.hpp>

#include "blackhole/error.hpp"
#include "blackhole/repository/config/formatter.hpp"
#include "blackhole/repository/config/sink.hpp"
#include "blackhole/repository/factory/frontend/keeper.hpp"
#include "blackhole/repository/factory/frontend/traits.hpp"

namespace blackhole {

class frontend_factory_t {
    mutable std::mutex mutex;
    std::unordered_map<std::string, function_keeper_t> factories;
public:
    template<class Sink, class Formatter>
    void add() {
        std::lock_guard<std::mutex> lock(mutex);

        auto it = factories.find(Formatter::name());
        if (it != factories.end()) {
            function_keeper_t& keeper = it->second;
            keeper.add<Sink, Formatter>();
        } else {
            function_keeper_t keeper;
            keeper.add<Sink, Formatter>();
            factories[Formatter::name()] = keeper;
        }
    }

    template<class Sink, class Formatter>
    bool has() const {
        std::lock_guard<std::mutex> lock(mutex);
        auto it = factories.find(Formatter::name());
        return it != factories.end() && it->second.template has<Sink>();
    }

    template<class Sink>
    typename frontend::traits<Sink>::return_type
    create(const formatter_config_t& formatter_config, std::unique_ptr<Sink> sink) const {
        typedef typename frontend::traits<Sink>::return_type return_type;

        try {
            std::lock_guard<std::mutex> lock(mutex);
            const function_keeper_t& keeper = factories.at(formatter_config.type);
            auto factory = keeper.get<Sink>();
            return factory(formatter_config, std::move(sink));
        } catch (const std::out_of_range&) {
            throw error_t(
                "there are no registered formatter '%s' for sink '%s",
                formatter_config.type,
                Sink::name()
            );
        } catch (const std::exception& e) {
            throw error_t(
                "failed to instantiate formatter for '%s/%s' frontend: %s",
                formatter_config.type,
                Sink::name(),
                e.what()
            );
        }

        return return_type();
    }

    void clear() {
        std::lock_guard<std::mutex> lock(mutex);
        factories.clear();
    }
};

} // namespace blackhole
<|endoftext|>