From fe3ab7b937c21807fc3c325965bae1b9e8c52446 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 14 Jul 2022 15:59:55 +0200 Subject: [PATCH] fs/Path: add WithSuffix() --- src/fs/AllocatedPath.cxx | 15 +++++++++++++++ src/fs/AllocatedPath.hxx | 21 +++++++++++++++++++++ src/fs/Path.hxx | 10 ++++++++++ src/fs/Path2.cxx | 8 ++++++++ test/fs/TestPath.cxx | 11 +++++++++++ 5 files changed, 65 insertions(+) diff --git a/src/fs/AllocatedPath.cxx b/src/fs/AllocatedPath.cxx index b6bf07eb7..85b539315 100644 --- a/src/fs/AllocatedPath.cxx +++ b/src/fs/AllocatedPath.cxx @@ -48,6 +48,21 @@ AllocatedPath::FromUTF8Throw(std::string_view path_utf8) #endif } +void +AllocatedPath::SetSuffix(const_pointer new_suffix) noexcept +{ + assert(new_suffix != nullptr); + assert(*new_suffix == '.'); + + const auto end = value.end(); + auto begin = end; + + if (auto old = GetSuffix()) + begin = std::next(value.begin(), old - value.data()); + + value.replace(begin, end, new_suffix); +} + void AllocatedPath::ChopSeparators() noexcept { diff --git a/src/fs/AllocatedPath.hxx b/src/fs/AllocatedPath.hxx index e07007838..428312206 100644 --- a/src/fs/AllocatedPath.hxx +++ b/src/fs/AllocatedPath.hxx @@ -304,6 +304,27 @@ public: return Path{*this}.GetSuffix(); } + /** + * Replace the suffix of this path (or append the suffix if + * there is none currently). + * + * @param new_suffix the new filename suffix (must start with + * a dot) + */ + void SetSuffix(const_pointer new_suffix) noexcept; + + /** + * Return a copy of this path but with the given suffix + * (replacing the existing suffix if there is one). + * + * @param new_suffix the new filename suffix (must start with + * a dot) + */ + [[gnu::pure]] + AllocatedPath WithSuffix(const_pointer new_suffix) const noexcept { + return Path{*this}.WithSuffix(new_suffix); + } + /** * Returns the filename extension (excluding the dot) or * nullptr if the path does not have one. diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx index d874fb015..0391f2781 100644 --- a/src/fs/Path.hxx +++ b/src/fs/Path.hxx @@ -173,6 +173,16 @@ public: [[gnu::pure]] const_pointer GetSuffix() const noexcept; + /** + * Return a copy of this path but with the given suffix + * (replacing the existing suffix if there is one). + * + * @param new_suffix the new filename suffix (must start with + * a dot) + */ + [[gnu::pure]] + AllocatedPath WithSuffix(const_pointer new_suffix) const noexcept; + /** * Returns the filename extension (excluding the dot) or * nullptr if the path does not have one. diff --git a/src/fs/Path2.cxx b/src/fs/Path2.cxx index 259a23f29..6d45b2cc7 100644 --- a/src/fs/Path2.cxx +++ b/src/fs/Path2.cxx @@ -26,6 +26,14 @@ Path::GetDirectoryName() const noexcept return AllocatedPath::FromFS(PathTraitsFS::GetParent(c_str())); } +AllocatedPath +Path::WithSuffix(const_pointer new_suffix) const noexcept +{ + AllocatedPath result{*this}; + result.SetSuffix(new_suffix); + return result; +} + AllocatedPath operator/(Path a, Path b) noexcept { diff --git a/test/fs/TestPath.cxx b/test/fs/TestPath.cxx index f8830feb9..613648e2c 100644 --- a/test/fs/TestPath.cxx +++ b/test/fs/TestPath.cxx @@ -96,3 +96,14 @@ TEST(Path, Suffix) EXPECT_STREQ(Path::FromFS(PATH_LITERAL("/foo/.bar.abc")).GetSuffix(), ".abc"); EXPECT_STREQ(Path::FromFS(PATH_LITERAL("/foo/.bar.abc.def")).GetSuffix(), ".def"); } + +TEST(Path, WithSuffix) +{ + EXPECT_STREQ(Path::FromFS(PATH_LITERAL("foo")).WithSuffix(".abc").c_str(), "foo.abc"); + EXPECT_STREQ(Path::FromFS(PATH_LITERAL("/foo/bar")).WithSuffix(".abc").c_str(), "/foo/bar.abc"); + EXPECT_STREQ(Path::FromFS(PATH_LITERAL("/foo.xyz/bar")).WithSuffix(".abc").c_str(), "/foo.xyz/bar.abc"); + EXPECT_STREQ(Path::FromFS(PATH_LITERAL("/foo.abc/bar.def")).WithSuffix(".xyz").c_str(), "/foo.abc/bar.xyz"); + EXPECT_STREQ(Path::FromFS(PATH_LITERAL("/foo.abc/bar.def.ghi")).WithSuffix(".xyz").c_str(), "/foo.abc/bar.def.xyz"); + EXPECT_STREQ(Path::FromFS(PATH_LITERAL("/foo/.bar.abc")).WithSuffix(".xyz").c_str(), "/foo/.bar.xyz"); + EXPECT_STREQ(Path::FromFS(PATH_LITERAL("/foo/.bar.abc.def")).WithSuffix(".xyz").c_str(), "/foo/.bar.abc.xyz"); +}