]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add size_hint parameter to Util::read_file
authorJoel Rosdahl <joel@rosdahl.net>
Fri, 17 Jul 2020 11:17:25 +0000 (13:17 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Fri, 17 Jul 2020 17:42:18 +0000 (19:42 +0200)
Similar to the legacy read_file’s size_hint parameter.

src/Util.cpp
src/Util.hpp

index 337392fcf240613dc38b2b254bacfc643b2b592e..e7323692db2e5b979a99a5ddbf81aa58c790e543 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "Config.hpp"
 #include "Context.hpp"
+#include "Fd.hpp"
 #include "FormatNonstdStringView.hpp"
 #include "legacy_util.hpp"
 #include "logging.hpp"
@@ -669,14 +670,54 @@ parse_int(const std::string& value)
 }
 
 std::string
-read_file(const std::string& path)
+read_file(const std::string& path, size_t size_hint)
 {
-  std::ifstream file(path);
-  if (!file) {
+  if (size_hint == 0) {
+    auto stat = Stat::stat(path, Stat::OnError::log);
+    if (!stat) {
+      throw Error(strerror(errno));
+    }
+    size_hint = stat.size();
+  }
+
+  // +1 to be able to detect EOF in the first read call
+  size_hint = (size_hint < 1024) ? 1024 : size_hint + 1;
+
+  Fd fd(open(path.c_str(), O_RDONLY | O_BINARY));
+  if (!fd) {
     throw Error(strerror(errno));
   }
-  return std::string(std::istreambuf_iterator<char>(file),
-                     std::istreambuf_iterator<char>());
+
+  ssize_t ret = 0;
+  size_t pos = 0;
+  std::string result;
+  result.resize(size_hint);
+
+  while (true) {
+    if (pos > result.size()) {
+      result.resize(2 * result.size());
+    }
+    const size_t max_read = result.size() - pos;
+    char* data = const_cast<char*>(result.data()); // cast needed before C++17
+    ret = read(*fd, data + pos, max_read);
+    if (ret == 0 || (ret == -1 && errno != EINTR)) {
+      break;
+    }
+    if (ret > 0) {
+      pos += ret;
+      if (static_cast<size_t>(ret) < max_read) {
+        break;
+      }
+    }
+  }
+
+  if (ret == -1) {
+    cc_log("Failed reading %s", path.c_str());
+    throw Error(strerror(errno));
+  }
+
+  result.resize(pos);
+  return result;
 }
 
 #ifndef _WIN32
index 62a0ffabe96b7e126ed3057f87245f4782e82b63..0bbb61e30d121fb43c8c3ddd005b033b9197d7a1 100644 (file)
@@ -275,11 +275,12 @@ std::string normalize_absolute_path(nonstd::string_view path);
 // Throws Error on error.
 int parse_int(const std::string& value);
 
-// Read file data as a string.
+// Return `path`'s content as a string. If `size_hint` is not 0 then assume that
+// `path` has this size (this saves system calls).
 //
 // Throws `Error` on error. The description contains the error message without
 // the path.
-std::string read_file(const std::string& path);
+std::string read_file(const std::string& path, size_t size_hint = 0);
 
 #ifndef _WIN32
 // Like readlink(2) but returns the string (or the empty string on failure).