forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			228 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===//
 | 
						|
//
 | 
						|
// 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 "llvm/ADT/FunctionExtras.h"
 | 
						|
#include "gtest/gtest.h"
 | 
						|
 | 
						|
#include <memory>
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
TEST(UniqueFunctionTest, Basic) {
 | 
						|
  unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
 | 
						|
  EXPECT_EQ(Sum(1, 2), 3);
 | 
						|
 | 
						|
  unique_function<int(int, int)> Sum2 = std::move(Sum);
 | 
						|
  EXPECT_EQ(Sum2(1, 2), 3);
 | 
						|
 | 
						|
  unique_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
 | 
						|
  Sum2 = std::move(Sum3);
 | 
						|
  EXPECT_EQ(Sum2(1, 2), 3);
 | 
						|
 | 
						|
  Sum2 = unique_function<int(int, int)>([](int A, int B) { return A + B; });
 | 
						|
  EXPECT_EQ(Sum2(1, 2), 3);
 | 
						|
 | 
						|
  // Explicit self-move test.
 | 
						|
  *&Sum2 = std::move(Sum2);
 | 
						|
  EXPECT_EQ(Sum2(1, 2), 3);
 | 
						|
 | 
						|
  Sum2 = unique_function<int(int, int)>();
 | 
						|
  EXPECT_FALSE(Sum2);
 | 
						|
 | 
						|
  // Make sure we can forward through l-value reference parameters.
 | 
						|
  unique_function<void(int &)> Inc = [](int &X) { ++X; };
 | 
						|
  int X = 42;
 | 
						|
  Inc(X);
 | 
						|
  EXPECT_EQ(X, 43);
 | 
						|
 | 
						|
  // Make sure we can forward through r-value reference parameters with
 | 
						|
  // move-only types.
 | 
						|
  unique_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
 | 
						|
      [](std::unique_ptr<int> &&Ptr) {
 | 
						|
        int V = *Ptr;
 | 
						|
        Ptr.reset();
 | 
						|
        return V;
 | 
						|
      };
 | 
						|
  std::unique_ptr<int> Ptr{new int(13)};
 | 
						|
  EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr)), 13);
 | 
						|
  EXPECT_FALSE((bool)Ptr);
 | 
						|
 | 
						|
  // Make sure we can pass a move-only temporary as opposed to a local variable.
 | 
						|
  EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42);
 | 
						|
 | 
						|
  // Make sure we can pass a move-only type by-value.
 | 
						|
  unique_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
 | 
						|
      [](std::unique_ptr<int> Ptr) {
 | 
						|
        int V = *Ptr;
 | 
						|
        Ptr.reset();
 | 
						|
        return V;
 | 
						|
      };
 | 
						|
  Ptr.reset(new int(13));
 | 
						|
  EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr)), 13);
 | 
						|
  EXPECT_FALSE((bool)Ptr);
 | 
						|
 | 
						|
  EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42);
 | 
						|
}
 | 
						|
 | 
						|
TEST(UniqueFunctionTest, Captures) {
 | 
						|
  long A = 1, B = 2, C = 3, D = 4, E = 5;
 | 
						|
 | 
						|
  unique_function<long()> Tmp;
 | 
						|
 | 
						|
  unique_function<long()> C1 = [A]() { return A; };
 | 
						|
  EXPECT_EQ(C1(), 1);
 | 
						|
  Tmp = std::move(C1);
 | 
						|
  EXPECT_EQ(Tmp(), 1);
 | 
						|
 | 
						|
  unique_function<long()> C2 = [A, B]() { return A + B; };
 | 
						|
  EXPECT_EQ(C2(), 3);
 | 
						|
  Tmp = std::move(C2);
 | 
						|
  EXPECT_EQ(Tmp(), 3);
 | 
						|
 | 
						|
  unique_function<long()> C3 = [A, B, C]() { return A + B + C; };
 | 
						|
  EXPECT_EQ(C3(), 6);
 | 
						|
  Tmp = std::move(C3);
 | 
						|
  EXPECT_EQ(Tmp(), 6);
 | 
						|
 | 
						|
  unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
 | 
						|
  EXPECT_EQ(C4(), 10);
 | 
						|
  Tmp = std::move(C4);
 | 
						|
  EXPECT_EQ(Tmp(), 10);
 | 
						|
 | 
						|
  unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; };
 | 
						|
  EXPECT_EQ(C5(), 15);
 | 
						|
  Tmp = std::move(C5);
 | 
						|
  EXPECT_EQ(Tmp(), 15);
 | 
						|
}
 | 
						|
 | 
						|
TEST(UniqueFunctionTest, MoveOnly) {
 | 
						|
  struct SmallCallable {
 | 
						|
    std::unique_ptr<int> A{new int(1)};
 | 
						|
 | 
						|
    int operator()(int B) { return *A + B; }
 | 
						|
  };
 | 
						|
  unique_function<int(int)> Small = SmallCallable();
 | 
						|
  EXPECT_EQ(Small(2), 3);
 | 
						|
  unique_function<int(int)> Small2 = std::move(Small);
 | 
						|
  EXPECT_EQ(Small2(2), 3);
 | 
						|
 | 
						|
  struct LargeCallable {
 | 
						|
    std::unique_ptr<int> A{new int(1)};
 | 
						|
    std::unique_ptr<int> B{new int(2)};
 | 
						|
    std::unique_ptr<int> C{new int(3)};
 | 
						|
    std::unique_ptr<int> D{new int(4)};
 | 
						|
    std::unique_ptr<int> E{new int(5)};
 | 
						|
 | 
						|
    int operator()() { return *A + *B + *C + *D + *E; }
 | 
						|
  };
 | 
						|
  unique_function<int()> Large = LargeCallable();
 | 
						|
  EXPECT_EQ(Large(), 15);
 | 
						|
  unique_function<int()> Large2 = std::move(Large);
 | 
						|
  EXPECT_EQ(Large2(), 15);
 | 
						|
}
 | 
						|
 | 
						|
TEST(UniqueFunctionTest, CountForwardingCopies) {
 | 
						|
  struct CopyCounter {
 | 
						|
    int &CopyCount;
 | 
						|
 | 
						|
    CopyCounter(int &CopyCount) : CopyCount(CopyCount) {}
 | 
						|
    CopyCounter(const CopyCounter &Arg) : CopyCount(Arg.CopyCount) {
 | 
						|
      ++CopyCount;
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
 | 
						|
  int CopyCount = 0;
 | 
						|
  ByValF(CopyCounter(CopyCount));
 | 
						|
  EXPECT_EQ(1, CopyCount);
 | 
						|
 | 
						|
  CopyCount = 0;
 | 
						|
  {
 | 
						|
    CopyCounter Counter{CopyCount};
 | 
						|
    ByValF(Counter);
 | 
						|
  }
 | 
						|
  EXPECT_EQ(2, CopyCount);
 | 
						|
 | 
						|
  // Check that we don't generate a copy at all when we can bind a reference all
 | 
						|
  // the way down, even if that reference could *in theory* allow copies.
 | 
						|
  unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) {
 | 
						|
  };
 | 
						|
  CopyCount = 0;
 | 
						|
  ByRefF(CopyCounter(CopyCount));
 | 
						|
  EXPECT_EQ(0, CopyCount);
 | 
						|
 | 
						|
  CopyCount = 0;
 | 
						|
  {
 | 
						|
    CopyCounter Counter{CopyCount};
 | 
						|
    ByRefF(Counter);
 | 
						|
  }
 | 
						|
  EXPECT_EQ(0, CopyCount);
 | 
						|
 | 
						|
  // If we use a reference, we can make a stronger guarantee that *no* copy
 | 
						|
  // occurs.
 | 
						|
  struct Uncopyable {
 | 
						|
    Uncopyable() = default;
 | 
						|
    Uncopyable(const Uncopyable &) = delete;
 | 
						|
  };
 | 
						|
  unique_function<void(const Uncopyable &)> UncopyableF =
 | 
						|
      [](const Uncopyable &) {};
 | 
						|
  UncopyableF(Uncopyable());
 | 
						|
  Uncopyable X;
 | 
						|
  UncopyableF(X);
 | 
						|
}
 | 
						|
 | 
						|
TEST(UniqueFunctionTest, CountForwardingMoves) {
 | 
						|
  struct MoveCounter {
 | 
						|
    int &MoveCount;
 | 
						|
 | 
						|
    MoveCounter(int &MoveCount) : MoveCount(MoveCount) {}
 | 
						|
    MoveCounter(MoveCounter &&Arg) : MoveCount(Arg.MoveCount) { ++MoveCount; }
 | 
						|
  };
 | 
						|
 | 
						|
  unique_function<void(MoveCounter)> ByValF = [](MoveCounter) {};
 | 
						|
  int MoveCount = 0;
 | 
						|
  ByValF(MoveCounter(MoveCount));
 | 
						|
  EXPECT_EQ(1, MoveCount);
 | 
						|
 | 
						|
  MoveCount = 0;
 | 
						|
  {
 | 
						|
    MoveCounter Counter{MoveCount};
 | 
						|
    ByValF(std::move(Counter));
 | 
						|
  }
 | 
						|
  EXPECT_EQ(2, MoveCount);
 | 
						|
 | 
						|
  // Check that when we use an r-value reference we get no spurious copies.
 | 
						|
  unique_function<void(MoveCounter &&)> ByRefF = [](MoveCounter &&) {};
 | 
						|
  MoveCount = 0;
 | 
						|
  ByRefF(MoveCounter(MoveCount));
 | 
						|
  EXPECT_EQ(0, MoveCount);
 | 
						|
 | 
						|
  MoveCount = 0;
 | 
						|
  {
 | 
						|
    MoveCounter Counter{MoveCount};
 | 
						|
    ByRefF(std::move(Counter));
 | 
						|
  }
 | 
						|
  EXPECT_EQ(0, MoveCount);
 | 
						|
 | 
						|
  // If we use an r-value reference we can in fact make a stronger guarantee
 | 
						|
  // with an unmovable type.
 | 
						|
  struct Unmovable {
 | 
						|
    Unmovable() = default;
 | 
						|
    Unmovable(Unmovable &&) = delete;
 | 
						|
  };
 | 
						|
  unique_function<void(const Unmovable &)> UnmovableF = [](const Unmovable &) {
 | 
						|
  };
 | 
						|
  UnmovableF(Unmovable());
 | 
						|
  Unmovable X;
 | 
						|
  UnmovableF(X);
 | 
						|
}
 | 
						|
 | 
						|
} // anonymous namespace
 |