Implement filesystem NB comments, relative paths, and related issues.

This is a fairly large patch that implements all of the filesystem NB comments
and the relative paths changes (ex. adding weakly_canonical). These issues
and papers are all interrelated so their implementation couldn't be split up
nicely.

This patch upgrades <experimental/filesystem> to match the C++17 spec and not
the published experimental TS spec. Some of the changes in this patch are both
API and ABI breaking, however libc++ makes no guarantee about stability for
experimental implementations.

The major changes in this patch are:

* Implement NB comments for filesystem (P0492R2), including:
  * Implement `perm_options` enum as part of NB comments, and update the
    `permissions` function to match.
  * Implement changes to `remove_filename` and `replace_filename`
  * Implement changes to `path::stem()` and `path::extension()` which support
    splitting examples like `.profile`.
  * Change path iteration to return an empty path instead of '.' for trailing
    separators.
  * Change `operator/=` to handle absolute paths on the RHS.
  * Change `absolute` to no longer accept a current path argument.

* Implement relative paths according to NB comments (P0219r1)

* Combine `path.cpp` and `operations.cpp` since some path functions require
  access to the operations internals, and some fs operations require access
  to the path parser.

llvm-svn: 329028
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: d7fae181c3954886257fb33d0a57b954b26da745
diff --git a/benchmarks/filesystem.bench.cpp b/benchmarks/filesystem.bench.cpp
index 6771980..3e49560 100644
--- a/benchmarks/filesystem.bench.cpp
+++ b/benchmarks/filesystem.bench.cpp
@@ -1,17 +1,14 @@
-#include <experimental/filesystem>
-
 #include "benchmark/benchmark.h"
 #include "GenerateInput.hpp"
 #include "test_iterators.h"
-
-namespace fs = std::experimental::filesystem;
+#include "filesystem_include.hpp"
 
 static const size_t TestNumInputs = 1024;
 
 
 template <class GenInputs>
 void BM_PathConstructString(benchmark::State &st, GenInputs gen) {
-  using namespace fs;
+  using fs::path;
   const auto in = gen(st.range(0));
   path PP;
   for (auto& Part : in)
@@ -21,14 +18,15 @@
     const path P(PP.native());
     benchmark::DoNotOptimize(P.native().data());
   }
+  st.SetComplexityN(st.range(0));
 }
 BENCHMARK_CAPTURE(BM_PathConstructString, large_string,
-  getRandomStringInputs)->Arg(TestNumInputs);
+  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
 
 
 template <class GenInputs>
 void BM_PathConstructCStr(benchmark::State &st, GenInputs gen) {
-  using namespace fs;
+  using fs::path;
   const auto in = gen(st.range(0));
   path PP;
   for (auto& Part : in)
@@ -45,7 +43,7 @@
 
 template <template <class...> class ItType, class GenInputs>
 void BM_PathConstructIter(benchmark::State &st, GenInputs gen) {
-  using namespace fs;
+  using fs::path;
   using Iter = ItType<std::string::const_iterator>;
   const auto in = gen(st.range(0));
   path PP;
@@ -60,6 +58,7 @@
     const path P(Start, End);
     benchmark::DoNotOptimize(P.native().data());
   }
+  st.SetComplexityN(st.range(0));
 }
 template <class GenInputs>
 void BM_PathConstructInputIter(benchmark::State &st, GenInputs gen) {
@@ -70,14 +69,14 @@
   BM_PathConstructIter<forward_iterator>(st, gen);
 }
 BENCHMARK_CAPTURE(BM_PathConstructInputIter, large_string,
-  getRandomStringInputs)->Arg(TestNumInputs);
+  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
 BENCHMARK_CAPTURE(BM_PathConstructForwardIter, large_string,
-  getRandomStringInputs)->Arg(TestNumInputs);
+  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
 
 
 template <class GenInputs>
 void BM_PathIterateMultipleTimes(benchmark::State &st, GenInputs gen) {
-  using namespace fs;
+  using fs::path;
   const auto in = gen(st.range(0));
   path PP;
   for (auto& Part : in)
@@ -89,14 +88,15 @@
     }
     benchmark::ClobberMemory();
   }
+  st.SetComplexityN(st.range(0));
 }
 BENCHMARK_CAPTURE(BM_PathIterateMultipleTimes, iterate_elements,
-  getRandomStringInputs)->Arg(TestNumInputs);
+  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
 
 
 template <class GenInputs>
 void BM_PathIterateOnce(benchmark::State &st, GenInputs gen) {
-  using namespace fs;
+  using fs::path;
   const auto in = gen(st.range(0));
   path PP;
   for (auto& Part : in)
@@ -109,13 +109,14 @@
     }
     benchmark::ClobberMemory();
   }
+  st.SetComplexityN(st.range(0));
 }
 BENCHMARK_CAPTURE(BM_PathIterateOnce, iterate_elements,
-  getRandomStringInputs)->Arg(TestNumInputs);
+  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
 
 template <class GenInputs>
 void BM_PathIterateOnceBackwards(benchmark::State &st, GenInputs gen) {
-  using namespace fs;
+  using fs::path;
   const auto in = gen(st.range(0));
   path PP;
   for (auto& Part : in)
@@ -135,4 +136,28 @@
 BENCHMARK_CAPTURE(BM_PathIterateOnceBackwards, iterate_elements,
   getRandomStringInputs)->Arg(TestNumInputs);
 
+static fs::path getRandomPaths(int NumParts, int PathLen) {
+  fs::path Result;
+  while (NumParts--) {
+    std::string Part = getRandomString(PathLen);
+    Result /= Part;
+  }
+  return Result;
+}
+
+template <class GenInput>
+void BM_LexicallyNormal(benchmark::State &st, GenInput gen, size_t PathLen) {
+  using fs::path;
+  auto In = gen(st.range(0), PathLen);
+  benchmark::DoNotOptimize(&In);
+  while (st.KeepRunning()) {
+    benchmark::DoNotOptimize(In.lexically_normal());
+  }
+  st.SetComplexityN(st.range(0));
+}
+BENCHMARK_CAPTURE(BM_LexicallyNormal, small_path,
+  getRandomPaths, /*PathLen*/5)->RangeMultiplier(2)->Range(2, 256)->Complexity();
+BENCHMARK_CAPTURE(BM_LexicallyNormal, large_path,
+  getRandomPaths, /*PathLen*/32)->RangeMultiplier(2)->Range(2, 256)->Complexity();
+
 BENCHMARK_MAIN();