Skip to content

Commit 00f5aaf

Browse files
[libc]: Clean up unnecessary function pointers in scanf (#121215)
Resolves #115394 1. Move definitions of cross-platform `getc` `ungetc` to `reader.h`. 2. Remove function pointer members to define them once per platform in `.h` 3. Built in overlay mode in macOS m1 4. Remove `reader.cpp` as it's empty now Also, full build doesn't yet build on macos m1 AFAIK
1 parent 2fab6db commit 00f5aaf

File tree

4 files changed

+86
-78
lines changed

4 files changed

+86
-78
lines changed

libc/src/stdio/scanf_core/CMakeLists.txt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,26 @@ add_object_library(
5454
libc.src.__support.arg_list
5555
)
5656

57-
add_object_library(
57+
if(LIBC_TARGET_OS_IS_GPU)
58+
add_header_library(
59+
reader
60+
HDRS
61+
reader.h
62+
DEPENDS
63+
libc.src.__support.macros.attributes
64+
)
65+
elseif((TARGET libc.src.__support.File.file) OR (NOT LLVM_LIBC_FULL_BUILD))
66+
add_header_library(
5867
reader
59-
SRCS
60-
reader.cpp
6168
HDRS
6269
reader.h
6370
DEPENDS
6471
libc.src.__support.macros.attributes
72+
libc.hdr.types.FILE
73+
libc.src.__support.File.file
74+
${use_system_file}
6575
)
76+
endif()
6677

6778
add_object_library(
6879
converter

libc/src/stdio/scanf_core/reader.cpp

Lines changed: 0 additions & 29 deletions
This file was deleted.

libc/src/stdio/scanf_core/reader.h

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,68 @@
99
#ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_READER_H
1010
#define LLVM_LIBC_SRC_STDIO_SCANF_CORE_READER_H
1111

12+
#include "hdr/types/FILE.h"
13+
14+
#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
15+
#include "src/__support/File/file.h"
16+
#endif
17+
1218
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
1319
#include "src/__support/macros/config.h"
20+
1421
#include <stddef.h>
1522

1623
namespace LIBC_NAMESPACE_DECL {
1724
namespace scanf_core {
18-
19-
using StreamGetc = int (*)(void *);
20-
using StreamUngetc = void (*)(int, void *);
25+
// We use the name "reader_internal" over "internal" because
26+
// "internal" causes name lookups in files that include the current header to be
27+
// ambigious i.e. `internal::foo` in those files, will try to lookup in
28+
// `LIBC_NAMESPACE::scanf_core::internal` over `LIBC_NAMESPACE::internal` for
29+
// e.g., `internal::ArgList` in `libc/src/stdio/scanf_core/scanf_main.h`
30+
namespace reader_internal {
31+
32+
#if defined(LIBC_TARGET_ARCH_IS_GPU)
33+
// The GPU build provides FILE access through the host operating system's
34+
// library. So here we simply use the public entrypoints like in the SYSTEM_FILE
35+
// interface. Entrypoints should normally not call others, this is an exception.
36+
// FIXME: We do not acquire any locks here, so this is not thread safe.
37+
LIBC_INLINE int getc(void *f) {
38+
return LIBC_NAMESPACE::getc(reinterpret_cast<::FILE *>(f));
39+
}
40+
41+
LIBC_INLINE void ungetc(int c, void *f) {
42+
LIBC_NAMESPACE::ungetc(c, reinterpret_cast<::FILE *>(f));
43+
}
44+
45+
#elif !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
46+
47+
LIBC_INLINE int getc(void *f) {
48+
unsigned char c;
49+
auto result =
50+
reinterpret_cast<LIBC_NAMESPACE::File *>(f)->read_unlocked(&c, 1);
51+
size_t r = result.value;
52+
if (result.has_error() || r != 1)
53+
return '\0';
54+
55+
return c;
56+
}
57+
58+
LIBC_INLINE void ungetc(int c, void *f) {
59+
reinterpret_cast<LIBC_NAMESPACE::File *>(f)->ungetc_unlocked(c);
60+
}
61+
62+
#else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
63+
64+
// Since ungetc_unlocked isn't always available, we don't acquire the lock for
65+
// system files.
66+
LIBC_INLINE int getc(void *f) { return ::getc(reinterpret_cast<::FILE *>(f)); }
67+
68+
LIBC_INLINE void ungetc(int c, void *f) {
69+
::ungetc(c, reinterpret_cast<::FILE *>(f));
70+
}
71+
#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
72+
73+
} // namespace reader_internal
2174

2275
// This is intended to be either a raw string or a buffer syncronized with the
2376
// file's internal buffer.
@@ -29,24 +82,15 @@ struct ReadBuffer {
2982

3083
class Reader {
3184
ReadBuffer *rb;
32-
3385
void *input_stream = nullptr;
34-
35-
// TODO: Remove these unnecessary function pointers
36-
StreamGetc stream_getc = nullptr;
37-
StreamUngetc stream_ungetc = nullptr;
38-
3986
size_t cur_chars_read = 0;
4087

4188
public:
4289
// TODO: Set buff_len with a proper constant
4390
LIBC_INLINE Reader(ReadBuffer *string_buffer) : rb(string_buffer) {}
4491

45-
LIBC_INLINE Reader(void *stream, StreamGetc stream_getc_in,
46-
StreamUngetc stream_ungetc_in,
47-
ReadBuffer *stream_buffer = nullptr)
48-
: rb(stream_buffer), input_stream(stream), stream_getc(stream_getc_in),
49-
stream_ungetc(stream_ungetc_in) {}
92+
LIBC_INLINE Reader(void *stream, ReadBuffer *stream_buffer = nullptr)
93+
: rb(stream_buffer), input_stream(stream) {}
5094

5195
// This returns the next character from the input and advances it by one
5296
// character. When it hits the end of the string or file it returns '\0' to
@@ -59,12 +103,23 @@ class Reader {
59103
return output;
60104
}
61105
// This should reset the buffer if applicable.
62-
return static_cast<char>(stream_getc(input_stream));
106+
return static_cast<char>(reader_internal::getc(input_stream));
63107
}
64108

65109
// This moves the input back by one character, placing c into the buffer if
66110
// this is a file reader, else c is ignored.
67-
void ungetc(char c);
111+
LIBC_INLINE void ungetc(char c) {
112+
--cur_chars_read;
113+
if (rb != nullptr && rb->buff_cur > 0) {
114+
// While technically c should be written back to the buffer, in scanf we
115+
// always write the character that was already there. Additionally, the
116+
// buffer is most likely to contain a string that isn't part of a file,
117+
// which may not be writable.
118+
--(rb->buff_cur);
119+
return;
120+
}
121+
reader_internal::ungetc(static_cast<int>(c), input_stream);
122+
}
68123

69124
LIBC_INLINE size_t chars_read() { return cur_chars_read; }
70125
};

libc/src/stdio/scanf_core/vfscanf_internal.h

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,6 @@ LIBC_INLINE void flockfile(::FILE *) { return; }
3838

3939
LIBC_INLINE void funlockfile(::FILE *) { return; }
4040

41-
LIBC_INLINE int getc(void *f) {
42-
return LIBC_NAMESPACE::getc(reinterpret_cast<::FILE *>(f));
43-
}
44-
45-
LIBC_INLINE void ungetc(int c, void *f) {
46-
LIBC_NAMESPACE::ungetc(c, reinterpret_cast<::FILE *>(f));
47-
}
48-
4941
LIBC_INLINE int ferror_unlocked(::FILE *f) { return LIBC_NAMESPACE::ferror(f); }
5042

5143
#elif !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
@@ -58,21 +50,6 @@ LIBC_INLINE void funlockfile(FILE *f) {
5850
reinterpret_cast<LIBC_NAMESPACE::File *>(f)->unlock();
5951
}
6052

61-
LIBC_INLINE int getc(void *f) {
62-
unsigned char c;
63-
auto result =
64-
reinterpret_cast<LIBC_NAMESPACE::File *>(f)->read_unlocked(&c, 1);
65-
size_t r = result.value;
66-
if (result.has_error() || r != 1)
67-
return '\0';
68-
69-
return c;
70-
}
71-
72-
LIBC_INLINE void ungetc(int c, void *f) {
73-
reinterpret_cast<LIBC_NAMESPACE::File *>(f)->ungetc_unlocked(c);
74-
}
75-
7653
LIBC_INLINE int ferror_unlocked(FILE *f) {
7754
return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->error_unlocked();
7855
}
@@ -85,12 +62,6 @@ LIBC_INLINE void flockfile(::FILE *) { return; }
8562

8663
LIBC_INLINE void funlockfile(::FILE *) { return; }
8764

88-
LIBC_INLINE int getc(void *f) { return ::getc(reinterpret_cast<::FILE *>(f)); }
89-
90-
LIBC_INLINE void ungetc(int c, void *f) {
91-
::ungetc(c, reinterpret_cast<::FILE *>(f));
92-
}
93-
9465
LIBC_INLINE int ferror_unlocked(::FILE *f) { return ::ferror(f); }
9566

9667
#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
@@ -103,7 +74,7 @@ LIBC_INLINE int vfscanf_internal(::FILE *__restrict stream,
10374
const char *__restrict format,
10475
internal::ArgList &args) {
10576
internal::flockfile(stream);
106-
scanf_core::Reader reader(stream, &internal::getc, internal::ungetc);
77+
scanf_core::Reader reader(stream);
10778
int retval = scanf_core::scanf_main(&reader, format, args);
10879
if (retval == 0 && internal::ferror_unlocked(stream))
10980
retval = EOF;

0 commit comments

Comments
 (0)