ReadFdToString: accommodate non-shrinking reserve

The file.ReadFileToString_capacity test verifies that
base::ReadFileToString shrinks an existing string's capacity to fit the
file. Previously, std::string::reserve was responsible for this, but as
of https://wg21.link/P0966R1, it no longer shrinks. Preserve the
existing behavior explicitly, and avoid reallocating when it isn't
needed.

Bug: b/175635923
Test: libbase_test
Change-Id: I0d77cf84527aa8209828914c7b665fcbbdf0e8b2
diff --git a/file.cpp b/file.cpp
index f71773b..55671b7 100644
--- a/file.cpp
+++ b/file.cpp
@@ -222,8 +222,18 @@
   // very large files too, where the std::string growth heuristics might not
   // be suitable. https://code.google.com/p/android/issues/detail?id=258500.
   struct stat sb;
-  if (fstat(fd.get(), &sb) != -1 && sb.st_size > 0) {
-    content->reserve(sb.st_size);
+  if (fstat(fd.get(), &sb) != -1 && sb.st_size > 0 && sb.st_size <= SSIZE_MAX) {
+    // Shrink the string capacity to fit the file, but if the capacity is only
+    // slightly larger than needed, avoid reallocating. std::string::reserve no
+    // longer lowers capacity after P0966R1, but it does round the request up a
+    // small amount (e.g. 8 or 16 bytes).
+    size_t fd_size = sb.st_size;
+    if (fd_size > content->capacity()) {
+      content->reserve(fd_size);
+    } else if (fd_size < content->capacity() && content->capacity() - fd_size >= 64) {
+      content->shrink_to_fit();
+      content->reserve(fd_size);
+    }
   }
 
   char buf[4096] __attribute__((__uninitialized__));