From 47959eaaeb04a78d27698725630b9834b4142c9f Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 19 Jan 2014 10:56:45 +0100 Subject: [PATCH] Added ParameterList class Former-commit-id: c592d0a09c33aa23b5efe635734c52b726364085 --- include/Nazara/Core/Enums.hpp | 13 + include/Nazara/Core/ParameterList.hpp | 94 +++++ src/Nazara/Core/ParameterList.cpp | 541 ++++++++++++++++++++++++++ 3 files changed, 648 insertions(+) create mode 100644 include/Nazara/Core/ParameterList.hpp create mode 100644 src/Nazara/Core/ParameterList.cpp diff --git a/include/Nazara/Core/Enums.hpp b/include/Nazara/Core/Enums.hpp index 251589f3b..b2eb2203e 100644 --- a/include/Nazara/Core/Enums.hpp +++ b/include/Nazara/Core/Enums.hpp @@ -60,6 +60,19 @@ enum nzHash nzHash_Whirlpool }; +enum nzParameterType +{ + nzParameterType_Boolean, + nzParameterType_Float, + nzParameterType_Integer, + nzParameterType_None, + nzParameterType_Pointer, + nzParameterType_String, + nzParameterType_Userdata, + + nzParameterType_Max = nzParameterType_Userdata +}; + enum nzPlugin { nzPlugin_Assimp, diff --git a/include/Nazara/Core/ParameterList.hpp b/include/Nazara/Core/ParameterList.hpp new file mode 100644 index 000000000..f77957af0 --- /dev/null +++ b/include/Nazara/Core/ParameterList.hpp @@ -0,0 +1,94 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PARAMETERLIST_HPP +#define NAZARA_PARAMETERLIST_HPP + +#include +#include +#include +#include + +class NAZARA_API NzParameterList +{ + public: + using Destructor = void (*)(void* value); + + NzParameterList() = default; + NzParameterList(const NzParameterList& list); + NzParameterList(NzParameterList&& list); + virtual ~NzParameterList(); + + void Clear(); + + bool GetBooleanParameter(const NzString& name, bool* succeeded = nullptr) const; + float GetFloatParameter(const NzString& name, bool* succeeded = nullptr) const; + int GetIntegerParameter(const NzString& name, bool* succeeded = nullptr) const; + nzParameterType GetParameterType(const NzString& name, bool* existing = nullptr) const; + void* GetPointerParameter(const NzString& name, bool* succeeded = nullptr) const; + NzString GetStringParameter(const NzString& name, bool* succeeded = nullptr) const; + void* GetUserdataParameter(const NzString& name, bool* succeeded = nullptr) const; + + bool HasParameter(const NzString& name) const; + + void RemoveParameter(const NzString& name); + + void SetParameter(const NzString& name); + void SetParameter(const NzString& name, const NzString& value); + void SetParameter(const NzString& name, const char* value); + void SetParameter(const NzString& name, void* value); + void SetParameter(const NzString& name, void* value, Destructor destructor); + void SetParameter(const NzString& name, bool value); + void SetParameter(const NzString& name, float value); + void SetParameter(const NzString& name, int value); + + NzParameterList& operator=(const NzParameterList& list); + NzParameterList& operator=(NzParameterList&& list); + + private: + struct Parameter + { + struct UserdataValue + { + UserdataValue(Destructor Destructor, void* value) : + counter(1), + destructor(Destructor), + ptr(value) + { + } + + std::atomic_uint counter; + Destructor destructor; + void* ptr; + }; + + nzParameterType type; + union Value + { + // On définit un constructeur/destructeur vide, permettant de mettre des classes dans l'union + Value() {} + Value(const Value&) {} // Placeholder + ~Value() {} + + bool boolVal; + float floatVal; + int intVal; + void* ptrVal; + NzString stringVal; + UserdataValue* userdataVal; + }; + + Value value; + }; + + using ParameterMap = std::unordered_map; + + void DestroyValue(Parameter& parameter); + + ParameterMap m_parameters; +}; + +#endif // NAZARA_PARAMETERLIST_HPP diff --git a/src/Nazara/Core/ParameterList.cpp b/src/Nazara/Core/ParameterList.cpp new file mode 100644 index 000000000..559db20cc --- /dev/null +++ b/src/Nazara/Core/ParameterList.cpp @@ -0,0 +1,541 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +NzParameterList::NzParameterList(const NzParameterList& list) +{ + operator=(list); +} + +NzParameterList::NzParameterList(NzParameterList&& list) : +m_parameters(std::move(list.m_parameters)) +{ +} + +NzParameterList::~NzParameterList() +{ + Clear(); +} + +void NzParameterList::Clear() +{ + for (auto it = m_parameters.begin(); it != m_parameters.end(); ++it) + DestroyValue(it->second); + + m_parameters.clear(); +} + +bool NzParameterList::GetBooleanParameter(const NzString& name, bool* succeeded) const +{ + auto it = m_parameters.find(name); + if (it == m_parameters.end()) + { + if (succeeded) + *succeeded = false; + + NazaraError("Parameter \"" + name + "\" is not present"); + return false; + } + + switch (it->second.type) + { + case nzParameterType_Boolean: + if (succeeded) + *succeeded = true; + + return it->second.value.boolVal; + + case nzParameterType_Integer: + if (succeeded) + *succeeded = true; + + return (it->second.value.intVal != 0); + + case nzParameterType_String: + { + bool value; + if (it->second.value.stringVal.ToBool(&value, NzString::CaseInsensitive)) + { + if (succeeded) + *succeeded = true; + + return value; + } + + break; + } + + case nzParameterType_Float: + case nzParameterType_None: + case nzParameterType_Pointer: + case nzParameterType_Userdata: + break; + } + + if (succeeded) + *succeeded = false; + + NazaraError("Parameter value is not representable as a boolean"); + return false; +} + +float NzParameterList::GetFloatParameter(const NzString& name, bool* succeeded) const +{ + auto it = m_parameters.find(name); + if (it == m_parameters.end()) + { + if (succeeded) + *succeeded = false; + + NazaraError("Parameter \"" + name + "\" is not present"); + return std::numeric_limits::quiet_NaN(); + } + + switch (it->second.type) + { + case nzParameterType_Float: + if (succeeded) + *succeeded = true; + + return it->second.value.floatVal; + + case nzParameterType_Integer: + if (succeeded) + *succeeded = true; + + return it->second.value.intVal; + + case nzParameterType_String: + { + double value; + if (it->second.value.stringVal.ToDouble(&value)) + { + if (succeeded) + *succeeded = true; + + return value; + } + + break; + } + + case nzParameterType_Boolean: + case nzParameterType_None: + case nzParameterType_Pointer: + case nzParameterType_Userdata: + break; + } + + if (succeeded) + *succeeded = false; + + NazaraError("Parameter value is not representable as a float"); + return std::numeric_limits::quiet_NaN(); +} + +int NzParameterList::GetIntegerParameter(const NzString& name, bool* succeeded) const +{ + auto it = m_parameters.find(name); + if (it == m_parameters.end()) + { + if (succeeded) + *succeeded = false; + + NazaraError("Parameter \"" + name + "\" is not present"); + return 0; + } + + switch (it->second.type) + { + case nzParameterType_Boolean: + return (it->second.value.boolVal) ? 1 : 0; + + case nzParameterType_Float: + if (succeeded) + *succeeded = true; + + return it->second.value.floatVal; + + case nzParameterType_Integer: + if (succeeded) + *succeeded = true; + + return it->second.value.intVal; + + case nzParameterType_String: + { + long long value; + if (it->second.value.stringVal.ToInteger(&value)) + { + if (value <= std::numeric_limits::max() && value >= std::numeric_limits::min()) + { + if (succeeded) + *succeeded = true; + + return value; + } + } + + break; + } + + case nzParameterType_None: + case nzParameterType_Pointer: + case nzParameterType_Userdata: + break; + } + + if (succeeded) + *succeeded = false; + + NazaraError("Parameter value is not representable as a integer"); + return 0; +} + +nzParameterType NzParameterList::GetParameterType(const NzString& name, bool* existing) const +{ + auto it = m_parameters.find(name); + if (it == m_parameters.end()) + { + if (existing) + *existing = false; + + return nzParameterType_None; + } + + if (existing) + *existing = true; + + return it->second.type; +} + +void* NzParameterList::GetPointerParameter(const NzString& name, bool* succeeded) const +{ + auto it = m_parameters.find(name); + if (it == m_parameters.end()) + { + if (succeeded) + *succeeded = false; + + NazaraError("Parameter \"" + name + "\" is not present"); + return nullptr; + } + + switch (it->second.type) + { + case nzParameterType_Pointer: + if (succeeded) + *succeeded = true; + + return it->second.value.ptrVal; + case nzParameterType_Userdata: + if (succeeded) + *succeeded = true; + + return it->second.value.userdataVal->ptr; + + case nzParameterType_Boolean: + case nzParameterType_Float: + case nzParameterType_Integer: + case nzParameterType_None: + case nzParameterType_String: + break; + } + + if (succeeded) + *succeeded = false; + + NazaraError("Parameter value is not a pointer"); + return nullptr; +} + +NzString NzParameterList::GetStringParameter(const NzString& name, bool* succeeded) const +{ + auto it = m_parameters.find(name); + if (it == m_parameters.end()) + { + if (succeeded) + *succeeded = false; + + NazaraError("Parameter \"" + name + "\" is not present"); + return NzString(); + } + + switch (it->second.type) + { + case nzParameterType_Boolean: + if (succeeded) + *succeeded = true; + + return NzString::Boolean(it->second.value.boolVal); + + case nzParameterType_Float: + if (succeeded) + *succeeded = true; + + return NzString::Number(it->second.value.floatVal); + + case nzParameterType_Integer: + if (succeeded) + *succeeded = true; + + return NzString::Number(it->second.value.intVal); + + case nzParameterType_String: + if (succeeded) + *succeeded = true; + + return it->second.value.stringVal; + + case nzParameterType_Pointer: + if (succeeded) + *succeeded = true; + + return NzString::Pointer(it->second.value.ptrVal); + + case nzParameterType_Userdata: + if (succeeded) + *succeeded = true; + + return NzString::Pointer(it->second.value.userdataVal->ptr); + + case nzParameterType_None: + if (succeeded) + *succeeded = true; + + return NzString(); + } + + if (succeeded) + *succeeded = false; + + NazaraInternalError("Parameter value is not valid"); + return NzString(); +} + +void* NzParameterList::GetUserdataParameter(const NzString& name, bool* succeeded) const +{ + auto it = m_parameters.find(name); + if (it == m_parameters.end()) + { + if (succeeded) + *succeeded = false; + + NazaraError("Parameter \"" + name + "\" is not present"); + return nullptr; + } + + switch (it->second.type) + { + case nzParameterType_Userdata: + if (succeeded) + *succeeded = true; + + return it->second.value.userdataVal->ptr; + + case nzParameterType_Boolean: + case nzParameterType_Float: + case nzParameterType_Integer: + case nzParameterType_None: + case nzParameterType_Pointer: + case nzParameterType_String: + break; + } + + if (succeeded) + *succeeded = false; + + NazaraError("Parameter value is not an userdata"); + return nullptr; +} + +bool NzParameterList::HasParameter(const NzString& name) const +{ + return m_parameters.find(name) != m_parameters.end(); +} + +void NzParameterList::RemoveParameter(const NzString& name) +{ + auto it = m_parameters.find(name); + if (it != m_parameters.end()) + { + DestroyValue(it->second); + m_parameters.erase(it); + } +} + +void NzParameterList::SetParameter(const NzString& name) +{ + std::pair pair = m_parameters.insert(std::make_pair(name, Parameter())); + Parameter& parameter = pair.first->second; + + if (!pair.second) + DestroyValue(parameter); + + parameter.type = nzParameterType_None; +} + +void NzParameterList::SetParameter(const NzString& name, const NzString& value) +{ + std::pair pair = m_parameters.insert(std::make_pair(name, Parameter())); + Parameter& parameter = pair.first->second; + + if (!pair.second) + DestroyValue(parameter); + + parameter.type = nzParameterType_String; + + new (¶meter.value.stringVal) NzString(value); +} + +void NzParameterList::SetParameter(const NzString& name, const char* value) +{ + std::pair pair = m_parameters.insert(std::make_pair(name, Parameter())); + Parameter& parameter = pair.first->second; + + if (!pair.second) + DestroyValue(parameter); + + parameter.type = nzParameterType_String; + + new (¶meter.value.stringVal) NzString(value); +} + +void NzParameterList::SetParameter(const NzString& name, void* value) +{ + std::pair pair = m_parameters.insert(std::make_pair(name, Parameter())); + Parameter& parameter = pair.first->second; + + if (!pair.second) + DestroyValue(parameter); + + parameter.type = nzParameterType_Pointer; + parameter.value.ptrVal = value; +} + +void NzParameterList::SetParameter(const NzString& name, void* value, Destructor destructor) +{ + std::pair pair = m_parameters.insert(std::make_pair(name, Parameter())); + Parameter& parameter = pair.first->second; + + if (!pair.second) + DestroyValue(parameter); + + parameter.type = nzParameterType_Userdata; + parameter.value.userdataVal = new Parameter::UserdataValue(destructor, value); +} + +void NzParameterList::SetParameter(const NzString& name, bool value) +{ + std::pair pair = m_parameters.insert(std::make_pair(name, Parameter())); + Parameter& parameter = pair.first->second; + + if (!pair.second) + DestroyValue(parameter); + + parameter.type = nzParameterType_Boolean; + parameter.value.boolVal = value; +} + +void NzParameterList::SetParameter(const NzString& name, float value) +{ + std::pair pair = m_parameters.insert(std::make_pair(name, Parameter())); + Parameter& parameter = pair.first->second; + + if (!pair.second) + DestroyValue(parameter); + + parameter.type = nzParameterType_Float; + parameter.value.floatVal = value; +} + +void NzParameterList::SetParameter(const NzString& name, int value) +{ + std::pair pair = m_parameters.insert(std::make_pair(name, Parameter())); + Parameter& parameter = pair.first->second; + + if (!pair.second) + DestroyValue(parameter); + + parameter.type = nzParameterType_Integer; + parameter.value.intVal = value; +} + +NzParameterList& NzParameterList::operator=(const NzParameterList& list) +{ + Clear(); + + for (auto it = list.m_parameters.begin(); it != list.m_parameters.end(); ++it) + { + Parameter& parameter = m_parameters[it->first]; + + switch (it->second.type) + { + case nzParameterType_Boolean: + case nzParameterType_Float: + case nzParameterType_Integer: + case nzParameterType_Pointer: + std::memcpy(¶meter, &it->second, sizeof(Parameter)); + break; + + case nzParameterType_String: + parameter.type = nzParameterType_String; + + new (¶meter.value.stringVal) NzString(it->second.value.stringVal); + break; + + case nzParameterType_Userdata: + parameter.type = nzParameterType_Userdata; + parameter.value.userdataVal = it->second.value.userdataVal; + ++(parameter.value.userdataVal->counter); + break; + + case nzParameterType_None: + parameter.type = nzParameterType_None; + break; + } + } + + return *this; +} + +NzParameterList& NzParameterList::operator=(NzParameterList&& list) +{ + m_parameters = std::move(list.m_parameters); + return *this; +} + +void NzParameterList::DestroyValue(Parameter& parameter) +{ + switch (parameter.type) + { + case nzParameterType_String: + parameter.value.stringVal.~NzString(); + break; + + case nzParameterType_Userdata: + { + Parameter::UserdataValue* userdata = parameter.value.userdataVal; + if (--userdata->counter == 0) + { + userdata->destructor(userdata->ptr); + delete userdata; + } + break; + } + + case nzParameterType_Boolean: + case nzParameterType_Float: + case nzParameterType_Integer: + case nzParameterType_None: + case nzParameterType_Pointer: + break; + } +}