Add Filesystem TS -- Complete

Add the completed std::experimental::filesystem implementation and tests.
The implementation supports C++11 or newer.

The TS is built as part of 'libc++experimental.a'. Users of the TS need to
manually link this library. Building and testing the TS can be disabled using
the CMake option '-DLIBCXX_ENABLE_FILESYSTEM=OFF'.

Currently 'libc++experimental.a' is not installed by default. To turn on the
installation of the library use '-DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON'.

llvm-svn: 273034
diff --git a/libcxx/src/experimental/filesystem/path.cpp b/libcxx/src/experimental/filesystem/path.cpp
new file mode 100644
index 0000000..9c72abd
--- /dev/null
+++ b/libcxx/src/experimental/filesystem/path.cpp
@@ -0,0 +1,392 @@
+//===--------------------- filesystem/path.cpp ----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "experimental/filesystem"
+#include "experimental/string_view"
+#include "utility"
+
+_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+_LIBCPP_CONSTEXPR path::value_type path::preferred_separator;
+
+
+namespace { namespace parser
+{
+
+using string_type = string_view;
+using value_type = path::value_type;
+
+using string_view_pair = pair<string_view, string_view>;
+
+// status reporting
+constexpr size_t npos = static_cast<size_t>(-1);
+
+inline bool good(size_t pos) { return pos != npos; }
+
+// lexical elements
+constexpr value_type preferred_separator = path::preferred_separator;
+constexpr value_type const * preferred_separator_str = "/";
+constexpr value_type const * dot = ".";
+
+// forward //
+bool is_separator(string_type const &, size_t);
+bool is_root_name(const string_type&, size_t);
+bool is_root_directory(string_type const &, size_t);
+bool is_trailing_separator(string_type const &, size_t);
+
+size_t start_of(string_type const &, size_t);
+size_t end_of(string_type const &, size_t);
+
+size_t root_name_start(const string_type& s);
+size_t root_name_end(const string_type&);
+
+size_t root_directory_start(string_type const &);
+size_t root_directory_end(string_type const &);
+
+string_view_pair separate_filename(string_type const &);
+string_view extract_raw(string_type const &, size_t);
+string_view extract_preferred(string_type const &, size_t);
+
+inline bool is_separator(const string_type& s, size_t pos) {
+    return (pos < s.size() && s[pos] == preferred_separator);
+}
+
+inline bool is_root_name(const string_type& s, size_t pos) {
+  return good(pos) && pos == 0 ? root_name_start(s) == pos : false;
+}
+
+inline bool is_root_directory(const string_type& s, size_t pos) {
+    return good(pos) ? root_directory_start(s) == pos : false;
+}
+
+inline bool is_trailing_separator(const string_type& s, size_t pos) {
+    return (pos < s.size() && is_separator(s, pos) &&
+            end_of(s, pos) == s.size()-1 &&
+            !is_root_directory(s, pos) && !is_root_name(s, pos));
+}
+
+size_t start_of(const string_type& s, size_t pos) {
+    if (pos >= s.size()) return npos;
+    bool in_sep = (s[pos] == preferred_separator);
+    while (pos - 1 < s.size() &&
+        (s[pos-1] == preferred_separator) == in_sep)
+    { --pos; }
+    if (pos == 2 && !in_sep && s[0] == preferred_separator &&
+        s[1] == preferred_separator)
+    { return 0; }
+    return pos;
+}
+
+size_t end_of(const string_type& s, size_t pos) {
+    if (pos >= s.size()) return npos;
+    // special case for root name
+    if (pos == 0 && is_root_name(s, pos)) return root_name_end(s);
+    bool in_sep = (s[pos] == preferred_separator);
+    while (pos + 1 < s.size() && (s[pos+1] == preferred_separator) == in_sep)
+    { ++pos; }
+    return pos;
+}
+
+inline size_t root_name_start(const string_type& s) {
+    return good(root_name_end(s)) ? 0 : npos;
+}
+
+size_t root_name_end(const string_type& s) {
+    if (s.size() < 2 || s[0] != preferred_separator
+        || s[1] != preferred_separator) {
+        return npos;
+    }
+    if (s.size() == 2) {
+        return 1;
+    }
+    size_t index = 2; // current position
+    if (s[index] == preferred_separator) {
+        return npos;
+    }
+    while (index + 1 < s.size() && s[index+1] != preferred_separator) {
+        ++index;
+    }
+    return index;
+}
+
+size_t root_directory_start(const string_type& s) {
+    size_t e = root_name_end(s);
+    if (!good(e))
+    return is_separator(s, 0) ? 0 : npos;
+    return is_separator(s, e + 1) ? e + 1 : npos;
+}
+
+size_t root_directory_end(const string_type& s) {
+    size_t st = root_directory_start(s);
+    if (!good(st)) return npos;
+    size_t index = st;
+    while (index + 1 < s.size() && s[index + 1] == preferred_separator)
+      { ++index; }
+    return index;
+}
+
+string_view_pair separate_filename(string_type const & s) {
+    if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""};
+    auto pos = s.find_last_of('.');
+    if (pos == string_type::npos) return string_view_pair{s, string_view{}};
+    return string_view_pair{s.substr(0, pos), s.substr(pos)};
+}
+
+inline string_view extract_raw(const string_type& s, size_t pos) {
+    size_t end_i = end_of(s, pos);
+    if (!good(end_i)) return string_view{};
+    return string_view(s).substr(pos, end_i - pos + 1);
+}
+
+string_view extract_preferred(const string_type& s, size_t pos) {
+    string_view raw = extract_raw(s, pos);
+    if (raw.empty())
+        return raw;
+    if (is_trailing_separator(s, pos))
+        return string_view{dot};
+    if (is_separator(s, pos) && !is_root_name(s, pos))
+        return string_view(preferred_separator_str);
+    return raw;
+}
+
+}} // namespace parser
+
+
+////////////////////////////////////////////////////////////////////////////////
+//                            path_view_iterator
+////////////////////////////////////////////////////////////////////////////////
+namespace {
+
+struct path_view_iterator {
+  const string_view __s_;
+  size_t __pos_;
+
+  explicit path_view_iterator(string_view const& __s) : __s_(__s), __pos_(__s_.empty() ? parser::npos : 0) {}
+  explicit path_view_iterator(string_view const& __s, size_t __p) : __s_(__s), __pos_(__p) {}
+
+  string_view operator*() const {
+    return parser::extract_preferred(__s_, __pos_);
+  }
+
+  path_view_iterator& operator++() {
+    increment();
+    return *this;
+  }
+
+  path_view_iterator& operator--() {
+    decrement();
+    return *this;
+  }
+
+  void increment() {
+    if (__pos_ == parser::npos) return;
+    while (! set_position(parser::end_of(__s_, __pos_)+1))
+        ;
+    return;
+  }
+
+  void decrement() {
+    if (__pos_ == 0) {
+      set_position(0);
+    }
+    else if (__pos_ == parser::npos) {
+      auto const str_size = __s_.size();
+      set_position(parser::start_of(
+          __s_, str_size != 0 ? str_size - 1 : str_size));
+    } else {
+      while (!set_position(parser::start_of(__s_, __pos_-1)))
+        ;
+    }
+  }
+
+  bool set_position(size_t pos) {
+    if (pos >= __s_.size()) {
+      __pos_ = parser::npos;
+    } else {
+      __pos_ = pos;
+    }
+    return valid_iterator_position();
+  }
+
+  bool valid_iterator_position() const {
+    if (__pos_ == parser::npos) return true; // end position is valid
+    return (!parser::is_separator      (__s_, __pos_) ||
+          parser::is_root_directory    (__s_, __pos_) ||
+          parser::is_trailing_separator(__s_, __pos_) ||
+          parser::is_root_name         (__s_, __pos_));
+  }
+
+  bool is_end() const { return __pos_ == parser::npos; }
+
+  inline bool operator==(path_view_iterator const& __p) {
+      return __pos_ == __p.__pos_;
+  }
+};
+
+path_view_iterator pbegin(path const& p) {
+    return path_view_iterator(p.native());
+}
+
+path_view_iterator pend(path const& p) {
+    path_view_iterator __p(p.native());
+    __p.__pos_ = parser::npos;
+    return __p;
+}
+
+} // end namespace
+///////////////////////////////////////////////////////////////////////////////
+//                            path definitions
+///////////////////////////////////////////////////////////////////////////////
+
+path & path::replace_extension(path const & replacement)
+{
+    path p = extension();
+    if (not p.empty()) {
+      __pn_.erase(__pn_.size() - p.native().size());
+    }
+    if (!replacement.empty()) {
+        if (replacement.native()[0] != '.') {
+            __pn_ += ".";
+        }
+        __pn_.append(replacement.__pn_);
+    }
+    return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// path.decompose
+
+string_view path::__root_name() const
+{
+    return parser::is_root_name(__pn_, 0)
+      ? parser::extract_preferred(__pn_, 0)
+      : string_view{};
+}
+
+string_view path::__root_directory() const
+{
+    auto start_i = parser::root_directory_start(__pn_);
+    if(!parser::good(start_i)) {
+        return {};
+    }
+    return parser::extract_preferred(__pn_, start_i);
+}
+
+string_view path::__relative_path() const
+{
+    if (empty()) {
+        return {__pn_};
+    }
+    auto end_i = parser::root_directory_end(__pn_);
+    if (not parser::good(end_i)) {
+        end_i = parser::root_name_end(__pn_);
+    }
+    if (not parser::good(end_i)) {
+        return {__pn_};
+    }
+    return string_view(__pn_).substr(end_i+1);
+}
+
+string_view path::__parent_path() const
+{
+    if (empty() || pbegin(*this) == --pend(*this)) {
+        return {};
+    }
+    auto end_it = --(--pend(*this));
+    auto end_i = parser::end_of(__pn_, end_it.__pos_);
+    return string_view(__pn_).substr(0, end_i+1);
+}
+
+string_view path::__filename() const
+{
+    return empty() ? string_view{} : *--pend(*this);
+}
+
+string_view path::__stem() const
+{
+    return parser::separate_filename(__filename()).first;
+}
+
+string_view path::__extension() const
+{
+    return parser::separate_filename(__filename()).second;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.comparisons
+int path::__compare(const value_type* __s) const {
+    path_view_iterator thisIter(this->native());
+    path_view_iterator sIter(__s);
+    while (!thisIter.is_end() && !sIter.is_end()) {
+        int res = (*thisIter).compare(*sIter);
+        if (res != 0) return res;
+        ++thisIter; ++sIter;
+    }
+    if (thisIter.is_end() && sIter.is_end())
+        return 0;
+    if (thisIter.is_end())
+        return -1;
+    return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.nonmembers
+size_t hash_value(const path& __p) _NOEXCEPT {
+  path_view_iterator thisIter(__p.native());
+  struct HashPairT {
+    size_t first;
+    size_t second;
+  };
+  HashPairT hp = {0, 0};
+  std::hash<string_view> hasher;
+  std::__scalar_hash<decltype(hp)> pair_hasher;
+  while (!thisIter.is_end()) {
+    hp.second = hasher(*thisIter);
+    hp.first = pair_hasher(hp);
+    ++thisIter;
+  }
+  return hp.first;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.itr
+path::iterator path::begin() const
+{
+    path_view_iterator pit = pbegin(*this);
+    iterator it;
+    it.__path_ptr_ = this;
+    it.__pos_ = pit.__pos_;
+    it.__elem_.__assign_view(*pit);
+    return it;
+}
+
+path::iterator path::end() const
+{
+    iterator it{};
+    it.__path_ptr_ = this;
+    it.__pos_ = parser::npos;
+    return it;
+}
+
+path::iterator& path::iterator::__increment() {
+  path_view_iterator it(__path_ptr_->native(), __pos_);
+  it.increment();
+  __pos_ = it.__pos_;
+  __elem_.__assign_view(*it);
+  return *this;
+}
+
+path::iterator& path::iterator::__decrement() {
+  path_view_iterator it(__path_ptr_->native(), __pos_);
+  it.decrement();
+  __pos_ = it.__pos_;
+  __elem_.__assign_view(*it);
+  return *this;
+}
+
+_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM