[libc-commits] [libc] [llvm] [libc] Assorted improvements to FixedVector (PR #217010)
via libc-commits
libc-commits at lists.llvm.org
Tue Aug 18 05:28:03 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Pavel Labath (labath)
<details>
<summary>Changes</summary>
- Assert that the stored type is trivially copyable (as other types are broken in various ways)
- remove UB in dereferencing the past-the-end array element
- remove the non-const_iterator constructor (as it is subsumed by the const_iterator version)
---
Full diff: https://github.com/llvm/llvm-project/pull/217010.diff
4 Files Affected:
- (modified) libc/src/__support/CMakeLists.txt (+2)
- (modified) libc/src/__support/fixedvector.h (+22-18)
- (modified) libc/test/src/__support/fixedvector_test.cpp (+68)
- (modified) utils/bazel/llvm-project-overlay/libc/BUILD.bazel (+1)
``````````diff
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index d3fd8a060ab15..ef07690e5ff9b 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -347,6 +347,8 @@ add_header_library(
DEPENDS
.libc_assert
libc.src.__support.CPP.array
+ libc.src.__support.CPP.type_traits
+ libc.src.__support.macros.config
libc.src.string.memory_utils.inline_memset
)
diff --git a/libc/src/__support/fixedvector.h b/libc/src/__support/fixedvector.h
index 34601f86dc017..83874adfc331c 100644
--- a/libc/src/__support/fixedvector.h
+++ b/libc/src/__support/fixedvector.h
@@ -1,43 +1,48 @@
-//===-- 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the FixedVector class: a fixed-capacity container with vector-like
+/// operations.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_FIXEDVECTOR_H
#define LLVM_LIBC_SRC___SUPPORT_FIXEDVECTOR_H
#include "src/__support/CPP/array.h"
#include "src/__support/CPP/iterator.h"
+#include "src/__support/CPP/type_traits/is_trivially_copyable.h"
#include "src/__support/libc_assert.h"
#include "src/__support/macros/config.h"
#include "src/string/memory_utils/inline_memset.h"
namespace LIBC_NAMESPACE_DECL {
-// 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.
+/// 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 <typename T, size_t CAPACITY> class FixedVector {
+ static_assert(cpp::is_trivially_copyable_v<T>,
+ "Non-trivially-copyable types not currently supported!");
cpp::array<T, CAPACITY> store;
size_t item_count = 0;
public:
- LIBC_INLINE constexpr FixedVector() = default;
-
using iterator = typename cpp::array<T, CAPACITY>::iterator;
- LIBC_INLINE constexpr FixedVector(iterator begin, iterator end)
- : store{}, item_count{} {
- LIBC_ASSERT(begin + CAPACITY >= end);
- for (; begin != end; ++begin)
- push_back(*begin);
- }
-
using const_iterator = typename cpp::array<T, CAPACITY>::const_iterator;
+ using reverse_iterator = typename cpp::array<T, CAPACITY>::reverse_iterator;
+
+ LIBC_INLINE constexpr FixedVector() = default;
+
LIBC_INLINE constexpr FixedVector(const_iterator begin, const_iterator end)
: store{}, item_count{} {
- LIBC_ASSERT(begin + CAPACITY >= end);
+ LIBC_ASSERT(end >= begin);
+ LIBC_ASSERT(static_cast<size_t>(end - begin) <= CAPACITY);
for (; begin != end; ++begin)
push_back(*begin);
}
@@ -100,25 +105,24 @@ template <typename T, size_t CAPACITY> class FixedVector {
// 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
+ // dynamically allocated storage. 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.
LIBC_INLINE static void destroy(FixedVector<T, CAPACITY> *store) {
store->reset();
}
- using reverse_iterator = typename cpp::array<T, CAPACITY>::reverse_iterator;
LIBC_INLINE constexpr reverse_iterator rbegin() {
- return reverse_iterator{&store[item_count]};
+ return reverse_iterator(begin() + item_count);
}
LIBC_INLINE constexpr reverse_iterator rend() { return store.rend(); }
LIBC_INLINE constexpr iterator begin() { return store.begin(); }
- LIBC_INLINE constexpr iterator end() { return iterator{&store[item_count]}; }
+ LIBC_INLINE constexpr iterator end() { return begin() + item_count; }
LIBC_INLINE constexpr const_iterator begin() const { return store.begin(); }
LIBC_INLINE constexpr const_iterator end() const {
- return const_iterator{&store[item_count]};
+ return begin() + item_count;
}
};
diff --git a/libc/test/src/__support/fixedvector_test.cpp b/libc/test/src/__support/fixedvector_test.cpp
index 8be18a52ec015..52ca16bd4d9b5 100644
--- a/libc/test/src/__support/fixedvector_test.cpp
+++ b/libc/test/src/__support/fixedvector_test.cpp
@@ -106,3 +106,71 @@ TEST(LlvmLibcFixedVectorTest, ConstForwardIteration) {
ASSERT_EQ(*it, arr[idx]);
}
}
+
+TEST(LlvmLibcFixedVectorTest, FullCapacityIteration) {
+ constexpr size_t CAPACITY = 10;
+ LIBC_NAMESPACE::FixedVector<int, CAPACITY> vec;
+ for (size_t i = 0; i < CAPACITY; ++i)
+ ASSERT_TRUE(vec.push_back(static_cast<int>(i)));
+
+ // Test forward iteration on full capacity.
+ size_t count = 0;
+ for (auto it = vec.begin(); it != vec.end(); ++it, ++count)
+ ASSERT_EQ(*it, static_cast<int>(count));
+ ASSERT_EQ(count, CAPACITY);
+
+ // Test const forward iteration.
+ const auto &const_vec = vec;
+ count = 0;
+ for (auto it = const_vec.begin(); it != const_vec.end(); ++it, ++count)
+ ASSERT_EQ(*it, static_cast<int>(count));
+ ASSERT_EQ(count, CAPACITY);
+
+ // Test reverse iteration on full capacity.
+ int expected = static_cast<int>(CAPACITY) - 1;
+ for (auto it = vec.rbegin(); it != vec.rend(); ++it, --expected)
+ ASSERT_EQ(*it, expected);
+ ASSERT_EQ(expected, -1);
+}
+
+TEST(LlvmLibcFixedVectorTest, EmptyIteration) {
+ LIBC_NAMESPACE::FixedVector<int, 5> vec;
+ ASSERT_TRUE(vec.begin() == vec.end());
+ ASSERT_TRUE(vec.rbegin() == vec.rend());
+
+ const auto &const_vec = vec;
+ ASSERT_TRUE(const_vec.begin() == const_vec.end());
+ ASSERT_TRUE(vec.rbegin() == vec.rend());
+}
+
+TEST(LlvmLibcFixedVectorTest, ConstructionFromEdgeRanges) {
+ LIBC_NAMESPACE::cpp::array<int, 5> arr{10, 20, 30, 40, 50};
+
+ // Construct from empty range.
+ LIBC_NAMESPACE::FixedVector<int, 5> empty_vec(arr.begin(), arr.begin());
+ ASSERT_TRUE(empty_vec.empty());
+ ASSERT_EQ(empty_vec.size(), static_cast<size_t>(0));
+
+ // Construct exactly at capacity.
+ LIBC_NAMESPACE::FixedVector<int, 5> full_vec(arr.begin(), arr.end());
+ ASSERT_EQ(full_vec.size(), static_cast<size_t>(5));
+ for (size_t i = 0; i < 5; ++i)
+ ASSERT_EQ(full_vec[i], arr[i]);
+}
+
+TEST(LlvmLibcFixedVectorTest, TriviallyCopyableCustomType) {
+ struct Point {
+ int x;
+ int y;
+ };
+ LIBC_NAMESPACE::FixedVector<Point, 3> vec;
+ ASSERT_TRUE(vec.push_back(Point{1, 2}));
+ ASSERT_TRUE(vec.push_back(Point{3, 4}));
+ ASSERT_EQ(vec.size(), static_cast<size_t>(2));
+ ASSERT_EQ(vec[0].x, 1);
+ ASSERT_EQ(vec[0].y, 2);
+ ASSERT_EQ(vec[1].x, 3);
+ ASSERT_EQ(vec[1].y, 4);
+ vec.reset();
+ ASSERT_TRUE(vec.empty());
+}
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index e5fdbebcf50d0..7e68c7bd8328a 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -1305,6 +1305,7 @@ libc_support_library(
deps = [
":__support_cpp_array",
":__support_cpp_iterator",
+ ":__support_cpp_type_traits",
":__support_libc_assert",
":__support_macros_config",
":string_memory_utils",
``````````
</details>
https://github.com/llvm/llvm-project/pull/217010
More information about the libc-commits
mailing list