diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -70,6 +70,14 @@ arg_list.h ) +add_header_library( + fixedvector + HDRS + fixedvector.h + DEPENDS + libc.src.__support.CPP.array +) + add_subdirectory(FPUtil) add_subdirectory(OSUtil) diff --git a/libc/src/__support/fixedvector.h b/libc/src/__support/fixedvector.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/fixedvector.h @@ -0,0 +1,62 @@ +//===-- A data structure for a fixed capacity data store --------*- 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_SUPPORT_FIXEDVECTOR_H +#define LLVM_LIBC_SUPPORT_FIXEDVECTOR_H + +#include "src/__support/CPP/array.h" + +namespace __llvm_libc { + +// A fixed size data store backed by an underlying cpp::array data structure. It +// supports vector like API but is not resizable like a vector. +template class FixedVector { + cpp::array store; + size_t item_count = 0; + +public: + constexpr FixedVector() = default; + + bool push_back(const T &obj) { + if (item_count == CAPACITY) + return false; + store[item_count] = obj; + ++item_count; + return true; + } + + const T &back() const { return store[item_count - 1]; } + + T &back() { return store[item_count - 1]; } + + bool pop_back() { + if (item_count == 0) + return false; + --item_count; + return true; + } + + bool empty() const { return item_count == 0; } + + // Empties the store for all practical purposes. + void reset() { item_count = 0; } + + // This static method does not free up the resources held by |store|, + // say by calling `free` or something similar. It just does the equivalent + // of the `reset` method. Considering that FixedVector is of fixed storage, + // a `destroy` method like this should not be required. However, FixedVector + // is used in a few places as an alternate for data structures which use + // dynamically allocated storate. So, the `destroy` method like this + // matches the `destroy` API of those other data structures so that users + // can easily swap one data structure for the other. + static void destroy(FixedVector *store) { store->reset(); } +}; + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SUPPORT_FIXEDVECTOR_H diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt --- a/libc/test/src/__support/CMakeLists.txt +++ b/libc/test/src/__support/CMakeLists.txt @@ -63,6 +63,16 @@ libc.src.__support.CPP.uint ) +add_libc_unittest( + fixedvector_test + SUITE + libc_support_unittests + SRCS + fixedvector_test.cpp + DEPENDS + libc.src.__support.fixedvector +) + add_executable( libc_str_to_float_comparison_test str_to_float_comparison_test.cpp diff --git a/libc/test/src/__support/fixedvector_test.cpp b/libc/test/src/__support/fixedvector_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/__support/fixedvector_test.cpp @@ -0,0 +1,45 @@ +//===-- Unittests for FixedVector -----------------------------------------===// +// +// 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/fixedvector.h" +#include "utils/UnitTest/Test.h" + +TEST(LlvmLibcFixedVectorTest, PushAndPop) { + __llvm_libc::FixedVector fixed_vector; + ASSERT_TRUE(fixed_vector.empty()); + for (int i = 0; i < 20; i++) + ASSERT_TRUE(fixed_vector.push_back(i)); + ASSERT_FALSE(fixed_vector.empty()); + ASSERT_FALSE(fixed_vector.push_back(123)); + for (int i = 20; i > 0; --i) { + ASSERT_EQ(fixed_vector.back(), i - 1); + ASSERT_TRUE(fixed_vector.pop_back()); + } + ASSERT_FALSE(fixed_vector.pop_back()); + ASSERT_TRUE(fixed_vector.empty()); +} + +TEST(LlvmLibcFixedVectorTest, Reset) { + __llvm_libc::FixedVector fixed_vector; + ASSERT_TRUE(fixed_vector.empty()); + for (int i = 0; i < 20; i++) + ASSERT_TRUE(fixed_vector.push_back(i)); + ASSERT_FALSE(fixed_vector.empty()); + fixed_vector.reset(); + ASSERT_TRUE(fixed_vector.empty()); +} + +TEST(LlvmLibcFixedVectorTest, Destroy) { + __llvm_libc::FixedVector fixed_vector; + ASSERT_TRUE(fixed_vector.empty()); + for (int i = 0; i < 20; i++) + ASSERT_TRUE(fixed_vector.push_back(i)); + ASSERT_FALSE(fixed_vector.empty()); + __llvm_libc::FixedVector::destroy(&fixed_vector); + ASSERT_TRUE(fixed_vector.empty()); +}