From 176c853d1da5c344194952659eeb74f063e13010 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Fri, 6 Jan 2023 15:00:51 -0800 Subject: [PATCH] [libc] add internal string class The scanf implementation needs a dynamically resizing string class. This patch adds a minimal version of that class along with tests to check the current functionality. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D141162 --- libc/src/__support/CMakeLists.txt | 6 ++ libc/src/__support/char_vector.h | 76 ++++++++++++++++++++++++ libc/test/src/__support/CMakeLists.txt | 10 ++++ libc/test/src/__support/CPP/stringview_test.cpp | 3 +- libc/test/src/__support/char_vector_test.cpp | 78 +++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 libc/src/__support/char_vector.h create mode 100644 libc/test/src/__support/char_vector_test.cpp diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt index fc80c53..8b702af 100644 --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -146,6 +146,12 @@ add_header_library( ) add_header_library( + char_vector + HDRS + char_vector.h +) + +add_header_library( number_pair HDRS number_pair.h diff --git a/libc/src/__support/char_vector.h b/libc/src/__support/char_vector.h new file mode 100644 index 0000000..0a9a2d7 --- /dev/null +++ b/libc/src/__support/char_vector.h @@ -0,0 +1,76 @@ +//===-- Standalone implementation of a char vector --------------*- 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_SUPPORT_CHARVECTOR_H +#define LLVM_LIBC_SRC_SUPPORT_CHARVECTOR_H + +#include +#include // For allocation. + +namespace __llvm_libc { + +// This is very simple alternate of the std::string class. There is no +// bounds check performed in any of the methods. The callers are expected to +// do the checks before invoking the methods. +// +// This class will be extended as needed in future. + +class CharVector { + static constexpr size_t INIT_BUFF_SIZE = 64; + char local_buffer[INIT_BUFF_SIZE]; + char *cur_str = local_buffer; + size_t cur_buff_size = INIT_BUFF_SIZE; + size_t index = 0; + +public: + CharVector() = default; + ~CharVector() { + if (cur_str != local_buffer) + free(cur_str); + } + + // append returns true on success and false on allocation failure. + bool append(char new_char) { + // Subtract 1 for index starting at 0 and another for the null terminator. + if (index >= cur_buff_size - 2) { + // If the new character would cause the string to be longer than the + // buffer's size, attempt to allocate a new buffer. + cur_buff_size = cur_buff_size * 2; + if (cur_str == local_buffer) { + char *new_str; + new_str = reinterpret_cast(malloc(cur_buff_size)); + if (new_str == NULL) { + return false; + } + // TODO: replace with inline memcpy + for (size_t i = 0; i < index; ++i) + new_str[i] = cur_str[i]; + cur_str = new_str; + } else { + cur_str = reinterpret_cast(realloc(cur_str, cur_buff_size)); + if (cur_str == NULL) { + return false; + } + } + } + cur_str[index] = new_char; + ++index; + return true; + } + + char *c_str() { + cur_str[index] = '\0'; + return cur_str; + } + + size_t length() { return index; } +}; + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SUPPORT_CHARVECTOR_H diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt index b835812..fa35aa4 100644 --- a/libc/test/src/__support/CMakeLists.txt +++ b/libc/test/src/__support/CMakeLists.txt @@ -84,6 +84,16 @@ add_libc_unittest( libc.src.__support.fixedvector ) +add_libc_unittest( + char_vector_test + SUITE + libc_support_unittests + SRCS + char_vector_test.cpp + DEPENDS + libc.src.__support.char_vector +) + add_executable( libc_str_to_float_comparison_test str_to_float_comparison_test.cpp diff --git a/libc/test/src/__support/CPP/stringview_test.cpp b/libc/test/src/__support/CPP/stringview_test.cpp index bd6b614..240b590 100644 --- a/libc/test/src/__support/CPP/stringview_test.cpp +++ b/libc/test/src/__support/CPP/stringview_test.cpp @@ -1,5 +1,4 @@ -//===-- Unittests for string_view -//------------------------------------------===// +//===-- Unittests for string_view -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libc/test/src/__support/char_vector_test.cpp b/libc/test/src/__support/char_vector_test.cpp new file mode 100644 index 0000000..15e269b --- /dev/null +++ b/libc/test/src/__support/char_vector_test.cpp @@ -0,0 +1,78 @@ +//===-- Unittests for char_vector ---------------------------------------===// +// +// 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/char_vector.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::CharVector; + +TEST(LlvmLibcCharVectorTest, InitializeCheck) { + CharVector v; + ASSERT_EQ(v.length(), size_t(0)); +} + +TEST(LlvmLibcCharVectorTest, AppendShort) { + CharVector v; + ASSERT_EQ(v.length(), size_t(0)); + + constexpr char test_str[] = "1234567890"; + for (size_t i = 0; test_str[i] != '\0'; ++i) { + v.append(test_str[i]); + } + ASSERT_STREQ(v.c_str(), test_str); +} + +TEST(LlvmLibcCharVectorTest, AppendMedium) { + CharVector v; + ASSERT_EQ(v.length(), size_t(0)); + + // 100 characters (each row is 50) + constexpr char test_str[] = + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy"; + for (size_t i = 0; test_str[i] != '\0'; ++i) { + ASSERT_EQ(v.length(), i); + v.append(test_str[i]); + } + ASSERT_STREQ(v.c_str(), test_str); + ASSERT_EQ(v.length(), size_t(100)); +} + +TEST(LlvmLibcCharVectorTest, AppendLong) { + CharVector v; + ASSERT_EQ(v.length(), size_t(0)); + + // 1000 characters + constexpr char test_str[] = + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "12345678901234567890123456789012345678901234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy"; + for (size_t i = 0; test_str[i] != '\0'; ++i) { + ASSERT_EQ(v.length(), i); + v.append(test_str[i]); + } + ASSERT_STREQ(v.c_str(), test_str); + ASSERT_EQ(v.length(), size_t(1000)); +} -- 2.7.4