[libc-commits] [libc] [libc] Templatize the scanf Reader interface (PR #131037)

Petr Hosek via libc-commits libc-commits at lists.llvm.org
Wed Mar 12 20:47:29 PDT 2025


================
@@ -9,121 +9,65 @@
 #ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_READER_H
 #define LLVM_LIBC_SRC_STDIO_SCANF_CORE_READER_H
 
-#include "hdr/types/FILE.h"
-
-#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
-#include "src/__support/File/file.h"
-#endif
-
-#if defined(LIBC_TARGET_ARCH_IS_GPU)
-#include "src/stdio/getc.h"
-#include "src/stdio/ungetc.h"
-#endif
-
 #include "src/__support/macros/attributes.h" // For LIBC_INLINE
 #include "src/__support/macros/config.h"
 
 #include <stddef.h>
 
 namespace LIBC_NAMESPACE_DECL {
 namespace scanf_core {
-// We use the name "reader_internal" over "internal" because
-// "internal" causes name lookups in files that include the current header to be
-// ambigious i.e. `internal::foo` in those files, will try to lookup in
-// `LIBC_NAMESPACE::scanf_core::internal` over `LIBC_NAMESPACE::internal` for
-// e.g., `internal::ArgList` in `libc/src/stdio/scanf_core/scanf_main.h`
-namespace reader_internal {
-
-#if defined(LIBC_TARGET_ARCH_IS_GPU)
-// The GPU build provides FILE access through the host operating system's
-// library. So here we simply use the public entrypoints like in the SYSTEM_FILE
-// interface. Entrypoints should normally not call others, this is an exception.
-// FIXME: We do not acquire any locks here, so this is not thread safe.
-LIBC_INLINE int getc(void *f) {
-  return LIBC_NAMESPACE::getc(reinterpret_cast<::FILE *>(f));
-}
-
-LIBC_INLINE void ungetc(int c, void *f) {
-  LIBC_NAMESPACE::ungetc(c, reinterpret_cast<::FILE *>(f));
-}
-
-#elif !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
-
-LIBC_INLINE int getc(void *f) {
-  unsigned char c;
-  auto result =
-      reinterpret_cast<LIBC_NAMESPACE::File *>(f)->read_unlocked(&c, 1);
-  size_t r = result.value;
-  if (result.has_error() || r != 1)
-    return '\0';
-
-  return c;
-}
 
-LIBC_INLINE void ungetc(int c, void *f) {
-  reinterpret_cast<LIBC_NAMESPACE::File *>(f)->ungetc_unlocked(c);
-}
-
-#else  // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
-
-// Since ungetc_unlocked isn't always available, we don't acquire the lock for
-// system files.
-LIBC_INLINE int getc(void *f) { return ::getc(reinterpret_cast<::FILE *>(f)); }
-
-LIBC_INLINE void ungetc(int c, void *f) {
-  ::ungetc(c, reinterpret_cast<::FILE *>(f));
-}
-#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
-
-} // namespace reader_internal
+template <typename Derived> struct ReadBuffer {
+  LIBC_INLINE char getc() { return static_cast<Derived *>(this)->getc(); }
+  LIBC_INLINE void ungetc(int c) { static_cast<Derived *>(this)->ungetc(c); }
+};
 
-// This is intended to be either a raw string or a buffer syncronized with the
-// file's internal buffer.
-struct ReadBuffer {
+class StringBuffer : public ReadBuffer<StringBuffer> {
   const char *buffer;
-  size_t buff_len;
+  [[maybe_unused]] size_t buff_len;
   size_t buff_cur = 0;
+
+public:
+  LIBC_INLINE StringBuffer(const char *buffer, size_t buff_len)
+      : buffer(buffer), buff_len(buff_len) {}
+
+  LIBC_INLINE char getc() {
+    char output = buffer[buff_cur];
+    ++buff_cur;
+    return output;
+  }
+  LIBC_INLINE void ungetc(int) {
+    if (buff_cur > 0) {
+      // While technically c should be written back to the buffer, in scanf we
+      // always write the character that was already there. Additionally, the
+      // buffer is most likely to contain a string that isn't part of a file,
+      // which may not be writable.
+      --buff_cur;
+    }
+  }
 };
 
-class Reader {
-  ReadBuffer *rb;
-  void *input_stream = nullptr;
+// TODO: We should be able to fold ReadBuffer into Reader.
----------------
petrhosek wrote:

Done.

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


More information about the libc-commits mailing list