From d01691d507726db1b6cf0a1429fbdfe4da767765 Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Tue, 30 Jul 2019 10:27:31 +0300 Subject: [PATCH 01/11] wip --- src/celengine/config.h | 98 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/celengine/config.h diff --git a/src/celengine/config.h b/src/celengine/config.h new file mode 100644 index 0000000000..d256510e9e --- /dev/null +++ b/src/celengine/config.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include "parser.h" + +namespace celengine +{ +class BaseProperty; +class Config +{ + public: + void setProperty(BaseProperty*); + const Value operator[](const std::string& name); +}; + +class BaseProperty +{ + public: + virtual void update() = 0; + friend class Config; +}; + +template +class Property : BaseProperty +{ + public: + Property() = default; + + Property(Config *config, std::string name) : + m_config(config), + m_name(std::move(name)) + { + m_config->setProperty(this); + }; + + Property(Config *config, std::string name, T value) : + m_config(config), + m_name(std::move(name)), + m_value(std::move(value)) + { + }; + + // Getters and setters + inline Property& set(T value) + { + m_value = value; + }; + + Property& operator() (T value) + { + return set(value); + }; + + Property& operator=(T value) + { + return set(value); + }; + + T get() const + { + return m_value; + }; + + T operator()() const + { + return get(); + }; + + // Used by Config to propagate changes + void update() override; + + private: + Config *m_config { nullptr }; + std::string m_name; + T m_value {}; +}; + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getNumber(); +} + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getString(); +} + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getBoolean(); +} + +Property p; +} // namespace; From d37f2e7dd60c22818ad4e044f8becedb798eb9dd Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Tue, 30 Jul 2019 23:50:41 +0300 Subject: [PATCH 02/11] wip --- src/celengine/config.cpp | 53 ++++++++++++++++++++++ src/celengine/config.h | 90 ++++++------------------------------ src/celengine/parser.h | 30 +++++++----- src/celengine/property.h | 98 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+), 89 deletions(-) create mode 100644 src/celengine/config.cpp create mode 100644 src/celengine/property.h diff --git a/src/celengine/config.cpp b/src/celengine/config.cpp new file mode 100644 index 0000000000..f730137a1a --- /dev/null +++ b/src/celengine/config.cpp @@ -0,0 +1,53 @@ +#include "config.h" +#include "property.h" + + +namespace celengine +{ + +void Config::setProperty(BaseProperty *p) +{ + auto pos = std::find(m_props.begin(), m_props.end(), p); + if (pos != m_props.end()) + m_props.push_back(p); +} + +void Config::removeProperty(BaseProperty *p) +{ + auto pos = std::find(m_props.begin(), m_props.end(), p); + if (pos != m_props.end()) + m_props.erase(pos); +} + +const Value Config::operator[](const std::string& name) +{ + auto pos = m_values.find(name); + if (pos != m_values.end()) + return pos->second; + + return Value(); +} + +void Config::beginUpdate() +{ + m_update = true; +} + +void Config::set(const std::string& name, const Value& value) +{ + m_values[name] = value; +} + +void Config::endUpdate() +{ + m_update = false; + onUpdate(); +} + +void Config::onUpdate() +{ + for (auto* p : m_props) + p->update(); +} + +} // namespace; diff --git a/src/celengine/config.h b/src/celengine/config.h index d256510e9e..be3b2b5e6a 100644 --- a/src/celengine/config.h +++ b/src/celengine/config.h @@ -2,97 +2,33 @@ #include #include +#include +#include #include "parser.h" + namespace celengine { class BaseProperty; + class Config { public: void setProperty(BaseProperty*); + void removeProperty(BaseProperty*); const Value operator[](const std::string& name); -}; - -class BaseProperty -{ - public: - virtual void update() = 0; - friend class Config; -}; - -template -class Property : BaseProperty -{ - public: - Property() = default; - - Property(Config *config, std::string name) : - m_config(config), - m_name(std::move(name)) - { - m_config->setProperty(this); - }; - - Property(Config *config, std::string name, T value) : - m_config(config), - m_name(std::move(name)), - m_value(std::move(value)) - { - }; - // Getters and setters - inline Property& set(T value) - { - m_value = value; - }; - - Property& operator() (T value) - { - return set(value); - }; - - Property& operator=(T value) - { - return set(value); - }; - - T get() const - { - return m_value; - }; - - T operator()() const - { - return get(); - }; - - // Used by Config to propagate changes - void update() override; + void beginUpdate(); + void set(const std::string& name, const Value& value); + void endUpdate(); private: - Config *m_config { nullptr }; - std::string m_name; - T m_value {}; -}; + void onUpdate(); -template<> -void Property::update() -{ - m_value = (*m_config)[m_name].getNumber(); -} - -template<> -void Property::update() -{ - m_value = (*m_config)[m_name].getString(); -} + std::vector m_props; + std::map m_values; -template<> -void Property::update() -{ - m_value = (*m_config)[m_name].getBoolean(); -} + bool m_update { false }; +}; -Property p; } // namespace; diff --git a/src/celengine/parser.h b/src/celengine/parser.h index a5d66250b1..5d7a350e00 100644 --- a/src/celengine/parser.h +++ b/src/celengine/parser.h @@ -72,13 +72,15 @@ typedef AssociativeArray Hash; class Value { -public: - enum ValueType { - NumberType = 0, - StringType = 1, - ArrayType = 2, - HashType = 3, - BooleanType = 4 + public: + enum ValueType + { + NullType = 0, + NumberType = 1, + StringType = 2, + ArrayType = 3, + HashType = 4, + BooleanType = 5 }; Value(double); @@ -86,25 +88,29 @@ class Value Value(ValueArray*); Value(Hash*); Value(bool); + Value() = default; ~Value(); ValueType getType() const; + bool isNull() const; double getNumber() const; string getString() const; ValueArray* getArray() const; Hash* getHash() const; bool getBoolean() const; -private: - ValueType type; - - union { + private: + union Data + { string* s; double d; ValueArray* a; Hash* h; - } data; + }; + + ValueType type{ NullType }; + Data data; }; diff --git a/src/celengine/property.h b/src/celengine/property.h new file mode 100644 index 0000000000..59ffb3f05c --- /dev/null +++ b/src/celengine/property.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include "config.h" +#include "parser.h" + + +namespace celengine +{ +class BaseProperty +{ + public: + virtual void update() = 0; + friend class Config; +}; + +template +class Property : BaseProperty +{ + public: + Property() = default; + + Property(std::shared_ptr config, std::string name) : + m_config(std::move(config)), + m_name(std::move(name)) + { + m_config->setProperty(this); + }; + + Property(std::shared_ptr config, std::string name, T value) : + m_config(std::move(config)), + m_name(std::move(name)), + m_value(std::move(value)) + { + }; + + ~Property(); + + // Getters and setters + inline Property& set(T value) + { + m_value = value; + }; + + Property& operator() (T value) + { + return set(value); + }; + + Property& operator=(T value) + { + return set(value); + }; + + T get() const + { + return m_value; + }; + + T operator()() const + { + return get(); + }; + + // Used by Config to propagate changes + void update() override; + + private: + std::shared_ptr m_config { nullptr }; + std::string m_name; + T m_value {}; +}; + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getNumber(); +} + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getString(); +} + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getBoolean(); +} + +template +Property::~Property() +{ + m_config->removeProperty(*this); +} + +} // namespace; From 608eb46a927f7444f2ffef9c065d5eda6d2c7398 Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Fri, 30 Aug 2019 23:47:55 +0300 Subject: [PATCH 03/11] wip --- src/celengine/config.cpp | 11 ++-- src/celengine/config.h | 38 ++++++++---- src/celengine/property.cpp | 28 +++++++++ src/celengine/property.h | 28 +++++---- src/celengine/testprops.cc | 29 +++++++++ src/celengine/value.cpp | 118 +++++++++++++++++++++++++++++++++++++ src/celengine/value.h | 72 ++++++++++++++++++++++ 7 files changed, 300 insertions(+), 24 deletions(-) create mode 100644 src/celengine/property.cpp create mode 100644 src/celengine/testprops.cc create mode 100644 src/celengine/value.cpp create mode 100644 src/celengine/value.h diff --git a/src/celengine/config.cpp b/src/celengine/config.cpp index f730137a1a..20731692ac 100644 --- a/src/celengine/config.cpp +++ b/src/celengine/config.cpp @@ -2,17 +2,19 @@ #include "property.h" -namespace celengine +namespace celestia +{ +namespace engine { -void Config::setProperty(BaseProperty *p) +void Config::addProperty(IProperty *p) { auto pos = std::find(m_props.begin(), m_props.end(), p); if (pos != m_props.end()) m_props.push_back(p); } -void Config::removeProperty(BaseProperty *p) +void Config::removeProperty(IProperty *p) { auto pos = std::find(m_props.begin(), m_props.end(), p); if (pos != m_props.end()) @@ -46,8 +48,9 @@ void Config::endUpdate() void Config::onUpdate() { - for (auto* p : m_props) + for (auto p : m_props) p->update(); } +} } // namespace; diff --git a/src/celengine/config.h b/src/celengine/config.h index be3b2b5e6a..06b0957231 100644 --- a/src/celengine/config.h +++ b/src/celengine/config.h @@ -4,31 +4,49 @@ #include #include #include -#include "parser.h" +#include "value.h" +#include -namespace celengine +namespace celestia { -class BaseProperty; +namespace engine +{ +class IProperty; +class IConfigWriter; class Config { public: - void setProperty(BaseProperty*); - void removeProperty(BaseProperty*); +// using SharedPtr = std::shared_ptr; + typedef std::shared_ptr SharedPtr; + + void addProperty(IProperty*); + void removeProperty(IProperty*); const Value operator[](const std::string& name); + private: + struct Cmp + { + bool operator()(const std::string &a, const std::string &b) + { + return compareIgnoringCase(a, b) == 0; + } + }; + + void onUpdate(); void beginUpdate(); void set(const std::string& name, const Value& value); void endUpdate(); - private: - void onUpdate(); - - std::vector m_props; - std::map m_values; + std::vector m_props; + std::map m_values; bool m_update { false }; + + friend class IConfigWriter; + friend class IProperty; }; +} } // namespace; diff --git a/src/celengine/property.cpp b/src/celengine/property.cpp new file mode 100644 index 0000000000..8fdc63a811 --- /dev/null +++ b/src/celengine/property.cpp @@ -0,0 +1,28 @@ +#include "property.h" + + +namespace celestia +{ +namespace engine +{ + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getNumber(); +} + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getString(); +} + +template<> +void Property::update() +{ + m_value = (*m_config)[m_name].getBoolean(); +} + +} +} // namespace; diff --git a/src/celengine/property.h b/src/celengine/property.h index 59ffb3f05c..ce0684ba94 100644 --- a/src/celengine/property.h +++ b/src/celengine/property.h @@ -5,9 +5,12 @@ #include "parser.h" -namespace celengine +namespace celestia { -class BaseProperty +namespace engine +{ + +class IProperty { public: virtual void update() = 0; @@ -15,7 +18,7 @@ class BaseProperty }; template -class Property : BaseProperty +class Property : IProperty { public: Property() = default; @@ -24,7 +27,7 @@ class Property : BaseProperty m_config(std::move(config)), m_name(std::move(name)) { - m_config->setProperty(this); + m_config->addProperty(this); }; Property(std::shared_ptr config, std::string name, T value) : @@ -32,9 +35,13 @@ class Property : BaseProperty m_name(std::move(name)), m_value(std::move(value)) { + m_config->addProperty(this); }; - ~Property(); + ~Property() + { + m_config->removeProperty(this); + }; // Getters and setters inline Property& set(T value) @@ -71,6 +78,7 @@ class Property : BaseProperty T m_value {}; }; +/* template<> void Property::update() { @@ -88,11 +96,11 @@ void Property::update() { m_value = (*m_config)[m_name].getBoolean(); } +*/ -template -Property::~Property() -{ - m_config->removeProperty(*this); -} +using NumericProperty = Property; +using StringProperty = Property; +using BoolProperty = Property; +} } // namespace; diff --git a/src/celengine/testprops.cc b/src/celengine/testprops.cc new file mode 100644 index 0000000000..a0ceceff5a --- /dev/null +++ b/src/celengine/testprops.cc @@ -0,0 +1,29 @@ +#include "property.h" +#include + +using namespace celestia::engine; +using namespace std; + +class Foo +{ + Property m_p1; + shared_ptr m_cfg; + + public: + Foo(shared_ptr c): + m_cfg(move(c)) + { + m_p1 = Property(m_cfg, "P1", 10.5); + } + double p1() + { + return m_p1.get(); + } +}; + +int main() +{ + auto c = make_shared(); + Foo f(c); + cout << f.p1(); +} diff --git a/src/celengine/value.cpp b/src/celengine/value.cpp new file mode 100644 index 0000000000..4df10f8e75 --- /dev/null +++ b/src/celengine/value.cpp @@ -0,0 +1,118 @@ +// value.cpp +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#include "value.h" + +namespace celestia +{ +namespace engine +{ + +/****** Value method implementations *******/ + +Value::Value(double d) +{ + type = NumberType; + data.d = d; +} + +Value::Value(const std::string& s) +{ + type = StringType; + data.s = new std::string(s); +} + +Value::Value(ValueArray* a) +{ + type = ArrayType; + data.a = a; +} + +Value::Value(Hash* h) +{ + type = HashType; + data.h = h; +} + +Value::Value(bool b) +{ + type = BooleanType; + data.d = b ? 1.0 : 0.0; +} + +Value::~Value() +{ + if (type == StringType) + { + delete data.s; + } + else if (type == ArrayType) + { + if (data.a != nullptr) + { + for (unsigned int i = 0; i < data.a->size(); i++) + delete (*data.a)[i]; + delete data.a; + } + } + else if (type == HashType) + { + if (data.h != nullptr) + { +#if 0 + Hash::iterator iter = data.h->begin(); + while (iter != data.h->end()) + { + delete iter->second; + iter++; + } +#endif + delete data.h; + } + } +} + +Value::ValueType Value::getType() const +{ + return type; +} + +double Value::getNumber() const +{ + // ASSERT(type == NumberType); + return data.d; +} + +std::string Value::getString() const +{ + // ASSERT(type == StringType); + return *data.s; +} + +ValueArray* Value::getArray() const +{ + // ASSERT(type == ArrayType); + return data.a; +} + +Hash* Value::getHash() const +{ + // ASSERT(type == HashType); + return data.h; +} + +bool Value::getBoolean() const +{ + // ASSERT(type == BooleanType); + return (data.d != 0.0); +} + +} +} diff --git a/src/celengine/value.h b/src/celengine/value.h new file mode 100644 index 0000000000..8d3497cf37 --- /dev/null +++ b/src/celengine/value.h @@ -0,0 +1,72 @@ +// value.h +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#pragma once + +#include +#include + +namespace celestia +{ +namespace engine +{ + +class Value; +class AssociativeArray; + +typedef std::vector Array; +typedef std::vector ValueArray; +typedef AssociativeArray Hash; + +class Value +{ + public: + enum ValueType + { + NullType = 0, + NumberType = 1, + StringType = 2, + ArrayType = 3, + HashType = 4, + BooleanType = 5 + }; + + Value(double); + Value(const std::string&); + Value(ValueArray*); + Value(Hash*); + Value(bool); + Value() = default; + ~Value(); + + ValueType getType() const; + + bool isNull() const; + double getNumber() const; + std::string getString() const; + ValueArray* getArray() const; + Hash* getHash() const; + bool getBoolean() const; + + private: + union Data + { + std::string* s; + double d; + ValueArray* a; + Hash* h; + }; + + ValueType type{ NullType }; + Data data; +}; + +} +} From 9e918f1a50bd71ca6717ed9154df3df96a7756e3 Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Mon, 2 Sep 2019 20:37:24 +0300 Subject: [PATCH 04/11] wip --- src/celengine/config.cpp | 56 ------------------- src/celengine/config.h | 52 ------------------ src/celengine/configuration.cpp | 97 +++++++++++++++++++++++++++++++++ src/celengine/configuration.h | 78 ++++++++++++++++++++++++++ src/celengine/property.cpp | 14 ++++- src/celengine/property.h | 42 +++----------- src/celengine/testprops.cc | 64 ++++++++++++++++++++-- 7 files changed, 252 insertions(+), 151 deletions(-) delete mode 100644 src/celengine/config.cpp delete mode 100644 src/celengine/config.h create mode 100644 src/celengine/configuration.cpp create mode 100644 src/celengine/configuration.h diff --git a/src/celengine/config.cpp b/src/celengine/config.cpp deleted file mode 100644 index 20731692ac..0000000000 --- a/src/celengine/config.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "config.h" -#include "property.h" - - -namespace celestia -{ -namespace engine -{ - -void Config::addProperty(IProperty *p) -{ - auto pos = std::find(m_props.begin(), m_props.end(), p); - if (pos != m_props.end()) - m_props.push_back(p); -} - -void Config::removeProperty(IProperty *p) -{ - auto pos = std::find(m_props.begin(), m_props.end(), p); - if (pos != m_props.end()) - m_props.erase(pos); -} - -const Value Config::operator[](const std::string& name) -{ - auto pos = m_values.find(name); - if (pos != m_values.end()) - return pos->second; - - return Value(); -} - -void Config::beginUpdate() -{ - m_update = true; -} - -void Config::set(const std::string& name, const Value& value) -{ - m_values[name] = value; -} - -void Config::endUpdate() -{ - m_update = false; - onUpdate(); -} - -void Config::onUpdate() -{ - for (auto p : m_props) - p->update(); -} - -} -} // namespace; diff --git a/src/celengine/config.h b/src/celengine/config.h deleted file mode 100644 index 06b0957231..0000000000 --- a/src/celengine/config.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include "value.h" -#include - - -namespace celestia -{ -namespace engine -{ -class IProperty; -class IConfigWriter; - -class Config -{ - public: -// using SharedPtr = std::shared_ptr; - typedef std::shared_ptr SharedPtr; - - void addProperty(IProperty*); - void removeProperty(IProperty*); - const Value operator[](const std::string& name); - - private: - struct Cmp - { - bool operator()(const std::string &a, const std::string &b) - { - return compareIgnoringCase(a, b) == 0; - } - }; - - void onUpdate(); - void beginUpdate(); - void set(const std::string& name, const Value& value); - void endUpdate(); - - std::vector m_props; - std::map m_values; - - bool m_update { false }; - - friend class IConfigWriter; - friend class IProperty; -}; - -} -} // namespace; diff --git a/src/celengine/configuration.cpp b/src/celengine/configuration.cpp new file mode 100644 index 0000000000..ff6a30d208 --- /dev/null +++ b/src/celengine/configuration.cpp @@ -0,0 +1,97 @@ +#include "configuration.h" +#include "property.h" +#include +#include + + +namespace celestia +{ +namespace engine +{ + +#ifdef DEBUG +void Config::dump() const +{ + for (const auto &m : m_values) + { + std::cout << m.first << ' '; + auto d = m.second; + std::cout << d->getType() << ' '; + switch (d->getType()) + { + case Value::NullType: + std::cout << "null"; + break; + case Value::NumberType: + std::cout << d->getNumber(); + break; + case Value::StringType: + std::cout << d->getString(); + break; + case Value::BooleanType: + std::cout << d->getBoolean(); + break; + default: + std::cout << "not supported yet"; + break; + } + std::cout << '\n'; + } +} +#endif + +void Config::addProperty(IProperty *p) +{ + if (std::find(m_props.begin(), m_props.end(), p) == m_props.end()) + m_props.push_back(p); + p->update(); +} + +void Config::removeProperty(IProperty *p) +{ + auto pos = std::find(m_props.begin(), m_props.end(), p); + if (pos != m_props.end()) + m_props.erase(pos); +} + +const Value* Config::find(const std::string& name) const +{ + static Value v; + + auto it = m_values.find(name); + if (it != m_values.end()) + return it->second; + + return &v; +} + +void Config::beginUpdate() +{ + m_update = true; +} + +void Config::set(const std::string& name, const Value* value) +{ + m_values[name] = value; +} + +void Config::endUpdate() +{ + m_update = false; + onUpdate(); +} + +void Config::onUpdate() +{ + for (auto *p : m_props) + p->update(); +} + +Config::~Config() +{ + for (const auto &p : m_values) + delete p.second; +} + +} +} // namespace; diff --git a/src/celengine/configuration.h b/src/celengine/configuration.h new file mode 100644 index 0000000000..bae873514a --- /dev/null +++ b/src/celengine/configuration.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include +#include +#include "value.h" +#include + + +namespace celestia +{ +namespace engine +{ +class IConfigUpdater; +class IConfigWriter; +class IProperty; + +class Config +{ + public: + Config() = default; + Config(const Config&) = delete; + Config(Config&&) = delete; + ~Config(); + + Config& operator=(const Config&) = delete; + Config& operator=(Config&&) = delete; + + void addProperty(IProperty*); + void removeProperty(IProperty*); + const Value* find(const std::string& name) const; + +#ifdef DEBUG + void dump() const; +#else + void dump() const {}; +#endif + + private: + struct Cmp + { + bool operator()(const std::string &a, const std::string &b) const + { + return compareIgnoringCase(a, b) < 0; + } + }; + + void onUpdate(); + void beginUpdate(); + void set(const std::string& name, const Value *value); + void endUpdate(); + + std::vector m_props; + std::map m_values; + + bool m_update { false }; + + friend class IConfigUpdater; + friend class IConfigWriter; + friend class IProperty; +}; + + +// Proxy class to invoke private Config's methods from derived classes +class IConfigUpdater +{ + std::shared_ptr m_cfg; + public: + IConfigUpdater(const std::shared_ptr &cfg) : m_cfg(cfg) {} + inline void beginUpdate() { m_cfg->beginUpdate(); } + inline void set(const std::string &name, Value *value) { m_cfg->set(name, value); } + inline void endUpdate() { m_cfg->endUpdate(); } +}; + + +} +} // namespace; diff --git a/src/celengine/property.cpp b/src/celengine/property.cpp index 8fdc63a811..e07efe50b6 100644 --- a/src/celengine/property.cpp +++ b/src/celengine/property.cpp @@ -6,23 +6,31 @@ namespace celestia namespace engine { +#define PROPERTY_UPDATE(ValueType) \ + auto v = m_config->find(m_name); \ + m_has_value = v->getType() == Value:: ValueType ## Type; \ + if (m_has_value) \ + m_value = v->get ## ValueType (); \ + template<> void Property::update() { - m_value = (*m_config)[m_name].getNumber(); + PROPERTY_UPDATE(Number); } template<> void Property::update() { - m_value = (*m_config)[m_name].getString(); + PROPERTY_UPDATE(String); } template<> void Property::update() { - m_value = (*m_config)[m_name].getBoolean(); + PROPERTY_UPDATE(Boolean); } +#undef PROPERTY_UPDATE + } } // namespace; diff --git a/src/celengine/property.h b/src/celengine/property.h index ce0684ba94..3de9258ce5 100644 --- a/src/celengine/property.h +++ b/src/celengine/property.h @@ -1,8 +1,7 @@ #pragma once #include -#include "config.h" -#include "parser.h" +#include "configuration.h" namespace celestia @@ -23,17 +22,10 @@ class Property : IProperty public: Property() = default; - Property(std::shared_ptr config, std::string name) : - m_config(std::move(config)), - m_name(std::move(name)) - { - m_config->addProperty(this); - }; - - Property(std::shared_ptr config, std::string name, T value) : + Property(std::shared_ptr config, std::string name, T def) : m_config(std::move(config)), m_name(std::move(name)), - m_value(std::move(value)) + m_default(std::move(def)) { m_config->addProperty(this); }; @@ -61,7 +53,7 @@ class Property : IProperty T get() const { - return m_value; + return m_has_value ? m_value : m_default; }; T operator()() const @@ -73,31 +65,13 @@ class Property : IProperty void update() override; private: - std::shared_ptr m_config { nullptr }; + std::shared_ptr m_config { nullptr }; std::string m_name; - T m_value {}; + T m_value {}; + T m_default {}; + bool m_has_value { false }; }; -/* -template<> -void Property::update() -{ - m_value = (*m_config)[m_name].getNumber(); -} - -template<> -void Property::update() -{ - m_value = (*m_config)[m_name].getString(); -} - -template<> -void Property::update() -{ - m_value = (*m_config)[m_name].getBoolean(); -} -*/ - using NumericProperty = Property; using StringProperty = Property; using BoolProperty = Property; diff --git a/src/celengine/testprops.cc b/src/celengine/testprops.cc index a0ceceff5a..179794fa18 100644 --- a/src/celengine/testprops.cc +++ b/src/celengine/testprops.cc @@ -1,29 +1,81 @@ #include "property.h" #include +#include using namespace celestia::engine; using namespace std; +class myconfig : IConfigUpdater +{ + public: + myconfig(const std::shared_ptr &cfg) : IConfigUpdater(cfg) {} + void read(); +}; + +void myconfig::read() +{ + beginUpdate(); + auto *v1 = new Value(10.18); + set("Distance", v1); + auto *v2 = new Value(std::string("foobar")); + set("Name", v2); + auto *v3 = new Value(true); + set("Visible", v3); + endUpdate(); +} + class Foo { - Property m_p1; - shared_ptr m_cfg; + Property m_p1; + NumericProperty m_distance; + StringProperty m_name, m_type; + BoolProperty m_visible; + shared_ptr m_cfg; public: - Foo(shared_ptr c): - m_cfg(move(c)) + Foo(const shared_ptr &cfg): + m_cfg (cfg), + m_p1 (Property(cfg, "P1", 10.5)), + m_distance (NumericProperty(cfg, "distance", 55.1)), + m_name (StringProperty(cfg, "name", "baz")), + m_type (StringProperty(cfg, "type", "baz")), + m_visible (BoolProperty(cfg, "visible", false)) { - m_p1 = Property(m_cfg, "P1", 10.5); } double p1() { return m_p1.get(); } + double distance() + { + return m_distance(); + } + string name() + { + return m_name(); + } + string type() + { + return m_type(); + } + bool visible() + { + return m_visible(); + } }; int main() { auto c = make_shared(); + myconfig my(c); + my.read(); + c->dump(); Foo f(c); - cout << f.p1(); + cout << f.p1() << ' ' << f.distance() << ' ' << f.name() << ' ' << f.type() << ' ' << f.visible() << '\n'; + auto *v = c->find("Name"); + if (v->getType() == Value::StringType) + cout << v->getString() << '\n'; + else + cout << "dunno\n"; + c->dump(); } From 3dc73080431576a9e6e2ab9c23f02f8c0b06e6dc Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Tue, 30 Jul 2019 23:50:41 +0300 Subject: [PATCH 05/11] Revert parser changes This reverts commit d37f2e7dd60c22818ad4e044f8becedb798eb9dd. # Conflicts: # src/celengine/config.h # src/celengine/property.h --- src/celengine/parser.h | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/celengine/parser.h b/src/celengine/parser.h index 5d7a350e00..a5d66250b1 100644 --- a/src/celengine/parser.h +++ b/src/celengine/parser.h @@ -72,15 +72,13 @@ typedef AssociativeArray Hash; class Value { - public: - enum ValueType - { - NullType = 0, - NumberType = 1, - StringType = 2, - ArrayType = 3, - HashType = 4, - BooleanType = 5 +public: + enum ValueType { + NumberType = 0, + StringType = 1, + ArrayType = 2, + HashType = 3, + BooleanType = 4 }; Value(double); @@ -88,29 +86,25 @@ class Value Value(ValueArray*); Value(Hash*); Value(bool); - Value() = default; ~Value(); ValueType getType() const; - bool isNull() const; double getNumber() const; string getString() const; ValueArray* getArray() const; Hash* getHash() const; bool getBoolean() const; - private: - union Data - { +private: + ValueType type; + + union { string* s; double d; ValueArray* a; Hash* h; - }; - - ValueType type{ NullType }; - Data data; + } data; }; From c3a05441916ff2074f0ee9389ad1954788757e6c Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Tue, 3 Sep 2019 16:22:42 +0300 Subject: [PATCH 06/11] add validator, refactor value.* and other changes --- src/celengine/property.cpp | 7 ++- src/celengine/property.h | 20 +++++--- src/celengine/testprops.cc | 12 ++--- src/celengine/value.cpp | 93 ++++++-------------------------------- src/celengine/value.h | 87 +++++++++++++++++++++++++++-------- 5 files changed, 107 insertions(+), 112 deletions(-) diff --git a/src/celengine/property.cpp b/src/celengine/property.cpp index e07efe50b6..5fbb242b86 100644 --- a/src/celengine/property.cpp +++ b/src/celengine/property.cpp @@ -10,7 +10,12 @@ namespace engine auto v = m_config->find(m_name); \ m_has_value = v->getType() == Value:: ValueType ## Type; \ if (m_has_value) \ - m_value = v->get ## ValueType (); \ + { \ + if (m_validate != nullptr) \ + m_value = m_validate(v->get ## ValueType ()); \ + else \ + m_value = v->get ## ValueType (); \ + } template<> void Property::update() diff --git a/src/celengine/property.h b/src/celengine/property.h index 3de9258ce5..82ba131429 100644 --- a/src/celengine/property.h +++ b/src/celengine/property.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include #include "configuration.h" @@ -20,19 +22,24 @@ template class Property : IProperty { public: + using validate_fn_t = std::function; + Property() = default; - Property(std::shared_ptr config, std::string name, T def) : - m_config(std::move(config)), - m_name(std::move(name)), - m_default(std::move(def)) + Property(std::shared_ptr config, std::string name, T _default, validate_fn_t validate = nullptr) : + m_config (std::move(config)), + m_name (std::move(name)), + m_default (std::move(_default)), + m_validate (std::move(validate)) { + assert(m_config != nullptr); m_config->addProperty(this); }; ~Property() { - m_config->removeProperty(this); + if (m_config != nullptr) + m_config->removeProperty(this); }; // Getters and setters @@ -70,11 +77,12 @@ class Property : IProperty T m_value {}; T m_default {}; bool m_has_value { false }; + validate_fn_t m_validate { nullptr }; }; using NumericProperty = Property; using StringProperty = Property; -using BoolProperty = Property; +using BooleanProperty = Property; } } // namespace; diff --git a/src/celengine/testprops.cc b/src/celengine/testprops.cc index 179794fa18..1c035d45d5 100644 --- a/src/celengine/testprops.cc +++ b/src/celengine/testprops.cc @@ -15,11 +15,11 @@ class myconfig : IConfigUpdater void myconfig::read() { beginUpdate(); - auto *v1 = new Value(10.18); + auto *v1 = new Value(10.18); set("Distance", v1); - auto *v2 = new Value(std::string("foobar")); + auto *v2 = new Value(std::string("foobar")); set("Name", v2); - auto *v3 = new Value(true); + auto *v3 = new Value(true); set("Visible", v3); endUpdate(); } @@ -29,17 +29,17 @@ class Foo Property m_p1; NumericProperty m_distance; StringProperty m_name, m_type; - BoolProperty m_visible; + BooleanProperty m_visible; shared_ptr m_cfg; public: Foo(const shared_ptr &cfg): m_cfg (cfg), m_p1 (Property(cfg, "P1", 10.5)), - m_distance (NumericProperty(cfg, "distance", 55.1)), + m_distance (NumericProperty(cfg, "distance", 55.1, [](const double &v){ return v > 0 ? -v : v; })), m_name (StringProperty(cfg, "name", "baz")), m_type (StringProperty(cfg, "type", "baz")), - m_visible (BoolProperty(cfg, "visible", false)) + m_visible (BooleanProperty(cfg, "visible", false)) { } double p1() diff --git a/src/celengine/value.cpp b/src/celengine/value.cpp index 4df10f8e75..f1517f3734 100644 --- a/src/celengine/value.cpp +++ b/src/celengine/value.cpp @@ -17,102 +17,37 @@ namespace engine /****** Value method implementations *******/ -Value::Value(double d) -{ - type = NumberType; - data.d = d; -} - -Value::Value(const std::string& s) -{ - type = StringType; - data.s = new std::string(s); -} - -Value::Value(ValueArray* a) -{ - type = ArrayType; - data.a = a; -} - -Value::Value(Hash* h) -{ - type = HashType; - data.h = h; -} - -Value::Value(bool b) -{ - type = BooleanType; - data.d = b ? 1.0 : 0.0; -} - Value::~Value() { - if (type == StringType) + switch (type) { + case StringType: delete data.s; - } - else if (type == ArrayType) - { + break; + case ArrayType: if (data.a != nullptr) { - for (unsigned int i = 0; i < data.a->size(); i++) - delete (*data.a)[i]; + for (auto *p : *data.a) + delete p; delete data.a; } - } - else if (type == HashType) - { + break; + case HashType: if (data.h != nullptr) { -#if 0 - Hash::iterator iter = data.h->begin(); - while (iter != data.h->end()) +#if 0 // TODO: fixme + for (const auto &t : *data.h) { - delete iter->second; - iter++; + delete t.second; } #endif delete data.h; } + break; + default: + break; } } -Value::ValueType Value::getType() const -{ - return type; -} - -double Value::getNumber() const -{ - // ASSERT(type == NumberType); - return data.d; -} - -std::string Value::getString() const -{ - // ASSERT(type == StringType); - return *data.s; -} - -ValueArray* Value::getArray() const -{ - // ASSERT(type == ArrayType); - return data.a; -} - -Hash* Value::getHash() const -{ - // ASSERT(type == HashType); - return data.h; -} - -bool Value::getBoolean() const -{ - // ASSERT(type == BooleanType); - return (data.d != 0.0); -} - } } diff --git a/src/celengine/value.h b/src/celengine/value.h index 8d3497cf37..30f09c9d28 100644 --- a/src/celengine/value.h +++ b/src/celengine/value.h @@ -10,6 +10,7 @@ #pragma once +#include #include #include @@ -21,9 +22,8 @@ namespace engine class Value; class AssociativeArray; -typedef std::vector Array; -typedef std::vector ValueArray; -typedef AssociativeArray Hash; +using Array = std::vector; +using Hash = AssociativeArray; class Value { @@ -38,33 +38,80 @@ class Value BooleanType = 5 }; - Value(double); - Value(const std::string&); - Value(ValueArray*); - Value(Hash*); - Value(bool); Value() = default; ~Value(); + Value(const Value&) = delete; // TODO: implement + Value(Value&&) = delete; // TODO: implement - ValueType getType() const; + Value(double d) : type(NumberType) + { + data.d = d; + } + Value(const char *s) : type(StringType) + { + data.s = new std::string(s); + } + explicit Value(const std::string &s) : type(StringType) + { + data.s = new std::string(s); + } + Value(Array *a) : type(ArrayType) + { + data.a = a; + } + Value(Hash *h) : type(HashType) + { + data.h = h; + } + Value(bool b) : type(BooleanType) + { + data.d = b ? 1.0 : 0.0; + } - bool isNull() const; - double getNumber() const; - std::string getString() const; - ValueArray* getArray() const; - Hash* getHash() const; - bool getBoolean() const; + ValueType getType() const + { + return type; + } + bool isNull() const + { + return type == NullType; + } + double getNumber() const + { + assert(type == NumberType); + return data.d; + } + std::string getString() const + { + assert(type == StringType); + return *data.s; + } + Array* getArray() const + { + assert(type == ArrayType); + return data.a; + } + Hash* getHash() const + { + assert(type == HashType); + return data.h; + } + bool getBoolean() const + { + assert(type == BooleanType); + return (data.d != 0.0); + } private: union Data { - std::string* s; - double d; - ValueArray* a; - Hash* h; + std::string *s; + double d; + Array *a; + Hash *h; }; - ValueType type{ NullType }; + ValueType type { NullType }; Data data; }; From 42bac080effe35f62323239d997ddd189a94dc7f Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Tue, 3 Sep 2019 16:52:42 +0300 Subject: [PATCH 07/11] Remove unneeded #include --- src/celengine/astro.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/celengine/astro.cpp b/src/celengine/astro.cpp index bdc687707e..52dea5683d 100644 --- a/src/celengine/astro.cpp +++ b/src/celengine/astro.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include "astro.h" #include "univcoord.h" #include From d06e160acb72ec5e659ed131aff671b795715418 Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Tue, 3 Sep 2019 16:53:41 +0300 Subject: [PATCH 08/11] Add Hash class --- src/celengine/hash.cpp | 508 ++++++++++++++++++++++++++++++++++++++++ src/celengine/hash.h | 81 +++++++ src/celengine/value.cpp | 11 +- src/celengine/value.h | 4 +- 4 files changed, 591 insertions(+), 13 deletions(-) create mode 100644 src/celengine/hash.cpp create mode 100644 src/celengine/hash.h diff --git a/src/celengine/hash.cpp b/src/celengine/hash.cpp new file mode 100644 index 0000000000..29c77c8ac6 --- /dev/null +++ b/src/celengine/hash.cpp @@ -0,0 +1,508 @@ +// hash.cpp +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#include +#include +#include "astro.h" +#include "hash.h" +#include "value.h" + +using namespace Eigen; +using namespace std; +using namespace celmath; + +namespace celestia +{ +namespace engine +{ + + +AssociativeArray::~AssociativeArray() +{ + for (const auto &t : assoc) + delete t.second; +} + +Value* AssociativeArray::getValue(const string& key) const +{ + auto iter = assoc.find(key); + if (iter == assoc.end()) + return nullptr; + + return iter->second; +} + +void AssociativeArray::addValue(const string& key, Value& val) +{ + assoc.insert(map::value_type(key, &val)); +} + +bool AssociativeArray::getNumber(const string& key, double& val) const +{ + Value* v = getValue(key); + if (v == nullptr || v->getType() != Value::NumberType) + return false; + + val = v->getNumber(); + return true; +} + +bool AssociativeArray::getNumber(const string& key, float& val) const +{ + double dval; + + if (!getNumber(key, dval)) + return false; + + val = (float) dval; + return true; +} + +bool AssociativeArray::getNumber(const string& key, int& val) const +{ + double ival; + + if (!getNumber(key, ival)) + return false; + + val = (int) ival; + return true; +} + +bool AssociativeArray::getNumber(const string& key, uint32_t& val) const +{ + double ival; + + if (!getNumber(key, ival)) + return false; + + val = (uint32_t) ival; + return true; +} + +bool AssociativeArray::getString(const string& key, string& val) const +{ + Value* v = getValue(key); + if (v == nullptr || v->getType() != Value::StringType) + return false; + + val = v->getString(); + return true; +} + +bool AssociativeArray::getBoolean(const string& key, bool& val) const +{ + Value* v = getValue(key); + if (v == nullptr || v->getType() != Value::BooleanType) + return false; + + val = v->getBoolean(); + return true; +} + +bool AssociativeArray::getVector(const string& key, Vector3d& val) const +{ + Value* v = getValue(key); + if (v == nullptr || v->getType() != Value::ArrayType) + return false; + + Array* arr = v->getArray(); + if (arr->size() != 3) + return false; + + Value* x = (*arr)[0]; + Value* y = (*arr)[1]; + Value* z = (*arr)[2]; + + if (x->getType() != Value::NumberType || + y->getType() != Value::NumberType || + z->getType() != Value::NumberType) + return false; + + val = Vector3d(x->getNumber(), y->getNumber(), z->getNumber()); + return true; +} + + +bool AssociativeArray::getVector(const string& key, Vector3f& val) const +{ + Vector3d vecVal; + + if (!getVector(key, vecVal)) + return false; + + val = vecVal.cast(); + return true; +} + + +/** + * Retrieves a quaternion, scaled to an associated angle unit. + * + * The quaternion is specified in the catalog file in axis-angle format as follows: + * \verbatim {PropertyName} [ angle axisX axisY axisZ ] \endverbatim + * + * @param[in] key Hash key for the rotation. + * @param[out] val A quaternion representing the value if present, unaffected if not. + * @return True if the key exists in the hash, false otherwise. + */ +bool AssociativeArray::getRotation(const string& key, Eigen::Quaternionf& val) const +{ + Value* v = getValue(key); + if (v == nullptr || v->getType() != Value::ArrayType) + return false; + + Array* arr = v->getArray(); + if (arr->size() != 4) + return false; + + Value* w = (*arr)[0]; + Value* x = (*arr)[1]; + Value* y = (*arr)[2]; + Value* z = (*arr)[3]; + + if (w->getType() != Value::NumberType || + x->getType() != Value::NumberType || + y->getType() != Value::NumberType || + z->getType() != Value::NumberType) + return false; + + Vector3f axis((float) x->getNumber(), + (float) y->getNumber(), + (float) z->getNumber()); + + double ang = w->getNumber(); + double angScale = 1.0; + getAngleScale(key, angScale); + float angle = degToRad((float) (ang * angScale)); + + val = Quaternionf(AngleAxisf(angle, axis.normalized())); + + return true; +} + + +bool AssociativeArray::getColor(const string& key, Color& val) const +{ + Vector3d vecVal; + + if (!getVector(key, vecVal)) + return false; + + val = Color((float) vecVal.x(), (float) vecVal.y(), (float) vecVal.z()); + + return true; +} + + +/** + * Retrieves a numeric quantity scaled to an associated angle unit. + * @param[in] key Hash key for the quantity. + * @param[out] val The returned quantity if present, unaffected if not. + * @param[in] outputScale Returned value is scaled to this value. + * @param[in] defaultScale If no units are specified, use this scale. Defaults to outputScale. + * @return True if the key exists in the hash, false otherwise. + */ +bool +AssociativeArray::getAngle(const string& key, double& val, double outputScale, double defaultScale) const +{ + if (!getNumber(key, val)) + return false; + + double angleScale; + if(getAngleScale(key, angleScale)) + { + angleScale /= outputScale; + } + else + { + angleScale = (defaultScale == 0.0) ? 1.0 : defaultScale / outputScale; + } + + val *= angleScale; + + return true; +} + + +/** @copydoc AssociativeArray::getAngle() */ +bool +AssociativeArray::getAngle(const string& key, float& val, double outputScale, double defaultScale) const +{ + double dval; + + if (!getAngle(key, dval, outputScale, defaultScale)) + return false; + + val = ((float) dval); + + return true; +} + + +/** + * Retrieves a numeric quantity scaled to an associated length unit. + * @param[in] key Hash key for the quantity. + * @param[out] val The returned quantity if present, unaffected if not. + * @param[in] outputScale Returned value is scaled to this value. + * @param[in] defaultScale If no units are specified, use this scale. Defaults to outputScale. + * @return True if the key exists in the hash, false otherwise. + */ +bool +AssociativeArray::getLength(const string& key, double& val, double outputScale, double defaultScale) const +{ + if(!getNumber(key, val)) + return false; + + double lengthScale; + if(getLengthScale(key, lengthScale)) + { + lengthScale /= outputScale; + } + else + { + lengthScale = (defaultScale == 0.0) ? 1.0 : defaultScale / outputScale; + } + + val *= lengthScale; + + return true; +} + + +/** @copydoc AssociativeArray::getLength() */ +bool AssociativeArray::getLength(const string& key, float& val, double outputScale, double defaultScale) const +{ + double dval; + + if (!getLength(key, dval, outputScale, defaultScale)) + return false; + + val = ((float) dval); + + return true; +} + + +/** + * Retrieves a numeric quantity scaled to an associated time unit. + * @param[in] key Hash key for the quantity. + * @param[out] val The returned quantity if present, unaffected if not. + * @param[in] outputScale Returned value is scaled to this value. + * @param[in] defaultScale If no units are specified, use this scale. Defaults to outputScale. + * @return True if the key exists in the hash, false otherwise. + */ +bool AssociativeArray::getTime(const string& key, double& val, double outputScale, double defaultScale) const +{ + if(!getNumber(key, val)) + return false; + + double timeScale; + if(getTimeScale(key, timeScale)) + { + timeScale /= outputScale; + } + else + { + timeScale = (defaultScale == 0.0) ? 1.0 : defaultScale / outputScale; + } + + val *= timeScale; + + return true; +} + + +/** @copydoc AssociativeArray::getTime() */ +bool AssociativeArray::getTime(const string& key, float& val, double outputScale, double defaultScale) const +{ + double dval; + + if(!getLength(key, dval, outputScale, defaultScale)) + return false; + + val = ((float) dval); + + return true; +} + + +/** + * Retrieves a vector quantity scaled to an associated length unit. + * @param[in] key Hash key for the quantity. + * @param[out] val The returned vector if present, unaffected if not. + * @param[in] outputScale Returned value is scaled to this value. + * @param[in] defaultScale If no units are specified, use this scale. Defaults to outputScale. + * @return True if the key exists in the hash, false otherwise. + */ +bool AssociativeArray::getLengthVector(const string& key, Eigen::Vector3d& val, double outputScale, double defaultScale) const +{ + if(!getVector(key, val)) + return false; + + double lengthScale; + if(getLengthScale(key, lengthScale)) + { + lengthScale /= outputScale; + } + else + { + lengthScale = (defaultScale == 0.0) ? 1.0 : defaultScale / outputScale; + } + + val *= lengthScale; + + return true; +} + + +/** @copydoc AssociativeArray::getLengthVector() */ +bool AssociativeArray::getLengthVector(const string& key, Eigen::Vector3f& val, double outputScale, double defaultScale) const +{ + Vector3d vecVal; + + if(!getLengthVector(key, vecVal, outputScale, defaultScale)) + return false; + + val = vecVal.cast(); + return true; +} + + +/** + * Retrieves a spherical tuple \verbatim [longitude, latitude, altitude] \endverbatim scaled to associated angle and length units. + * @param[in] key Hash key for the quantity. + * @param[out] val The returned tuple in units of degrees and kilometers if present, unaffected if not. + * @return True if the key exists in the hash, false otherwise. + */ +bool AssociativeArray::getSphericalTuple(const string& key, Vector3d& val) const +{ + if(!getVector(key, val)) + return false; + + double angleScale; + if(getAngleScale(key, angleScale)) + { + val[0] *= angleScale; + val[1] *= angleScale; + } + + double lengthScale = 1.0; + getLengthScale(key, lengthScale); + val[2] *= lengthScale; + + return true; +} + + +/** @copydoc AssociativeArray::getSphericalTuple */ +bool AssociativeArray::getSphericalTuple(const string& key, Vector3f& val) const +{ + Vector3d vecVal; + + if(!getSphericalTuple(key, vecVal)) + return false; + + val = vecVal.cast(); + return true; +} + + +/** + * Retrieves the angle unit associated with a given property. + * @param[in] key Hash key for the property. + * @param[out] scale The returned angle unit scaled to degrees if present, unaffected if not. + * @return True if an angle unit has been specified for the property, false otherwise. + */ +bool AssociativeArray::getAngleScale(const string& key, double& scale) const +{ + string unitKey(key + "%Angle"); + string unit; + + if (!getString(unitKey, unit)) + return false; + + return astro::getAngleScale(unit, scale); +} + + +/** @copydoc AssociativeArray::getAngleScale() */ +bool AssociativeArray::getAngleScale(const string& key, float& scale) const +{ + double dscale; + if (!getAngleScale(key, dscale)) + return false; + + scale = ((float) dscale); + return true; +} + + +/** + * Retrieves the length unit associated with a given property. + * @param[in] key Hash key for the property. + * @param[out] scale The returned length unit scaled to kilometers if present, unaffected if not. + * @return True if a length unit has been specified for the property, false otherwise. + */ +bool AssociativeArray::getLengthScale(const string& key, double& scale) const +{ + string unitKey(key + "%Length"); + string unit; + + if (!getString(unitKey, unit)) + return false; + + return astro::getLengthScale(unit, scale); +} + + +/** @copydoc AssociativeArray::getLengthScale() */ +bool AssociativeArray::getLengthScale(const string& key, float& scale) const +{ + double dscale; + if (!getLengthScale(key, dscale)) + return false; + + scale = ((float) dscale); + return true; +} + + +/** + * Retrieves the time unit associated with a given property. + * @param[in] key Hash key for the property. + * @param[out] scale The returned time unit scaled to days if present, unaffected if not. + * @return True if a time unit has been specified for the property, false otherwise. + */ +bool AssociativeArray::getTimeScale(const string& key, double& scale) const +{ + string unitKey(key + "%Time"); + string unit; + + if (!getString(unitKey, unit)) + return false; + + return astro::getTimeScale(unit, scale); +} + + +/** @copydoc AssociativeArray::getTimeScale() */ +bool AssociativeArray::getTimeScale(const string& key, float& scale) const +{ + double dscale; + if (!getTimeScale(key, dscale)) + return false; + + scale = ((float) dscale); + return true; +} + +} +} diff --git a/src/celengine/hash.h b/src/celengine/hash.h new file mode 100644 index 0000000000..8126c24f6b --- /dev/null +++ b/src/celengine/hash.h @@ -0,0 +1,81 @@ +// hash.h +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#pragma once + +#include +#include +#include + + +class Color; + +namespace celestia +{ +namespace engine +{ + +class Value; + +using HashIterator = std::map::const_iterator; + +class AssociativeArray +{ + public: + AssociativeArray() = default; + ~AssociativeArray(); + + Value* getValue(const std::string&) const; + void addValue(const std::string&, Value&); + + bool getNumber(const std::string&, double&) const; + bool getNumber(const std::string&, float&) const; + bool getNumber(const std::string&, int&) const; + bool getNumber(const std::string&, uint32_t&) const; + bool getString(const std::string&, std::string&) const; + bool getBoolean(const std::string&, bool&) const; + bool getVector(const std::string&, Eigen::Vector3d&) const; + bool getVector(const std::string&, Eigen::Vector3f&) const; + bool getRotation(const std::string&, Eigen::Quaternionf&) const; + bool getColor(const std::string&, Color&) const; + bool getAngle(const std::string&, double&, double = 1.0, double = 0.0) const; + bool getAngle(const std::string&, float&, double = 1.0, double = 0.0) const; + bool getLength(const std::string&, double&, double = 1.0, double = 0.0) const; + bool getLength(const std::string&, float&, double = 1.0, double = 0.0) const; + bool getTime(const std::string&, double&, double = 1.0, double = 0.0) const; + bool getTime(const std::string&, float&, double = 1.0, double = 0.0) const; + bool getLengthVector(const std::string&, Eigen::Vector3d&, double = 1.0, double = 0.0) const; + bool getLengthVector(const std::string&, Eigen::Vector3f&, double = 1.0, double = 0.0) const; + bool getSphericalTuple(const std::string&, Eigen::Vector3d&) const; + bool getSphericalTuple(const std::string&, Eigen::Vector3f&) const; + bool getAngleScale(const std::string&, double&) const; + bool getAngleScale(const std::string&, float&) const; + bool getLengthScale(const std::string&, double&) const; + bool getLengthScale(const std::string&, float&) const; + bool getTimeScale(const std::string&, double&) const; + bool getTimeScale(const std::string&, float&) const; + + HashIterator begin() + { + return assoc.begin(); + } + HashIterator end() + { + return assoc.end(); + } + + private: + std::map assoc; +}; + +using Hash = AssociativeArray; + +} +} diff --git a/src/celengine/value.cpp b/src/celengine/value.cpp index f1517f3734..d40bbdf16e 100644 --- a/src/celengine/value.cpp +++ b/src/celengine/value.cpp @@ -33,16 +33,7 @@ Value::~Value() } break; case HashType: - if (data.h != nullptr) - { -#if 0 // TODO: fixme - for (const auto &t : *data.h) - { - delete t.second; - } -#endif - delete data.h; - } + delete data.h; break; default: break; diff --git a/src/celengine/value.h b/src/celengine/value.h index 30f09c9d28..f54c5414b8 100644 --- a/src/celengine/value.h +++ b/src/celengine/value.h @@ -13,6 +13,7 @@ #include #include #include +#include "hash.h" namespace celestia { @@ -20,10 +21,7 @@ namespace engine { class Value; -class AssociativeArray; - using Array = std::vector; -using Hash = AssociativeArray; class Value { From 0d4ec40e71d0807536f8bef48796c26237d88063 Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Tue, 3 Sep 2019 17:10:14 +0300 Subject: [PATCH 09/11] refactor parser.* --- src/celengine/hash.cpp | 6 +- src/celengine/parser.cpp | 614 +-------------------------------------- src/celengine/parser.h | 106 +------ src/celengine/value.cpp | 2 +- src/celengine/value.h | 2 +- 5 files changed, 22 insertions(+), 708 deletions(-) diff --git a/src/celengine/hash.cpp b/src/celengine/hash.cpp index 29c77c8ac6..761eddf96c 100644 --- a/src/celengine/hash.cpp +++ b/src/celengine/hash.cpp @@ -10,9 +10,9 @@ #include #include -#include "astro.h" -#include "hash.h" -#include "value.h" +#include +#include +#include using namespace Eigen; using namespace std; diff --git a/src/celengine/parser.cpp b/src/celengine/parser.cpp index ce24f0fa37..2028c878c0 100644 --- a/src/celengine/parser.cpp +++ b/src/celengine/parser.cpp @@ -1,6 +1,6 @@ // parser.cpp // -// Copyright (C) 2001-2009, the Celestia Development Team +// Copyright (C) 2001-2019, the Celestia Development Team // Original version by Chris Laurel // // This program is free software; you can redistribute it and/or @@ -8,114 +8,16 @@ // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -#include "parser.h" -#include "astro.h" +#include +#include using namespace Eigen; using namespace celmath; - -/****** Value method implementations *******/ - -Value::Value(double d) -{ - type = NumberType; - data.d = d; -} - -Value::Value(const string& s) -{ - type = StringType; - data.s = new string(s); -} - -Value::Value(ValueArray* a) -{ - type = ArrayType; - data.a = a; -} - -Value::Value(Hash* h) -{ - type = HashType; - data.h = h; -} - -Value::Value(bool b) -{ - type = BooleanType; - data.d = b ? 1.0 : 0.0; -} - -Value::~Value() -{ - if (type == StringType) - { - delete data.s; - } - else if (type == ArrayType) - { - if (data.a != nullptr) - { - for (unsigned int i = 0; i < data.a->size(); i++) - delete (*data.a)[i]; - delete data.a; - } - } - else if (type == HashType) - { - if (data.h != nullptr) - { -#if 0 - Hash::iterator iter = data.h->begin(); - while (iter != data.h->end()) - { - delete iter->second; - iter++; - } -#endif - delete data.h; - } - } -} - -Value::ValueType Value::getType() const -{ - return type; -} - -double Value::getNumber() const -{ - // ASSERT(type == NumberType); - return data.d; -} - -string Value::getString() const +namespace celestia { - // ASSERT(type == StringType); - return *data.s; -} - -ValueArray* Value::getArray() const +namespace engine { - // ASSERT(type == ArrayType); - return data.a; -} - -Hash* Value::getHash() const -{ - // ASSERT(type == HashType); - return data.h; -} - -bool Value::getBoolean() const -{ - // ASSERT(type == BooleanType); - return (data.d != 0.0); -} - - -/****** Parser method implementation ******/ Parser::Parser(Tokenizer* _tokenizer) : tokenizer(_tokenizer) @@ -123,7 +25,7 @@ Parser::Parser(Tokenizer* _tokenizer) : } -ValueArray* Parser::readArray() +Array* Parser::readArray() { Tokenizer::TokenType tok = tokenizer->nextToken(); if (tok != Tokenizer::TokenBeginArray) @@ -132,7 +34,7 @@ ValueArray* Parser::readArray() return nullptr; } - auto* array = new ValueArray(); + auto* array = new Array(); Value* v = readValue(); while (v != nullptr) @@ -279,7 +181,7 @@ Value* Parser::readValue() case Tokenizer::TokenBeginArray: tokenizer->pushBack(); { - ValueArray* array = readArray(); + Array* array = readArray(); if (array == nullptr) return nullptr; else @@ -302,505 +204,5 @@ Value* Parser::readValue() } } - -AssociativeArray::~AssociativeArray() -{ -#if 0 - Hash::iterator iter = data.h->begin(); - while (iter != data.h->end()) - { - delete iter->second; - iter++; - } -#endif - for (const auto iter : assoc) - delete iter.second; -} - -Value* AssociativeArray::getValue(const string& key) const -{ - map::const_iterator iter = assoc.find(key); - if (iter == assoc.end()) - return nullptr; - - return iter->second; -} - -void AssociativeArray::addValue(const string& key, Value& val) -{ - assoc.insert(map::value_type(key, &val)); -} - -bool AssociativeArray::getNumber(const string& key, double& val) const -{ - Value* v = getValue(key); - if (v == nullptr || v->getType() != Value::NumberType) - return false; - - val = v->getNumber(); - return true; -} - -bool AssociativeArray::getNumber(const string& key, float& val) const -{ - double dval; - - if (!getNumber(key, dval)) - return false; - - val = (float) dval; - return true; -} - -bool AssociativeArray::getNumber(const string& key, int& val) const -{ - double ival; - - if (!getNumber(key, ival)) - return false; - - val = (int) ival; - return true; -} - -bool AssociativeArray::getNumber(const string& key, uint32_t& val) const -{ - double ival; - - if (!getNumber(key, ival)) - return false; - - val = (uint32_t) ival; - return true; -} - -bool AssociativeArray::getString(const string& key, string& val) const -{ - Value* v = getValue(key); - if (v == nullptr || v->getType() != Value::StringType) - return false; - - val = v->getString(); - return true; -} - -bool AssociativeArray::getBoolean(const string& key, bool& val) const -{ - Value* v = getValue(key); - if (v == nullptr || v->getType() != Value::BooleanType) - return false; - - val = v->getBoolean(); - return true; -} - -bool AssociativeArray::getVector(const string& key, Vector3d& val) const -{ - Value* v = getValue(key); - if (v == nullptr || v->getType() != Value::ArrayType) - return false; - - ValueArray* arr = v->getArray(); - if (arr->size() != 3) - return false; - - Value* x = (*arr)[0]; - Value* y = (*arr)[1]; - Value* z = (*arr)[2]; - - if (x->getType() != Value::NumberType || - y->getType() != Value::NumberType || - z->getType() != Value::NumberType) - return false; - - val = Vector3d(x->getNumber(), y->getNumber(), z->getNumber()); - return true; -} - - -bool AssociativeArray::getVector(const string& key, Vector3f& val) const -{ - Vector3d vecVal; - - if (!getVector(key, vecVal)) - return false; - - val = vecVal.cast(); - return true; -} - - -/** - * Retrieves a quaternion, scaled to an associated angle unit. - * - * The quaternion is specified in the catalog file in axis-angle format as follows: - * \verbatim {PropertyName} [ angle axisX axisY axisZ ] \endverbatim - * - * @param[in] key Hash key for the rotation. - * @param[out] val A quaternion representing the value if present, unaffected if not. - * @return True if the key exists in the hash, false otherwise. - */ -bool AssociativeArray::getRotation(const string& key, Eigen::Quaternionf& val) const -{ - Value* v = getValue(key); - if (v == nullptr || v->getType() != Value::ArrayType) - return false; - - ValueArray* arr = v->getArray(); - if (arr->size() != 4) - return false; - - Value* w = (*arr)[0]; - Value* x = (*arr)[1]; - Value* y = (*arr)[2]; - Value* z = (*arr)[3]; - - if (w->getType() != Value::NumberType || - x->getType() != Value::NumberType || - y->getType() != Value::NumberType || - z->getType() != Value::NumberType) - return false; - - Vector3f axis((float) x->getNumber(), - (float) y->getNumber(), - (float) z->getNumber()); - - double ang = w->getNumber(); - double angScale = 1.0; - getAngleScale(key, angScale); - float angle = degToRad((float) (ang * angScale)); - - val = Quaternionf(AngleAxisf(angle, axis.normalized())); - - return true; -} - - -bool AssociativeArray::getColor(const string& key, Color& val) const -{ - Vector3d vecVal; - - if (!getVector(key, vecVal)) - return false; - - val = Color((float) vecVal.x(), (float) vecVal.y(), (float) vecVal.z()); - - return true; -} - - -/** - * Retrieves a numeric quantity scaled to an associated angle unit. - * @param[in] key Hash key for the quantity. - * @param[out] val The returned quantity if present, unaffected if not. - * @param[in] outputScale Returned value is scaled to this value. - * @param[in] defaultScale If no units are specified, use this scale. Defaults to outputScale. - * @return True if the key exists in the hash, false otherwise. - */ -bool -AssociativeArray::getAngle(const string& key, double& val, double outputScale, double defaultScale) const -{ - if (!getNumber(key, val)) - return false; - - double angleScale; - if(getAngleScale(key, angleScale)) - { - angleScale /= outputScale; - } - else - { - angleScale = (defaultScale == 0.0) ? 1.0 : defaultScale / outputScale; - } - - val *= angleScale; - - return true; -} - - -/** @copydoc AssociativeArray::getAngle() */ -bool -AssociativeArray::getAngle(const string& key, float& val, double outputScale, double defaultScale) const -{ - double dval; - - if (!getAngle(key, dval, outputScale, defaultScale)) - return false; - - val = ((float) dval); - - return true; -} - - -/** - * Retrieves a numeric quantity scaled to an associated length unit. - * @param[in] key Hash key for the quantity. - * @param[out] val The returned quantity if present, unaffected if not. - * @param[in] outputScale Returned value is scaled to this value. - * @param[in] defaultScale If no units are specified, use this scale. Defaults to outputScale. - * @return True if the key exists in the hash, false otherwise. - */ -bool -AssociativeArray::getLength(const string& key, double& val, double outputScale, double defaultScale) const -{ - if(!getNumber(key, val)) - return false; - - double lengthScale; - if(getLengthScale(key, lengthScale)) - { - lengthScale /= outputScale; - } - else - { - lengthScale = (defaultScale == 0.0) ? 1.0 : defaultScale / outputScale; - } - - val *= lengthScale; - - return true; -} - - -/** @copydoc AssociativeArray::getLength() */ -bool AssociativeArray::getLength(const string& key, float& val, double outputScale, double defaultScale) const -{ - double dval; - - if (!getLength(key, dval, outputScale, defaultScale)) - return false; - - val = ((float) dval); - - return true; -} - - -/** - * Retrieves a numeric quantity scaled to an associated time unit. - * @param[in] key Hash key for the quantity. - * @param[out] val The returned quantity if present, unaffected if not. - * @param[in] outputScale Returned value is scaled to this value. - * @param[in] defaultScale If no units are specified, use this scale. Defaults to outputScale. - * @return True if the key exists in the hash, false otherwise. - */ -bool AssociativeArray::getTime(const string& key, double& val, double outputScale, double defaultScale) const -{ - if(!getNumber(key, val)) - return false; - - double timeScale; - if(getTimeScale(key, timeScale)) - { - timeScale /= outputScale; - } - else - { - timeScale = (defaultScale == 0.0) ? 1.0 : defaultScale / outputScale; - } - - val *= timeScale; - - return true; -} - - -/** @copydoc AssociativeArray::getTime() */ -bool AssociativeArray::getTime(const string& key, float& val, double outputScale, double defaultScale) const -{ - double dval; - - if(!getLength(key, dval, outputScale, defaultScale)) - return false; - - val = ((float) dval); - - return true; -} - - -/** - * Retrieves a vector quantity scaled to an associated length unit. - * @param[in] key Hash key for the quantity. - * @param[out] val The returned vector if present, unaffected if not. - * @param[in] outputScale Returned value is scaled to this value. - * @param[in] defaultScale If no units are specified, use this scale. Defaults to outputScale. - * @return True if the key exists in the hash, false otherwise. - */ -bool AssociativeArray::getLengthVector(const string& key, Eigen::Vector3d& val, double outputScale, double defaultScale) const -{ - if(!getVector(key, val)) - return false; - - double lengthScale; - if(getLengthScale(key, lengthScale)) - { - lengthScale /= outputScale; - } - else - { - lengthScale = (defaultScale == 0.0) ? 1.0 : defaultScale / outputScale; - } - - val *= lengthScale; - - return true; -} - - -/** @copydoc AssociativeArray::getLengthVector() */ -bool AssociativeArray::getLengthVector(const string& key, Eigen::Vector3f& val, double outputScale, double defaultScale) const -{ - Vector3d vecVal; - - if(!getLengthVector(key, vecVal, outputScale, defaultScale)) - return false; - - val = vecVal.cast(); - return true; -} - - -/** - * Retrieves a spherical tuple \verbatim [longitude, latitude, altitude] \endverbatim scaled to associated angle and length units. - * @param[in] key Hash key for the quantity. - * @param[out] val The returned tuple in units of degrees and kilometers if present, unaffected if not. - * @return True if the key exists in the hash, false otherwise. - */ -bool AssociativeArray::getSphericalTuple(const string& key, Vector3d& val) const -{ - if(!getVector(key, val)) - return false; - - double angleScale; - if(getAngleScale(key, angleScale)) - { - val[0] *= angleScale; - val[1] *= angleScale; - } - - double lengthScale = 1.0; - getLengthScale(key, lengthScale); - val[2] *= lengthScale; - - return true; -} - - -/** @copydoc AssociativeArray::getSphericalTuple */ -bool AssociativeArray::getSphericalTuple(const string& key, Vector3f& val) const -{ - Vector3d vecVal; - - if(!getSphericalTuple(key, vecVal)) - return false; - - val = vecVal.cast(); - return true; -} - - -/** - * Retrieves the angle unit associated with a given property. - * @param[in] key Hash key for the property. - * @param[out] scale The returned angle unit scaled to degrees if present, unaffected if not. - * @return True if an angle unit has been specified for the property, false otherwise. - */ -bool AssociativeArray::getAngleScale(const string& key, double& scale) const -{ - string unitKey(key + "%Angle"); - string unit; - - if (!getString(unitKey, unit)) - return false; - - return astro::getAngleScale(unit, scale); -} - - -/** @copydoc AssociativeArray::getAngleScale() */ -bool AssociativeArray::getAngleScale(const string& key, float& scale) const -{ - double dscale; - if (!getAngleScale(key, dscale)) - return false; - - scale = ((float) dscale); - return true; } - - -/** - * Retrieves the length unit associated with a given property. - * @param[in] key Hash key for the property. - * @param[out] scale The returned length unit scaled to kilometers if present, unaffected if not. - * @return True if a length unit has been specified for the property, false otherwise. - */ -bool AssociativeArray::getLengthScale(const string& key, double& scale) const -{ - string unitKey(key + "%Length"); - string unit; - - if (!getString(unitKey, unit)) - return false; - - return astro::getLengthScale(unit, scale); -} - - -/** @copydoc AssociativeArray::getLengthScale() */ -bool AssociativeArray::getLengthScale(const string& key, float& scale) const -{ - double dscale; - if (!getLengthScale(key, dscale)) - return false; - - scale = ((float) dscale); - return true; -} - - -/** - * Retrieves the time unit associated with a given property. - * @param[in] key Hash key for the property. - * @param[out] scale The returned time unit scaled to days if present, unaffected if not. - * @return True if a time unit has been specified for the property, false otherwise. - */ -bool AssociativeArray::getTimeScale(const string& key, double& scale) const -{ - string unitKey(key + "%Time"); - string unit; - - if (!getString(unitKey, unit)) - return false; - - return astro::getTimeScale(unit, scale); -} - - -/** @copydoc AssociativeArray::getTimeScale() */ -bool AssociativeArray::getTimeScale(const string& key, float& scale) const -{ - double dscale; - if (!getTimeScale(key, dscale)) - return false; - - scale = ((float) dscale); - return true; -} - - -HashIterator -AssociativeArray::begin() -{ - return assoc.begin(); -} - - -HashIterator -AssociativeArray::end() -{ - return assoc.end(); } diff --git a/src/celengine/parser.h b/src/celengine/parser.h index a5d66250b1..dc6a9c7732 100644 --- a/src/celengine/parser.h +++ b/src/celengine/parser.h @@ -1,6 +1,6 @@ // parser.h // -// Copyright (C) 2001-2009, the Celestia Development Team +// Copyright (C) 2001-2019, the Celestia Development Team // Original version by Chris Laurel // // This program is free software; you can redistribute it and/or @@ -8,105 +8,16 @@ // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -#ifndef _PARSER_H_ -#define _PARSER_H_ +#pragma once -#include -#include -#include -#include #include -#include -#include +#include +#include -class Value; - -typedef map::const_iterator HashIterator; - -class AssociativeArray +namespace celestia { - public: - AssociativeArray() = default; - ~AssociativeArray(); - - Value* getValue(const std::string&) const; - void addValue(const std::string&, Value&); - - bool getNumber(const std::string&, double&) const; - bool getNumber(const std::string&, float&) const; - bool getNumber(const std::string&, int&) const; - bool getNumber(const std::string&, uint32_t&) const; - bool getString(const std::string&, std::string&) const; - bool getBoolean(const std::string&, bool&) const; - bool getVector(const std::string&, Eigen::Vector3d&) const; - bool getVector(const std::string&, Eigen::Vector3f&) const; - bool getRotation(const std::string&, Eigen::Quaternionf&) const; - bool getColor(const std::string&, Color&) const; - bool getAngle(const std::string&, double&, double = 1.0, double = 0.0) const; - bool getAngle(const std::string&, float&, double = 1.0, double = 0.0) const; - bool getLength(const std::string&, double&, double = 1.0, double = 0.0) const; - bool getLength(const std::string&, float&, double = 1.0, double = 0.0) const; - bool getTime(const std::string&, double&, double = 1.0, double = 0.0) const; - bool getTime(const std::string&, float&, double = 1.0, double = 0.0) const; - bool getLengthVector(const std::string&, Eigen::Vector3d&, double = 1.0, double = 0.0) const; - bool getLengthVector(const std::string&, Eigen::Vector3f&, double = 1.0, double = 0.0) const; - bool getSphericalTuple(const std::string&, Eigen::Vector3d&) const; - bool getSphericalTuple(const std::string&, Eigen::Vector3f&) const; - bool getAngleScale(const std::string&, double&) const; - bool getAngleScale(const std::string&, float&) const; - bool getLengthScale(const std::string&, double&) const; - bool getLengthScale(const std::string&, float&) const; - bool getTimeScale(const std::string&, double&) const; - bool getTimeScale(const std::string&, float&) const; - - HashIterator begin(); - HashIterator end(); - - private: - map assoc; -}; - -typedef vector Array; -typedef vector ValueArray; -typedef AssociativeArray Hash; - -class Value +namespace engine { -public: - enum ValueType { - NumberType = 0, - StringType = 1, - ArrayType = 2, - HashType = 3, - BooleanType = 4 - }; - - Value(double); - Value(const string&); - Value(ValueArray*); - Value(Hash*); - Value(bool); - ~Value(); - - ValueType getType() const; - - double getNumber() const; - string getString() const; - ValueArray* getArray() const; - Hash* getHash() const; - bool getBoolean() const; - -private: - ValueType type; - - union { - string* s; - double d; - ValueArray* a; - Hash* h; - } data; -}; - class Parser { @@ -119,8 +30,9 @@ class Parser Tokenizer* tokenizer; bool readUnits(const std::string&, Hash*); - ValueArray* readArray(); + Array* readArray(); Hash* readHash(); }; -#endif // _PARSER_H_ +} +} diff --git a/src/celengine/value.cpp b/src/celengine/value.cpp index d40bbdf16e..acc3636278 100644 --- a/src/celengine/value.cpp +++ b/src/celengine/value.cpp @@ -8,7 +8,7 @@ // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -#include "value.h" +#include namespace celestia { diff --git a/src/celengine/value.h b/src/celengine/value.h index f54c5414b8..8b37cc5056 100644 --- a/src/celengine/value.h +++ b/src/celengine/value.h @@ -13,7 +13,7 @@ #include #include #include -#include "hash.h" +#include namespace celestia { From bdd50e9879da899a26a8f206d08645d208086b79 Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Mon, 9 Sep 2019 00:54:07 +0300 Subject: [PATCH 10/11] rewrite using watcher/watchable (broken, no override for virtual fn) --- src/celengine/configuration.cpp | 23 +----------- src/celengine/configuration.h | 12 +++---- src/celengine/property.cpp | 12 +++---- src/celengine/property.h | 39 +++++++-------------- src/celengine/testprops.cc | 16 ++++----- src/celutil/watchable.h | 62 +++++++++++++++++++++++++++++++++ src/celutil/watcher.h | 35 ++++++++++++++----- 7 files changed, 118 insertions(+), 81 deletions(-) create mode 100644 src/celutil/watchable.h diff --git a/src/celengine/configuration.cpp b/src/celengine/configuration.cpp index ff6a30d208..62e4bd56e0 100644 --- a/src/celengine/configuration.cpp +++ b/src/celengine/configuration.cpp @@ -1,7 +1,6 @@ #include "configuration.h" #include "property.h" #include -#include namespace celestia @@ -40,20 +39,6 @@ void Config::dump() const } #endif -void Config::addProperty(IProperty *p) -{ - if (std::find(m_props.begin(), m_props.end(), p) == m_props.end()) - m_props.push_back(p); - p->update(); -} - -void Config::removeProperty(IProperty *p) -{ - auto pos = std::find(m_props.begin(), m_props.end(), p); - if (pos != m_props.end()) - m_props.erase(pos); -} - const Value* Config::find(const std::string& name) const { static Value v; @@ -78,13 +63,7 @@ void Config::set(const std::string& name, const Value* value) void Config::endUpdate() { m_update = false; - onUpdate(); -} - -void Config::onUpdate() -{ - for (auto *p : m_props) - p->update(); + notifyWatchers(); } Config::~Config() diff --git a/src/celengine/configuration.h b/src/celengine/configuration.h index bae873514a..4cb32daa08 100644 --- a/src/celengine/configuration.h +++ b/src/celengine/configuration.h @@ -4,8 +4,9 @@ #include #include #include -#include "value.h" +#include #include +#include namespace celestia @@ -14,9 +15,8 @@ namespace engine { class IConfigUpdater; class IConfigWriter; -class IProperty; -class Config +class Config : public utility::Watchable { public: Config() = default; @@ -27,8 +27,6 @@ class Config Config& operator=(const Config&) = delete; Config& operator=(Config&&) = delete; - void addProperty(IProperty*); - void removeProperty(IProperty*); const Value* find(const std::string& name) const; #ifdef DEBUG @@ -46,19 +44,17 @@ class Config } }; - void onUpdate(); void beginUpdate(); void set(const std::string& name, const Value *value); void endUpdate(); - std::vector m_props; std::map m_values; bool m_update { false }; friend class IConfigUpdater; friend class IConfigWriter; - friend class IProperty; + friend class utility::Watcher; }; diff --git a/src/celengine/property.cpp b/src/celengine/property.cpp index 5fbb242b86..b1cb0d15d4 100644 --- a/src/celengine/property.cpp +++ b/src/celengine/property.cpp @@ -7,30 +7,30 @@ namespace engine { #define PROPERTY_UPDATE(ValueType) \ - auto v = m_config->find(m_name); \ + auto v = watched()->find(m_name); \ m_has_value = v->getType() == Value:: ValueType ## Type; \ if (m_has_value) \ { \ if (m_validate != nullptr) \ - m_value = m_validate(v->get ## ValueType ()); \ + m_value = m_validate(v->get ## ValueType()); \ else \ - m_value = v->get ## ValueType (); \ + m_value = v->get ## ValueType(); \ } template<> -void Property::update() +void Property::notifyChange(int /* unused */) { PROPERTY_UPDATE(Number); } template<> -void Property::update() +void Property::notifyChange(int /* unused */) { PROPERTY_UPDATE(String); } template<> -void Property::update() +void Property::notifyChange(int /* unused */) { PROPERTY_UPDATE(Boolean); } diff --git a/src/celengine/property.h b/src/celengine/property.h index 82ba131429..ffbaab4878 100644 --- a/src/celengine/property.h +++ b/src/celengine/property.h @@ -2,8 +2,8 @@ #include #include -#include -#include "configuration.h" +#include +#include namespace celestia @@ -11,35 +11,23 @@ namespace celestia namespace engine { -class IProperty -{ - public: - virtual void update() = 0; - friend class Config; -}; - template -class Property : IProperty +class Property : public utility::Watcher { public: using validate_fn_t = std::function; - Property() = default; - - Property(std::shared_ptr config, std::string name, T _default, validate_fn_t validate = nullptr) : - m_config (std::move(config)), - m_name (std::move(name)), - m_default (std::move(_default)), - m_validate (std::move(validate)) - { - assert(m_config != nullptr); - m_config->addProperty(this); - }; +// Property() = default; - ~Property() + Property(const std::shared_ptr& config, + const std::string &name, + const T &_default, + validate_fn_t validate = nullptr) : + utility::Watcher(config), + m_name { name }, + m_default { _default }, + m_validate { validate } { - if (m_config != nullptr) - m_config->removeProperty(this); }; // Getters and setters @@ -69,10 +57,9 @@ class Property : IProperty }; // Used by Config to propagate changes - void update() override; + void notifyChange(int = 0) override; private: - std::shared_ptr m_config { nullptr }; std::string m_name; T m_value {}; T m_default {}; diff --git a/src/celengine/testprops.cc b/src/celengine/testprops.cc index 1c035d45d5..ac9f754893 100644 --- a/src/celengine/testprops.cc +++ b/src/celengine/testprops.cc @@ -26,20 +26,16 @@ void myconfig::read() class Foo { - Property m_p1; - NumericProperty m_distance; - StringProperty m_name, m_type; - BooleanProperty m_visible; shared_ptr m_cfg; + Property m_p1 { m_cfg, "P1", 10.5 }; + NumericProperty m_distance { m_cfg, "distance", 55.1, [](const double &v){ return v > 0 ? -v : v; } }; + StringProperty m_name { m_cfg, "name", "baz" }; + StringProperty m_type { m_cfg, "type", "baz" }; + BooleanProperty m_visible { m_cfg, "visible", false }; public: Foo(const shared_ptr &cfg): - m_cfg (cfg), - m_p1 (Property(cfg, "P1", 10.5)), - m_distance (NumericProperty(cfg, "distance", 55.1, [](const double &v){ return v > 0 ? -v : v; })), - m_name (StringProperty(cfg, "name", "baz")), - m_type (StringProperty(cfg, "type", "baz")), - m_visible (BooleanProperty(cfg, "visible", false)) + m_cfg { cfg } { } double p1() diff --git a/src/celutil/watchable.h b/src/celutil/watchable.h new file mode 100644 index 0000000000..328b220d8b --- /dev/null +++ b/src/celutil/watchable.h @@ -0,0 +1,62 @@ +// watchable.h +// +// Copyright (C) 2019, Celestia Development Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#pragma once +#include +#include +#include +#include + +namespace celestia +{ +namespace utility +{ + +template class Watchable +{ + std::vector*> m_watchers; + + protected: + inline const std::vector*>& watchers() + { + return m_watchers; + } + + public: + virtual void notifyWatchers(int = 0); + virtual void addWatcher(Watcher*); + virtual void removeWatcher(Watcher*); +}; + +template void Watchable::addWatcher(Watcher* watcher) +{ + assert(watcher != nullptr); + auto w = std::find(m_watchers.cbegin(), m_watchers.cend(), watcher); + if (w == m_watchers.cend()) + { + m_watchers.push_back(watcher); + watcher->notifyChange(); + } +} + +template void Watchable::removeWatcher(Watcher* watcher) +{ + assert(watcher != nullptr); + std::remove_if(m_watchers.begin(), m_watchers.end(), + [&watcher](Watcher* w) { return w == watcher; }); +} + +template void Watchable::notifyWatchers(int property) +{ + for (auto *watcher : m_watchers) + watcher->notifyChange(property); +} + +} +} diff --git a/src/celutil/watcher.h b/src/celutil/watcher.h index 7793c5102c..21b1b895e6 100644 --- a/src/celutil/watcher.h +++ b/src/celutil/watcher.h @@ -1,5 +1,6 @@ // watcher.h // +// Copyright (C) 2019, Celestia Development Team // Copyright (C) 2002, Chris Laurel // // This program is free software; you can redistribute it and/or @@ -7,26 +8,42 @@ // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -#ifndef _CELUTIL_WATCHER_H_ -#define _CELUTIL_WATCHER_H_ +#pragma once +#include +#include -template class Watcher +namespace celestia +{ +namespace utility +{ + +template class Watcher { private: - T& watched; + std::shared_ptr m_watched; + + protected: + const std::shared_ptr& watched() + { + return m_watched; + } public: - Watcher(T& _watched) : watched(_watched) + Watcher() = default; + Watcher(const std::shared_ptr& watched) : + m_watched(watched) { - watched.addWatcher(this); + m_watched->addWatcher(this); }; virtual ~Watcher() { - watched.removeWatcher(this); + if (m_watched != nullptr) + m_watched->removeWatcher(this); } - virtual void notifyChange(T*, int) = 0; + virtual void notifyChange(int = 0) /*= 0*/{std::cout << "Watcher::notifyChange()\n";}; }; -#endif // _CELUTIL_WATCHER_H_ +} +} From abb47594efa6f2e67c78e72ccaa1d41f1e25498f Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Mon, 9 Sep 2019 18:24:38 +0300 Subject: [PATCH 11/11] Revert "rewrite using watcher/watchable (broken, no override for virtual fn)" This reverts commit bdd50e9879da899a26a8f206d08645d208086b79. --- src/celengine/configuration.cpp | 23 +++++++++++- src/celengine/configuration.h | 12 ++++--- src/celengine/property.cpp | 12 +++---- src/celengine/property.h | 39 ++++++++++++++------- src/celengine/testprops.cc | 16 +++++---- src/celutil/watchable.h | 62 --------------------------------- src/celutil/watcher.h | 35 +++++-------------- 7 files changed, 81 insertions(+), 118 deletions(-) delete mode 100644 src/celutil/watchable.h diff --git a/src/celengine/configuration.cpp b/src/celengine/configuration.cpp index 62e4bd56e0..ff6a30d208 100644 --- a/src/celengine/configuration.cpp +++ b/src/celengine/configuration.cpp @@ -1,6 +1,7 @@ #include "configuration.h" #include "property.h" #include +#include namespace celestia @@ -39,6 +40,20 @@ void Config::dump() const } #endif +void Config::addProperty(IProperty *p) +{ + if (std::find(m_props.begin(), m_props.end(), p) == m_props.end()) + m_props.push_back(p); + p->update(); +} + +void Config::removeProperty(IProperty *p) +{ + auto pos = std::find(m_props.begin(), m_props.end(), p); + if (pos != m_props.end()) + m_props.erase(pos); +} + const Value* Config::find(const std::string& name) const { static Value v; @@ -63,7 +78,13 @@ void Config::set(const std::string& name, const Value* value) void Config::endUpdate() { m_update = false; - notifyWatchers(); + onUpdate(); +} + +void Config::onUpdate() +{ + for (auto *p : m_props) + p->update(); } Config::~Config() diff --git a/src/celengine/configuration.h b/src/celengine/configuration.h index 4cb32daa08..bae873514a 100644 --- a/src/celengine/configuration.h +++ b/src/celengine/configuration.h @@ -4,9 +4,8 @@ #include #include #include -#include +#include "value.h" #include -#include namespace celestia @@ -15,8 +14,9 @@ namespace engine { class IConfigUpdater; class IConfigWriter; +class IProperty; -class Config : public utility::Watchable +class Config { public: Config() = default; @@ -27,6 +27,8 @@ class Config : public utility::Watchable Config& operator=(const Config&) = delete; Config& operator=(Config&&) = delete; + void addProperty(IProperty*); + void removeProperty(IProperty*); const Value* find(const std::string& name) const; #ifdef DEBUG @@ -44,17 +46,19 @@ class Config : public utility::Watchable } }; + void onUpdate(); void beginUpdate(); void set(const std::string& name, const Value *value); void endUpdate(); + std::vector m_props; std::map m_values; bool m_update { false }; friend class IConfigUpdater; friend class IConfigWriter; - friend class utility::Watcher; + friend class IProperty; }; diff --git a/src/celengine/property.cpp b/src/celengine/property.cpp index b1cb0d15d4..5fbb242b86 100644 --- a/src/celengine/property.cpp +++ b/src/celengine/property.cpp @@ -7,30 +7,30 @@ namespace engine { #define PROPERTY_UPDATE(ValueType) \ - auto v = watched()->find(m_name); \ + auto v = m_config->find(m_name); \ m_has_value = v->getType() == Value:: ValueType ## Type; \ if (m_has_value) \ { \ if (m_validate != nullptr) \ - m_value = m_validate(v->get ## ValueType()); \ + m_value = m_validate(v->get ## ValueType ()); \ else \ - m_value = v->get ## ValueType(); \ + m_value = v->get ## ValueType (); \ } template<> -void Property::notifyChange(int /* unused */) +void Property::update() { PROPERTY_UPDATE(Number); } template<> -void Property::notifyChange(int /* unused */) +void Property::update() { PROPERTY_UPDATE(String); } template<> -void Property::notifyChange(int /* unused */) +void Property::update() { PROPERTY_UPDATE(Boolean); } diff --git a/src/celengine/property.h b/src/celengine/property.h index ffbaab4878..82ba131429 100644 --- a/src/celengine/property.h +++ b/src/celengine/property.h @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include "configuration.h" namespace celestia @@ -11,23 +11,35 @@ namespace celestia namespace engine { +class IProperty +{ + public: + virtual void update() = 0; + friend class Config; +}; + template -class Property : public utility::Watcher +class Property : IProperty { public: using validate_fn_t = std::function; -// Property() = default; + Property() = default; + + Property(std::shared_ptr config, std::string name, T _default, validate_fn_t validate = nullptr) : + m_config (std::move(config)), + m_name (std::move(name)), + m_default (std::move(_default)), + m_validate (std::move(validate)) + { + assert(m_config != nullptr); + m_config->addProperty(this); + }; - Property(const std::shared_ptr& config, - const std::string &name, - const T &_default, - validate_fn_t validate = nullptr) : - utility::Watcher(config), - m_name { name }, - m_default { _default }, - m_validate { validate } + ~Property() { + if (m_config != nullptr) + m_config->removeProperty(this); }; // Getters and setters @@ -57,9 +69,10 @@ class Property : public utility::Watcher }; // Used by Config to propagate changes - void notifyChange(int = 0) override; + void update() override; private: + std::shared_ptr m_config { nullptr }; std::string m_name; T m_value {}; T m_default {}; diff --git a/src/celengine/testprops.cc b/src/celengine/testprops.cc index ac9f754893..1c035d45d5 100644 --- a/src/celengine/testprops.cc +++ b/src/celengine/testprops.cc @@ -26,16 +26,20 @@ void myconfig::read() class Foo { + Property m_p1; + NumericProperty m_distance; + StringProperty m_name, m_type; + BooleanProperty m_visible; shared_ptr m_cfg; - Property m_p1 { m_cfg, "P1", 10.5 }; - NumericProperty m_distance { m_cfg, "distance", 55.1, [](const double &v){ return v > 0 ? -v : v; } }; - StringProperty m_name { m_cfg, "name", "baz" }; - StringProperty m_type { m_cfg, "type", "baz" }; - BooleanProperty m_visible { m_cfg, "visible", false }; public: Foo(const shared_ptr &cfg): - m_cfg { cfg } + m_cfg (cfg), + m_p1 (Property(cfg, "P1", 10.5)), + m_distance (NumericProperty(cfg, "distance", 55.1, [](const double &v){ return v > 0 ? -v : v; })), + m_name (StringProperty(cfg, "name", "baz")), + m_type (StringProperty(cfg, "type", "baz")), + m_visible (BooleanProperty(cfg, "visible", false)) { } double p1() diff --git a/src/celutil/watchable.h b/src/celutil/watchable.h deleted file mode 100644 index 328b220d8b..0000000000 --- a/src/celutil/watchable.h +++ /dev/null @@ -1,62 +0,0 @@ -// watchable.h -// -// Copyright (C) 2019, Celestia Development Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. - -#pragma once -#include -#include -#include -#include - -namespace celestia -{ -namespace utility -{ - -template class Watchable -{ - std::vector*> m_watchers; - - protected: - inline const std::vector*>& watchers() - { - return m_watchers; - } - - public: - virtual void notifyWatchers(int = 0); - virtual void addWatcher(Watcher*); - virtual void removeWatcher(Watcher*); -}; - -template void Watchable::addWatcher(Watcher* watcher) -{ - assert(watcher != nullptr); - auto w = std::find(m_watchers.cbegin(), m_watchers.cend(), watcher); - if (w == m_watchers.cend()) - { - m_watchers.push_back(watcher); - watcher->notifyChange(); - } -} - -template void Watchable::removeWatcher(Watcher* watcher) -{ - assert(watcher != nullptr); - std::remove_if(m_watchers.begin(), m_watchers.end(), - [&watcher](Watcher* w) { return w == watcher; }); -} - -template void Watchable::notifyWatchers(int property) -{ - for (auto *watcher : m_watchers) - watcher->notifyChange(property); -} - -} -} diff --git a/src/celutil/watcher.h b/src/celutil/watcher.h index 21b1b895e6..7793c5102c 100644 --- a/src/celutil/watcher.h +++ b/src/celutil/watcher.h @@ -1,6 +1,5 @@ // watcher.h // -// Copyright (C) 2019, Celestia Development Team // Copyright (C) 2002, Chris Laurel // // This program is free software; you can redistribute it and/or @@ -8,42 +7,26 @@ // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -#pragma once -#include -#include +#ifndef _CELUTIL_WATCHER_H_ +#define _CELUTIL_WATCHER_H_ -namespace celestia -{ -namespace utility -{ - -template class Watcher +template class Watcher { private: - std::shared_ptr m_watched; - - protected: - const std::shared_ptr& watched() - { - return m_watched; - } + T& watched; public: - Watcher() = default; - Watcher(const std::shared_ptr& watched) : - m_watched(watched) + Watcher(T& _watched) : watched(_watched) { - m_watched->addWatcher(this); + watched.addWatcher(this); }; virtual ~Watcher() { - if (m_watched != nullptr) - m_watched->removeWatcher(this); + watched.removeWatcher(this); } - virtual void notifyChange(int = 0) /*= 0*/{std::cout << "Watcher::notifyChange()\n";}; + virtual void notifyChange(T*, int) = 0; }; -} -} +#endif // _CELUTIL_WATCHER_H_