<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Feb 6, 2016 at 4:02 PM, Duncan P. N. Exon Smith <span dir="ltr"><<a href="mailto:dexonsmith@apple.com" target="_blank">dexonsmith@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Light review below, looks like great work.<br>
<br>
I noticed the tests seem somewhat inconsistent about whether to<br>
glue `&` to the type or use two spaces (i.e., ` & `).  Which one is<br>
preferred in this codebase?  Or is it laissez-faire?<br>
<br>
The rest of my comments are inline.<br>
<div><div class="h5"><br>
> On 2016-Feb-06, at 12:48, Eric Fiselier via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br>
><br>
> EricWF updated this revision to Diff 47095.<br>
> EricWF added a comment.<br>
><br>
> Remove unintentional change in CMake.<br>
><br>
><br>
> <a href="http://reviews.llvm.org/D16948" rel="noreferrer" target="_blank">http://reviews.llvm.org/D16948</a><br>
><br>
> Files:<br>
>  CMakeLists.txt<br>
>  include/experimental/__config<br>
>  include/experimental/filesystem<br>
>  include/iomanip<br>
>  lib/filesystem/CMakeLists.txt<br>
>  src/filesystem/path.cpp<br>
>  test/CMakeLists.txt<br>
>  test/libcxx/experimental/filesystem/class.path/path.req/is_pathable.pass.cpp<br>
>  test/libcxx/test/config.py<br>
>  test/std/experimental/filesystem/class.directory_entry/directory_entry.cons.pass.cpp<br>
>  test/std/experimental/filesystem/class.directory_entry/directory_entry.mods.pass.cpp<br>
>  test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/comparisons.pass.cpp<br>
>  test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/path.pass.cpp<br>
>  test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/status.pass.cpp<br>
>  test/std/experimental/filesystem/class.file_status/file_status.cons.pass.cpp<br>
>  test/std/experimental/filesystem/class.file_status/file_status.mods.pass.cpp<br>
>  test/std/experimental/filesystem/class.file_status/file_status.obs.pass.cpp<br>
>  test/std/experimental/filesystem/class.filesystem_error/filesystem_error.members.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.itr/iterator.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.assign/copy.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.assign/move.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.construct/copy.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.construct/default.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.construct/move.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.modifiers/clear.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.modifiers/make_preferred.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_extension.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.modifiers/swap.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.native.obs/c_str.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.native.obs/named_overloads.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.native.obs/native.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.native.obs/operator_string.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.native.obs/string_alloc.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.nonmember/append_op.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.nonmember/path.factory.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.nonmember/path.io.unicode_bug.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/path.nonmember/swap.pass.cpp<br>
>  test/std/experimental/filesystem/class.path/synop.pass.cpp<br>
>  test/std/experimental/filesystem/fs.enum/check_bitmask_types.hpp<br>
>  test/std/experimental/filesystem/fs.enum/enum.copy_options.pass.cpp<br>
>  test/std/experimental/filesystem/fs.enum/enum.directory_options.pass.cpp<br>
>  test/std/experimental/filesystem/fs.enum/enum.file_type.pass.cpp<br>
>  test/std/experimental/filesystem/fs.enum/enum.perms.pass.cpp<br>
>  test/std/experimental/filesystem/fs.error.report/tested_elsewhere.pass.cpp<br>
>  test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp<br>
>  test/std/experimental/filesystem/fs.req.macros/feature_macro.pass.cpp<br>
>  test/std/experimental/filesystem/fs.req.namespace/namespace.pass.cpp<br>
>  test/std/experimental/filesystem/static_test_env/bad_symlink<br>
>  test/std/experimental/filesystem/static_test_env/dir1/dir2/dir3/.gitkeep<br>
>  test/std/experimental/filesystem/static_test_env/dir1/file1<br>
>  test/std/experimental/filesystem/static_test_env/dir1/file2<br>
>  test/std/experimental/filesystem/static_test_env/empty_file<br>
>  test/std/experimental/filesystem/static_test_env/non_empty_file<br>
>  test/std/experimental/filesystem/static_test_env/symlink_to_empty_file<br>
>  test/std/experimental/filesystem/test.pass.cpp<br>
>  test/support/count_new.hpp<br>
>  test/support/filesystem_dynamic_test_helper.py<br>
>  test/support/filesystem_test_helper.hpp<br>
>  test/support/min_allocator.h<br>
>  test/support/test_iterators.h<br>
>  test/support/test_macros.h<br>
><br>
</div></div>> <D16948.47095.patch>_______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
<br>
> Index: test/support/test_macros.h<br>
> ===================================================================<br>
> --- test/support/test_macros.h<br>
> +++ test/support/test_macros.h<br>
> @@ -91,8 +91,23 @@<br>
>  template <> struct static_assert_incomplete_test<true> {};<br>
>  template <unsigned> struct static_assert_check {};<br>
><br>
> +template <class T, class U> struct test_is_same { enum { value = false}; };<br>
> +template <class T> struct test_is_same<T, T> { enum { value = true}; };<br>
> +<br>
> +<br>
>  } // end namespace test_detail<br>
><br>
> +#define ASSERT_SAME_TYPE(...) \<br>
> +  static_assert(test_detail::test_is_same<__VA_ARGS__>::value, \<br>
> +    "Return type differs from expected type")<br>
> +<br>
> +#define ASSERT_NOEXCEPT(...)  \<br>
> +  static_assert(noexcept(__VA_ARGS__), "Expression expected to be noexcept")<br>
> +<br>
> +<br>
> +#define ASSERT_NOT_NOEXCEPT(...)  \<br>
> +  static_assert(noexcept(__VA_ARGS__) == false, "Expression expected NOT to be noexcept")<br>
<br>
Why not `!noexcept(__VA_ARGS__)`?<br></blockquote><div><br></div><div>No particular reason. Just trying to clearly differentiate the two. </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +<br>
><br>
>  #if !TEST_HAS_FEATURE(cxx_rtti) && !defined(__cxx_rtti)<br>
>  #define TEST_HAS_NO_RTTI<br>
> @@ -107,4 +122,6 @@<br>
>  #define TEST_HAS_SANITIZERS<br>
>  #endif<br>
><br>
> +<br>
> +<br>
>  #endif // SUPPORT_TEST_MACROS_HPP<br>
> Index: test/support/min_allocator.h<br>
> ===================================================================<br>
> --- test/support/min_allocator.h<br>
> +++ test/support/min_allocator.h<br>
> @@ -11,6 +11,7 @@<br>
>  #define MIN_ALLOCATOR_H<br>
><br>
>  #include <cstddef><br>
> +#include <cstdlib><br>
><br>
>  #include "test_macros.h"<br>
><br>
> @@ -39,6 +40,55 @@<br>
>      friend bool operator!=(bare_allocator x, bare_allocator y) {return !(x == y);}<br>
>  };<br>
><br>
> +struct malloc_allocator_base {<br>
> +    static size_t alloc_count;<br>
> +    static size_t dealloc_count;<br>
> +    static size_t outstanding_alloc;<br>
<br>
Why have this?  I would have expected.<br>
```<br>
static size_t outstanding_alloc() { return alloc_count - dealloc_count; }<br>
```<br>
<br></blockquote><div>Good point. Fixed.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +    static bool disable_default_constructor;<br>
> +<br>
> +    static void reset() {<br>
> +        assert(outstanding_alloc == 0);<br>
<br>
And here:<br>
```<br>
assert(alloc_count == dealloc_count);<br>
```<br>
<br>
> +        disable_default_constructor = false;<br>
> +        alloc_count = 0;<br>
> +        dealloc_count = 0;<br>
> +        outstanding_alloc = 0;<br>
> +    }<br>
> +};<br>
> +<br>
> +<br>
> +size_t malloc_allocator_base::alloc_count = 0;<br>
> +size_t malloc_allocator_base::dealloc_count = 0;<br>
> +size_t malloc_allocator_base::outstanding_alloc = 0;<br>
> +bool malloc_allocator_base::disable_default_constructor = false;<br>
> +<br>
> +<br>
> +template <class T><br>
> +class malloc_allocator : public malloc_allocator_base<br>
> +{<br>
> +public:<br>
> +    typedef T value_type;<br>
> +<br>
> +    malloc_allocator() TEST_NOEXCEPT { assert(!disable_default_constructor); }<br>
> +<br>
> +    template <class U><br>
> +    malloc_allocator(malloc_allocator<U>) TEST_NOEXCEPT {}<br>
> +<br>
> +    T* allocate(std::size_t n)<br>
> +    {;<br>
<br>
Nit: stray semi-colon.<br></blockquote><div><br></div><div>Ack. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +        ++alloc_count; ++outstanding_alloc;<br>
> +        return static_cast<T*>(std::malloc(n*sizeof(T)));<br>
> +    }<br>
> +<br>
> +    void deallocate(T* p, std::size_t)<br>
> +    {<br>
> +        ++dealloc_count; --outstanding_alloc;<br>
> +        std::free(static_cast<void*>(p));<br>
> +    }<br>
> +<br>
> +    friend bool operator==(malloc_allocator, malloc_allocator) {return true;}<br>
> +    friend bool operator!=(malloc_allocator x, malloc_allocator y) {return !(x == y);}<br>
> +};<br>
> +<br>
><br>
>  #if __cplusplus >= 201103L<br>
><br>
> Index: test/support/filesystem_test_helper.hpp<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ test/support/filesystem_test_helper.hpp<br>
> @@ -0,0 +1,308 @@<br>
> +#ifndef FILESYSTEM_TEST_HELPER_HPP<br>
> +#define FILESYSTEM_TEST_HELPER_HPP<br>
> +<br>
> +#include <experimental/filesystem><br>
> +#include <cassert><br>
> +#include <cstdio> // for tempnam<br>
> +#include <string><br>
> +<br>
> +namespace fs = std::experimental::filesystem;<br>
> +<br>
> +// static test helpers<br>
> +<br>
> +#ifndef LIBCXX_FILESYSTEM_STATIC_TEST_ROOT<br>
> +#warning "STATIC TESTS DISABLED"<br>
> +#else // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT<br>
> +<br>
> +inline fs::path static_test_env_path()<br>
> +{<br>
> +    static const fs::path env_path = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;<br>
> +    return env_path;<br>
> +}<br>
> +<br>
> +inline fs::path make_static_env_path(fs::path const& p)<br>
> +{<br>
> +    return static_test_env_path() / p;<br>
> +}<br>
> +<br>
> +namespace StaticEnv {<br>
> +<br>
> +inline fs::path makePath(fs::path const& p) {<br>
> +    return static_test_env_path() / p;<br>
> +}<br>
> +<br>
> +static const fs::path EnvRoot = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;<br>
> +<br>
> +static const fs::path TestFileList[] = {<br>
> +        makePath("empty_file"),<br>
> +        makePath("non_empty_file"),<br>
> +        makePath("dir1/file1"),<br>
> +        makePath("dir1/file2")<br>
> +};<br>
> +const std::size_t TestFileListSize = sizeof(TestFileList) / sizeof(fs::path);<br>
> +<br>
> +static const fs::path TestDirList[] = {<br>
> +        makePath("dir1"),<br>
> +        makePath("dir1/dir2"),<br>
> +        makePath("dir1/dir2/dir3")<br>
> +};<br>
> +const std::size_t TestDirListSize = sizeof(TestDirList) / sizeof(fs::path);<br>
> +<br>
> +static const fs::path File          = TestFileList[0];<br>
> +static const fs::path Dir           = TestDirList[0];<br>
> +static const fs::path SymlinkToFile = makePath("symlink_to_empty_file");<br>
> +static const fs::path DNE           = makePath("DNE");<br>
> +<br>
> +} // namespace StaticEnv<br>
> +<br>
> +#endif // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT<br>
> +<br>
> +<br>
> +#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT<br>
> +#warning LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be defined<br>
> +#else // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT<br>
> +<br>
> +#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER<br>
> +#error LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER must be defined<br>
> +#endif<br>
> +// dynamic test helpers<br>
> +<br>
> +inline fs::path test_env_path()<br>
> +{<br>
> +    static const fs::path env_path = LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT;<br>
> +    return env_path;<br>
> +}<br>
> +<br>
> +inline fs::path random_env_path()<br>
> +{<br>
> +    // assert that tmpdir is not set.<br>
> +    char* tmpdir = std::getenv("TMPDIR");<br>
> +    assert(!tmpdir);<br>
> +    char* s = ::tempnam(test_env_path().c_str(), "test.");<br>
> +    fs::path p(s);<br>
> +    std::free(s);<br>
> +    return p;<br>
> +}<br>
> +<br>
> +inline std::string<br>
> +fs_make_cmd(std::string const& cmd_name, std::string const& arg)<br>
> +{<br>
> +    std::string cmd = cmd_name + "('" + arg + "')";<br>
> +    return cmd;<br>
> +}<br>
> +<br>
> +inline std::string<br>
> +fs_make_cmd(std::string const& cmd_name,std::string const& arg1, std::string const& arg2)<br>
> +{<br>
> +    std::string cmd = cmd_name + "('";<br>
> +    cmd += arg1 + "', '";<br>
> +    cmd += arg2 + "')";<br>
> +    return cmd;<br>
> +}<br>
> +<br>
> +inline std::string<br>
> +fs_make_cmd(std::string const& cmd_name, std::string const& arg1, std::size_t const& arg2)<br>
> +{<br>
> +    std::string cmd = cmd_name + "('";<br>
> +    cmd += arg1 + "', ";<br>
> +    cmd += std::to_string(arg2) + ")";<br>
> +    return cmd;<br>
> +}<br>
> +<br>
> +inline void fs_helper_run(std::string const& raw_cmd) {<br>
> +    // check that the fs test root in the enviroment matches what we were<br>
> +    // compiled with.<br>
> +    char* fs_root = std::getenv("LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT");<br>
> +    assert(fs_root);<br>
> +    assert(std::string(fs_root) == LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT);<br>
> +<br>
> +    std::string cmd = LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER;<br>
> +    cmd += "\"";<br>
> +    cmd += raw_cmd;<br>
> +    cmd += "\"";<br>
> +    int ret = std::system(cmd.c_str());<br>
> +    assert(ret == 0);<br>
> +}<br>
> +<br>
> +struct scoped_test_env<br>
> +{<br>
> +    scoped_test_env()<br>
> +      : test_root(random_env_path())<br>
> +    {<br>
> +        fs_helper_run(fs_make_cmd("init", test_root));<br>
> +    }<br>
> +<br>
> +    scoped_test_env(scoped_test_env const &) = delete;<br>
> +    scoped_test_env & operator=(scoped_test_env const &) = delete;<br>
> +<br>
> +    ~scoped_test_env()<br>
> +    {<br>
> +        fs_helper_run(fs_make_cmd("clean", test_root));<br>
> +    }<br>
> +<br>
> +    fs::path make_env_path(fs::path const & p)<br>
> +    {<br>
> +        return test_root / p;<br>
> +    }<br>
> +<br>
> +    std::string sanitize_path(std::string const & raw)<br>
> +    {<br>
> +        if (raw.substr(0, test_root.native().size()) == test_root) {<br>
> +            return raw;<br>
> +        } else {<br>
> +            return test_root / fs::path(raw);<br>
> +        }<br>
> +    }<br>
> +<br>
> +    void create_file(std::string filename, std::size_t size = 0)<br>
> +    {<br>
> +        filename = sanitize_path(filename);<br>
> +        fs_helper_run(fs_make_cmd("create_file", filename, size));<br>
> +    }<br>
> +<br>
> +    void create_dir(std::string filename)<br>
> +    {<br>
> +        filename = sanitize_path(filename);<br>
> +        fs_helper_run(fs_make_cmd("create_dir", filename));<br>
> +    }<br>
> +<br>
> +    void create_symlink(std::string source, std::string to)<br>
> +    {<br>
> +        source = sanitize_path(source);<br>
> +        to = sanitize_path(to);<br>
> +        fs_helper_run(fs_make_cmd("create_symlink", source, to));<br>
> +    }<br>
> +<br>
> +    void create_hardlink(std::string source, std::string to)<br>
> +    {<br>
> +        source = sanitize_path(source);<br>
> +        to = sanitize_path(to);<br>
> +        fs_helper_run(fs_make_cmd("create_hardlink", source, to));<br>
> +    }<br>
> +<br>
> +    void create_fifo(std::string file)<br>
> +    {<br>
> +        file = sanitize_path(file);<br>
> +        fs_helper_run(fs_make_cmd("create_fifo", file));<br>
> +    }<br>
> +<br>
> +    void create_socket(std::string file)<br>
> +    {<br>
> +        file = sanitize_path(file);<br>
> +        fs_helper_run(fs_make_cmd("create_socket", file));<br>
> +    }<br>
> +<br>
> +    fs::path const test_root;<br>
> +};<br>
> +<br>
> +#endif // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT<br>
> +<br>
> +// Misc test types<br>
> +<br>
> +<br>
> +#define CONCAT2(LHS, RHS) LHS##RHS<br>
> +#define CONCAT(LHS, RHS) CONCAT2(LHS, RHS)<br>
> +#define MKSTR(Str) {Str, CONCAT(L, Str), CONCAT(u, Str), CONCAT(U, Str)}<br>
> +<br>
> +struct MultiStringType {<br>
> +  const char* s;<br>
> +  const wchar_t* w;<br>
> +  const char16_t* u16;<br>
> +  const char32_t* u32;<br>
> +<br>
> +  operator const char* () const { return s; }<br>
> +  operator const wchar_t* () const { return w; }<br>
> +  operator const char16_t* () const { return u16; }<br>
> +  operator const char32_t* () const { return u32; }<br>
> +};<br>
> +<br>
> +<br>
> +const MultiStringType PathList[] = {<br>
> +        MKSTR(""),<br>
> +        MKSTR(" "),<br>
> +        MKSTR("//"),<br>
> +        MKSTR("."),<br>
> +        MKSTR(".."),<br>
> +        MKSTR("foo"),<br>
> +        MKSTR("/"),<br>
> +        MKSTR("/foo"),<br>
> +        MKSTR("foo/"),<br>
> +        MKSTR("/foo/"),<br>
> +        MKSTR("foo/bar"),<br>
> +        MKSTR("/foo/bar"),<br>
> +        MKSTR("//net"),<br>
> +        MKSTR("//net/foo"),<br>
> +        MKSTR("///foo///"),<br>
> +        MKSTR("///foo///bar"),<br>
> +        MKSTR("/."),<br>
> +        MKSTR("./"),<br>
> +        MKSTR("/.."),<br>
> +        MKSTR("../"),<br>
> +        MKSTR("foo/."),<br>
> +        MKSTR("foo/.."),<br>
> +        MKSTR("foo/./"),<br>
> +        MKSTR("foo/./bar"),<br>
> +        MKSTR("foo/../"),<br>
> +        MKSTR("foo/../bar"),<br>
> +        MKSTR("c:"),<br>
> +        MKSTR("c:/"),<br>
> +        MKSTR("c:foo"),<br>
> +        MKSTR("c:/foo"),<br>
> +        MKSTR("c:foo/"),<br>
> +        MKSTR("c:/foo/"),<br>
> +        MKSTR("c:/foo/bar"),<br>
> +        MKSTR("prn:"),<br>
> +        MKSTR("c:\\"),<br>
> +        MKSTR("c:\\foo"),<br>
> +        MKSTR("c:foo\\"),<br>
> +        MKSTR("c:\\foo\\"),<br>
> +        MKSTR("c:\\foo/"),<br>
> +        MKSTR("c:/foo\\bar"),<br>
> +        MKSTR("//"),<br>
> +        MKSTR("/finally/we/need/one/really/really/really/really/really/really/really/long/string")<br>
> +};<br>
> +const unsigned PathListSize = sizeof(PathList) / sizeof(MultiStringType);<br>
> +<br>
> +template <class Iter><br>
> +Iter IterEnd(Iter B) {<br>
> +  using VT = typename std::iterator_traits<Iter>::value_type;<br>
> +  for (; *B != VT{}; ++B)<br>
> +    ;<br>
> +  return B;<br>
> +}<br>
> +<br>
> +template <class CharT><br>
> +const CharT* StrEnd(CharT const* P) {<br>
> +    return IterEnd(P);<br>
> +}<br>
> +<br>
> +template <class CharT><br>
> +std::size_t StrLen(CharT const* P) {<br>
> +    return StrEnd(P) - P;<br>
> +}<br>
> +<br>
> +// Testing the allocation behavior of the code_cvt functions requires<br>
> +// *knowning* that the allocation was not done by "path::__str_".<br>
<br>
s/knowning/knowing/<br>
<br></blockquote><div>Ack.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +// This hack forces path to allocate enough memory.<br>
> +inline void PathReserve(fs::path& p, std::size_t N) {<br>
> +  auto const& native_ref = p.native();<br>
> +  const_cast<std::string&>(native_ref).reserve(N);<br>
> +}<br>
> +<br>
> +<br>
> +template <class Iter1, class Iter2><br>
> +bool checkCollectionsEqual(<br>
> +    Iter1 start1, Iter1 const end1<br>
> +  , Iter2 start2, Iter2 const end2<br>
> +  )<br>
> +{<br>
<br>
Isn't this `std::equal(start1, end1, start2, end2)`?  Can you assume<br>
this available from C++14?<br></blockquote><div><br></div><div>I'm trying to keep this building in C++11. It's simple enough to reimplement this for testing.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +    while (start1 != end1 && start2 != end2) {<br>
> +        if (*start1 != *start2) {<br>
> +            return false;<br>
> +        }<br>
> +        ++start1; ++start2;<br>
> +    }<br>
> +    return (start1 == end1 && start2 == end2);<br>
> +}<br>
> +<br>
> +#endif /* FILESYSTEM_TEST_HELPER_HPP */<br>
> \ No newline at end of file<br>
<br>
^ Missing newline.<br>
<br>
The diff has this warning in a lot of places, actually.  IIRC that makes<br>
the code ill-formed in -pedantic mode (besides making `cat` behave<br>
badly).<br>
<br></blockquote><div>Yeah I need to clean these up. -pedantic isn't a worry for this in C++11 though.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> Index: test/std/experimental/filesystem/test.pass.cpp<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ test/std/experimental/filesystem/test.pass.cpp<br>
> @@ -0,0 +1,5 @@<br>
> +#include "filesystem_test_helper.hpp"<br>
> +<br>
> +int main() {<br>
> +<br>
> +}<br>
> \ No newline at end of file<br>
> Index: test/std/experimental/filesystem/static_test_env/symlink_to_empty_file<br>
<br>
In LLVM we usually put test inputs inside a directory called `Inputs/`,<br>
which makes it clear it's not a subdirectory with more tests, just test<br>
data.  What do you think of putting this parent directory at<br>
test/std/experimental/filesystem/Inputs/static_test_env instead of<br>
test/std/experimental/filesystem/static_test_env?<br></blockquote><div><br></div><div>Sounds like a great idea!</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ test/std/experimental/filesystem/static_test_env/symlink_to_empty_file<br>
> @@ -0,0 +1 @@<br>
> +empty_file<br>
> \ No newline at end of file<br>
> Index: test/std/experimental/filesystem/fs.error.report/tested_elsewhere.pass.cpp<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ test/std/experimental/filesystem/fs.error.report/tested_elsewhere.pass.cpp<br>
> @@ -0,0 +1,12 @@<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is dual licensed under the MIT and the University of Illinois Open<br>
> +// Source Licenses. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +int main()<br>
> +{<br>
> +}<br>
<br>
What's this for?<br></blockquote><div><br></div><div>The test suite is laid out according to the stable section names in the standard. When the requirements</div><div>of one section are tested as part of another we do something like this. It keeps the directory in SVN/Git and it shows it hasn't been forgotten.</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> Index: test/std/experimental/filesystem/fs.enum/enum.perms.pass.cpp<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ test/std/experimental/filesystem/fs.enum/enum.perms.pass.cpp<br>
> @@ -0,0 +1,69 @@<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is dual licensed under the MIT and the University of Illinois Open<br>
> +// Source Licenses. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +// UNSUPPORTED: c++98, c++03<br>
> +<br>
> +// <experimental/filesystem><br>
> +<br>
> +// enum class perms;<br>
> +<br>
> +#include <experimental/filesystem><br>
> +#include <type_traits><br>
> +#include <cassert><br>
> +#include <sys/stat.h><br>
> +<br>
> +#include "test_macros.h"<br>
> +#include "check_bitmask_types.hpp"<br>
> +<br>
> +namespace fs = std::experimental::filesystem;<br>
> +<br>
> +constexpr fs::perms ME(int val) { return static_cast<fs::perms>(val); }<br>
> +<br>
> +int main() {<br>
> +  typedef fs::perms E;<br>
> +  static_assert(std::is_enum<E>::value, "");<br>
> +<br>
> +  // Check that E is a scoped enum by checking for conversions.<br>
> +  typedef std::underlying_type<E>::type UT;<br>
> +  static_assert(!std::is_convertible<E, UT>::value, "");<br>
> +<br>
> +  static_assert(std::is_same<UT, unsigned >::value, ""); // Implementation detail<br>
> +<br>
> +  typedef check_bitmask_type<E, E::group_all, E::owner_all> BitmaskTester;<br>
> +  assert(BitmaskTester::check());<br>
> +<br>
> +  static_assert(<br>
> +        E::none         == ME(0) &&<br>
<br>
A rare case where `0` isn't the only octal value in a file ;).<br>
<br>
> +        E::owner_read   == ME(0400) &&<br>
> +        E::owner_write  == ME(0200) &&<br>
> +        E::owner_exec   == ME(0100) &&<br>
> +        E::owner_all    == ME(0700) &&<br>
> +<br>
> +        E::group_read   == ME(040) &&<br>
> +        E::group_write  == ME(020) &&<br>
> +        E::group_exec   == ME(010) &&<br>
> +        E::group_all    == ME(070) &&<br>
> +<br>
> +        E::others_read  == ME(04) &&<br>
> +        E::others_write == ME(02) &&<br>
> +        E::others_exec  == ME(01) &&<br>
> +        E::others_all   == ME(07) &&<br>
> +        E::all          == ME(0777) &&<br>
> +        E::set_uid      == ME(04000) &&<br>
> +        E::set_gid      == ME(02000) &&<br>
> +        E::sticky_bit   == ME(01000) &&<br>
> +        E::mask         == ME(07777) &&<br>
> +        E::unknown      == ME(0xFFFF) &&<br>
> +        E::add_perms        == ME(0x10000) &&<br>
> +        E::remove_perms     == ME(0x20000) &&<br>
> +        E::resolve_symlinks == ME(0x40000),<br>
> +        "Expected enumeration values do not match");<br>
> +<br>
> +}<br>
> Index: test/std/experimental/filesystem/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ test/std/experimental/filesystem/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp<br>
> @@ -0,0 +1,14 @@<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is dual licensed under the MIT and the University of Illinois Open<br>
> +// Source Licenses. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +// UNSUPPORTED: c++98, c++03<br>
> +<br>
> +// The "hash_value" function is tested as part of [path.compare]<br>
> +// in class.path/path.members/path.compare.pass.cpp<br>
> +int main() {}<br>
<br>
Okay, I get the idea of the one above.  I'm guessing this is just how<br>
we mark that something has been properly tested.<br>
<br>
However, it uses up bot time to have these extra tests to compile, link,<br>
and potentially shoot down to devices and pass output/exit status back.<br>
Is there any way of marking these things as "tested elsewhere" without<br>
adding load to the bots?<br></blockquote><div><br></div><div><br></div><div>Maybe? I'm not sure this review is a good place for that discussion.</div><div>FWIW I don't think these actually slow down the bots a noticeable amount.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> Index: test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp<br>
> @@ -0,0 +1,198 @@<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is dual licensed under the MIT and the University of Illinois Open<br>
> +// Source Licenses. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +// UNSUPPORTED: c++98, c++03<br>
> +<br>
> +// <experimental/filesystem><br>
> +<br>
> +// class path<br>
> +<br>
> +// 8.4.9 path decomposition [path.decompose]<br>
> +//------------------------------------------<br>
> +// path root_name() const;<br>
> +// path root_directory() const;<br>
> +// path root_path() const;<br>
> +// path relative_path() const;<br>
> +// path parent_path() const;<br>
> +// path filename() const;<br>
> +// path stem() const;<br>
> +// path extension() const;<br>
> +//-------------------------------<br>
> +// 8.4.10 path query [path.query]<br>
> +//-------------------------------<br>
> +// bool empty() const noexcept;<br>
> +// bool has_root_path() const;<br>
> +// bool has_root_name() const;<br>
> +// bool has_root_directory() const;<br>
> +// bool has_relative_path() const;<br>
> +// bool has_parent_path() const;<br>
> +// bool has_filename() const;<br>
> +// bool has_stem() const;<br>
> +// bool has_extension() const;<br>
> +// bool is_absolute() const;<br>
> +// bool is_relative() const;<br>
> +//-------------------------------<br>
> +// 8.5 path iterators [path.itr]<br>
> +//-------------------------------<br>
> +// iterator begin() const;<br>
> +// iterator end() const;<br>
> +<br>
> +<br>
> +#include <experimental/filesystem><br>
> +#include <type_traits><br>
> +#include <vector><br>
> +#include <cassert><br>
> +<br>
> +#include "test_macros.h"<br>
> +#include "test_iterators.h"<br>
> +#include "count_new.hpp"<br>
> +#include "filesystem_test_helper.hpp"<br>
> +<br>
> +template <class It><br>
> +std::reverse_iterator<It> mkRev(It it) {<br>
> +  return std::reverse_iterator<It>(it);<br>
> +}<br>
> +<br>
> +<br>
> +namespace fs = std::experimental::filesystem;<br>
> +struct PathDecomposeTestcase<br>
> +{<br>
> +    std::string raw;<br>
> +    std::vector<std::string> elements;<br>
> +    std::string root_path;<br>
> +    std::string root_name;<br>
> +    std::string root_directory;<br>
> +    std::string relative_path;<br>
> +    std::string parent_path;<br>
> +    std::string filename;<br>
> +};<br>
> +<br>
> +const PathDecomposeTestcase PathTestCases[] =<br>
> +  {<br>
> +      {"", {}, "", "", "", "", "", ""}<br>
> +    , {".", {"."}, "", "", "", ".", "", "."}<br>
> +    , {"..", {".."}, "", "", "", "..", "", ".."}<br>
> +    , {"foo", {"foo"}, "", "", "", "foo", "", "foo"}<br>
> +    , {"/", {"/"}, "/", "", "/", "", "", "/"}<br>
> +    , {"/foo", {"/", "foo"}, "/", "", "/", "foo", "/", "foo"}<br>
> +    , {"foo/", {"foo", "."}, "", "", "", "foo/", "foo", "."}<br>
> +    , {"/foo/", {"/", "foo", "."}, "/", "", "/", "foo/", "/foo", "."}<br>
> +    , {"foo/bar", {"foo","bar"}, "",  "", "",  "foo/bar", "foo", "bar"}<br>
> +    , {"/foo//bar", {"/","foo","bar"}, "/", "", "/", "foo/bar", "/foo", "bar"}<br>
> +    , {"//net", {"//net"}, "//net", "//net", "", "", "", "//net"}<br>
> +    , {"//net/foo", {"//net", "/", "foo"}, "//net/", "//net", "/", "foo", "//net/", "foo"}<br>
> +    , {"///foo///", {"/", "foo", "."}, "/", "", "/", "foo///", "///foo", "."}<br>
> +    , {"///foo///bar", {"/", "foo", "bar"}, "/", "", "/", "foo///bar", "///foo", "bar"}<br>
> +    , {"/.", {"/", "."}, "/", "", "/", ".", "/", "."}<br>
> +    , {"./", {".", "."}, "", "", "", "./", ".", "."}<br>
> +    , {"/..", {"/", ".."}, "/", "", "/", "..", "/", ".."}<br>
> +    , {"../", {"..", "."}, "", "", "", "../", "..", "."}<br>
> +    , {"foo/.", {"foo", "."}, "", "", "", "foo/.", "foo", "."}<br>
> +    , {"foo/..", {"foo", ".."}, "", "", "", "foo/..", "foo", ".."}<br>
> +    , {"foo/./", {"foo", ".", "."}, "", "", "", "foo/./", "foo/.", "."}<br>
> +    , {"foo/./bar", {"foo", ".", "bar"}, "", "", "", "foo/./bar", "foo/.", "bar"}<br>
> +    , {"foo/../", {"foo", "..", "."}, "", "", "", "foo/../", "foo/..", "."}<br>
> +    , {"foo/../bar", {"foo", "..", "bar"}, "", "", "", "foo/../bar", "foo/..", "bar"}<br>
> +    , {"c:", {"c:"}, "", "", "", "c:", "", "c:"}<br>
> +    , {"c:/", {"c:", "."}, "", "", "", "c:/", "c:", "."}<br>
> +    , {"c:foo", {"c:foo"}, "", "", "", "c:foo", "", "c:foo"}<br>
> +    , {"c:/foo", {"c:", "foo"}, "", "", "", "c:/foo", "c:", "foo"}<br>
> +    , {"c:foo/", {"c:foo", "."}, "", "", "", "c:foo/", "c:foo", "."}<br>
> +    , {"c:/foo/", {"c:", "foo", "."}, "", "", "", "c:/foo/",  "c:/foo", "."}<br>
> +    , {"c:/foo/bar", {"c:", "foo", "bar"}, "", "", "", "c:/foo/bar", "c:/foo", "bar"}<br>
> +    , {"prn:", {"prn:"}, "", "", "", "prn:", "", "prn:"}<br>
> +    , {"c:\\", {"c:\\"}, "", "", "", "c:\\", "", "c:\\"}<br>
> +    , {"c:\\foo", {"c:\\foo"}, "", "", "", "c:\\foo", "", "c:\\foo"}<br>
> +    , {"c:foo\\", {"c:foo\\"}, "", "", "", "c:foo\\", "", "c:foo\\"}<br>
> +    , {"c:\\foo\\", {"c:\\foo\\"}, "", "", "", "c:\\foo\\", "", "c:\\foo\\"}<br>
> +    , {"c:\\foo/",  {"c:\\foo", "."}, "", "", "", "c:\\foo/", "c:\\foo", "."}<br>
> +    , {"c:/foo\\bar", {"c:", "foo\\bar"}, "", "", "", "c:/foo\\bar", "c:", "foo\\bar"}<br>
> +    , {"//", {"//"}, "//", "//", "", "", "", "//"}<br>
> +  };<br>
> +<br>
> +void decompPathTest()<br>
> +{<br>
> +  using namespace fs;<br>
> +  for (auto const & TC : PathTestCases) {<br>
> +    path p(TC.raw);<br>
> +    assert(p == TC.raw);<br>
> +<br>
> +    assert(p.root_path() == TC.root_path);<br>
> +    assert(p.has_root_path() == not TC.root_path.empty());<br>
<br>
Huh, I've never actually seen `not` (or any of the other alternative<br>
operator representations) used before.  It looks pretty strange,<br>
partly because you're using a mix of primary operators and alternative<br>
operators, and maybe partly just due to my own unfamiliarity.<br>
<br>
Why are you using them?  (Maybe it's already common in the libc++<br>
codebase, I guess I'm not sure.)<br></blockquote><div><br></div><div>I originally wrote this code 2-3 years ago and I liked that style then. I've been trying to cleanup the "nots" as I go.</div><div>I don't think we should start using them in the libc++ code base.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
(Actually, I'm not sure why you don't just use `!=`; even `== !` seems<br>
strange when you're dealing with Boolean values.)<br></blockquote><div><br></div><div>Changed it to do exactly that. Thank you. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +<br>
> +    assert(p.root_name() == TC.root_name);<br>
> +    assert(p.has_root_name() == not TC.root_name.empty());<br>
> +<br>
> +    assert(p.root_directory() == TC.root_directory);<br>
> +    assert(p.has_root_directory() == not TC.root_directory.empty());<br>
> +<br>
> +    assert(p.relative_path() == TC.relative_path);<br>
> +    assert(p.has_relative_path() == not TC.relative_path.empty());<br>
> +<br>
> +    assert(p.parent_path() == TC.parent_path);<br>
> +    assert(p.has_parent_path() == not TC.parent_path.empty());<br>
> +<br>
> +    assert(p.filename() == TC.filename);<br>
> +    assert(p.has_filename() == not TC.filename.empty());<br>
> +<br>
> +    assert(p.is_absolute() == p.has_root_directory());<br>
> +    assert(p.is_relative() == not p.is_absolute());<br>
> +<br>
> +    assert(checkCollectionsEqual(p.begin(), p.end(),<br>
> +                                 TC.elements.begin(), TC.elements.end()));<br>
> +    // check backwards<br>
> +    assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()),<br>
> +                                 TC.elements.rbegin(), TC.elements.rend()));<br>
> +  }<br>
> +}<br>
> +<br>
> +<br>
> +struct FilenameDecompTestcase<br>
> +{<br>
> +  std::string raw;<br>
> +  std::string filename;<br>
> +  std::string stem;<br>
> +  std::string extension;<br>
> +};<br>
> +<br>
> +const FilenameDecompTestcase FilenameTestCases[] =<br>
> +{<br>
> +    {"", "", "", ""}<br>
> +  , {".", ".", ".", ""}<br>
> +  , {"..", "..", "..", ""}<br>
> +  , {"/", "/", "/", ""}<br>
> +  , {"foo", "foo", "foo", ""}<br>
> +  , {"/foo/bar.txt", "bar.txt", "bar", ".txt"}<br>
> +  , {"foo..txt", "foo..txt", "foo.", ".txt"}<br>
> +};<br>
> +<br>
> +<br>
> +void decompFilenameTest()<br>
> +{<br>
> +  using namespace fs;<br>
> +  for (auto const & TC : FilenameTestCases) {<br>
> +    path p(TC.raw);<br>
> +    assert(p == TC.raw);<br>
> +<br>
> +    assert(p.filename() == TC.filename);<br>
> +    assert(p.has_filename() == not TC.filename.empty());<br>
> +<br>
> +    assert(p.stem() == TC.stem);<br>
> +    assert(p.has_stem() == not TC.stem.empty());<br>
> +<br>
> +    assert(p.extension() == TC.extension);<br>
> +    assert(p.has_extension() == not TC.extension.empty());<br>
> +  }<br>
> +}<br>
> +<br>
> +int main()<br>
> +{<br>
> +  decompPathTest();<br>
> +  decompFilenameTest();<br>
> +}<br>
> \ No newline at end of file<br>
> Index: test/std/experimental/filesystem/class.path/path.member/path.construct/move.pass.cpp<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ test/std/experimental/filesystem/class.path/path.member/path.construct/move.pass.cpp<br>
> @@ -0,0 +1,41 @@<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is dual licensed under the MIT and the University of Illinois Open<br>
> +// Source Licenses. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +// UNSUPPORTED: c++98, c++03<br>
> +<br>
> +// <experimental/filesystem><br>
> +<br>
> +// class path<br>
> +<br>
> +// path(path&&) noexcept<br>
> +<br>
> +#include <experimental/filesystem><br>
> +#include <type_traits><br>
> +#include <cassert><br>
> +<br>
> +#include "test_macros.h"<br>
> +#include "count_new.hpp"<br>
> +<br>
> +namespace fs = std::experimental::filesystem;<br>
> +<br>
> +int main() {<br>
> +  using namespace fs;<br>
> +  static_assert(std::is_nothrow_move_constructible<path>::value, "");<br>
> +  assert(globalMemCounter.checkOutstandingNewEq(0));<br>
> +  const std::string s("we really really really really really really really "<br>
> +                      "really really long string so that we allocate");<br>
<br>
Kind of an irrelevant nitpick, but your long string is missing "need a"<br>
or "want a" (or some such).<br>
<br>
> +  assert(globalMemCounter.checkOutstandingNewEq(1));<br>
> +  path p(s);<br>
> +  {<br>
> +    DisableAllocationGuard g;<br>
> +    path p2(std::move(p));<br>
> +    assert(p2.native() == s);<br>
> +    assert(p.native() != s); // Testing moved from state<br>
> +  }<br>
> +}<br>
> \ No newline at end of file<br>
> Index: include/iomanip<br>
> ===================================================================<br>
> --- include/iomanip<br>
> +++ include/iomanip<br>
> @@ -512,8 +512,6 @@<br>
>      return __iom_t10<_CharT>(__tm, __fmt);<br>
>  }<br>
><br>
> -#if _LIBCPP_STD_VER > 11<br>
> -<br>
>  template <class _CharT, class _Traits, class _ForwardIterator><br>
>  std::basic_ostream<_CharT, _Traits> &<br>
>  __quoted_output ( basic_ostream<_CharT, _Traits> &__os,<br>
> @@ -631,22 +629,41 @@<br>
>      return __quoted_output_proxy<_CharT, const _CharT *> ( __s, __end, __delim, __escape );<br>
>  }<br>
><br>
> +<br>
>  template <class _CharT, class _Traits, class _Allocator><br>
>  _LIBCPP_INLINE_VISIBILITY<br>
>  __quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator><br>
> -quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))<br>
> +__quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))<br>
>  {<br>
> -    return __quoted_output_proxy<_CharT,<br>
> -            typename basic_string <_CharT, _Traits, _Allocator>::const_iterator><br>
> +    return __quoted_output_proxy<_CharT,<br>
> +            typename basic_string <_CharT, _Traits, _Allocator>::const_iterator><br>
<br>
These changes seem unrelated to me (and the rest of the file).  Can they<br>
be split out?<br></blockquote><div><br></div><div>They will be, eventually.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
>                      ( __s.cbegin(), __s.cend (), __delim, __escape );<br>
>  }<br>
><br>
>  template <class _CharT, class _Traits, class _Allocator><br>
>  __quoted_proxy<_CharT, _Traits, _Allocator><br>
> -quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))<br>
> +__quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))<br>
<br>
With this change, should we use _LIBCPP_INLNE_VISIBILITY here?<br>
<br>
>  {<br>
>      return __quoted_proxy<_CharT, _Traits, _Allocator>( __s, __delim, __escape );<br>
>  }<br>
> +<br>
> +<br>
> +#if _LIBCPP_STD_VER > 11<br>
> +<br>
> +template <class _CharT, class _Traits, class _Allocator><br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +__quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator><br>
> +quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))<br>
> +{<br>
> +    return __quoted(__s, __delim, __escape);<br>
> +}<br>
> +<br>
> +template <class _CharT, class _Traits, class _Allocator><br>
> +__quoted_proxy<_CharT, _Traits, _Allocator><br>
<br>
Do you happen to know why _LIBCPP_INLNE_VISIBILITY wasn't used above for<br>
`quoted()`?  Should it be added now?<br></blockquote><div><br></div><div>Not sure, I added it now.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))<br>
> +{<br>
> +    return__quoted(__s, __delim, __escape);<br>
<br>
It looks like there is a space missing between `return` and `__quoted`.<br>
<br></blockquote><div>Ack.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +}<br>
>  #endif<br>
><br>
>  _LIBCPP_END_NAMESPACE_STD<br>
> Index: include/experimental/filesystem<br>
> ===================================================================<br>
> --- /dev/null<br>
> +++ include/experimental/filesystem<br>
> @@ -0,0 +1,1243 @@<br>
> +// -*- C++ -*-<br>
> +//===--------------------------- filesystem -------------------------------===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is dual licensed under the MIT and the University of Illinois Open<br>
> +// Source Licenses. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +#ifndef _LIBCPP_EXPERIMENTAL_FILESYSTEM<br>
> +#define _LIBCPP_EXPERIMENTAL_FILESYSTEM<br>
> +/*<br>
> +    filesystem synopsis<br>
> +<br>
> +    namespace std { namespace experimental { namespace filesystem { inline namespace v1 {<br>
> +<br>
> +    class path;<br>
> +<br>
> +    void swap(path& lhs, path& rhs) _NOEXCEPT;<br>
> +    size_t hash_value(const path& p) _NOEXCEPT;<br>
> +<br>
> +    bool operator==(const path& lhs, const path& rhs) _NOEXCEPT;<br>
> +    bool operator!=(const path& lhs, const path& rhs) _NOEXCEPT;<br>
> +    bool operator< (const path& lhs, const path& rhs) _NOEXCEPT;<br>
> +    bool operator<=(const path& lhs, const path& rhs) _NOEXCEPT;<br>
> +    bool operator> (const path& lhs, const path& rhs) _NOEXCEPT;<br>
> +    bool operator>=(const path& lhs, const path& rhs) _NOEXCEPT;<br>
> +<br>
> +    path operator/ (const path& lhs, const path& rhs);<br>
> +<br>
> +    template <class charT, class traits><br>
> +    basic_ostream<charT, traits>&<br>
> +    operator<<(basic_ostream<charT, traits>& os, const path& p);<br>
> +<br>
> +    template <class charT, class traits><br>
> +    basic_istream<charT, traits>&<br>
> +    operator>>(basic_istream<charT, traits>& is, path& p);<br>
> +<br>
> +    template <class Source><br>
> +      path u8path(const Source& source);<br>
> +    template <class InputIterator><br>
> +      path u8path(InputIterator first, InputIterator last);<br>
> +<br>
> +    class filesystem_error;<br>
> +    class directory_entry;<br>
> +<br>
> +    class directory_iterator;<br>
> +<br>
> +    // enable directory_iterator range-based for statements<br>
> +    directory_iterator begin(directory_iterator iter) noexcept;<br>
> +    directory_iterator end(const directory_iterator&) noexcept;<br>
> +<br>
> +    class recursive_directory_iterator;<br>
> +<br>
> +    // enable recursive_directory_iterator range-based for statements<br>
> +    recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;<br>
> +    recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;<br>
> +<br>
> +    class file_status;<br>
> +<br>
> +    struct space_info<br>
> +    {<br>
> +      uintmax_t capacity;<br>
> +      uintmax_t free;<br>
> +      uintmax_t available;<br>
> +    };<br>
> +<br>
> +    enum class file_type;<br>
> +    enum class perms;<br>
> +    enum class copy_options;<br>
> +    enum class directory_options;<br>
> +<br>
> +    typedef chrono::time_point<trivial-clock>  file_time_type;<br>
> +<br>
> +    // operational functions<br>
> +<br>
> +    path absolute(const path& p, const path& base=current_path());<br>
> +<br>
> +    path canonical(const path& p, const path& base = current_path());<br>
> +    path canonical(const path& p, error_code& ec);<br>
> +    path canonical(const path& p, const path& base, error_code& ec);<br>
> +<br>
> +    void copy(const path& from, const path& to);<br>
> +    void copy(const path& from, const path& to, error_code& ec) _NOEXCEPT;<br>
> +    void copy(const path& from, const path& to, copy_options options);<br>
> +    void copy(const path& from, const path& to, copy_options options,<br>
> +                   error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool copy_file(const path& from, const path& to);<br>
> +    bool copy_file(const path& from, const path& to, error_code& ec) _NOEXCEPT;<br>
> +    bool copy_file(const path& from, const path& to, copy_options option);<br>
> +    bool copy_file(const path& from, const path& to, copy_options option,<br>
> +                           error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    void copy_symlink(const path& existing_symlink, const path& new_symlink);<br>
> +    void copy_symlink(const path& existing_symlink, const path& new_symlink,<br>
> +                              error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool create_directories(const path& p);<br>
> +    bool create_directories(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool create_directory(const path& p);<br>
> +    bool create_directory(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool create_directory(const path& p, const path& attributes);<br>
> +    bool create_directory(const path& p, const path& attributes,<br>
> +                                  error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    void create_directory_symlink(const path& to, const path& new_symlink);<br>
> +    void create_directory_symlink(const path& to, const path& new_symlink,<br>
> +                                          error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    void create_hard_link(const path& to, const path& new_hard_link);<br>
> +    void create_hard_link(const path& to, const path& new_hard_link,<br>
> +                                  error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    void create_symlink(const path& to, const path& new_symlink);<br>
> +    void create_symlink(const path& to, const path& new_symlink,<br>
> +                                error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    path current_path();<br>
> +    path current_path(error_code& ec);<br>
> +    void current_path(const path& p);<br>
> +    void current_path(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool exists(file_status s) _NOEXCEPT;<br>
> +    bool exists(const path& p);<br>
> +    bool exists(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool equivalent(const path& p1, const path& p2);<br>
> +    bool equivalent(const path& p1, const path& p2, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    uintmax_t    file_size(const path& p);<br>
> +    uintmax_t    file_size(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    uintmax_t    hard_link_count(const path& p);<br>
> +    uintmax_t    hard_link_count(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_block_file(file_status s) _NOEXCEPT;<br>
> +    bool is_block_file(const path& p);<br>
> +    bool is_block_file(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_character_file(file_status s) _NOEXCEPT;<br>
> +    bool is_character_file(const path& p);<br>
> +    bool is_character_file(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_directory(file_status s) _NOEXCEPT;<br>
> +    bool is_directory(const path& p);<br>
> +    bool is_directory(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_empty(const path& p);<br>
> +    bool is_empty(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_fifo(file_status s) _NOEXCEPT;<br>
> +    bool is_fifo(const path& p);<br>
> +    bool is_fifo(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_other(file_status s) _NOEXCEPT;<br>
> +    bool is_other(const path& p);<br>
> +    bool is_other(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_regular_file(file_status s) _NOEXCEPT;<br>
> +    bool is_regular_file(const path& p);<br>
> +    bool is_regular_file(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_socket(file_status s) _NOEXCEPT;<br>
> +    bool is_socket(const path& p);<br>
> +    bool is_socket(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool is_symlink(file_status s) _NOEXCEPT;<br>
> +    bool is_symlink(const path& p);<br>
> +    bool is_symlink(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    file_time_type  last_write_time(const path& p);<br>
> +    file_time_type  last_write_time(const path& p, error_code& ec) _NOEXCEPT;<br>
> +    void last_write_time(const path& p, file_time_type new_time);<br>
> +    void last_write_time(const path& p, file_time_type new_time,<br>
> +                                 error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    void permissions(const path& p, perms prms);<br>
> +    void permissions(const path& p, perms prms, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    path read_symlink(const path& p);<br>
> +    path read_symlink(const path& p, error_code& ec);<br>
> +<br>
> +    bool remove(const path& p);<br>
> +    bool remove(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    uintmax_t    remove_all(const path& p);<br>
> +    uintmax_t    remove_all(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    void rename(const path& from, const path& to);<br>
> +    void rename(const path& from, const path& to, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    void resize_file(const path& p, uintmax_t size);<br>
> +    void resize_file(const path& p, uintmax_t size, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    space_info   space(const path& p);<br>
> +    space_info   space(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    file_status  status(const path& p);<br>
> +    file_status  status(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    bool status_known(file_status s) _NOEXCEPT;<br>
> +<br>
> +    file_status  symlink_status(const path& p);<br>
> +    file_status  symlink_status(const path& p, error_code& ec) _NOEXCEPT;<br>
> +<br>
> +    path system_complete(const path& p);<br>
> +    path system_complete(const path& p, error_code& ec);<br>
> +<br>
> +    path temp_directory_path();<br>
> +    path temp_directory_path(error_code& ec);<br>
> +<br>
> +} } } }  // namespaces std::experimental::filesystem::v1<br>
> +<br>
> +*/<br>
> +<br>
> +#include <experimental/__config><br>
> +#include <cstddef><br>
> +#include <chrono><br>
> +#include <iterator><br>
> +#include <iosfwd><br>
> +#include <locale><br>
> +#include <memory><br>
> +#include <stack><br>
> +#include <string><br>
> +#include <system_error><br>
> +#include <utility><br>
> +#include <iomanip> // for quoted<br>
> +#include <experimental/string_view><br>
> +<br>
> +#include <__debug><br>
> +<br>
> +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)<br>
> +#pragma GCC system_header<br>
> +#endif<br>
> +<br>
> +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM<br>
> +<br>
> +typedef chrono::time_point<std::chrono::system_clock>  file_time_type;<br>
> +<br>
> +struct _LIBCPP_TYPE_VIS space_info<br>
> +{<br>
> +  uintmax_t capacity;<br>
> +  uintmax_t free;<br>
> +  uintmax_t available;<br>
> +};<br>
> +<br>
> +enum class _LIBCPP_TYPE_VIS file_type : signed char<br>
> +{<br>
> +    none       = 0,<br>
> +    not_found  = -1,<br>
> +    regular    = 1,<br>
> +    directory  = 2,<br>
> +    symlink    = 3,<br>
> +    block      = 4,<br>
> +    character  = 5,<br>
> +    fifo       = 6,<br>
> +    socket     = 7,<br>
> +    unknown    = 8<br>
> +};<br>
> +<br>
> +enum class _LIBCPP_TYPE_VIS perms : unsigned<br>
> +{<br>
> +    none         = 0,<br>
> +<br>
> +    owner_read   = 0400,<br>
> +    owner_write  = 0200,<br>
> +    owner_exec   = 0100,<br>
> +    owner_all    = 0700,<br>
> +<br>
> +    group_read   = 040,<br>
> +    group_write  = 020,<br>
> +    group_exec   = 010,<br>
> +    group_all    = 070,<br>
> +<br>
> +    others_read  = 04,<br>
> +    others_write = 02,<br>
> +    others_exec  = 01,<br>
> +    others_all   = 07,<br>
> +<br>
> +    all          = 0777,<br>
> +<br>
> +    set_uid      = 04000,<br>
> +    set_gid      = 02000,<br>
> +    sticky_bit   = 01000,<br>
> +    mask         = 07777,<br>
> +    unknown      = 0xFFFF,<br>
> +<br>
> +    add_perms        = 0x10000,<br>
> +    remove_perms     = 0x20000,<br>
> +    resolve_symlinks = 0x40000<br>
> +};<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR perms operator&(perms _LHS, perms _RHS)<br>
> +{ return static_cast<perms>(static_cast<unsigned>(_LHS) & static_cast<unsigned>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR perms operator|(perms _LHS, perms _RHS)<br>
> +{ return static_cast<perms>(static_cast<unsigned>(_LHS) | static_cast<unsigned>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR perms operator^(perms _LHS, perms _RHS)<br>
> +{ return static_cast<perms>(static_cast<unsigned>(_LHS) ^ static_cast<unsigned>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR perms operator~(perms _LHS)<br>
> +{ return static_cast<perms>(~static_cast<unsigned>(_LHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline perms& operator&=(perms& _LHS, perms _RHS)<br>
> +{ return _LHS = _LHS & _RHS; }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline perms& operator|=(perms& _LHS, perms _RHS)<br>
> +{ return _LHS = _LHS | _RHS; }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline perms& operator^=(perms& _LHS, perms _RHS)<br>
> +{ return _LHS = _LHS ^ _RHS; }<br>
> +<br>
> +enum class _LIBCPP_TYPE_VIS copy_options : unsigned short<br>
> +{<br>
> +    none               = 0,<br>
> +    skip_existing      = 1,<br>
> +    overwrite_existing = 2,<br>
> +    update_existing    = 4,<br>
> +    recursive          = 8,<br>
> +    copy_symlinks      = 16,<br>
> +    skip_symlinks      = 32,<br>
> +    directories_only   = 64,<br>
> +    create_symlinks    = 128,<br>
> +    create_hard_links  = 256,<br>
> +    __in_recursive_copy = 512,<br>
> +};<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR copy_options operator&(copy_options _LHS, copy_options _RHS)<br>
> +{ return static_cast<copy_options>(static_cast<unsigned short>(_LHS) & static_cast<unsigned short>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR copy_options operator|(copy_options _LHS, copy_options _RHS)<br>
> +{ return static_cast<copy_options>(static_cast<unsigned short>(_LHS) | static_cast<unsigned short>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR copy_options operator^(copy_options _LHS, copy_options _RHS)<br>
> +{ return static_cast<copy_options>(static_cast<unsigned short>(_LHS) ^ static_cast<unsigned short>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR copy_options operator~(copy_options _LHS)<br>
> +{ return static_cast<copy_options>(~static_cast<unsigned short>(_LHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline copy_options& operator&=(copy_options& _LHS, copy_options _RHS)<br>
> +{ return _LHS = _LHS & _RHS; }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline copy_options& operator|=(copy_options& _LHS, copy_options _RHS)<br>
> +{ return _LHS = _LHS | _RHS; }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline copy_options& operator^=(copy_options& _LHS, copy_options _RHS)<br>
> +{ return _LHS = _LHS ^ _RHS; }<br>
> +<br>
> +<br>
> +enum class directory_options : unsigned char<br>
> +{<br>
> +    none                     = 0,<br>
> +    follow_directory_symlink = 1,<br>
> +    skip_permission_denied   = 2<br>
> +};<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR directory_options operator&(directory_options _LHS, directory_options _RHS)<br>
> +{ return static_cast<directory_options>(static_cast<unsigned char>(_LHS) & static_cast<unsigned char>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR directory_options operator|(directory_options _LHS, directory_options _RHS)<br>
> +{ return static_cast<directory_options>(static_cast<unsigned char>(_LHS) | static_cast<unsigned char>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR directory_options operator^(directory_options _LHS, directory_options _RHS)<br>
> +{ return static_cast<directory_options>(static_cast<unsigned char>(_LHS) ^ static_cast<unsigned char>(_RHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline _LIBCPP_CONSTEXPR directory_options operator~(directory_options _LHS)<br>
> +{ return static_cast<directory_options>(~static_cast<unsigned char>(_LHS)); }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline directory_options& operator&=(directory_options& _LHS, directory_options _RHS)<br>
> +{ return _LHS = _LHS & _RHS; }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline directory_options& operator|=(directory_options& _LHS, directory_options _RHS)<br>
> +{ return _LHS = _LHS | _RHS; }<br>
> +<br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +inline directory_options& operator^=(directory_options& _LHS, directory_options _RHS)<br>
> +{ return _LHS = _LHS ^ _RHS; }<br>
> +<br>
> +<br>
> +class _LIBCPP_TYPE_VIS file_status<br>
> +{<br>
> +public:<br>
> +    // constructors<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    explicit file_status(file_type __ft = file_type::none,<br>
> +                         perms __prms   = perms::unknown) _NOEXCEPT<br>
> +      : __ft_(__ft), __prms_(__prms)<br>
> +    {}<br>
> +<br>
> +    file_status(const file_status&) _NOEXCEPT = default;<br>
> +    file_status(file_status&&) _NOEXCEPT = default;<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    ~file_status() {}<br>
> +<br>
> +    file_status& operator=(const file_status&) _NOEXCEPT = default;<br>
> +    file_status& operator=(file_status&&) _NOEXCEPT = default;<br>
> +<br>
> +    // observers<br>
> +    _LIBCPP_ALWAYS_INLINE<br>
> +    file_type type() const _NOEXCEPT {<br>
> +        return __ft_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_ALWAYS_INLINE<br>
> +    perms permissions() const _NOEXCEPT {<br>
> +        return __prms_;<br>
> +    }<br>
> +<br>
> +    // modifiers<br>
> +    _LIBCPP_ALWAYS_INLINE<br>
> +    void type(file_type __ft) _NOEXCEPT {<br>
> +        __ft_ = __ft;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_ALWAYS_INLINE<br>
> +    void permissions(perms __p) _NOEXCEPT {<br>
> +        __prms_ = __p;<br>
> +    }<br>
> +private:<br>
> +    file_type __ft_;<br>
> +    perms __prms_;<br>
> +};<br>
> +<br>
> +class _LIBCPP_TYPE_VIS directory_entry;<br>
> +<br>
> +template <class _Tp> struct __can_convert_char {<br>
> +  static const bool value = false;<br>
> +};<br>
> +template <> struct __can_convert_char<char> {<br>
> +    static const bool value = true;<br>
> +    using __char_type = char;<br>
> +};<br>
> +template <> struct __can_convert_char<wchar_t>  {<br>
> +    static const bool value = true;<br>
> +    using __char_type = wchar_t;<br>
> +};<br>
> +template <> struct __can_convert_char<char16_t> {<br>
> +    static const bool value = true;<br>
> +    using __char_type = char16_t;<br>
> +};<br>
> +template <> struct __can_convert_char<char32_t> {<br>
> +    static const bool value = true;<br>
> +    using __char_type = char32_t;<br>
> +};<br>
> +<br>
> +template <class _ECharT><br>
> +typename enable_if<__can_convert_char<_ECharT>::value, bool>::type<br>
> +__is_separator(_ECharT __e) {<br>
> +    return __e == _ECharT('/');<br>
> +};<br>
> +<br>
> +struct _NullSentinal {};<br>
> +<br>
> +template <class _Tp><br>
> +using _Void = void;<br>
> +<br>
> +template <class _Tp, class = void><br>
> +struct __is_pathable_string : public false_type {};<br>
> +<br>
> +template <class _ECharT, class _Traits, class _Alloc><br>
> +struct __is_pathable_string<basic_string<_ECharT, _Traits, _Alloc>,<br>
> +                            _Void<typename __can_convert_char<_ECharT>::__char_type>><br>
> +: public __can_convert_char<_ECharT><br>
> +{<br>
> +    using _Str = basic_string<_ECharT, _Traits, _Alloc>;<br>
> +    using _Base = __can_convert_char<_ECharT>;<br>
> +    static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }<br>
> +    static _ECharT const* __range_end(_Str const& __s) { return __s.data() + __s.length(); }<br>
> +    static _ECharT __first_or_null(_Str const& __s) {<br>
> +        return __s.empty() ? _ECharT{} : __s[0];<br>
> +    }<br>
> +};<br>
> +<br>
> +template <class _Source,<br>
> +          class _DS = typename decay<_Source>::type,<br>
> +          class _UnqualPtrType = typename remove_const<<br>
> +              typename remove_pointer<_DS>::type>::type,<br>
> +          bool _IsCharPtr = is_pointer<_DS>::value &&<br>
> +                            __can_convert_char<_UnqualPtrType>::value<br>
> +        ><br>
> +struct __is_pathable_char_array : false_type {};<br>
> +<br>
> +template <class _Source, class _ECharT, class _UPtr><br>
> +struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true><br>
> +        : __can_convert_char<typename remove_const<_ECharT>::type><br>
> +{<br>
> +  using _Base = __can_convert_char<typename remove_const<_ECharT>::type>;<br>
> +<br>
> +  static _ECharT const* __range_begin(const _ECharT* __b) { return __b; }<br>
> +  static _ECharT const* __range_end(const _ECharT* __b)<br>
> +  {<br>
> +      using _Iter = const _ECharT*;<br>
> +      const _ECharT __sentinal = _ECharT{};<br>
> +      _Iter __e = __b;<br>
> +      for (; *__e != __sentinal; ++__e)<br>
> +          ;<br>
> +      return __e;<br>
> +  }<br>
> +<br>
> +  static _ECharT __first_or_null(const _ECharT* __b) { return *__b; }<br>
> +};<br>
> +<br>
> +template <class _Iter, bool _IsIt = __is_input_iterator<_Iter>::value, class = void><br>
> +struct __is_pathable_iter : false_type {};<br>
> +<br>
> +template <class _Iter><br>
> +struct __is_pathable_iter<_Iter, true,<br>
> +        _Void<typename __can_convert_char<typename iterator_traits<_Iter>::value_type>::__char_type>><br>
> +        : __can_convert_char<typename iterator_traits<_Iter>::value_type><br>
> +{<br>
> +  using _ECharT = typename iterator_traits<_Iter>::value_type;<br>
> +  using _Base = __can_convert_char<_ECharT>;<br>
> +<br>
> +  static _Iter         __range_begin(_Iter __b) { return __b; }<br>
> +  static _NullSentinal __range_end(_Iter)       { return _NullSentinal{}; }<br>
> +<br>
> +  static _ECharT __first_or_null(_Iter __b) { return *__b; }<br>
> +};<br>
> +<br>
> +template <class _Tp, bool _IsStringT =  __is_pathable_string<_Tp>::value,<br>
> +                     bool _IsCharIterT = __is_pathable_char_array<_Tp>::value,<br>
> +                     bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value<br>
> +         ><br>
> +struct __is_pathable : false_type {<br>
> +  static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false");<br>
> +};<br>
> +<br>
> +template <class _Tp><br>
> +struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {};<br>
> +<br>
> +<br>
> +template <class _Tp><br>
> +struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {};<br>
> +<br>
> +<br>
> +template <class _Tp><br>
> +struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {};<br>
> +<br>
> +<br>
> +template <class _ECharT><br>
> +struct _PathCVT {<br>
> +    static_assert(__can_convert_char<_ECharT>::value, "Char type not convertible");<br>
> +<br>
> +    typedef __narrow_to_utf8<sizeof(_ECharT)*__CHAR_BIT__> _Narrower;<br>
> +<br>
> +    static void __append_range(string& __dest, _ECharT const* __b, _ECharT const* __e)  {<br>
> +        _Narrower()(back_inserter(__dest), __b, __e);<br>
> +    }<br>
> +<br>
> +    template <class _Iter><br>
> +    static void __append_range(string& __dest, _Iter __b, _Iter __e) {<br>
> +        static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");<br>
> +        if (__b == __e) return;<br>
> +        basic_string<_ECharT> __tmp(__b, __e);<br>
> +        _Narrower()(back_inserter(__dest), __tmp.data(),<br>
> +                    __tmp.data() + __tmp.length());<br>
> +    }<br>
> +<br>
> +    template <class _Iter><br>
> +    static void __append_range(string& __dest, _Iter __b, _NullSentinal) {<br>
> +        static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");<br>
> +        const _ECharT __sentinal = _ECharT{};<br>
> +        if (*__b == __sentinal) return;<br>
> +        basic_string<_ECharT> __tmp;<br>
> +        for (; *__b != __sentinal; ++__b)<br>
> +            __tmp.push_back(*__b);<br>
> +        _Narrower()(back_inserter(__dest), __tmp.data(),<br>
> +                    __tmp.data() + __tmp.length());<br>
> +    }<br>
> +<br>
> +    template <class _Source><br>
> +    static void __append_source(string& __dest, _Source const& __s)<br>
> +    {<br>
> +        using _Traits = __is_pathable<_Source>;<br>
> +        __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s));<br>
> +    }<br>
> +};<br>
> +<br>
> +template <><br>
> +struct _PathCVT<char> {<br>
> +    template <class _Iter><br>
> +    static void __append_range(string& __dest, _Iter __b, _Iter __e) {<br>
> +        // TODO(EricWF) We get better allocation behavior here if we don't<br>
> +        // provide the same exception safety guarantees as string.append.<br>
> +        // __dest.append(__b, __e);<br>
> +        for (; __b != __e; ++__b)<br>
> +            __dest.push_back(*__b);<br>
> +    }<br>
> +<br>
> +    template <class _Iter><br>
> +    static void __append_range(string& __dest, _Iter __b, _NullSentinal) {<br>
> +        const char __sentinal = char{};<br>
> +        for (; *__b != __sentinal; ++__b)<br>
> +            __dest.push_back(*__b);<br>
> +    }<br>
> +<br>
> +    template <class _Source><br>
> +    static void __append_source(string& __dest, _Source const& __s)<br>
> +    {<br>
> +        using _Traits = __is_pathable<_Source>;<br>
> +        __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s));<br>
> +    }<br>
> +};<br>
> +<br>
> +<br>
> +class _LIBCPP_TYPE_VIS path<br>
> +{<br>
> +    template <class _SourceOrIter, class _Tp = path&><br>
> +    using _EnableIfPathable = typename<br>
> +        enable_if<__is_pathable<_SourceOrIter>::value, _Tp>::type;<br>
> +<br>
> +    template <class _Tp><br>
> +    using _SourceChar = typename __is_pathable<_Tp>::__char_type;<br>
> +<br>
> +    template <class _Tp><br>
> +    using _SourceCVT = _PathCVT<_SourceChar<_Tp>>;<br>
> +<br>
> +public:<br>
> +    typedef char value_type;<br>
> +    typedef basic_string<value_type> string_type;<br>
> +    static _LIBCPP_CONSTEXPR value_type preferred_separator = '/';<br>
> +<br>
> +    // constructors and destructor<br>
> +    _LIBCPP_INLINE_VISIBILITY path() _NOEXCEPT {}<br>
> +    _LIBCPP_INLINE_VISIBILITY path(const path& __p)      : __pn_(__p.__pn_) {}<br>
> +    _LIBCPP_INLINE_VISIBILITY path(path&& __p) _NOEXCEPT : __pn_(_VSTD::move(__p.__pn_)) {}<br>
> +<br>
> +    template <<br>
> +        class _Source,<br>
> +        class = _EnableIfPathable<_Source, void><br>
> +        ><br>
> +    path(const _Source& __src) {<br>
> +        _SourceCVT<_Source>::__append_source(__pn_, __src);<br>
> +    }<br>
> +<br>
> +    template <class _InputIt><br>
> +    path(_InputIt __first, _InputIt __last) {<br>
> +        typedef typename iterator_traits<_InputIt>::value_type _ItVal;<br>
> +        _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);<br>
> +    }<br>
> +<br>
> +    // TODO<br>
> +    template <class _Source,<br>
> +              class = _EnableIfPathable<_Source, void><br>
> +             ><br>
> +        path(const _Source& __src, const locale& __loc);<br>
> +    template <class _InputIt><br>
> +        path(_InputIt __first, _InputIt _last, const locale& __loc);<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    ~path() {}<br>
> +<br>
> +    // assignments<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    path& operator=(const path& __p) {<br>
> +        __pn_ = __p.__pn_;<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    path& operator=(path&& __p) _NOEXCEPT {<br>
> +        __pn_ = _VSTD::move(__p.__pn_);<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    template <class _Source><br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    _EnableIfPathable<_Source><br>
> +    operator=(const _Source& __src)<br>
> +    { return this->assign(__src); }<br>
> +<br>
> +<br>
> +    template <class _Source><br>
> +    _EnableIfPathable<_Source><br>
> +    assign(const _Source& __src) {<br>
> +        __pn_.clear();<br>
> +        _SourceCVT<_Source>::__append_source(__pn_, __src);<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    template <class _InputIt><br>
> +    path& assign(_InputIt __first, _InputIt __last) {<br>
> +        typedef typename iterator_traits<_InputIt>::value_type _ItVal;<br>
> +        __pn_.clear();<br>
> +        _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +private:<br>
> +    template <class _ECharT><br>
> +    void __append_sep_if_needed(_ECharT __first_or_null) {<br>
> +        const _ECharT __null_val = {};<br>
> +        bool __append_sep = !empty()                       &&<br>
> +                            !__is_separator(__pn_.back())  &&<br>
> +                            __first_or_null != __null_val  && // non-empty<br>
> +                            !__is_separator(__first_or_null);<br>
> +        if (__append_sep)<br>
> +            __pn_ += preferred_separator;<br>
> +    }<br>
> +<br>
> +public:<br>
> +    // appends<br>
> +    path& operator/=(const path& __p) {<br>
> +        __append_sep_if_needed(__p.empty() ? char{} : __p.__pn_[0]);<br>
> +        __pn_ += __p.native();<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    template <class _Source><br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    _EnableIfPathable<_Source><br>
> +    operator/=(const _Source& __src) {<br>
> +        return this->append(__src);<br>
> +    }<br>
> +<br>
> +    template <class _Source><br>
> +    _EnableIfPathable<_Source><br>
> +    append(const _Source& __src) {<br>
> +        using _Traits = __is_pathable<_Source>;<br>
> +        using _CVT = _PathCVT<_SourceChar<_Source>>;<br>
> +        __append_sep_if_needed(_Traits::__first_or_null(__src));<br>
> +        _CVT::__append_source(__pn_, __src);<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    template <class _InputIt><br>
> +    path& append(_InputIt __first, _InputIt __last) {<br>
> +        typedef typename iterator_traits<_InputIt>::value_type _ItVal;<br>
> +        static_assert(__can_convert_char<_ItVal>::value, "Must convertible");<br>
> +        using _CVT = _PathCVT<_ItVal>;<br>
> +        if (__first != __last) {<br>
> +            __append_sep_if_needed(*__first);<br>
> +            _CVT::__append_range(__pn_, __first, __last);<br>
> +        }<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    // concatenation<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    path& operator+=(const path& __x) {<br>
> +        __pn_ += __x.__pn_;<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    path& operator+=(const string_type& __x) {<br>
> +        __pn_ += __x;<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    path& operator+=(const value_type* __x) {<br>
> +        __pn_ += __x;<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    path& operator+=(value_type __x) {<br>
> +        __pn_ += __x;<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +<br>
> +    template <class _ECharT><br>
> +    typename enable_if<__can_convert_char<_ECharT>::value, path&>::type<br>
> +    operator+=(_ECharT __x)<br>
> +    {<br>
> +        basic_string<_ECharT> __tmp;<br>
> +        __tmp += __x;<br>
> +        _PathCVT<_ECharT>::__append_source(__pn_, __tmp);<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    template <class _Source><br>
> +    _EnableIfPathable<_Source><br>
> +    operator+=(const _Source& __x) {<br>
> +       return this->concat(__x);<br>
> +    }<br>
> +<br>
> +    template <class _Source><br>
> +    _EnableIfPathable<_Source><br>
> +    concat(const _Source& __x){<br>
<br>
Missing a space before the brace.<br></blockquote><div><br></div><div>Ack.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +         _SourceCVT<_Source>::__append_source(__pn_, __x);<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    template <class _InputIt><br>
> +    path& concat(_InputIt __first, _InputIt __last) {<br>
> +        typedef typename iterator_traits<_InputIt>::value_type _ItVal;<br>
> +        _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);<br>
> +        return *this;<br>
> +    }<br>
> +<br>
> +    // modifiers<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    void  clear() _NOEXCEPT {<br>
<br>
Seems like a double space here.<br></blockquote><div><br></div><div>Ack.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +        __pn_.clear();<br>
> +    }<br>
> +<br>
> +    path& make_preferred() { return *this; }<br>
> +    path& remove_filename() { return *this = parent_path(); }<br>
> +<br>
> +    path& replace_filename(const path& __replacement) {<br>
> +        remove_filename();<br>
> +        return (*this /= __replacement);<br>
> +    }<br>
> +<br>
> +    path& replace_extension(const path& __replacement = path());<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    void  swap(path& __rhs) _NOEXCEPT {<br>
> +        __pn_.swap(__rhs.__pn_);<br>
> +    }<br>
> +<br>
> +    // native format observers<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    const string_type& native() const _NOEXCEPT {<br>
> +        return __pn_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    const value_type*  c_str() const _NOEXCEPT { return __pn_.c_str(); }<br>
<br>Ack.<br>
<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_;  }<br>
> +<br>
> +    template <class _ECharT, class _Traits = char_traits<_ECharT>,<br>
> +              class _Allocator = allocator<_ECharT> ><br>
<br>
Does libc++ support compilers that can't handle `>>` in whatever mode<br>
filesystem is being made available?<br></blockquote><div><br></div><div>No. That's probably habit or my IDE.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +    basic_string<_ECharT, _Traits, _Allocator><br>
> +    string(const _Allocator& __a = _Allocator()) const {<br>
> +        using _CVT = __widen_from_utf8<sizeof(_ECharT)*__CHAR_BIT__>;<br>
> +        using _Str = basic_string<_ECharT, _Traits, _Allocator>;<br>
> +        _Str __s(__a);<br>
> +        __s.reserve(__pn_.size());<br>
> +        _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size());<br>
> +        return __s;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY std::string    string()    const { return __pn_; }<br>
> +    _LIBCPP_INLINE_VISIBILITY std::wstring   wstring()   const { return string<wchar_t>(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY std::string    u8string()  const { return __pn_; }<br>
> +    _LIBCPP_INLINE_VISIBILITY std::u16string u16string() const { return string<char16_t>(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY std::u32string u32string() const { return string<char32_t>(); }<br>
> +<br>
> +    // generic format observers<br>
> +    template <class _ECharT, class _Traits = char_traits<_ECharT>,<br>
> +              class _Allocator = allocator<_ECharT><br>
> +    ><br>
> +    basic_string<_ECharT, _Traits, _Allocator><br>
> +    generic_string(const _Allocator& __a = _Allocator()) const {<br>
> +        return string<_ECharT, _Traits, _Allocator>(__a);<br>
> +    }<br>
> +<br>
> +    std::string    generic_string()    const { return __pn_; }<br>
> +    std::wstring   generic_wstring()   const { return string<wchar_t>(); }<br>
> +    std::string    generic_u8string()  const { return __pn_; }<br>
> +    std::u16string generic_u16string() const { return string<char16_t>(); }<br>
> +    std::u32string generic_u32string() const { return string<char32_t>(); }<br>
> +<br>
> +private:<br>
> +    _LIBCPP_FUNC_VIS int __compare(const value_type*) const;<br>
> +    _LIBCPP_FUNC_VIS string_view __root_name() const;<br>
> +    _LIBCPP_FUNC_VIS string_view __root_directory() const;<br>
> +    _LIBCPP_FUNC_VIS string_view __relative_path() const;<br>
> +    _LIBCPP_FUNC_VIS string_view __parent_path() const;<br>
> +    _LIBCPP_FUNC_VIS string_view __filename() const;<br>
> +    _LIBCPP_FUNC_VIS string_view __stem() const;<br>
> +    _LIBCPP_FUNC_VIS string_view __extension() const;<br>
> +<br>
> +public:<br>
> +    // compare<br>
> +    _LIBCPP_INLINE_VISIBILITY int compare(const path& __p) const _NOEXCEPT { return __compare(__p.c_str());}<br>
> +    _LIBCPP_INLINE_VISIBILITY int compare(const string_type& __s) const { return __compare(__s.c_str()); }<br>
> +    _LIBCPP_INLINE_VISIBILITY int compare(const value_type* __s) const  { return __compare(__s); }<br>
> +<br>
> +    // decomposition<br>
> +    _LIBCPP_INLINE_VISIBILITY path root_name()      const { return  __root_name().to_string(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY path root_directory() const { return  __root_directory().to_string(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY path root_path()      const { return root_name().append(__root_directory().to_string()); }<br>
> +    _LIBCPP_INLINE_VISIBILITY path relative_path()  const { return __relative_path().to_string(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY path parent_path()    const { return __parent_path().to_string(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY path filename()       const { return __filename().to_string(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY path stem()           const { return __stem().to_string();}<br>
> +    _LIBCPP_INLINE_VISIBILITY path extension()      const { return __extension().to_string(); }<br>
> +<br>
> +    // query<br>
> +    _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT { return __pn_.empty(); }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY bool has_root_name()      const { return !__root_name().empty(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY bool has_root_directory() const { return !__root_directory().empty(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY bool has_root_path()      const { return !(__root_name().empty() && __root_directory().empty()); }<br>
> +    _LIBCPP_INLINE_VISIBILITY bool has_relative_path()  const { return !__relative_path().empty(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY bool has_parent_path()    const { return !__parent_path().empty(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY bool has_filename()       const { return !__filename().empty(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY bool has_stem()           const { return !__stem().empty(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY bool has_extension()      const { return !__extension().empty(); }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY bool is_absolute()        const { return has_root_directory(); }<br>
> +    _LIBCPP_INLINE_VISIBILITY bool is_relative()        const { return !is_absolute(); }<br>
> +<br>
> +    // iterators<br>
> +    class _LIBCPP_TYPE_VIS iterator;<br>
> +    typedef iterator const_iterator;<br>
> +<br>
> +    _LIBCPP_FUNC_VIS iterator begin() const;<br>
> +    _LIBCPP_FUNC_VIS iterator end() const;<br>
> +<br>
> +private:<br>
> +    inline _LIBCPP_INLINE_VISIBILITY<br>
> +    path& __assign_view(string_view const& __s) noexcept { __pn_ = __s.to_string(); return *this; }<br>
> +    string_type __pn_;<br>
> +};<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +bool operator==(const path& __lhs, const path& __rhs) _NOEXCEPT<br>
> +{ return __lhs.compare(__rhs) == 0; }<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +bool operator!=(const path& __lhs, const path& __rhs) _NOEXCEPT<br>
> +{ return __lhs.compare(__rhs) != 0; }<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +bool operator<(const path& __lhs, const path& __rhs) _NOEXCEPT<br>
> +{ return __lhs.compare(__rhs) < 0; }<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +bool operator<=(const path& __lhs, const path& __rhs) _NOEXCEPT<br>
> +{ return __lhs.compare(__rhs) <= 0; }<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +bool operator>(const path& __lhs, const path& __rhs) _NOEXCEPT<br>
> +{ return __lhs.compare(__rhs) > 0; }<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +bool operator>=(const path& __lhs, const path& __rhs) _NOEXCEPT<br>
> +{ return __lhs.compare(__rhs) >= 0; }<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +path operator/(const path& __lhs, const path& __rhs) {<br>
> +    return path(__lhs) /= __rhs;<br>
> +}<br>
> +<br>
> +inline _LIBCPP_ALWAYS_INLINE<br>
> +void swap(path& __lhs, path& __rhs) _NOEXCEPT {<br>
> +    __lhs.swap(__rhs);<br>
> +}<br>
> +<br>
> +_LIBCPP_FUNC_VIS<br>
> +size_t hash_value(const path& __p) _NOEXCEPT;<br>
> +<br>
> +template <class _CharT, class _Traits><br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +typename enable_if<is_same<_CharT, char>::value &&<br>
> +                   is_same<_Traits, char_traits<char>>::value,<br>
> +                   basic_ostream<_CharT, _Traits>&<br>
> +>::type<br>
> +operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {<br>
> +    __os << std::__quoted(__p.native());<br>
> +    return __os;<br>
> +}<br>
> +<br>
> +template <class _CharT, class _Traits><br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +typename enable_if<!is_same<_CharT, char>::value ||<br>
> +                   !is_same<_Traits, char_traits<char>>::value,<br>
> +                   basic_ostream<_CharT, _Traits>&<br>
> +>::type<br>
> +operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {<br>
> +    __os << std::__quoted(__p.string<_CharT, _Traits>());<br>
> +    return __os;<br>
> +}<br>
> +<br>
> +template <class _CharT, class _Traits><br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +basic_istream<_CharT, _Traits>&<br>
> +operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)<br>
> +{<br>
> +    basic_string<_CharT, _Traits> __tmp;<br>
> +    __is >> __quoted(__tmp);<br>
> +    __p = __tmp;<br>
> +    return __is;<br>
> +}<br>
> +<br>
> +template <class _Source><br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +typename enable_if<__is_pathable<_Source>::value, path>::type<br>
> +u8path(const _Source& __s){<br>
> +    static_assert(is_same<typename __is_pathable<_Source>::__char_type, char>::value,<br>
> +        "u8path(Source const&) requires Source have a character type of type 'char'");<br>
> +    return path(__s);<br>
> +}<br>
> +<br>
> +template <class _InputIt><br>
> +_LIBCPP_INLINE_VISIBILITY<br>
> +typename enable_if<__is_pathable<_InputIt>::value, path>::type<br>
> +u8path(_InputIt __f, _InputIt __l) {<br>
> +    static_assert(is_same<typename __is_pathable<_InputIt>::__char_type, char>::value,<br>
> +        "u8path(Iter, Iter) requires Iter have a value_type of type 'char'");<br>
> +    return path(__f, __l);<br>
> +}<br>
> +<br>
> +class _LIBCPP_TYPE_VIS path::iterator<br>
> +{<br>
> +public:<br>
> +    typedef bidirectional_iterator_tag iterator_category;<br>
> +    typedef path                       value_type;<br>
> +    typedef std::ptrdiff_t             difference_type;<br>
> +    typedef const path*                pointer;<br>
> +    typedef const path&                reference;<br>
> +public:<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    iterator() : __elem_(), __path_ptr_(nullptr), __pos_(0) {}<br>
> +<br>
> +    iterator(const iterator&) = default;<br>
> +    ~iterator() = default;<br>
> +<br>
> +    iterator& operator=(const iterator&) = default;<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    reference operator*() const {<br>
> +        return __elem_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    pointer operator->() const {<br>
> +        return &__elem_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    iterator& operator++() {<br>
> +        return __increment();<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    iterator operator++(int) {<br>
> +        iterator __it(*this);<br>
> +        this->operator++();<br>
> +        return __it;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    iterator& operator--() {<br>
> +        return __decrement();<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    iterator operator--(int) {<br>
> +        iterator __it(*this);<br>
> +        this->operator--();<br>
> +        return __it;<br>
> +    }<br>
> +<br>
> +private:<br>
> +    friend class path;<br>
> +    friend bool operator==(const iterator&, const iterator&);<br>
> +<br>
> +    _LIBCPP_FUNC_VIS iterator& __increment();<br>
> +    _LIBCPP_FUNC_VIS iterator& __decrement();<br>
> +<br>
> +    path __elem_;<br>
> +    const path* __path_ptr_;<br>
> +    size_t __pos_;<br>
> +};<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +bool operator==(const path::iterator& __lhs, const path::iterator& __rhs) {<br>
> +    return __lhs.__path_ptr_ == __rhs.__path_ptr_ &&<br>
> +           __lhs.__pos_      == __rhs.__pos_;<br>
> +}<br>
> +<br>
> +inline _LIBCPP_INLINE_VISIBILITY<br>
> +bool operator!=(const path::iterator& __lhs, const path::iterator& __rhs) {<br>
> +    return !(__lhs == __rhs);<br>
> +}<br>
> +<br>
> +<br>
> +class _LIBCPP_EXCEPTION_ABI filesystem_error : public system_error<br>
> +{<br>
> +public:<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    filesystem_error(const string& __what, error_code __ec)<br>
> +        : system_error(__ec, __what),<br>
> +          __paths_(make_shared<_Storage>(path(), path()))<br>
> +    {}<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    filesystem_error(const string& __what, const path& __p1, error_code __ec)<br>
> +        : system_error(__ec, __what),<br>
> +        __paths_(make_shared<_Storage>(__p1, path()))<br>
> +    {}<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    filesystem_error(const string& __what, const path& __p1, const path& __p2,<br>
> +                     error_code __ec)<br>
> +        : system_error(__ec, __what),<br>
> +          __paths_(make_shared<_Storage>(__p1, __p2))<br>
> +    {}<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    const path& path1() const _NOEXCEPT {<br>
> +        return __paths_->first;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    const path& path2() const _NOEXCEPT {<br>
> +        return __paths_->second;<br>
> +    }<br>
> +<br>
> +    // COMMENTED OUT FOR REVIEW<br>
> +    //_LIBCPP_FUNC_VIS ~filesystem_error() override; // key function<br>
> +<br>
> +    // TODO(ericwf): Create a custom error message.<br>
> +    //const char* what() const _NOEXCEPT;<br>
> +<br>
> +private:<br>
> +    typedef pair<path, path> _Storage;<br>
> +    shared_ptr<_Storage> __paths_;<br>
> +};<br>
> +<br>
> +file_status status(path const&);<br>
> +file_status status(path const&, error_code&) _NOEXCEPT;<br>
> +file_status symlink_status(path const&);<br>
> +file_status symlink_status(path const&, error_code&) _NOEXCEPT;<br>
> +<br>
> +<br>
> +class directory_entry<br>
> +{<br>
> +    typedef _VSTD_FS::path _Path;<br>
> +<br>
> +public:<br>
> +    // constructors and destructors<br>
> +    directory_entry() _NOEXCEPT = default;<br>
> +    directory_entry(directory_entry const&) = default;<br>
> +    directory_entry(directory_entry&&) _NOEXCEPT = default;<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    explicit directory_entry(_Path const& __p) : __p_(__p) {}<br>
> +<br>
> +    ~directory_entry() {}<br>
> +<br>
> +    directory_entry& operator=(directory_entry const&) = default;<br>
> +    directory_entry& operator=(directory_entry&&) _NOEXCEPT = default;<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    void assign(_Path const& __p) {<br>
> +        __p_ = __p;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    void replace_filename(_Path const& __p) {<br>
> +        __p_ = __p_.parent_path() / __p;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    _Path const& path() const _NOEXCEPT {<br>
> +        return __p_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    operator const _Path&() const _NOEXCEPT {<br>
> +        return __p_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    file_status status() const {<br>
> +        return _VSTD_FS::status(__p_);<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    file_status status(error_code& __ec) const _NOEXCEPT {<br>
> +        return _VSTD_FS::status(__p_, __ec);<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    file_status symlink_status() const {<br>
> +        return _VSTD_FS::symlink_status(__p_);<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    file_status symlink_status(error_code& __ec) const _NOEXCEPT {<br>
> +        return _VSTD_FS::symlink_status(__p_, __ec);<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    bool operator< (directory_entry const& __rhs) const _NOEXCEPT {<br>
> +        return __p_ < __rhs.__p_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    bool operator==(directory_entry const& __rhs) const _NOEXCEPT {<br>
> +        return __p_ == __rhs.__p_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    bool operator!=(directory_entry const& __rhs) const _NOEXCEPT {<br>
> +        return __p_ != __rhs.__p_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    bool operator<=(directory_entry const& __rhs) const _NOEXCEPT {<br>
> +        return __p_ <= __rhs.__p_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    bool operator> (directory_entry const& __rhs) const _NOEXCEPT {<br>
> +        return __p_ > __rhs.__p_;<br>
> +    }<br>
> +<br>
> +    _LIBCPP_INLINE_VISIBILITY<br>
> +    bool operator>=(directory_entry const& __rhs) const _NOEXCEPT {<br>
> +        return __p_ >= __rhs.__p_;<br>
> +    }<br>
> +private:<br>
> +    _Path __p_;<br>
> +};<br>
> +<br>
> +_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM<br>
> +<br>
> +#endif // _LIBCPP_EXPERIMENTAL_FILESYSTEM<br>
<br>
</blockquote></div><br></div></div>