diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt --- a/libc/src/__support/CPP/CMakeLists.txt +++ b/libc/src/__support/CPP/CMakeLists.txt @@ -93,6 +93,12 @@ expected.h ) +add_header_library( + vector_string + HDRS + vector_string.h +) + add_object_library( new SRCS diff --git a/libc/src/__support/CPP/vector_string.h b/libc/src/__support/CPP/vector_string.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/CPP/vector_string.h @@ -0,0 +1,78 @@ +//===-- Standalone implementation of a vector string ------------*- 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_CPP_VECTORSTRING_H +#define LLVM_LIBC_SRC_SUPPORT_CPP_VECTORSTRING_H + +#include +#include // For allocation. + +namespace __llvm_libc { +namespace cpp { + +// 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 VectorString { + 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: + VectorString() = default; + ~VectorString() { + 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 cpp +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SUPPORT_CPP_VECTORSTRING_H diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt --- a/libc/test/src/__support/CPP/CMakeLists.txt +++ b/libc/test/src/__support/CPP/CMakeLists.txt @@ -91,3 +91,14 @@ DEPENDS libc.src.__support.CPP.span ) + + +add_libc_unittest( + vector_string_test + SUITE + libc_cpp_utils_unittests + SRCS + vector_string_test.cpp + DEPENDS + libc.src.__support.CPP.vector_string +) diff --git a/libc/test/src/__support/CPP/stringview_test.cpp b/libc/test/src/__support/CPP/stringview_test.cpp --- 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/CPP/vector_string_test.cpp b/libc/test/src/__support/CPP/vector_string_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/__support/CPP/vector_string_test.cpp @@ -0,0 +1,78 @@ +//===-- Unittests for vector_string ---------------------------------------===// +// +// 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/vector_string.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::cpp::VectorString; + +TEST(LlvmLibcVectorStringTest, InitializeCheck) { + VectorString v; + ASSERT_EQ(v.length(), size_t(0)); +} + +TEST(LlvmLibcVectorStringTest, AppendShort) { + VectorString 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(LlvmLibcVectorStringTest, AppendMedium) { + VectorString 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(LlvmLibcVectorStringTest, AppendLong) { + VectorString 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)); +}