[libc-commits] [libc] [libc][CPP] Add vector container and unit tests (PR #222972)

Jeff Bailey via libc-commits libc-commits at lists.llvm.org
Fri Sep 11 11:51:29 PDT 2026


================
@@ -0,0 +1,321 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Implementation of vector container.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_VECTOR_H
+#define LLVM_LIBC_SRC___SUPPORT_CPP_VECTOR_H
+
+#include "hdr/func/free.h"
+#include "hdr/func/realloc.h"
+#include "hdr/types/size_t.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/CPP/utility.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_assert.h"
+#include "src/__support/macros/config.h"
+
+#include <stddef.h> // For max_align_t, ptrdiff_t
+
+namespace LIBC_NAMESPACE_DECL {
+namespace cpp {
+
+template <typename T> class vector {
+  static_assert(alignof(T) <= alignof(max_align_t),
+                "Overaligned types are not supported by cpp::vector");
+
+public:
+  using value_type = T;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+  using reference = T &;
+  using const_reference = const T &;
+  using pointer = T *;
+  using const_pointer = const T *;
+  using iterator = T *;
+  using const_iterator = const T *;
+
+  [[nodiscard]] LIBC_INLINE constexpr size_type max_size() const noexcept {
+    return static_cast<size_type>(-1) / sizeof(T);
+  }
+
+private:
+  T *data_ = nullptr;
+  size_t size_ = 0;
+  size_t capacity_ = 0;
+
+  static constexpr size_t DEFAULT_INITIAL_CAPACITY = 16;
+
+  LIBC_INLINE void destroy_elements(size_t from, size_t to) {
+    if constexpr (!is_trivially_destructible_v<T>) {
+      while (to > from) {
+        --to;
+        data_[to].~T();
+      }
+    }
+  }
+
+  LIBC_INLINE void deallocate() {
+    if (data_) {
+      destroy_elements(0, size_);
+      ::free(data_);
+      data_ = nullptr;
+      size_ = 0;
+      capacity_ = 0;
+    }
+  }
+
+public:
+  LIBC_INLINE constexpr vector() = default;
+
+  LIBC_INLINE ~vector() { deallocate(); }
+
+  // Move constructor
+  LIBC_INLINE vector(vector &&other) noexcept
+      : data_(other.data_), size_(other.size_), capacity_(other.capacity_) {
+    other.data_ = nullptr;
+    other.size_ = 0;
+    other.capacity_ = 0;
+  }
+
+  // Move assignment
+  LIBC_INLINE vector &operator=(vector &&other) noexcept {
+    if (this != &other) {
+      deallocate();
+      data_ = other.data_;
+      size_ = other.size_;
+      capacity_ = other.capacity_;
+      other.data_ = nullptr;
+      other.size_ = 0;
+      other.capacity_ = 0;
+    }
+    return *this;
+  }
+
+  // Copy operations are deleted to prevent accidental implicit allocations.
+  vector(const vector &) = delete;
+  vector &operator=(const vector &) = delete;
+
+  // Element access
+  LIBC_INLINE reference operator[](size_t i) {
+    LIBC_ASSERT(i < size_);
+    return data_[i];
+  }
+
+  LIBC_INLINE const_reference operator[](size_t i) const {
+    LIBC_ASSERT(i < size_);
+    return data_[i];
+  }
+
+  LIBC_INLINE pointer data() { return data_; }
+  LIBC_INLINE const_pointer data() const { return data_; }
+
+  LIBC_INLINE reference front() {
+    LIBC_ASSERT(size_ > 0);
+    return data_[0];
+  }
+
+  LIBC_INLINE const_reference front() const {
+    LIBC_ASSERT(size_ > 0);
+    return data_[0];
+  }
+
+  LIBC_INLINE reference back() {
+    LIBC_ASSERT(size_ > 0);
+    return data_[size_ - 1];
+  }
+
+  LIBC_INLINE const_reference back() const {
+    LIBC_ASSERT(size_ > 0);
+    return data_[size_ - 1];
+  }
+
+  // Iterators
+  LIBC_INLINE iterator begin() { return data_; }
+  LIBC_INLINE const_iterator begin() const { return data_; }
+  LIBC_INLINE const_iterator cbegin() const { return data_; }
+  LIBC_INLINE iterator end() { return data_ + size_; }
+  LIBC_INLINE const_iterator end() const { return data_ + size_; }
+  LIBC_INLINE const_iterator cend() const { return data_ + size_; }
+
+  // Capacity
+  [[nodiscard]] LIBC_INLINE bool empty() const { return size_ == 0; }
+  LIBC_INLINE size_t size() const { return size_; }
+  LIBC_INLINE size_t capacity() const { return capacity_; }
+
+  // Reserves at least new_cap elements. Returns true on success, false on OOM.
+  [[nodiscard]] LIBC_INLINE bool reserve(size_t new_cap) {
+    if (new_cap <= capacity_)
+      return true;
+    if (new_cap > max_size())
+      return false;
+
+    if constexpr (is_trivially_copyable_v<T>) {
+      void *new_data = ::realloc(data_, new_cap * sizeof(T));
+      if (!new_data)
+        return false;
+      data_ = static_cast<T *>(new_data);
+      capacity_ = new_cap;
+      return true;
+    } else {
+      void *new_raw = ::realloc(nullptr, new_cap * sizeof(T));
----------------
kaladron wrote:

Sorry, thinko from trying to combine some code earlier.  Fixing.

https://github.com/llvm/llvm-project/pull/222972


More information about the libc-commits mailing list