mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 16:29:55 +00:00
Add NormalizedView for normalized paths
This commit is contained in:
parent
1689c59546
commit
062d3e9c00
2 changed files with 128 additions and 9 deletions
|
@ -37,6 +37,13 @@ namespace VFS::Path
|
||||||
EXPECT_EQ(value.view(), "foo/bar/baz");
|
EXPECT_EQ(value.view(), "foo/bar/baz");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(NormalizedTest, shouldSupportConstructorFromNormalizedView)
|
||||||
|
{
|
||||||
|
const NormalizedView view = "foo/bar/baz";
|
||||||
|
const Normalized value(view);
|
||||||
|
EXPECT_EQ(value.view(), "foo/bar/baz");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(NormalizedTest, supportMovingValueOut)
|
TEST(NormalizedTest, supportMovingValueOut)
|
||||||
{
|
{
|
||||||
Normalized value("Foo\\Bar/baz");
|
Normalized value("Foo\\Bar/baz");
|
||||||
|
@ -67,9 +74,11 @@ namespace VFS::Path
|
||||||
|
|
||||||
TYPED_TEST_P(NormalizedOperatorsTest, supportsEqual)
|
TYPED_TEST_P(NormalizedOperatorsTest, supportsEqual)
|
||||||
{
|
{
|
||||||
const Normalized normalized("a/foo/bar/baz");
|
using Type0 = typename TypeParam::Type0;
|
||||||
const TypeParam otherEqual{ "a/foo/bar/baz" };
|
using Type1 = typename TypeParam::Type1;
|
||||||
const TypeParam otherNotEqual{ "b/foo/bar/baz" };
|
const Type0 normalized{ "a/foo/bar/baz" };
|
||||||
|
const Type1 otherEqual{ "a/foo/bar/baz" };
|
||||||
|
const Type1 otherNotEqual{ "b/foo/bar/baz" };
|
||||||
EXPECT_EQ(normalized, otherEqual);
|
EXPECT_EQ(normalized, otherEqual);
|
||||||
EXPECT_EQ(otherEqual, normalized);
|
EXPECT_EQ(otherEqual, normalized);
|
||||||
EXPECT_NE(normalized, otherNotEqual);
|
EXPECT_NE(normalized, otherNotEqual);
|
||||||
|
@ -78,10 +87,12 @@ namespace VFS::Path
|
||||||
|
|
||||||
TYPED_TEST_P(NormalizedOperatorsTest, supportsLess)
|
TYPED_TEST_P(NormalizedOperatorsTest, supportsLess)
|
||||||
{
|
{
|
||||||
const Normalized normalized("b/foo/bar/baz");
|
using Type0 = typename TypeParam::Type0;
|
||||||
const TypeParam otherEqual{ "b/foo/bar/baz" };
|
using Type1 = typename TypeParam::Type1;
|
||||||
const TypeParam otherLess{ "a/foo/bar/baz" };
|
const Type0 normalized{ "b/foo/bar/baz" };
|
||||||
const TypeParam otherGreater{ "c/foo/bar/baz" };
|
const Type1 otherEqual{ "b/foo/bar/baz" };
|
||||||
|
const Type1 otherLess{ "a/foo/bar/baz" };
|
||||||
|
const Type1 otherGreater{ "c/foo/bar/baz" };
|
||||||
EXPECT_FALSE(normalized < otherEqual);
|
EXPECT_FALSE(normalized < otherEqual);
|
||||||
EXPECT_FALSE(otherEqual < normalized);
|
EXPECT_FALSE(otherEqual < normalized);
|
||||||
EXPECT_LT(otherLess, normalized);
|
EXPECT_LT(otherLess, normalized);
|
||||||
|
@ -92,8 +103,37 @@ namespace VFS::Path
|
||||||
|
|
||||||
REGISTER_TYPED_TEST_SUITE_P(NormalizedOperatorsTest, supportsEqual, supportsLess);
|
REGISTER_TYPED_TEST_SUITE_P(NormalizedOperatorsTest, supportsEqual, supportsLess);
|
||||||
|
|
||||||
using StringTypes = Types<Normalized, const char*, std::string, std::string_view>;
|
template <class T0, class T1>
|
||||||
|
struct TypePair
|
||||||
|
{
|
||||||
|
using Type0 = T0;
|
||||||
|
using Type1 = T1;
|
||||||
|
};
|
||||||
|
|
||||||
INSTANTIATE_TYPED_TEST_SUITE_P(Typed, NormalizedOperatorsTest, StringTypes);
|
using TypePairs = Types<TypePair<Normalized, Normalized>, TypePair<Normalized, const char*>,
|
||||||
|
TypePair<Normalized, std::string>, TypePair<Normalized, std::string_view>,
|
||||||
|
TypePair<Normalized, NormalizedView>, TypePair<NormalizedView, Normalized>,
|
||||||
|
TypePair<NormalizedView, const char*>, TypePair<NormalizedView, std::string>,
|
||||||
|
TypePair<NormalizedView, std::string_view>, TypePair<NormalizedView, NormalizedView>>;
|
||||||
|
|
||||||
|
INSTANTIATE_TYPED_TEST_SUITE_P(Typed, NormalizedOperatorsTest, TypePairs);
|
||||||
|
|
||||||
|
TEST(NormalizedViewTest, shouldSupportConstructorFromNormalized)
|
||||||
|
{
|
||||||
|
const Normalized value("Foo\\Bar/baz");
|
||||||
|
const NormalizedView view(value);
|
||||||
|
EXPECT_EQ(view.value(), "foo/bar/baz");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NormalizedViewTest, shouldSupportConstexprConstructorFromNormalizedStringLiteral)
|
||||||
|
{
|
||||||
|
constexpr NormalizedView view("foo/bar/baz");
|
||||||
|
EXPECT_EQ(view.value(), "foo/bar/baz");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NormalizedViewTest, constructorShouldThrowExceptionOnNotNormalized)
|
||||||
|
{
|
||||||
|
EXPECT_THROW([] { NormalizedView("Foo\\Bar/baz"); }(), std::invalid_argument);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
@ -58,6 +59,59 @@ namespace VFS::Path
|
||||||
bool operator()(std::string_view left, std::string_view right) const { return pathLess(left, right); }
|
bool operator()(std::string_view left, std::string_view right) const { return pathLess(left, right); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Normalized;
|
||||||
|
|
||||||
|
class NormalizedView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
constexpr NormalizedView() noexcept = default;
|
||||||
|
|
||||||
|
constexpr NormalizedView(const char* value)
|
||||||
|
: mValue(value)
|
||||||
|
{
|
||||||
|
if (!isNormalized(mValue))
|
||||||
|
throw std::invalid_argument("NormalizedView value is not normalized: \"" + std::string(mValue) + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
NormalizedView(const Normalized& value) noexcept;
|
||||||
|
|
||||||
|
constexpr std::string_view value() const noexcept { return mValue; }
|
||||||
|
|
||||||
|
friend constexpr bool operator==(const NormalizedView& lhs, const NormalizedView& rhs) = default;
|
||||||
|
|
||||||
|
friend constexpr bool operator==(const NormalizedView& lhs, const auto& rhs) { return lhs.mValue == rhs; }
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1935
|
||||||
|
friend constexpr bool operator==(const auto& lhs, const NormalizedView& rhs)
|
||||||
|
{
|
||||||
|
return lhs == rhs.mValue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
friend constexpr bool operator<(const NormalizedView& lhs, const NormalizedView& rhs)
|
||||||
|
{
|
||||||
|
return lhs.mValue < rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator<(const NormalizedView& lhs, const auto& rhs)
|
||||||
|
{
|
||||||
|
return lhs.mValue < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator<(const auto& lhs, const NormalizedView& rhs)
|
||||||
|
{
|
||||||
|
return lhs < rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& stream, const NormalizedView& value)
|
||||||
|
{
|
||||||
|
return stream << value.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string_view mValue;
|
||||||
|
};
|
||||||
|
|
||||||
class Normalized
|
class Normalized
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -84,6 +138,11 @@ namespace VFS::Path
|
||||||
normalizeFilenameInPlace(mValue);
|
normalizeFilenameInPlace(mValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit Normalized(NormalizedView value)
|
||||||
|
: mValue(value.value())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& value() const& { return mValue; }
|
const std::string& value() const& { return mValue; }
|
||||||
|
|
||||||
std::string value() && { return std::move(mValue); }
|
std::string value() && { return std::move(mValue); }
|
||||||
|
@ -105,6 +164,11 @@ namespace VFS::Path
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
friend bool operator==(const Normalized& lhs, const NormalizedView& rhs)
|
||||||
|
{
|
||||||
|
return lhs.mValue == rhs.value();
|
||||||
|
}
|
||||||
|
|
||||||
friend bool operator<(const Normalized& lhs, const Normalized& rhs)
|
friend bool operator<(const Normalized& lhs, const Normalized& rhs)
|
||||||
{
|
{
|
||||||
return lhs.mValue < rhs.mValue;
|
return lhs.mValue < rhs.mValue;
|
||||||
|
@ -120,6 +184,16 @@ namespace VFS::Path
|
||||||
return lhs < rhs.mValue;
|
return lhs < rhs.mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend bool operator<(const Normalized& lhs, const NormalizedView& rhs)
|
||||||
|
{
|
||||||
|
return lhs.mValue < rhs.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<(const NormalizedView& lhs, const Normalized& rhs)
|
||||||
|
{
|
||||||
|
return lhs.value() < rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& stream, const Normalized& value)
|
friend std::ostream& operator<<(std::ostream& stream, const Normalized& value)
|
||||||
{
|
{
|
||||||
return stream << value.mValue;
|
return stream << value.mValue;
|
||||||
|
@ -128,6 +202,11 @@ namespace VFS::Path
|
||||||
private:
|
private:
|
||||||
std::string mValue;
|
std::string mValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline NormalizedView::NormalizedView(const Normalized& value) noexcept
|
||||||
|
: mValue(value.view())
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue