text: //===- unittests/ADT/BumpPtrListTest.cpp - BumpPtrList unit tests ---------===//
  //
  //                     The LLVM Compiler Infrastructure
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  
  #include "llvm/ADT/AllocatorList.h"
  #include "llvm/ADT/STLExtras.h"
  #include "gtest/gtest.h"
  
  using namespace llvm;
  
  namespace {
  
  struct CountsDestructors {
    static unsigned NumCalls;
    ~CountsDestructors() { ++NumCalls; }
  };
  unsigned CountsDestructors::NumCalls = 0;
  
  struct MoveOnly {
    int V;
    explicit MoveOnly(int V) : V(V) {}
    MoveOnly() = delete;
    MoveOnly(MoveOnly &&X) { V = X.V; }
    MoveOnly(const MoveOnly &X) = delete;
    MoveOnly &operator=(MoveOnly &&X) = delete;
    MoveOnly &operator=(const MoveOnly &X) = delete;
  };
  
  struct EmplaceOnly {
    int V1, V2;
    explicit EmplaceOnly(int V1, int V2) : V1(V1), V2(V2) {}
    EmplaceOnly() = delete;
    EmplaceOnly(EmplaceOnly &&X) = delete;
    EmplaceOnly(const EmplaceOnly &X) = delete;
    EmplaceOnly &operator=(EmplaceOnly &&X) = delete;
    EmplaceOnly &operator=(const EmplaceOnly &X) = delete;
  };
  
  TEST(BumpPtrListTest, DefaultConstructor) {
    BumpPtrList<int> L;
    EXPECT_TRUE(L.empty());
  }
  
  TEST(BumpPtrListTest, pushPopBack) {
    // Build a list with push_back.
    BumpPtrList<int> L;
    int Ns[] = {1, 3, 9, 5, 7};
    for (const int N : Ns)
      L.push_back(N);
  
    // Use iterators to check contents.
    auto I = L.begin();
    for (int N : Ns)
      EXPECT_EQ(N, *I++);
    EXPECT_EQ(I, L.end());
  
    // Unbuild the list with pop_back.
    for (int N : llvm::reverse(Ns)) {
      EXPECT_EQ(N, L.back());
      L.pop_back();
    }
    EXPECT_TRUE(L.empty());
  }
  
  TEST(BumpPtrListTest, pushPopFront) {
    // Build a list with push_front.
    BumpPtrList<int> L;
    int Ns[] = {1, 3, 9, 5, 7};
    for (const int N : Ns)
      L.push_front(N);
  
    // Use reverse iterators to check contents.
    auto I = L.rbegin();
    for (int N : Ns)
      EXPECT_EQ(N, *I++);
    EXPECT_EQ(I, L.rend());
  
    // Unbuild the list with pop_front.
    for (int N : llvm::reverse(Ns)) {
      EXPECT_EQ(N, L.front());
      L.pop_front();
    }
    EXPECT_TRUE(L.empty());
  }
  
  TEST(BumpPtrListTest, pushBackMoveOnly) {
    BumpPtrList<MoveOnly> L;
    int Ns[] = {1, 3, 9, 5, 7};
    for (const int N : Ns) {
      L.push_back(MoveOnly(N));
      EXPECT_EQ(N, L.back().V);
    }
    // Instantiate with MoveOnly.
    while (!L.empty())
      L.pop_back();
  }
  
  TEST(BumpPtrListTest, pushFrontMoveOnly) {
    BumpPtrList<MoveOnly> L;
    int Ns[] = {1, 3, 9, 5, 7};
    for (const int N : Ns) {
      L.push_front(MoveOnly(N));
      EXPECT_EQ(N, L.front().V);
    }
    // Instantiate with MoveOnly.
    while (!L.empty())
      L.pop_front();
  }
  
  TEST(BumpPtrListTest, emplaceBack) {
    BumpPtrList<EmplaceOnly> L;
    int N1s[] = {1, 3, 9, 5, 7};
    int N2s[] = {7, 3, 1, 8, 2};
    for (int I = 0; I != 5; ++I) {
      L.emplace_back(N1s[I], N2s[I]);
      EXPECT_EQ(N1s[I], L.back().V1);
      EXPECT_EQ(N2s[I], L.back().V2);
    }
    // Instantiate with EmplaceOnly.
    while (!L.empty())
      L.pop_back();
  }
  
  TEST(BumpPtrListTest, emplaceFront) {
    BumpPtrList<EmplaceOnly> L;
    int N1s[] = {1, 3, 9, 5, 7};
    int N2s[] = {7, 3, 1, 8, 2};
    for (int I = 0; I != 5; ++I) {
      L.emplace_front(N1s[I], N2s[I]);
      EXPECT_EQ(N1s[I], L.front().V1);
      EXPECT_EQ(N2s[I], L.front().V2);
    }
    // Instantiate with EmplaceOnly.
    while (!L.empty())
      L.pop_front();
  }
  
  TEST(BumpPtrListTest, swap) {
    // Build two lists with different lifetimes and swap them.
    int N1s[] = {1, 3, 5, 7, 9};
    int N2s[] = {2, 4, 6, 8, 10};
  
    BumpPtrList<int> L1;
    L1.insert(L1.end(), std::begin(N1s), std::end(N1s));
    {
      BumpPtrList<int> L2;
      L2.insert(L2.end(), std::begin(N2s), std::end(N2s));
  
      // Swap the lists.
      L1.swap(L2);
  
      // Check L2's contents before it goes out of scope.
      auto I = L2.begin();
      for (int N : N1s)
        EXPECT_EQ(N, *I++);
      EXPECT_EQ(I, L2.end());
    }
  
    // Check L1's contents now that L2 is out of scope (with its allocation
    // blocks).
    auto I = L1.begin();
    for (int N : N2s)
      EXPECT_EQ(N, *I++);
    EXPECT_EQ(I, L1.end());
  }
  
  TEST(BumpPtrListTest, clear) {
    CountsDestructors::NumCalls = 0;
    CountsDestructors N;
    BumpPtrList<CountsDestructors> L;
    L.push_back(N);
    L.push_back(N);
    L.push_back(N);
    EXPECT_EQ(3u, L.size());
    EXPECT_EQ(0u, CountsDestructors::NumCalls);
    L.pop_back();
    EXPECT_EQ(1u, CountsDestructors::NumCalls);
    L.clear();
    EXPECT_EQ(3u, CountsDestructors::NumCalls);
  }
  
  TEST(BumpPtrListTest, move) {
    BumpPtrList<int> L1, L2;
    L1.push_back(1);
    L2.push_back(2);
    L1 = std::move(L2);
    EXPECT_EQ(1u, L1.size());
    EXPECT_EQ(2, L1.front());
    EXPECT_EQ(0u, L2.size());
  }
  
  TEST(BumpPtrListTest, moveCallsDestructors) {
    CountsDestructors::NumCalls = 0;
    BumpPtrList<CountsDestructors> L1, L2;
    L1.emplace_back();
    EXPECT_EQ(0u, CountsDestructors::NumCalls);
    L1 = std::move(L2);
    EXPECT_EQ(1u, CountsDestructors::NumCalls);
  }
  
  TEST(BumpPtrListTest, copy) {
    BumpPtrList<int> L1, L2;
    L1.push_back(1);
    L2.push_back(2);
    L1 = L2;
    EXPECT_EQ(1u, L1.size());
    EXPECT_EQ(2, L1.front());
    EXPECT_EQ(1u, L2.size());
    EXPECT_EQ(2, L2.front());
  }
  
  TEST(BumpPtrListTest, copyCallsDestructors) {
    CountsDestructors::NumCalls = 0;
    BumpPtrList<CountsDestructors> L1, L2;
    L1.emplace_back();
    EXPECT_EQ(0u, CountsDestructors::NumCalls);
    L1 = L2;
    EXPECT_EQ(1u, CountsDestructors::NumCalls);
  }
  
  TEST(BumpPtrListTest, resetAlloc) {
    // Resetting an empty list should work.
    BumpPtrList<int> L;
  
    // Resetting an empty list that has allocated should also work.
    L.resetAlloc();
    L.push_back(5);
    L.erase(L.begin());
    L.resetAlloc();
  
    // Resetting a non-empty list should crash.
    L.push_back(5);
  #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
    EXPECT_DEATH(L.resetAlloc(), "Cannot reset allocator if not empty");
  #endif
  }
  
  } // end namespace
  