From 8e1c92d9afa951e1dd4195e81a6161266fbef6e0 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 4 Apr 2021 19:17:10 +0200 Subject: [PATCH] Use std::variant for ESM::Variant implementation --- apps/openmw_test_suite/esm/variant.cpp | 18 +-- components/esm/variant.cpp | 177 ++++++----------------- components/esm/variant.hpp | 38 ++--- components/esm/variantimp.cpp | 188 +++--------------------- components/esm/variantimp.hpp | 193 +++++-------------------- 5 files changed, 133 insertions(+), 481 deletions(-) diff --git a/apps/openmw_test_suite/esm/variant.cpp b/apps/openmw_test_suite/esm/variant.cpp index 9615222fe..10d35e486 100644 --- a/apps/openmw_test_suite/esm/variant.cpp +++ b/apps/openmw_test_suite/esm/variant.cpp @@ -180,19 +180,19 @@ namespace TEST(ESMVariantGetStringTest, for_default_constructed_should_throw_exception) { - ASSERT_THROW(Variant().getString(), std::runtime_error); + ASSERT_THROW(Variant().getString(), std::bad_variant_access); } TEST(ESMVariantGetStringTest, for_constructed_from_int_should_throw_exception) { const Variant variant(int{42}); - ASSERT_THROW(variant.getString(), std::runtime_error); + ASSERT_THROW(variant.getString(), std::bad_variant_access); } TEST(ESMVariantGetStringTest, for_constructed_from_float_should_throw_exception) { const Variant variant(float{2.7}); - ASSERT_THROW(variant.getString(), std::runtime_error); + ASSERT_THROW(variant.getString(), std::bad_variant_access); } TEST(ESMVariantGetStringTest, for_constructed_from_string_should_return_same_value) @@ -372,40 +372,40 @@ namespace TEST(ESMVariantSetStringTest, for_default_constructed_should_throw_exception) { Variant variant; - ASSERT_THROW(variant.setString("foo"), std::runtime_error); + ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); } TEST(ESMVariantSetStringTest, for_unknown_should_throw_exception) { Variant variant; variant.setType(VT_Unknown); - ASSERT_THROW(variant.setString("foo"), std::runtime_error); + ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); } TEST(ESMVariantSetStringTest, for_default_int_should_throw_exception) { Variant variant(int{13}); - ASSERT_THROW(variant.setString("foo"), std::runtime_error); + ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); } TEST(ESMVariantSetStringTest, for_int_should_throw_exception) { Variant variant; variant.setType(VT_Int); - ASSERT_THROW(variant.setString("foo"), std::runtime_error); + ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); } TEST(ESMVariantSetStringTest, for_short_should_throw_exception) { Variant variant; variant.setType(VT_Short); - ASSERT_THROW(variant.setString("foo"), std::runtime_error); + ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); } TEST(ESMVariantSetStringTest, for_float_should_throw_exception) { Variant variant(float{2.7f}); - ASSERT_THROW(variant.setString("foo"), std::runtime_error); + ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); } TEST(ESMVariantSetStringTest, for_string_should_change_value) diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index cbcb6e002..3e0417ef7 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -14,106 +14,53 @@ namespace const uint32_t INTV = ESM::FourCC<'I','N','T','V'>::value; const uint32_t FLTV = ESM::FourCC<'F','L','T','V'>::value; const uint32_t STTV = ESM::FourCC<'S','T','T','V'>::value; -} -ESM::Variant::Variant() : mType (VT_None), mData (nullptr) {} - -ESM::Variant::Variant(const std::string &value) -{ - mData = nullptr; - mType = VT_None; - setType(VT_String); - setString(value); -} - -ESM::Variant::Variant(int value) -{ - mData = nullptr; - mType = VT_None; - setType(VT_Long); - setInteger(value); -} - -ESM::Variant::Variant(float value) -{ - mData = nullptr; - mType = VT_None; - setType(VT_Float); - setFloat(value); -} - -ESM::Variant::~Variant() -{ - delete mData; -} - -ESM::Variant& ESM::Variant::operator= (const Variant& variant) -{ - if (&variant!=this) + template + struct GetValue { - VariantDataBase *newData = variant.mData ? variant.mData->clone() : nullptr; + T operator()(int value) const { return static_cast(value); } - delete mData; + T operator()(float value) const { return static_cast(value); } - mType = variant.mType; - mData = newData; - } + template + T operator()(const V&) const + { + if constexpr (orDefault) + return T {}; + else + throw std::runtime_error("cannot convert variant"); + } + }; - return *this; -} - -ESM::Variant& ESM::Variant::operator= (Variant&& variant) -{ - if (&variant!=this) + template + struct SetValue { - delete mData; + T mValue; - mType = variant.mType; - mData = variant.mData; + explicit SetValue(T value) : mValue(value) {} - variant.mData = nullptr; - } + void operator()(int& value) const { value = static_cast(mValue); } - return *this; -} + void operator()(float& value) const { value = static_cast(mValue); } -ESM::Variant::Variant (const Variant& variant) -: mType (variant.mType), mData (variant.mData ? variant.mData->clone() : nullptr) -{} - -ESM::Variant::Variant(Variant&& variant) -: mType (variant.mType), mData (variant.mData) -{ - variant.mData = nullptr; -} - -ESM::VarType ESM::Variant::getType() const -{ - return mType; + template + void operator()(V&) const { throw std::runtime_error("cannot convert variant"); } + }; } std::string ESM::Variant::getString() const { - if (!mData) - throw std::runtime_error ("can not convert empty variant to string"); - - return mData->getString(); + return std::get(mData); } int ESM::Variant::getInteger() const { - if (!mData) - throw std::runtime_error ("can not convert empty variant to integer"); - - return mData->getInteger(); + return std::visit(GetValue{}, mData); } float ESM::Variant::getFloat() const { - if (!mData) - throw std::runtime_error ("can not convert empty variant to float"); - - return mData->getFloat(); + return std::visit(GetValue{}, mData); } void ESM::Variant::read (ESMReader& esm, Format format) @@ -202,9 +149,7 @@ void ESM::Variant::read (ESMReader& esm, Format format) setType (type); - // data - if (mData) - mData->read (esm, format, mType); + std::visit(ReadESMVariantValue {esm, format, mType}, mData); } void ESM::Variant::write (ESMWriter& esm, Format format) const @@ -227,7 +172,7 @@ void ESM::Variant::write (ESMWriter& esm, Format format) const // nothing to do here for GMST format } else - mData->write (esm, format, mType); + std::visit(WriteESMVariantValue {esm, format, mType}, mData); } void ESM::Variant::write (std::ostream& stream) const @@ -246,27 +191,27 @@ void ESM::Variant::write (std::ostream& stream) const case VT_Short: - stream << "variant short: " << mData->getInteger(); + stream << "variant short: " << std::get(mData); break; case VT_Int: - stream << "variant int: " << mData->getInteger(); + stream << "variant int: " << std::get(mData); break; case VT_Long: - stream << "variant long: " << mData->getInteger(); + stream << "variant long: " << std::get(mData); break; case VT_Float: - stream << "variant float: " << mData->getFloat(); + stream << "variant float: " << std::get(mData); break; case VT_String: - stream << "variant string: \"" << mData->getString() << "\""; + stream << "variant string: \"" << std::get(mData) << "\""; break; } } @@ -275,74 +220,50 @@ void ESM::Variant::setType (VarType type) { if (type!=mType) { - VariantDataBase *newData = nullptr; - switch (type) { case VT_Unknown: case VT_None: - - break; // no data + mData = std::monostate {}; + break; case VT_Short: case VT_Int: case VT_Long: - - newData = new VariantIntegerData (mData); + mData = std::visit(GetValue{}, mData); break; case VT_Float: - - newData = new VariantFloatData (mData); + mData = std::visit(GetValue{}, mData); break; case VT_String: - - newData = new VariantStringData (mData); + mData = std::string {}; break; } - delete mData; - mData = newData; mType = type; } } void ESM::Variant::setString (const std::string& value) { - if (!mData) - throw std::runtime_error ("can not assign string to empty variant"); + std::get(mData) = value; +} - mData->setString (value); +void ESM::Variant::setString (std::string&& value) +{ + std::get(mData) = std::move(value); } void ESM::Variant::setInteger (int value) { - if (!mData) - throw std::runtime_error ("can not assign integer to empty variant"); - - mData->setInteger (value); + std::visit(SetValue(value), mData); } void ESM::Variant::setFloat (float value) { - if (!mData) - throw std::runtime_error ("can not assign float to empty variant"); - - mData->setFloat (value); -} - -bool ESM::Variant::isEqual (const Variant& value) const -{ - if (mType!=value.mType) - return false; - - if (!mData) - return true; - - assert (value.mData); - - return mData->isEqual (*value.mData); + std::visit(SetValue(value), mData); } std::ostream& ESM::operator<< (std::ostream& stream, const Variant& value) @@ -350,13 +271,3 @@ std::ostream& ESM::operator<< (std::ostream& stream, const Variant& value) value.write (stream); return stream; } - -bool ESM::operator== (const Variant& left, const Variant& right) -{ - return left.isEqual (right); -} - -bool ESM::operator!= (const Variant& left, const Variant& right) -{ - return !(left==right); -} diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index 20b3aa76e..f0a16d4d5 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include namespace ESM { @@ -20,12 +22,10 @@ namespace ESM VT_String }; - class VariantDataBase; - class Variant { VarType mType; - VariantDataBase *mData; + std::variant mData; public: @@ -37,21 +37,17 @@ namespace ESM Format_Local // local script variables in save game files }; - Variant(); + Variant() : mType (VT_None), mData (std::monostate{}) {} - Variant (const std::string& value); - Variant (int value); - Variant (float value); + explicit Variant(const std::string& value) : mType(VT_String), mData(value) {} - ~Variant(); + explicit Variant(std::string&& value) : mType(VT_String), mData(std::move(value)) {} - Variant& operator= (const Variant& variant); - Variant& operator= (Variant && variant); + explicit Variant(int value) : mType(VT_Long), mData(value) {} - Variant (const Variant& variant); - Variant (Variant&& variant); + explicit Variant(float value) : mType(VT_Float), mData(value) {} - VarType getType() const; + VarType getType() const { return mType; } std::string getString() const; ///< Will throw an exception, if value can not be represented as a string. @@ -75,19 +71,27 @@ namespace ESM void setString (const std::string& value); ///< Will throw an exception, if type is not compatible with string. + void setString (std::string&& value); + ///< Will throw an exception, if type is not compatible with string. + void setInteger (int value); ///< Will throw an exception, if type is not compatible with integer. void setFloat (float value); ///< Will throw an exception, if type is not compatible with float. - bool isEqual (const Variant& value) const; + friend bool operator==(const Variant& left, const Variant& right) + { + return std::tie(left.mType, left.mData) == std::tie(right.mType, right.mData); + } + + friend bool operator!=(const Variant& left, const Variant& right) + { + return !(left == right); + } }; std::ostream& operator<<(std::ostream& stream, const Variant& value); - - bool operator== (const Variant& left, const Variant& right); - bool operator!= (const Variant& left, const Variant& right); } #endif diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index 2b69923d1..74d1351ec 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -5,71 +5,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -ESM::VariantDataBase::~VariantDataBase() {} - -std::string ESM::VariantDataBase::getString (bool default_) const -{ - if (default_) - return ""; - - throw std::runtime_error ("can not convert variant to string"); -} - -int ESM::VariantDataBase::getInteger (bool default_) const -{ - if (default_) - return 0; - - throw std::runtime_error ("can not convert variant to integer"); -} - -float ESM::VariantDataBase::getFloat (bool default_) const -{ - if (default_) - return 0; - - throw std::runtime_error ("can not convert variant to float"); -} - -void ESM::VariantDataBase::setString (const std::string& value) -{ - throw std::runtime_error ("conversion of string to variant not possible"); -} - -void ESM::VariantDataBase::setInteger (int value) -{ - throw std::runtime_error ("conversion of integer to variant not possible"); -} - -void ESM::VariantDataBase::setFloat (float value) -{ - throw std::runtime_error ("conversion of float to variant not possible"); -} - - - -ESM::VariantStringData::VariantStringData (const VariantDataBase *data) -{ - if (data) - mValue = data->getString (true); -} - -ESM::VariantDataBase *ESM::VariantStringData::clone() const -{ - return new VariantStringData (*this); -} - -std::string ESM::VariantStringData::getString (bool default_) const -{ - return mValue; -} - -void ESM::VariantStringData::setString (const std::string& value) -{ - mValue = value; -} - -void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarType type) +void ESM::readESMVariantValue(ESMReader& esm, Variant::Format format, VarType type, std::string& out) { if (type!=VT_String) throw std::logic_error ("not a string type"); @@ -84,10 +20,10 @@ void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarTy esm.fail ("local variables of type string not supported"); // GMST - mValue = esm.getHString(); + out = esm.getHString(); } -void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarType type) const +void ESM::writeESMVariantValue(ESMWriter& esm, Variant::Format format, VarType type, const std::string& in) { if (type!=VT_String) throw std::logic_error ("not a string type"); @@ -102,48 +38,10 @@ void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarT throw std::runtime_error ("local variables of type string not supported"); // GMST - esm.writeHNString ("STRV", mValue); + esm.writeHNString("STRV", in); } -bool ESM::VariantStringData::isEqual (const VariantDataBase& value) const -{ - return dynamic_cast (value).mValue==mValue; -} - - - -ESM::VariantIntegerData::VariantIntegerData (const VariantDataBase *data) : mValue (0) -{ - if (data) - mValue = data->getInteger (true); -} - -ESM::VariantDataBase *ESM::VariantIntegerData::clone() const -{ - return new VariantIntegerData (*this); -} - -int ESM::VariantIntegerData::getInteger (bool default_) const -{ - return mValue; -} - -float ESM::VariantIntegerData::getFloat (bool default_) const -{ - return static_cast(mValue); -} - -void ESM::VariantIntegerData::setInteger (int value) -{ - mValue = value; -} - -void ESM::VariantIntegerData::setFloat (float value) -{ - mValue = static_cast (value); -} - -void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarType type) +void ESM::readESMVariantValue(ESMReader& esm, Variant::Format format, VarType type, int& out) { if (type!=VT_Short && type!=VT_Long && type!=VT_Int) throw std::logic_error ("not an integer type"); @@ -156,12 +54,12 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT if (type==VT_Short) { if (value!=value) - mValue = 0; // nan + out = 0; // nan else - mValue = static_cast (value); + out = static_cast (value); } else if (type==VT_Long) - mValue = static_cast (value); + out = static_cast (value); else esm.fail ("unsupported global variable integer type"); } @@ -176,7 +74,7 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT esm.fail (stream.str()); } - esm.getHT (mValue); + esm.getHT(out); } else if (format==Variant::Format_Local) { @@ -184,18 +82,18 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT { short value; esm.getHT(value); - mValue = value; + out = value; } else if (type==VT_Int) { - esm.getHT(mValue); + esm.getHT(out); } else esm.fail("unsupported local variable integer type"); } } -void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const +void ESM::writeESMVariantValue(ESMWriter& esm, Variant::Format format, VarType type, int in) { if (type!=VT_Short && type!=VT_Long && type!=VT_Int) throw std::logic_error ("not an integer type"); @@ -204,7 +102,7 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var { if (type==VT_Short || type==VT_Long) { - float value = static_cast(mValue); + float value = static_cast(in); esm.writeHNString ("FNAM", type==VT_Short ? "s" : "l"); esm.writeHNT ("FLTV", value); } @@ -222,72 +120,35 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var throw std::runtime_error (stream.str()); } - esm.writeHNT ("INTV", mValue); + esm.writeHNT("INTV", in); } else if (format==Variant::Format_Local) { if (type==VT_Short) - esm.writeHNT ("STTV", (short)mValue); + esm.writeHNT("STTV", static_cast(in)); else if (type == VT_Int) - esm.writeHNT ("INTV", mValue); + esm.writeHNT("INTV", in); else throw std::runtime_error("unsupported local variable integer type"); } } -bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const -{ - return dynamic_cast (value).mValue==mValue; -} - - -ESM::VariantFloatData::VariantFloatData (const VariantDataBase *data) : mValue (0) -{ - if (data) - mValue = data->getFloat (true); -} - -ESM::VariantDataBase *ESM::VariantFloatData::clone() const -{ - return new VariantFloatData (*this); -} - -int ESM::VariantFloatData::getInteger (bool default_) const -{ - return static_cast (mValue); -} - -float ESM::VariantFloatData::getFloat (bool default_) const -{ - return mValue; -} - -void ESM::VariantFloatData::setInteger (int value) -{ - mValue = static_cast(value); -} - -void ESM::VariantFloatData::setFloat (float value) -{ - mValue = value; -} - -void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarType type) +void ESM::readESMVariantValue(ESMReader& esm, Variant::Format format, VarType type, float& out) { if (type!=VT_Float) throw std::logic_error ("not a float type"); if (format==Variant::Format_Global) { - esm.getHNT (mValue, "FLTV"); + esm.getHNT(out, "FLTV"); } else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local) { - esm.getHT (mValue); + esm.getHT(out); } } -void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarType type) const +void ESM::writeESMVariantValue(ESMWriter& esm, Variant::Format format, VarType type, float in) { if (type!=VT_Float) throw std::logic_error ("not a float type"); @@ -295,15 +156,10 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy if (format==Variant::Format_Global) { esm.writeHNString ("FNAM", "f"); - esm.writeHNT ("FLTV", mValue); + esm.writeHNT("FLTV", in); } else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local) { - esm.writeHNT ("FLTV", mValue); + esm.writeHNT("FLTV", in); } } - -bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const -{ - return dynamic_cast (value).mValue==mValue; -} diff --git a/components/esm/variantimp.hpp b/components/esm/variantimp.hpp index c1203ddf8..945872811 100644 --- a/components/esm/variantimp.hpp +++ b/components/esm/variantimp.hpp @@ -2,177 +2,58 @@ #define OPENMW_ESM_VARIANTIMP_H #include +#include #include "variant.hpp" namespace ESM { - class VariantDataBase + void readESMVariantValue(ESMReader& reader, Variant::Format format, VarType type, std::string& value); + + void readESMVariantValue(ESMReader& reader, Variant::Format format, VarType type, float& value); + + void readESMVariantValue(ESMReader& reader, Variant::Format format, VarType type, int& value); + + void writeESMVariantValue(ESMWriter& writer, Variant::Format format, VarType type, const std::string& value); + + void writeESMVariantValue(ESMWriter& writer, Variant::Format format, VarType type, float value); + + void writeESMVariantValue(ESMWriter& writer, Variant::Format format, VarType type, int value); + + struct ReadESMVariantValue { - public: + std::reference_wrapper mReader; + Variant::Format mFormat; + VarType mType; - virtual ~VariantDataBase(); + ReadESMVariantValue(ESMReader& reader, Variant::Format format, VarType type) + : mReader(reader), mFormat(format), mType(type) {} - virtual VariantDataBase *clone() const = 0; - - virtual std::string getString (bool default_ = false) const; - ///< Will throw an exception, if value can not be represented as a string. - /// - /// \note Numeric values are not converted to strings. - /// - /// \param default_ Return a default value instead of throwing an exception. - /// - /// Default-implementation: throw an exception. - - virtual int getInteger (bool default_ = false) const; - ///< Will throw an exception, if value can not be represented as an integer (implicit - /// casting of float values is permitted). - /// - /// \param default_ Return a default value instead of throwing an exception. - /// - /// Default-implementation: throw an exception. - - virtual float getFloat (bool default_ = false) const; - ///< Will throw an exception, if value can not be represented as a float value. - /// - /// \param default_ Return a default value instead of throwing an exception. - /// - /// Default-implementation: throw an exception. - - virtual void setString (const std::string& value); - ///< Will throw an exception, if type is not compatible with string. - /// - /// Default-implementation: throw an exception. - - virtual void setInteger (int value); - ///< Will throw an exception, if type is not compatible with integer. - /// - /// Default-implementation: throw an exception. - - virtual void setFloat (float value); - ///< Will throw an exception, if type is not compatible with float. - /// - /// Default-implementation: throw an exception. - - virtual void read (ESMReader& esm, Variant::Format format, VarType type) = 0; - ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail - - virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const = 0; - ///< If \a type is not supported by \a format, an exception is thrown. - - virtual bool isEqual (const VariantDataBase& value) const = 0; - ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + void operator()(std::monostate) const {} + template + void operator()(T& value) const + { + readESMVariantValue(mReader.get(), mFormat, mType, value); + } }; - class VariantStringData : public VariantDataBase + struct WriteESMVariantValue { - std::string mValue; + std::reference_wrapper mWriter; + Variant::Format mFormat; + VarType mType; - public: + WriteESMVariantValue(ESMWriter& writer, Variant::Format format, VarType type) + : mWriter(writer), mFormat(format), mType(type) {} - VariantStringData (const VariantDataBase *data = nullptr); - ///< Calling the constructor with an incompatible data type will result in a silent - /// default initialisation. + void operator()(std::monostate) const {} - VariantDataBase *clone() const override; - - std::string getString (bool default_ = false) const override; - ///< Will throw an exception, if value can not be represented as a string. - /// - /// \note Numeric values are not converted to strings. - /// - /// \param default_ Return a default value instead of throwing an exception. - - void setString (const std::string& value) override; - ///< Will throw an exception, if type is not compatible with string. - - void read (ESMReader& esm, Variant::Format format, VarType type) override; - ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail - - void write (ESMWriter& esm, Variant::Format format, VarType type) const override; - ///< If \a type is not supported by \a format, an exception is thrown. - - bool isEqual (const VariantDataBase& value) const override; - ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. - }; - - class VariantIntegerData : public VariantDataBase - { - int mValue; - - public: - - VariantIntegerData (const VariantDataBase *data = nullptr); - ///< Calling the constructor with an incompatible data type will result in a silent - /// default initialisation. - - VariantDataBase *clone() const override; - - int getInteger (bool default_ = false) const override; - ///< Will throw an exception, if value can not be represented as an integer (implicit - /// casting of float values is permitted). - /// - /// \param default_ Return a default value instead of throwing an exception. - - float getFloat (bool default_ = false) const override; - ///< Will throw an exception, if value can not be represented as a float value. - /// - /// \param default_ Return a default value instead of throwing an exception. - - void setInteger (int value) override; - ///< Will throw an exception, if type is not compatible with integer. - - void setFloat (float value) override; - ///< Will throw an exception, if type is not compatible with float. - - void read (ESMReader& esm, Variant::Format format, VarType type) override; - ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail - - void write (ESMWriter& esm, Variant::Format format, VarType type) const override; - ///< If \a type is not supported by \a format, an exception is thrown. - - bool isEqual (const VariantDataBase& value) const override; - ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. - }; - - class VariantFloatData : public VariantDataBase - { - float mValue; - - public: - - VariantFloatData (const VariantDataBase *data = nullptr); - ///< Calling the constructor with an incompatible data type will result in a silent - /// default initialisation. - - VariantDataBase *clone() const override; - - int getInteger (bool default_ = false) const override; - ///< Will throw an exception, if value can not be represented as an integer (implicit - /// casting of float values is permitted). - /// - /// \param default_ Return a default value instead of throwing an exception. - - float getFloat (bool default_ = false) const override; - ///< Will throw an exception, if value can not be represented as a float value. - /// - /// \param default_ Return a default value instead of throwing an exception. - - void setInteger (int value) override; - ///< Will throw an exception, if type is not compatible with integer. - - void setFloat (float value) override; - ///< Will throw an exception, if type is not compatible with float. - - void read (ESMReader& esm, Variant::Format format, VarType type) override; - ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail - - void write (ESMWriter& esm, Variant::Format format, VarType type) const override; - ///< If \a type is not supported by \a format, an exception is thrown. - - bool isEqual (const VariantDataBase& value) const override; - ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + template + void operator()(const T& value) const + { + writeESMVariantValue(mWriter.get(), mFormat, mType, value); + } }; }