forked from OSchip/llvm-project
[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
This commit is contained in:
parent
6a6101958a
commit
0c8db885f6
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue