[libc-commits] [libc] 0c8db88 - [libc] add scanf reader

Michael Jones via libc-commits libc-commits at lists.llvm.org
Mon Nov 7 13:49:06 PST 2022


Author: Michael Jones
Date: 2022-11-07T13:48:58-08:00
New Revision: 0c8db885f62713af06116fc02cf19b4e0ba701f4

URL: https://github.com/llvm/llvm-project/commit/0c8db885f62713af06116fc02cf19b4e0ba701f4
DIFF: https://github.com/llvm/llvm-project/commit/0c8db885f62713af06116fc02cf19b4e0ba701f4.diff

LOG: [libc] add scanf reader

This is the interface that will be used to read from a file or string in
scanf. This patch also adds the string and file implementations of the
reader, although the file reader is not yet complete since ungetc has
not yet been implemented.

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D137117

Added: 
    libc/src/stdio/scanf_core/file_reader.cpp
    libc/src/stdio/scanf_core/file_reader.h
    libc/src/stdio/scanf_core/reader.cpp
    libc/src/stdio/scanf_core/reader.h
    libc/src/stdio/scanf_core/string_reader.cpp
    libc/src/stdio/scanf_core/string_reader.h
    libc/test/src/stdio/scanf_core/string_reader_test.cpp

Modified: 
    libc/src/stdio/scanf_core/CMakeLists.txt
    libc/test/src/stdio/scanf_core/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/src/stdio/scanf_core/CMakeLists.txt b/libc/src/stdio/scanf_core/CMakeLists.txt
index 3941d40a838c7..91cf5e2ada907 100644
--- a/libc/src/stdio/scanf_core/CMakeLists.txt
+++ b/libc/src/stdio/scanf_core/CMakeLists.txt
@@ -23,3 +23,38 @@ add_object_library(
     libc.src.__support.CPP.bitset
     libc.src.__support.CPP.string_view
 )
+
+if(NOT (TARGET libc.src.__support.File.file))
+  # Not all platforms have a file implementation. If file is unvailable,
+  # then we must skip all the parts that need file.
+  return()
+endif()
+
+add_object_library(
+  string_reader
+  SRCS
+    string_reader.cpp
+  HDRS
+    string_reader.h
+)
+
+add_object_library(
+  file_reader
+  SRCS
+    file_reader.cpp
+  HDRS
+    file_reader.h
+  DEPENDS
+    libc.src.__support.File.file
+)
+
+add_object_library(
+  reader
+  SRCS
+    reader.cpp
+  HDRS
+    reader.h
+  DEPENDS
+    .string_reader
+    .file_reader
+)

diff  --git a/libc/src/stdio/scanf_core/file_reader.cpp b/libc/src/stdio/scanf_core/file_reader.cpp
new file mode 100644
index 0000000000000..f39c3b9ab8412
--- /dev/null
+++ b/libc/src/stdio/scanf_core/file_reader.cpp
@@ -0,0 +1,26 @@
+//===-- FILE Reader implementation for scanf --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/scanf_core/file_reader.h"
+#include "src/__support/File/file.h"
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace scanf_core {
+
+char FileReader::get_char() {
+  char tiny_buff = 0;
+  if (file->read_unlocked(&tiny_buff, 1) != 1)
+    return 0;
+  return tiny_buff;
+}
+
+void FileReader::unget_char(char c) { file->ungetc_unlocked(c); }
+
+} // namespace scanf_core
+} // namespace __llvm_libc

diff  --git a/libc/src/stdio/scanf_core/file_reader.h b/libc/src/stdio/scanf_core/file_reader.h
new file mode 100644
index 0000000000000..5e97eb604e66b
--- /dev/null
+++ b/libc/src/stdio/scanf_core/file_reader.h
@@ -0,0 +1,38 @@
+//===-- FILE Reader definition for scanf ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_FILE_READER_H
+#define LLVM_LIBC_SRC_STDIO_SCANF_CORE_FILE_READER_H
+
+#include "src/__support/File/file.h"
+
+#include <stddef.h>
+#include <stdio.h>
+
+namespace __llvm_libc {
+namespace scanf_core {
+
+class FileReader {
+  __llvm_libc::File *file;
+
+public:
+  FileReader(::FILE *init_file) {
+    file = reinterpret_cast<__llvm_libc::File *>(init_file);
+    file->lock();
+  }
+
+  ~FileReader() { file->unlock(); }
+
+  char get_char();
+  void unget_char(char c);
+};
+
+} // namespace scanf_core
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_SCANF_CORE_FILE_READER_H

diff  --git a/libc/src/stdio/scanf_core/reader.cpp b/libc/src/stdio/scanf_core/reader.cpp
new file mode 100644
index 0000000000000..23dcbd405505d
--- /dev/null
+++ b/libc/src/stdio/scanf_core/reader.cpp
@@ -0,0 +1,35 @@
+//===-- Reader definition for scanf -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/scanf_core/reader.h"
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace scanf_core {
+
+char Reader::getc() {
+  if (reader_type == ReaderType::String) {
+    return string_reader->get_char();
+  } else {
+    return file_reader->get_char();
+  }
+}
+
+void Reader::ungetc(char c) {
+  if (reader_type == ReaderType::String) {
+    // The string reader ignores the char c passed to unget since it doesn't
+    // need to place anything back into a buffer, and modifying the source
+    // string would be dangerous.
+    return string_reader->unget_char();
+  } else {
+    return file_reader->unget_char(c);
+  }
+}
+
+} // namespace scanf_core
+} // namespace __llvm_libc

diff  --git a/libc/src/stdio/scanf_core/reader.h b/libc/src/stdio/scanf_core/reader.h
new file mode 100644
index 0000000000000..4d6ed06c00e7c
--- /dev/null
+++ b/libc/src/stdio/scanf_core/reader.h
@@ -0,0 +1,49 @@
+//===-- Reader definition for scanf -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_READER_H
+#define LLVM_LIBC_SRC_STDIO_SCANF_CORE_READER_H
+
+#include "src/stdio/scanf_core/file_reader.h"
+#include "src/stdio/scanf_core/string_reader.h"
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace scanf_core {
+
+enum class ReaderType { String, File };
+
+class Reader final {
+  union {
+    StringReader *string_reader;
+    FileReader *file_reader;
+  };
+
+  const ReaderType reader_type;
+
+public:
+  Reader(StringReader *init_string_reader)
+      : string_reader(init_string_reader), reader_type(ReaderType::String) {}
+
+  Reader(FileReader *init_file_reader)
+      : file_reader(init_file_reader), reader_type(ReaderType::File) {}
+
+  // This returns the next character from the input and advances it by one
+  // character. When it hits the end of the string or file it returns '\0' to
+  // signal to stop parsing.
+  char getc();
+
+  // This moves the input back by one character, placing c into the buffer if
+  // this is a file reader, else c is ignored.
+  void ungetc(char c);
+};
+
+} // namespace scanf_core
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_SCANF_CORE_READER_H

diff  --git a/libc/src/stdio/scanf_core/string_reader.cpp b/libc/src/stdio/scanf_core/string_reader.cpp
new file mode 100644
index 0000000000000..1d728d2b9eb35
--- /dev/null
+++ b/libc/src/stdio/scanf_core/string_reader.cpp
@@ -0,0 +1,24 @@
+//===-- String Reader implementation for scanf ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/scanf_core/string_reader.h"
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace scanf_core {
+
+char StringReader::get_char() {
+  char cur_char = string[cur_index];
+  ++cur_index;
+  return cur_char;
+}
+
+void StringReader::unget_char() { --cur_index; }
+
+} // namespace scanf_core
+} // namespace __llvm_libc

diff  --git a/libc/src/stdio/scanf_core/string_reader.h b/libc/src/stdio/scanf_core/string_reader.h
new file mode 100644
index 0000000000000..35550b16c3214
--- /dev/null
+++ b/libc/src/stdio/scanf_core/string_reader.h
@@ -0,0 +1,33 @@
+//===-- String Reader definition for scanf ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_STRING_READER_H
+#define LLVM_LIBC_SRC_STDIO_SCANF_CORE_STRING_READER_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace scanf_core {
+
+class StringReader {
+  const char *string;
+  size_t cur_index = 0;
+
+public:
+  StringReader(const char *init_string) { string = init_string; }
+
+  ~StringReader() {}
+
+  char get_char();
+  void unget_char();
+};
+
+} // namespace scanf_core
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_SCANF_CORE_STRING_READER_H

diff  --git a/libc/test/src/stdio/scanf_core/CMakeLists.txt b/libc/test/src/stdio/scanf_core/CMakeLists.txt
index 3235a0e53e010..fa4878ae5b15f 100644
--- a/libc/test/src/stdio/scanf_core/CMakeLists.txt
+++ b/libc/test/src/stdio/scanf_core/CMakeLists.txt
@@ -12,3 +12,21 @@ add_libc_unittest(
     libc.src.__support.CPP.string_view
     libc.src.__support.arg_list
 )
+
+if(NOT (TARGET libc.src.__support.File.file))
+  # Not all platforms have a file implementation. If file is unvailable,
+  # then we must skip all the parts that need file.
+  return()
+endif()
+
+add_libc_unittest(
+  string_reader_test
+  SUITE
+    libc_stdio_unittests
+  SRCS
+    string_reader_test.cpp
+  DEPENDS
+    libc.src.stdio.scanf_core.reader
+    libc.src.stdio.scanf_core.string_reader
+    libc.src.__support.CPP.string_view
+)

diff  --git a/libc/test/src/stdio/scanf_core/string_reader_test.cpp b/libc/test/src/stdio/scanf_core/string_reader_test.cpp
new file mode 100644
index 0000000000000..43e65cc1bab6e
--- /dev/null
+++ b/libc/test/src/stdio/scanf_core/string_reader_test.cpp
@@ -0,0 +1,66 @@
+//===-- Unittests for the scanf String Reader -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/string_view.h"
+#include "src/stdio/scanf_core/reader.h"
+#include "src/stdio/scanf_core/string_reader.h"
+
+#include "utils/UnitTest/Test.h"
+
+TEST(LlvmLibcScanfStringReaderTest, Constructor) {
+  char str[10];
+  __llvm_libc::scanf_core::StringReader str_reader(str);
+  __llvm_libc::scanf_core::Reader reader(&str_reader);
+}
+
+TEST(LlvmLibcScanfStringReaderTest, SimpleRead) {
+  const char *str = "abc";
+  __llvm_libc::scanf_core::StringReader str_reader(str);
+  __llvm_libc::scanf_core::Reader reader(&str_reader);
+
+  for (size_t i = 0; i < sizeof(str); ++i) {
+    ASSERT_EQ(str[i], reader.getc());
+  }
+}
+
+TEST(LlvmLibcScanfStringReaderTest, ReadAndReverse) {
+  const char *str = "abcDEF123";
+  __llvm_libc::scanf_core::StringReader str_reader(str);
+  __llvm_libc::scanf_core::Reader reader(&str_reader);
+
+  for (size_t i = 0; i < 5; ++i) {
+    ASSERT_EQ(str[i], reader.getc());
+  }
+
+  // Move back by 3, cursor should now be on 2
+  reader.ungetc(str[4]);
+  reader.ungetc(str[3]);
+  reader.ungetc(str[2]);
+
+  for (size_t i = 2; i < 7; ++i) {
+    ASSERT_EQ(str[i], reader.getc());
+  }
+
+  // Move back by 2, cursor should now be on 5
+  reader.ungetc(str[6]);
+  reader.ungetc(str[5]);
+
+  for (size_t i = 5; i < 10; ++i) {
+    ASSERT_EQ(str[i], reader.getc());
+  }
+
+  // Move back by 10, which should be back to the start.
+  for (size_t i = 0; i < 10; ++i) {
+    reader.ungetc(str[9 - i]);
+  }
+
+  // Check the whole string.
+  for (size_t i = 0; i < sizeof(str); ++i) {
+    ASSERT_EQ(str[i], reader.getc());
+  }
+}


        


More information about the libc-commits mailing list