diff options
-rw-r--r-- | include/llvm/Support/PathV2.h | 23 | ||||
-rw-r--r-- | lib/Support/PathV2.cpp | 123 | ||||
-rw-r--r-- | unittests/Support/Path.cpp | 12 |
3 files changed, 148 insertions, 10 deletions
diff --git a/include/llvm/Support/PathV2.h b/include/llvm/Support/PathV2.h index fcdeff9b6d..e1b0a1d0e3 100644 --- a/include/llvm/Support/PathV2.h +++ b/include/llvm/Support/PathV2.h @@ -81,16 +81,21 @@ public: typedef value_type *pointer; typedef std::bidirectional_iterator_tag iterator_category; - reference operator*() const; - pointer operator->() const; + reference operator*() const { return Component; } + pointer operator->() const { return &Component; } const_iterator &operator++(); // preincrement const_iterator &operator++(int); // postincrement const_iterator &operator--(); // predecrement const_iterator &operator--(int); // postdecrement bool operator==(const const_iterator &RHS) const; bool operator!=(const const_iterator &RHS) const; + + /// @brief Difference in bytes between this and RHS. + ptrdiff_t operator-(const const_iterator &RHS) const; }; +typedef std::reverse_iterator<const_iterator> reverse_iterator; + /// @brief Get begin iterator over \a path. /// @param path Input path. /// @returns Iterator initialized with the first component of \a path. @@ -101,6 +106,20 @@ const_iterator begin(const StringRef &path); /// @returns Iterator initialized to the end of \a path. const_iterator end(const StringRef &path); +/// @brief Get reverse begin iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized with the first reverse component of \a path. +inline reverse_iterator rbegin(const StringRef &path) { + return reverse_iterator(end(path)); +} + +/// @brief Get reverse end iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized to the reverse end of \a path. +inline reverse_iterator rend(const StringRef &path) { + return reverse_iterator(begin(path)); +} + /// @} /// @name Lexical Modifiers /// @{ diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp index 115f29447e..a97f3ec711 100644 --- a/lib/Support/PathV2.cpp +++ b/lib/Support/PathV2.cpp @@ -82,6 +82,78 @@ namespace { return StringRef(); } + + size_t filename_pos(const StringRef &str) { + if (str.size() == 2 && + is_separator(str[0]) && + is_separator(str[1])) + return 0; + + if (str.size() > 0 && is_separator(str[str.size() - 1])) + return str.size() - 1; + + size_t pos = str.find_last_of(separators, str.size() - 1); + +#ifdef LLVM_ON_WIN32 + if (pos == StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); +#endif + + if (pos == StringRef::npos || + (pos == 1 && is_separator(str[0]))) + return 0; + + return pos + 1; + } + + size_t root_dir_start(const StringRef &str) { + // case "c:/" +#ifdef LLVM_ON_WIN32 + if (str.size() > 2 && + str[1] == ':' && + is_separator(str[2])) + return 2; +#endif + + // case "//" + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return StringRef::npos; + + // case "//net" + if (str.size() > 3 && + is_separator(str[0]) && + str[0] == str[1] && + !is_separator(str[2])) { + return str.find_first_of(separators, 2); + } + + // case "/" + if (str.size() > 0 && is_separator(str[0])) + return 0; + + return StringRef::npos; + } + + size_t parent_path_end(const StringRef &path) { + size_t end_pos = filename_pos(path); + + bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); + + // Skip separators except for root dir. + size_t root_dir_pos = root_dir_start(StringRef(path.begin(), end_pos)); + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(path[end_pos - 1])) + --end_pos; + + if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) + return StringRef::npos; + + return end_pos; + } } namespace llvm { @@ -103,14 +175,6 @@ const_iterator end(const StringRef &path) { return i; } -const_iterator::reference const_iterator::operator*() const { - return Component; -} - -const_iterator::pointer const_iterator::operator->() const { - return &Component; -} - const_iterator &const_iterator::operator++() { assert(Position < Path.size() && "Tried to increment past end!"); @@ -166,6 +230,36 @@ const_iterator &const_iterator::operator++() { return *this; } +const_iterator &const_iterator::operator--() { + // If we're at the end and the previous char was a '/', return '.'. + if (Position == Path.size() && + Path.size() > 1 && + is_separator(Path[Position - 1]) +#ifdef LLVM_ON_WIN32 + && Path[Position - 2] != ':' +#endif + ) { + --Position; + Component = "."; + return *this; + } + + // Skip separators unless it's the root directory. + size_t root_dir_pos = root_dir_start(Path); + size_t end_pos = Position; + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(Path[end_pos - 1])) + --end_pos; + + // Find next separator. + size_t start_pos = filename_pos(StringRef(Path.begin(), end_pos)); + Component = StringRef(Path.begin() + start_pos, end_pos - start_pos); + Position = start_pos; + return *this; +} + bool const_iterator::operator==(const const_iterator &RHS) const { return Path.begin() == RHS.Path.begin() && Position == RHS.Position; @@ -175,6 +269,10 @@ bool const_iterator::operator!=(const const_iterator &RHS) const { return !(*this == RHS); } +ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { + return Position - RHS.Position; +} + error_code root_path(const StringRef &path, StringRef &result) { const_iterator b = begin(path), pos = b, @@ -396,6 +494,15 @@ error_code make_absolute(SmallVectorImpl<char> &path) { "occurred above!"); } +error_code parent_path(const StringRef &path, StringRef &result) { + size_t end_pos = parent_path_end(path); + if (end_pos == StringRef::npos) + result = StringRef(); + else + result = StringRef(path.data(), end_pos); + return make_error_code(errc::success); +} + } } } diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp index 2c7c3cba9e..b8f818ff1d 100644 --- a/unittests/Support/Path.cpp +++ b/unittests/Support/Path.cpp @@ -71,6 +71,15 @@ TEST(Support, Path) { } outs() << "]\n"; + outs() << " Reverse Iteration: ["; + for (sys::path::reverse_iterator ci = sys::path::rbegin(*i), + ce = sys::path::rend(*i); + ci != ce; + ++ci) { + outs() << *ci << ','; + } + outs() << "]\n"; + StringRef res; SmallString<16> temp_store; if (error_code ec = sys::path::root_path(*i, res)) @@ -82,6 +91,9 @@ TEST(Support, Path) { if (error_code ec = sys::path::root_directory(*i, res)) ASSERT_FALSE(ec.message().c_str()); outs() << " root_directory: " << res << '\n'; + if (error_code ec = sys::path::parent_path(*i, res)) + ASSERT_FALSE(ec.message().c_str()); + outs() << " parent_path: " << res << '\n'; temp_store = *i; if (error_code ec = sys::path::make_absolute(temp_store)) |