From e7a1a559e989ee25d34fc9beb4a087ae566dd13a Mon Sep 17 00:00:00 2001 From: Daniel Stevens Date: Sun, 16 Mar 2025 10:26:47 -0600 Subject: [PATCH 1/2] Add `FilesystemPathParents` collection class --- NAS2D/FilesystemPathParents.cpp | 100 ++++++++++++++++++++++++++++++++ NAS2D/FilesystemPathParents.h | 48 +++++++++++++++ NAS2D/NAS2D.vcxproj | 2 + NAS2D/NAS2D.vcxproj.filters | 6 ++ 4 files changed, 156 insertions(+) create mode 100644 NAS2D/FilesystemPathParents.cpp create mode 100644 NAS2D/FilesystemPathParents.h diff --git a/NAS2D/FilesystemPathParents.cpp b/NAS2D/FilesystemPathParents.cpp new file mode 100644 index 00000000..600242e5 --- /dev/null +++ b/NAS2D/FilesystemPathParents.cpp @@ -0,0 +1,100 @@ +#include "FilesystemPathParents.h" + +#include + + +namespace +{ + std::size_t parentCount(const NAS2D::FilesystemPath& path) + { + std::size_t count = 1; + for (auto lastPath = path, nextPath = path.parent(); lastPath != nextPath;) + { + ++count; + lastPath = nextPath; + nextPath = nextPath.parent(); + } + return count; + } +} + + +namespace NAS2D +{ + static_assert(std::forward_iterator); + + + FilesystemPathParents::FilesystemPathParents(const FilesystemPath& folder) : + FilesystemPathParents(folder, parentCount(folder)) + { + } + + + FilesystemPathParents::FilesystemPathParents(const FilesystemPath& folder, std::size_t maxLevels) : + mPath{folder}, + mMaxLevels{std::min(maxLevels, parentCount(folder))} + { + } + + + std::size_t FilesystemPathParents::size() const + { + return mMaxLevels; + } + + + FilesystemPathParents::Iterator FilesystemPathParents::begin() const + { + return {mPath, mMaxLevels}; + } + + + FilesystemPathParents::Iterator FilesystemPathParents::end() const + { + return {}; + } + + + FilesystemPathParents::Iterator::Iterator() : + FilesystemPathParents::Iterator::Iterator("", 0) + { + } + + + FilesystemPathParents::Iterator::Iterator(const FilesystemPath& folder, std::size_t levelsRemaining) : + mPath{folder}, + mLevelsRemaining{levelsRemaining} + { + } + + + bool FilesystemPathParents::Iterator::operator==(const Iterator& other) const + { + return mLevelsRemaining == other.mLevelsRemaining && (mLevelsRemaining == 0 || mPath == other.mPath); + } + + + FilesystemPathParents::Iterator& FilesystemPathParents::Iterator::operator++() + { + if (mLevelsRemaining > 0) + { + mPath = mPath.parent(); + --mLevelsRemaining; + } + return *this; + } + + + FilesystemPathParents::Iterator FilesystemPathParents::Iterator::operator++(int) + { + auto temp = *this; + ++*this; + return temp; + } + + + const FilesystemPath& FilesystemPathParents::Iterator::operator*() const + { + return mPath; + } +} diff --git a/NAS2D/FilesystemPathParents.h b/NAS2D/FilesystemPathParents.h new file mode 100644 index 00000000..beaa6417 --- /dev/null +++ b/NAS2D/FilesystemPathParents.h @@ -0,0 +1,48 @@ +#pragma once + +#include "FilesystemPath.h" + + +namespace NAS2D +{ + class FilesystemPathParents + { + public: + class Iterator; + + FilesystemPathParents(const FilesystemPath& folder); + FilesystemPathParents(const FilesystemPath& folder, std::size_t maxLevels); + + std::size_t size() const; + + Iterator begin() const; + Iterator end() const; + + private: + FilesystemPath mPath; + std::size_t mMaxLevels; + + + public: + class Iterator + { + public: + using value_type = FilesystemPath; + using difference_type = std::ptrdiff_t; + + Iterator(); + Iterator(const FilesystemPath& folder, std::size_t levelsRemaining); + + bool operator==(const Iterator& other) const; + + Iterator& operator++(); + Iterator operator++(int); + + const FilesystemPath& operator*() const; + + private: + FilesystemPath mPath; + std::size_t mLevelsRemaining; + }; + }; +} diff --git a/NAS2D/NAS2D.vcxproj b/NAS2D/NAS2D.vcxproj index b255e1b1..9d332ca2 100644 --- a/NAS2D/NAS2D.vcxproj +++ b/NAS2D/NAS2D.vcxproj @@ -156,6 +156,7 @@ + @@ -214,6 +215,7 @@ + diff --git a/NAS2D/NAS2D.vcxproj.filters b/NAS2D/NAS2D.vcxproj.filters index b86fa2c5..c2576b43 100644 --- a/NAS2D/NAS2D.vcxproj.filters +++ b/NAS2D/NAS2D.vcxproj.filters @@ -66,6 +66,9 @@ Source Files + + Source Files + Source Files @@ -236,6 +239,9 @@ Header Files + + Header Files + Header Files From 5669aa9cea05c9e38cc4b6f51e16cd76976a1a21 Mon Sep 17 00:00:00 2001 From: Daniel Stevens Date: Sun, 16 Mar 2025 10:27:27 -0600 Subject: [PATCH 2/2] Add unit tests for `FilesystemPathParents` class --- test/FilesystemPathParents.test.cpp | 45 +++++++++++++++++++++++++++++ test/test.vcxproj | 1 + 2 files changed, 46 insertions(+) create mode 100644 test/FilesystemPathParents.test.cpp diff --git a/test/FilesystemPathParents.test.cpp b/test/FilesystemPathParents.test.cpp new file mode 100644 index 00000000..66002200 --- /dev/null +++ b/test/FilesystemPathParents.test.cpp @@ -0,0 +1,45 @@ +#include "NAS2D/FilesystemPathParents.h" + +#include +#include + + +TEST(FilesystemPathParents, sizeRelativeTrailingSlash) { + EXPECT_EQ(1u, NAS2D::FilesystemPathParents{""}.size()); + EXPECT_EQ(2u, NAS2D::FilesystemPathParents{"a/"}.size()); + EXPECT_EQ(3u, NAS2D::FilesystemPathParents{"a/b/"}.size()); + EXPECT_EQ(4u, NAS2D::FilesystemPathParents{"a/b/c/"}.size()); +} + +TEST(FilesystemPathParents, sizeRelativeNoTrailingSlash) { + EXPECT_EQ(1u, NAS2D::FilesystemPathParents{""}.size()); + EXPECT_EQ(2u, NAS2D::FilesystemPathParents{"a"}.size()); + EXPECT_EQ(3u, NAS2D::FilesystemPathParents{"a/b"}.size()); + EXPECT_EQ(4u, NAS2D::FilesystemPathParents{"a/b/c"}.size()); +} + +TEST(FilesystemPathParents, sizeAbsoluteTrailingSlash) { + EXPECT_EQ(1u, NAS2D::FilesystemPathParents{"/"}.size()); + EXPECT_EQ(2u, NAS2D::FilesystemPathParents{"/a/"}.size()); + EXPECT_EQ(3u, NAS2D::FilesystemPathParents{"/a/b/"}.size()); + EXPECT_EQ(4u, NAS2D::FilesystemPathParents{"/a/b/c/"}.size()); +} + +TEST(FilesystemPathParents, sizeAbsoluteNoTrailingSlash) { + EXPECT_EQ(1u, NAS2D::FilesystemPathParents{"/"}.size()); + EXPECT_EQ(2u, NAS2D::FilesystemPathParents{"/a"}.size()); + EXPECT_EQ(3u, NAS2D::FilesystemPathParents{"/a/b"}.size()); + EXPECT_EQ(4u, NAS2D::FilesystemPathParents{"/a/b/c"}.size()); +} + +TEST(FilesystemPathParents, iterationValuesRelative) { + const auto parentPaths = NAS2D::FilesystemPathParents("a/b/c/"); + const auto paths = std::vector(parentPaths.begin(), parentPaths.end()); + ASSERT_THAT(paths, testing::ElementsAre("a/b/c/", "a/b/", "a/", "")); +} + +TEST(FilesystemPathParents, iterationValuesAbsolute) { + const auto parentPaths = NAS2D::FilesystemPathParents("/a/b/c/"); + const auto paths = std::vector(parentPaths.begin(), parentPaths.end()); + ASSERT_THAT(paths, testing::ElementsAre("/a/b/c/", "/a/b/", "/a/", "/")); +} diff --git a/test/test.vcxproj b/test/test.vcxproj index 49c805e8..b3978a83 100644 --- a/test/test.vcxproj +++ b/test/test.vcxproj @@ -165,6 +165,7 @@ +