[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