mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 16:29:55 +00:00
Fix loading order in EsmLoader
Need to load the last present record from a sequence of loaded records. That means reverse should be called before unique or unique should be applied for a reversed range. Since unique keeps only the first element from a sub sequence of equal elements. Use forEachUnique with reversed range to avoid redundant container modifications.
This commit is contained in:
parent
d3d9abede4
commit
194c11f214
3 changed files with 110 additions and 3 deletions
|
@ -67,6 +67,7 @@ if (GTEST_FOUND AND GMOCK_FOUND)
|
||||||
|
|
||||||
esmloader/load.cpp
|
esmloader/load.cpp
|
||||||
esmloader/esmdata.cpp
|
esmloader/esmdata.cpp
|
||||||
|
esmloader/record.cpp
|
||||||
|
|
||||||
files/hash.cpp
|
files/hash.cpp
|
||||||
|
|
||||||
|
|
105
apps/openmw_test_suite/esmloader/record.cpp
Normal file
105
apps/openmw_test_suite/esmloader/record.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#include <components/esmloader/record.hpp>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace testing;
|
||||||
|
using namespace EsmLoader;
|
||||||
|
|
||||||
|
struct Value
|
||||||
|
{
|
||||||
|
int mKey;
|
||||||
|
int mValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto tie(const Value& v)
|
||||||
|
{
|
||||||
|
return std::tie(v.mKey, v.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Value& l, const Value& r)
|
||||||
|
{
|
||||||
|
return tie(l) == tie(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& s, const Value& v)
|
||||||
|
{
|
||||||
|
return s << "Value {" << v.mKey << ", " << v.mValue << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
Record<Value> present(const Value& v)
|
||||||
|
{
|
||||||
|
return Record<Value>(false, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Record<Value> deleted(const Value& v)
|
||||||
|
{
|
||||||
|
return Record<Value>(true, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Params
|
||||||
|
{
|
||||||
|
Records<Value> mRecords;
|
||||||
|
std::vector<Value> mResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EsmLoaderPrepareRecordTest : TestWithParam<Params> {};
|
||||||
|
|
||||||
|
TEST_P(EsmLoaderPrepareRecordTest, prepareRecords)
|
||||||
|
{
|
||||||
|
auto records = GetParam().mRecords;
|
||||||
|
const auto getKey = [&] (const Record<Value>& v) { return v.mValue.mKey; };
|
||||||
|
EXPECT_THAT(prepareRecords(records, getKey), ElementsAreArray(GetParam().mResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array params = {
|
||||||
|
Params {{}, {}},
|
||||||
|
Params {
|
||||||
|
{present(Value {1, 1})},
|
||||||
|
{Value {1, 1}}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{deleted(Value {1, 1})},
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{present(Value {1, 1}), present(Value {2, 2})},
|
||||||
|
{Value {1, 1}, Value {2, 2}}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{present(Value {2, 2}), present(Value {1, 1})},
|
||||||
|
{Value {1, 1}, Value {2, 2}}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{present(Value {1, 1}), present(Value {1, 2})},
|
||||||
|
{Value {1, 2}}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{present(Value {1, 2}), present(Value {1, 1})},
|
||||||
|
{Value {1, 1}}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{present(Value {1, 1}), deleted(Value {1, 2})},
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{deleted(Value {1, 1}), present(Value {1, 2})},
|
||||||
|
{Value {1, 2}}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{present(Value {1, 2}), deleted(Value {1, 1})},
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
Params {
|
||||||
|
{deleted(Value {1, 2}), present(Value {1, 1})},
|
||||||
|
{Value {1, 1}}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(Params, EsmLoaderPrepareRecordTest, ValuesIn(params));
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_COMPONENTS_ESMLOADER_RECORD_H
|
#define OPENMW_COMPONENTS_ESMLOADER_RECORD_H
|
||||||
|
|
||||||
#include <components/esm3/loadcell.hpp>
|
#include <components/esm3/loadcell.hpp>
|
||||||
|
#include <components/misc/algorithm.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -31,12 +32,12 @@ namespace EsmLoader
|
||||||
const auto greaterByKey = [&] (const auto& l, const auto& r) { return getKey(r) < getKey(l); };
|
const auto greaterByKey = [&] (const auto& l, const auto& r) { return getKey(r) < getKey(l); };
|
||||||
const auto equalByKey = [&] (const auto& l, const auto& r) { return getKey(l) == getKey(r); };
|
const auto equalByKey = [&] (const auto& l, const auto& r) { return getKey(l) == getKey(r); };
|
||||||
std::stable_sort(records.begin(), records.end(), greaterByKey);
|
std::stable_sort(records.begin(), records.end(), greaterByKey);
|
||||||
records.erase(std::unique(records.begin(), records.end(), equalByKey), records.end());
|
|
||||||
std::reverse(records.begin(), records.end());
|
|
||||||
std::vector<T> result;
|
std::vector<T> result;
|
||||||
for (Record<T>& v : records)
|
Misc::forEachUnique(records.rbegin(), records.rend(), equalByKey, [&] (const auto& v)
|
||||||
|
{
|
||||||
if (!v.mDeleted)
|
if (!v.mDeleted)
|
||||||
result.emplace_back(std::move(v.mValue));
|
result.emplace_back(std::move(v.mValue));
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue