[libc-commits] [libc] c63a291 - [libc][cpp] reverse_iterator support (#85702)
via libc-commits
libc-commits at lists.llvm.org
Tue Mar 19 09:26:01 PDT 2024
Author: Nick Desaulniers
Date: 2024-03-19T09:25:57-07:00
New Revision: c63a291c64852a086cb447c7078e5312aac1a05c
URL: https://github.com/llvm/llvm-project/commit/c63a291c64852a086cb447c7078e5312aac1a05c
DIFF: https://github.com/llvm/llvm-project/commit/c63a291c64852a086cb447c7078e5312aac1a05c.diff
LOG: [libc][cpp] reverse_iterator support (#85702)
Towards the goal of implementing __cxa_finalize (#85651) I'd like to be able to
reverse iterate over cpp::arrays such as the one used in FixedVector.
Implement the enough iterator support to be able to iterate a cpp::array in
reverse, and add tests.
Of note, reverse iterator's begin() refers to forward iterator's end() (and
vice versa). When dereferenced (operator*), the reverse iterator returns a copy
that's been pre-decremented (the underlying forward iterator is advanced).
Added:
libc/src/__support/CPP/iterator.h
libc/test/src/__support/CPP/array_test.cpp
Modified:
libc/src/__support/CPP/array.h
libc/test/src/__support/CPP/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/src/__support/CPP/array.h b/libc/src/__support/CPP/array.h
index fb5a79225beb7d..4e69ba003e800b 100644
--- a/libc/src/__support/CPP/array.h
+++ b/libc/src/__support/CPP/array.h
@@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_ARRAY_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_ARRAY_H
+#include "src/__support/CPP/iterator.h" // reverse_iterator
#include "src/__support/macros/attributes.h"
#include <stddef.h> // For size_t.
@@ -23,6 +24,8 @@ template <class T, size_t N> struct array {
using value_type = T;
using iterator = T *;
using const_iterator = const T *;
+ using reverse_iterator = cpp::reverse_iterator<iterator>;
+ using const_reverse_iterator = cpp::reverse_iterator<const_iterator>;
LIBC_INLINE constexpr T *data() { return Data; }
LIBC_INLINE constexpr const T *data() const { return Data; }
@@ -45,9 +48,29 @@ template <class T, size_t N> struct array {
LIBC_INLINE constexpr iterator begin() { return Data; }
LIBC_INLINE constexpr const_iterator begin() const { return Data; }
+ LIBC_INLINE constexpr const_iterator cbegin() const { return begin(); }
LIBC_INLINE constexpr iterator end() { return Data + N; }
LIBC_INLINE constexpr const_iterator end() const { return Data + N; }
+ LIBC_INLINE constexpr const_iterator cend() const { return end(); }
+
+ LIBC_INLINE constexpr reverse_iterator rbegin() {
+ return reverse_iterator{end()};
+ }
+ LIBC_INLINE constexpr const_reverse_iterator rbegin() const {
+ return const_reverse_iterator{end()};
+ }
+ LIBC_INLINE constexpr const_reverse_iterator crbegin() const {
+ return rbegin();
+ }
+
+ LIBC_INLINE constexpr reverse_iterator rend() {
+ return reverse_iterator{begin()};
+ }
+ LIBC_INLINE constexpr const_reverse_iterator rend() const {
+ return const_reverse_iterator{begin()};
+ }
+ LIBC_INLINE constexpr const_reverse_iterator crend() const { return rend(); }
};
} // namespace cpp
diff --git a/libc/src/__support/CPP/iterator.h b/libc/src/__support/CPP/iterator.h
new file mode 100644
index 00000000000000..c5bfb1912c7b74
--- /dev/null
+++ b/libc/src/__support/CPP/iterator.h
@@ -0,0 +1,63 @@
+//===-- Standalone implementation of iterator -------------------*- 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_ITERATOR_H
+#define LLVM_LIBC_SRC___SUPPORT_CPP_ITERATOR_H
+
+#include "src/__support/CPP/type_traits/enable_if.h"
+#include "src/__support/CPP/type_traits/is_convertible.h"
+#include "src/__support/CPP/type_traits/is_same.h"
+#include "src/__support/macros/attributes.h"
+
+namespace LIBC_NAMESPACE {
+namespace cpp {
+
+template <typename T> struct iterator_traits;
+template <typename T> struct iterator_traits<T *> {
+ using reference = T &;
+};
+
+template <typename Iter> class reverse_iterator {
+ Iter current;
+
+public:
+ using reference = typename iterator_traits<Iter>::reference;
+
+ LIBC_INLINE reverse_iterator() : current() {}
+ LIBC_INLINE constexpr explicit reverse_iterator(Iter it) : current(it) {}
+
+ template <typename Other,
+ cpp::enable_if_t<!cpp::is_same_v<Iter, Other> &&
+ cpp::is_convertible_v<const Other &, Iter>,
+ int> = 0>
+ LIBC_INLINE constexpr explicit reverse_iterator(const Other &it)
+ : current(it) {}
+
+ LIBC_INLINE constexpr reference operator*() const {
+ Iter tmp = current;
+ return *--tmp;
+ }
+ LIBC_INLINE constexpr reverse_iterator operator--() {
+ ++current;
+ return *this;
+ }
+ LIBC_INLINE constexpr reverse_iterator &operator++() {
+ --current;
+ return *this;
+ }
+ LIBC_INLINE constexpr reverse_iterator operator++(int) {
+ reverse_iterator tmp(*this);
+ --current;
+ return tmp;
+ }
+};
+
+} // namespace cpp
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC___SUPPORT_CPP_ITERATOR_H
diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index f94429e03b3cbc..74aa0c705ec467 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -1,5 +1,15 @@
add_custom_target(libc-cpp-utils-tests)
+add_libc_test(
+ array_test
+ SUITE
+ libc-cpp-utils-tests
+ SRCS
+ array_test.cpp
+ DEPENDS
+ libc.src.__support.CPP.array
+ )
+
add_libc_test(
bit_test
SUITE
diff --git a/libc/test/src/__support/CPP/array_test.cpp b/libc/test/src/__support/CPP/array_test.cpp
new file mode 100644
index 00000000000000..f2d7bff636e42c
--- /dev/null
+++ b/libc/test/src/__support/CPP/array_test.cpp
@@ -0,0 +1,66 @@
+//===-- Unittests for Array -----------------------------------------------===//
+//
+// 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/array.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::cpp::array;
+
+TEST(LlvmLibcArrayTest, Basic) {
+ array<int, 3> a = {0, 1, 2};
+
+ ASSERT_EQ(a.data(), &a.front());
+ ASSERT_EQ(a.front(), 0);
+ ASSERT_EQ(a.back(), 2);
+ ASSERT_EQ(a.size(), size_t{3});
+ ASSERT_EQ(a[1], 1);
+ ASSERT_FALSE(a.empty());
+ ASSERT_NE(a.begin(), a.end());
+ ASSERT_EQ(*a.begin(), a.front());
+
+ auto it = a.rbegin();
+ ASSERT_EQ(*it, 2);
+ ASSERT_EQ(*(++it), 1);
+ ASSERT_EQ(*(++it), 0);
+
+ for (int &x : a)
+ ASSERT_GE(x, 0);
+}
+
+// Test const_iterator and const variant methods.
+TEST(LlvmLibcArrayTest, Const) {
+ const array<int, 3> z = {3, 4, 5};
+
+ ASSERT_EQ(3, z.front());
+ ASSERT_EQ(4, z[1]);
+ ASSERT_EQ(5, z.back());
+ ASSERT_EQ(3, *z.data());
+
+ // begin, cbegin, end, cend
+ array<int, 3>::const_iterator it2 = z.begin();
+ ASSERT_EQ(*it2, z.front());
+ it2 = z.cbegin();
+ ASSERT_EQ(*it2, z.front());
+ it2 = z.end();
+ ASSERT_NE(it2, z.begin());
+ it2 = z.cend();
+ ASSERT_NE(it2, z.begin());
+
+ // rbegin, crbegin, rend, crend
+ array<int, 3>::const_reverse_iterator it = z.rbegin();
+ ASSERT_EQ(*it, z.back());
+ it = z.crbegin();
+ ASSERT_EQ(*it, z.back());
+ it = z.rend();
+ ASSERT_EQ(*--it, z.front());
+ it = z.crend();
+ ASSERT_EQ(*--it, z.front());
+
+ for (const int &x : z)
+ ASSERT_GE(x, 0);
+}
More information about the libc-commits
mailing list