1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 19:19:56 +00:00

Merge branch 'esm_variant' into 'master'

Use std::variant for ESM::Variant implementation

See merge request OpenMW/openmw!719
This commit is contained in:
psi29a 2021-04-10 12:53:11 +00:00
commit 301411c5c5
5 changed files with 148 additions and 498 deletions

View file

@ -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)
@ -420,7 +420,6 @@ namespace
Variant mVariant;
Variant::Format mFormat;
std::size_t mDataSize {};
std::size_t mDataHash {};
};
std::string write(const Variant& variant, const Variant::Format format)
@ -442,11 +441,10 @@ namespace
return result;
}
Variant writeAndRead(const Variant& variant, const Variant::Format format, std::size_t dataSize, std::size_t dataHash)
Variant writeAndRead(const Variant& variant, const Variant::Format format, std::size_t dataSize)
{
const std::string data = write(variant, format);
EXPECT_EQ(data.size(), dataSize);
EXPECT_EQ(std::hash<std::string>{}(data), dataHash);
return read(format, data);
}
@ -455,20 +453,20 @@ namespace
TEST_P(ESMVariantToESMTest, deserialized_is_equal_to_serialized)
{
const auto param = GetParam();
const auto result = writeAndRead(param.mVariant, param.mFormat, param.mDataSize, param.mDataHash);
const auto result = writeAndRead(param.mVariant, param.mFormat, param.mDataSize);
ASSERT_EQ(param.mVariant, result);
}
INSTANTIATE_TEST_SUITE_P(VariantAndData, ESMVariantToESMTest, Values(
WriteToESMTestCase {Variant(), Variant::Format_Gmst, 324, 10398667754238537314ul},
WriteToESMTestCase {Variant(int{42}), Variant::Format_Global, 345, 2440845426097842853ul},
WriteToESMTestCase {Variant(float{2.7f}), Variant::Format_Global, 345, 8428720798053904009ul},
WriteToESMTestCase {Variant(float{2.7f}), Variant::Format_Info, 336, 11930997575130354755ul},
WriteToESMTestCase {Variant(float{2.7f}), Variant::Format_Local, 336, 11930997575130354755ul},
WriteToESMTestCase {makeVariant(VT_Short, 42), Variant::Format_Global, 345, 7812065815960720679ul},
WriteToESMTestCase {makeVariant(VT_Short, 42), Variant::Format_Local, 334, 5017869102981712080ul},
WriteToESMTestCase {makeVariant(VT_Int, 42), Variant::Format_Info, 336, 12560431547347287906ul},
WriteToESMTestCase {makeVariant(VT_Int, 42), Variant::Format_Local, 336, 12560431547347287906ul}
WriteToESMTestCase {Variant(), Variant::Format_Gmst, 324},
WriteToESMTestCase {Variant(int{42}), Variant::Format_Global, 345},
WriteToESMTestCase {Variant(float{2.7f}), Variant::Format_Global, 345},
WriteToESMTestCase {Variant(float{2.7f}), Variant::Format_Info, 336},
WriteToESMTestCase {Variant(float{2.7f}), Variant::Format_Local, 336},
WriteToESMTestCase {makeVariant(VT_Short, 42), Variant::Format_Global, 345},
WriteToESMTestCase {makeVariant(VT_Short, 42), Variant::Format_Local, 334},
WriteToESMTestCase {makeVariant(VT_Int, 42), Variant::Format_Info, 336},
WriteToESMTestCase {makeVariant(VT_Int, 42), Variant::Format_Local, 336}
));
struct ESMVariantToESMNoneTest : TestWithParam<WriteToESMTestCase> {};
@ -476,14 +474,14 @@ namespace
TEST_P(ESMVariantToESMNoneTest, deserialized_is_none)
{
const auto param = GetParam();
const auto result = writeAndRead(param.mVariant, param.mFormat, param.mDataSize, param.mDataHash);
const auto result = writeAndRead(param.mVariant, param.mFormat, param.mDataSize);
ASSERT_EQ(Variant(), result);
}
INSTANTIATE_TEST_SUITE_P(VariantAndData, ESMVariantToESMNoneTest, Values(
WriteToESMTestCase {Variant(float{2.7f}), Variant::Format_Gmst, 336, 11930997575130354755ul},
WriteToESMTestCase {Variant(std::string("foo")), Variant::Format_Gmst, 335, 7604528240659685057ul},
WriteToESMTestCase {makeVariant(VT_Int, 42), Variant::Format_Gmst, 336, 12560431547347287906ul}
WriteToESMTestCase {Variant(float{2.7f}), Variant::Format_Gmst, 336},
WriteToESMTestCase {Variant(std::string("foo")), Variant::Format_Gmst, 335},
WriteToESMTestCase {makeVariant(VT_Int, 42), Variant::Format_Gmst, 336}
));
struct ESMVariantWriteToESMFailTest : TestWithParam<WriteToESMTestCase> {};

View file

@ -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 <typename T, bool orDefault = false>
struct GetValue
{
VariantDataBase *newData = variant.mData ? variant.mData->clone() : nullptr;
T operator()(int value) const { return static_cast<T>(value); }
delete mData;
T operator()(float value) const { return static_cast<T>(value); }
mType = variant.mType;
mData = newData;
}
template <typename V>
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 <typename T>
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<int>(mValue); }
return *this;
}
void operator()(float& value) const { value = static_cast<float>(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 <typename V>
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<std::string>(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<int>{}, 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<float>{}, 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<int>(mData);
break;
case VT_Int:
stream << "variant int: " << mData->getInteger();
stream << "variant int: " << std::get<int>(mData);
break;
case VT_Long:
stream << "variant long: " << mData->getInteger();
stream << "variant long: " << std::get<int>(mData);
break;
case VT_Float:
stream << "variant float: " << mData->getFloat();
stream << "variant float: " << std::get<float>(mData);
break;
case VT_String:
stream << "variant string: \"" << mData->getString() << "\"";
stream << "variant string: \"" << std::get<std::string>(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<int, true>{}, mData);
break;
case VT_Float:
newData = new VariantFloatData (mData);
mData = std::visit(GetValue<float, true>{}, 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<std::string>(mData) = value;
}
mData->setString (value);
void ESM::Variant::setString (std::string&& value)
{
std::get<std::string>(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);
}

View file

@ -3,6 +3,8 @@
#include <string>
#include <iosfwd>
#include <variant>
#include <tuple>
namespace ESM
{
@ -20,12 +22,10 @@ namespace ESM
VT_String
};
class VariantDataBase;
class Variant
{
VarType mType;
VariantDataBase *mData;
std::variant<std::monostate, int, float, std::string> 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

View file

@ -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<const VariantStringData&> (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<float>(mValue);
}
void ESM::VariantIntegerData::setInteger (int value)
{
mValue = value;
}
void ESM::VariantIntegerData::setFloat (float value)
{
mValue = static_cast<int> (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<short> (value);
out = static_cast<short> (value);
}
else if (type==VT_Long)
mValue = static_cast<int> (value);
out = static_cast<int> (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<float>(mValue);
float value = static_cast<float>(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<short>(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<const VariantIntegerData&> (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<int> (mValue);
}
float ESM::VariantFloatData::getFloat (bool default_) const
{
return mValue;
}
void ESM::VariantFloatData::setInteger (int value)
{
mValue = static_cast<float>(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<const VariantFloatData&> (value).mValue==mValue;
}

View file

@ -2,177 +2,58 @@
#define OPENMW_ESM_VARIANTIMP_H
#include <string>
#include <functional>
#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<ESMReader> 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 <typename T>
void operator()(T& value) const
{
readESMVariantValue(mReader.get(), mFormat, mType, value);
}
};
class VariantStringData : public VariantDataBase
struct WriteESMVariantValue
{
std::string mValue;
std::reference_wrapper<ESMWriter> 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 <typename T>
void operator()(const T& value) const
{
writeESMVariantValue(mWriter.get(), mFormat, mType, value);
}
};
}