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:
commit
301411c5c5
5 changed files with 148 additions and 498 deletions
|
@ -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> {};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue