[clang] Introduce paged vector (PR #66430)

Vassil Vassilev via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 29 02:30:21 PDT 2023


================
@@ -0,0 +1,342 @@
+//===- llvm/unittest/ADT/PagedVectorTest.cpp ------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// PagedVector unit tests.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/PagedVector.h"
+#include "gtest/gtest.h"
+#include <iterator>
+
+namespace llvm {
+TEST(PagedVectorTest, EmptyTest) {
+  PagedVector<int, 10> V;
+  EXPECT_EQ(V.empty(), true);
+  EXPECT_EQ(V.size(), 0ULL);
+  EXPECT_EQ(V.capacity(), 0ULL);
+  EXPECT_EQ(V.materialized_begin().getIndex(), 0ULL);
+  EXPECT_EQ(V.materialized_end().getIndex(), 0ULL);
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 0LL);
+
+  EXPECT_DEATH(V[0], "Index < Size");
+  EXPECT_DEATH(PagedVector<int>(nullptr), "Allocator cannot be null");
+}
+
+TEST(PagedVectorTest, ExpandTest) {
+  PagedVector<int, 10> V;
+  V.resize(2);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 2ULL);
+  EXPECT_EQ(V.capacity(), 10ULL);
+  EXPECT_EQ(V.materialized_begin().getIndex(), 2ULL);
+  EXPECT_EQ(V.materialized_end().getIndex(), 2ULL);
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 0LL);
+}
+
+TEST(PagedVectorTest, FullPageFillingTest) {
+  PagedVector<int, 10> V;
+  V.resize(10);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 10ULL);
+  EXPECT_EQ(V.capacity(), 10ULL);
+  for (int I = 0; I < 10; ++I) {
+    V[I] = I;
+  }
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 10ULL);
+  EXPECT_EQ(V.capacity(), 10ULL);
+  EXPECT_EQ(V.materialized_begin().getIndex(), 0ULL);
+  EXPECT_EQ(V.materialized_end().getIndex(), 10ULL);
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 10LL);
+  for (int I = 0; I < 10; ++I) {
+    EXPECT_EQ(V[I], I);
+  }
+}
+
+TEST(PagedVectorTest, HalfPageFillingTest) {
+  PagedVector<int, 10> V;
+  V.resize(5);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 5ULL);
+  EXPECT_EQ(V.capacity(), 10ULL);
+  for (int I = 0; I < 5; ++I) {
+    V[I] = I;
+  }
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 5LL);
+  for (int I = 0; I < 5; ++I) {
+    EXPECT_EQ(V[I], I);
+  }
+  for (int I = 5; I < 10; ++I) {
+    EXPECT_DEATH(V[I], "Index < Size");
+  }
+}
+
+TEST(PagedVectorTest, FillFullMultiPageTest) {
+  PagedVector<int, 10> V;
+  V.resize(20);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 20ULL);
+  EXPECT_EQ(V.capacity(), 20ULL);
+  for (int I = 0; I < 20; ++I) {
+    V[I] = I;
+  }
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 20LL);
+  for (auto MI = V.materialized_begin(), ME = V.materialized_end(); MI != ME;
+       ++MI) {
+    EXPECT_EQ(*MI, std::distance(V.materialized_begin(), MI));
+  }
+}
+
+TEST(PagedVectorTest, FillHalfMultiPageTest) {
+  PagedVector<int, 10> V;
+  V.resize(20);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 20ULL);
+  EXPECT_EQ(V.capacity(), 20ULL);
+  for (int I = 0; I < 5; ++I) {
+    V[I] = I;
+  }
+  for (int I = 10; I < 15; ++I) {
+    V[I] = I;
+  }
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 20LL);
+  for (int I = 0; I < 5; ++I) {
+    EXPECT_EQ(V[I], I);
+  }
+  for (int I = 10; I < 15; ++I) {
+    EXPECT_EQ(V[I], I);
+  }
+}
+
+TEST(PagedVectorTest, FillLastMultiPageTest) {
+  PagedVector<int, 10> V;
+  V.resize(20);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 20ULL);
+  EXPECT_EQ(V.capacity(), 20ULL);
+  for (int I = 10; I < 15; ++I) {
+    V[I] = I;
+  }
+  for (int I = 10; I < 15; ++I) {
+    EXPECT_EQ(V[I], I);
+  }
+
+  // Since we fill the last page only, the materialized vector
+  // should contain only the last page.
+  int J = 10;
+  for (auto MI = V.materialized_begin(), ME = V.materialized_end(); MI != ME;
+       ++MI) {
+    if (J < 15) {
+      EXPECT_EQ(*MI, J);
+    } else {
+      EXPECT_EQ(*MI, 0);
+    }
+    ++J;
+  }
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 10LL);
+}
+
+// Filling the first element of all the pages
+// will allocate all of them
+TEST(PagedVectorTest, FillSparseMultiPageTest) {
+  PagedVector<int, 10> V;
+  V.resize(100);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 100ULL);
+  EXPECT_EQ(V.capacity(), 100ULL);
+  for (int I = 0; I < 10; ++I) {
+    V[I * 10] = I;
+  }
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 100LL);
+  for (int I = 0; I < 100; ++I) {
+    if (I % 10 == 0) {
+      EXPECT_EQ(V[I], I / 10);
+    } else {
+      EXPECT_EQ(V[I], 0);
+    }
+  }
+}
+
+struct TestHelper {
+  int A = -1;
+};
+
+// Use this to count how many times the constructor / destructor are called
+struct TestHelper2 {
+  int A = -1;
+  static int constructed;
+  static int destroyed;
+
+  TestHelper2() { constructed++; }
+  ~TestHelper2() { destroyed++; }
+};
+
+int TestHelper2::constructed = 0;
+int TestHelper2::destroyed = 0;
+
+TEST(PagedVectorTest, FillNonTrivialConstructor) {
+  PagedVector<TestHelper, 10> V;
+  V.resize(10);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 10ULL);
+  EXPECT_EQ(V.capacity(), 10ULL);
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 0LL);
+  for (int I = 0; I < 10; ++I) {
+    EXPECT_EQ(V[I].A, -1);
+  }
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 10LL);
+}
+
+// Elements are constructed, destructed in pages, so we expect
+// the number of constructed / destructed elements to be a multiple of the
+// page size and the constructor is invoked when the page is actually accessed
+// the first time.
+TEST(PagedVectorTest, FillNonTrivialConstructorDestructor) {
+  PagedVector<TestHelper2, 10> V;
+  V.resize(19);
+  EXPECT_EQ(TestHelper2::constructed, 0);
+  EXPECT_EQ(V.empty(), false);
+  EXPECT_EQ(V.size(), 19ULL);
+  EXPECT_EQ(V.capacity(), 20ULL);
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 0LL);
+  EXPECT_EQ(V[0].A, -1);
+  EXPECT_EQ(TestHelper2::constructed, 10);
+
+  for (int I = 0; I < 10; ++I) {
+    EXPECT_EQ(V[I].A, -1);
+    EXPECT_EQ(TestHelper2::constructed, 10);
+  }
+  for (int I = 10; I < 11; ++I) {
+    EXPECT_EQ(V[I].A, -1);
+    EXPECT_EQ(TestHelper2::constructed, 20);
+  }
+  for (int I = 0; I < 19; ++I) {
+    EXPECT_EQ(V[I].A, -1);
+    EXPECT_EQ(TestHelper2::constructed, 20);
+  }
+  EXPECT_EQ(std::distance(V.materialized_begin(), V.materialized_end()), 19LL);
+  // We initialise the whole page, not just the materialized part
----------------
vgvassilev wrote:

```suggestion
  // We initialize the whole page, not just the materialized part
```

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


More information about the cfe-commits mailing list