This is an automated email from the ASF dual-hosted git repository.

bennoe pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit ddf59b8b99b95fe3dc0e862f36dfeed2c0fd287a
Author: Benjamin Bannier <[email protected]>
AuthorDate: Tue Jan 7 13:19:04 2020 +0100

    Added iteration support to stout's Path.
    
    Review: https://reviews.apache.org/r/71878/
---
 3rdparty/stout/include/stout/path.hpp | 85 +++++++++++++++++++++++++++++++++++
 3rdparty/stout/tests/path_tests.cpp   | 44 ++++++++++++++++++
 2 files changed, 129 insertions(+)

diff --git a/3rdparty/stout/include/stout/path.hpp 
b/3rdparty/stout/include/stout/path.hpp
index ba1f665..0aa3b01 100644
--- a/3rdparty/stout/include/stout/path.hpp
+++ b/3rdparty/stout/include/stout/path.hpp
@@ -17,6 +17,8 @@
 #include <utility>
 #include <vector>
 
+#include <glog/logging.h>
+
 #include <stout/stringify.hpp>
 #include <stout/strings.hpp>
 
@@ -379,6 +381,89 @@ public:
     return value;
   }
 
+  // An iterator over path components. Paths are expected to be normalized.
+  //
+  // The effect of using this iterator is to split the path at its
+  // separator and iterate over the different splits. This means in
+  // particular that this class performs no path normalization.
+  class const_iterator
+  {
+  public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = std::string;
+    using difference_type = std::string::const_iterator::difference_type;
+    using pointer = std::string::const_iterator::pointer;
+
+    // We cannot return a reference type (or `const char*` for that
+    // matter) as we neither own string values nor deal with setting up
+    // proper null-terminated output buffers.
+    //
+    // TODO(bbannier): Consider introducing a `string_view`-like class
+    // to wrap path components and use it as a reference type here and as
+    // `value_type`, and as return value for most `Path` member functions 
above.
+    using reference = std::string;
+
+    explicit const_iterator(
+        const Path* path_,
+        std::string::const_iterator offset_)
+      : path(path_), offset(offset_) {}
+
+    // Disallow construction from temporary as we hold a reference to `path`.
+    explicit const_iterator(Path&& path) = delete;
+
+    const_iterator& operator++()
+    {
+      offset = std::find(offset, path->string().end(), path->separator);
+
+      // If after incrementing we have reached the end return immediately.
+      if (offset == path->string().end()) {
+        return *this;
+      } else {
+        // If we are not at the end we have a separator to skip.
+        ++offset;
+      }
+
+      return *this;
+    }
+
+    const_iterator operator++(int)
+    {
+      const_iterator it = *this;
+      ++(*this);
+      return it;
+    }
+
+    bool operator==(const const_iterator& other) const
+    {
+      CHECK_EQ(path, other.path)
+        << "Iterators into different paths cannot be compared";
+
+      return (!path && !other.path) || offset == other.offset;
+    }
+
+    bool operator!=(const const_iterator& other) const
+    {
+      return !(*this == other);
+    }
+
+    reference operator*() const
+    {
+      auto end = std::find(offset, path->string().end(), path->separator);
+      return reference(offset, end);
+    }
+
+  private:
+    const Path* path = nullptr;
+    std::string::const_iterator offset;
+  };
+
+  const_iterator begin() const
+  {
+    return const_iterator(this, string().begin());
+  }
+
+  const_iterator end() const { return const_iterator(this, string().end()); }
+
 private:
   std::string value;
   char separator;
diff --git a/3rdparty/stout/tests/path_tests.cpp 
b/3rdparty/stout/tests/path_tests.cpp
index 19dd910..41c5f6c 100644
--- a/3rdparty/stout/tests/path_tests.cpp
+++ b/3rdparty/stout/tests/path_tests.cpp
@@ -398,6 +398,50 @@ TEST(PathTest, FromURI)
 }
 
 
+TEST(PathTest, PathIteration)
+{
+  {
+    // An empty path should contain no elements and have its begin and
+    // end iterators compare equal.
+    Path path;
+    EXPECT_EQ(0u, std::distance(path.begin(), path.end()));
+    EXPECT_EQ(path.begin(), path.end());
+  }
+
+  {
+    // Checks for behavior of relative paths.
+    const vector<string> components{"1", "2", "3", "4", "5", "file.ext"};
+    const Path relative_path(
+      strings::join(string(1, os::PATH_SEPARATOR), components));
+
+    EXPECT_NE(relative_path.begin(), relative_path.end());
+    EXPECT_EQ(
+      components.size(),
+      std::distance(relative_path.begin(), relative_path.end()));
+
+    EXPECT_EQ(
+        components, vector<string>(relative_path.begin(), 
relative_path.end()));
+  }
+
+  {
+    // Checks for behavior of absolute paths.
+    const vector<string> components{"", "1", "2", "3", "4", "5", "file.ext"};
+    const Path absolute_path(
+      strings::join(string(1, os::PATH_SEPARATOR), components));
+
+    ASSERT_TRUE(absolute_path.absolute());
+
+    EXPECT_NE(absolute_path.begin(), absolute_path.end());
+    EXPECT_EQ(
+        components.size(),
+        std::distance(absolute_path.begin(), absolute_path.end()));
+
+    EXPECT_EQ(
+        components, vector<string>(absolute_path.begin(), 
absolute_path.end()));
+  }
+}
+
+
 class PathFileTest : public TemporaryDirectoryTest {};
 
 

Reply via email to