[llvm] [llvm-strings] Use small buffer instead of reading whole file (PR #163073)

James Henderson via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 20 02:03:47 PDT 2026


================
@@ -88,41 +90,83 @@ static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value) {
   }
 }
 
-static void strings(raw_ostream &OS, StringRef FileName, StringRef Contents) {
-  auto print = [&OS, FileName](unsigned Offset, StringRef L) {
-    if (L.size() < static_cast<size_t>(MinLength))
-      return;
+static bool isStringChar(char C) { return isPrint(C) || C == '\t'; }
+
+static void strings(raw_ostream &OS, StringRef FileName,
+                    sys::fs::file_t Handle) {
+  SmallString<sys::fs::DefaultReadChunkSize> Buffer;
+  auto printHeader = [&OS, FileName](unsigned StringStart) {
     if (PrintFileName)
       OS << FileName << ": ";
     switch (Radix) {
     case none:
       break;
     case octal:
-      OS << format("%7o ", Offset);
+      OS << format("%7o ", StringStart);
       break;
     case hexadecimal:
-      OS << format("%7x ", Offset);
+      OS << format("%7x ", StringStart);
       break;
     case decimal:
-      OS << format("%7u ", Offset);
+      OS << format("%7u ", StringStart);
       break;
     }
-    OS << L << '\n';
   };
 
-  const char *B = Contents.begin();
-  const char *P = nullptr, *E = nullptr, *S = nullptr;
-  for (P = Contents.begin(), E = Contents.end(); P < E; ++P) {
-    if (isPrint(*P) || *P == '\t') {
-      if (S == nullptr)
-        S = P;
-    } else if (S) {
-      print(S - B, StringRef(S, P - S));
-      S = nullptr;
+  // llvm-strings should be able to process a very large file on a
+  // memory-budgeted machine, so the file is read in chunks. To handle this, we
+  // read the file in chunk instead of copying the whole file into memory.
+  SmallString<DefaultMinLength> Candidate;
+  bool InString = false;
+  unsigned StringStart = 0, Offset = 0;
+
+  Buffer.resize_for_overwrite(sys::fs::DefaultReadChunkSize);
+  while (true) {
+    Expected<size_t> ReadBytesOrErr = sys::fs::readNativeFile(
+        Handle, MutableArrayRef(Buffer.data(), Buffer.size()));
+    if (!ReadBytesOrErr) {
+      errs() << FileName << ": "
+             << errorToErrorCode(ReadBytesOrErr.takeError()).message() << '\n';
+      return;
+    }
+    std::size_t CurSize = *ReadBytesOrErr;
+    if (CurSize == 0)
+      break;
+
+    std::size_t I = 0;
+    while (I != CurSize) {
+      if (InString) {
+        std::size_t Start = I;
+        while (I != CurSize && isStringChar(Buffer[I]))
----------------
jh7370 wrote:

I wonder if we could use some variation of `find_first_of`/`find_first_not_of`/`find_if` to prevent the need to explicitly use a `while` loop? We could probably also use it to detect whether a sequence of characters is a viable candidate, without needing to explicitly loop over every character.

The other advantage to doing this is that it makes the code more readable and might even be more efficient, since it'll be leveraging hopefully-optimized existing code rather than reinventing things.

https://github.com/llvm/llvm-project/pull/163073


More information about the llvm-commits mailing list