xref: /llvm-project/libcxx/test/support/variant_test_helpers.h (revision dfde6e89ecc10b1f1eebdb0e409ef1a084030a6c)
1cc89063bSNico Weber // -*- C++ -*-
2cc89063bSNico Weber //===----------------------------------------------------------------------===//
3cc89063bSNico Weber //
4cc89063bSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5cc89063bSNico Weber // See https://llvm.org/LICENSE.txt for license information.
6cc89063bSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7cc89063bSNico Weber //
8cc89063bSNico Weber //===----------------------------------------------------------------------===//
9*480cd780SLouis Dionne 
10cc89063bSNico Weber #ifndef SUPPORT_VARIANT_TEST_HELPERS_H
11cc89063bSNico Weber #define SUPPORT_VARIANT_TEST_HELPERS_H
12cc89063bSNico Weber 
13cc89063bSNico Weber #include <type_traits>
14cc89063bSNico Weber #include <utility>
15cc89063bSNico Weber #include <cassert>
16cc89063bSNico Weber 
17cc89063bSNico Weber #include "test_macros.h"
1851faba35SRuslan Arutyunyan #include "type_id.h"
19cc89063bSNico Weber 
20cc89063bSNico Weber #if TEST_STD_VER <= 14
21cc89063bSNico Weber #error This file requires C++17
22cc89063bSNico Weber #endif
23cc89063bSNico Weber 
24cc89063bSNico Weber #ifndef TEST_HAS_NO_EXCEPTIONS
25cc89063bSNico Weber struct CopyThrows {
26cc89063bSNico Weber   CopyThrows() = default;
CopyThrowsCopyThrows27cc89063bSNico Weber   CopyThrows(CopyThrows const&) { throw 42; }
28cc89063bSNico Weber   CopyThrows& operator=(CopyThrows const&) { throw 42; }
29cc89063bSNico Weber };
30cc89063bSNico Weber 
31cc89063bSNico Weber struct MoveThrows {
32cc89063bSNico Weber   static int alive;
MoveThrowsMoveThrows33cc89063bSNico Weber   MoveThrows() { ++alive; }
MoveThrowsMoveThrows34cc89063bSNico Weber   MoveThrows(MoveThrows const&) {++alive;}
MoveThrowsMoveThrows35cc89063bSNico Weber   MoveThrows(MoveThrows&&) {  throw 42; }
36cc89063bSNico Weber   MoveThrows& operator=(MoveThrows const&) { return *this; }
37cc89063bSNico Weber   MoveThrows& operator=(MoveThrows&&) { throw 42; }
~MoveThrowsMoveThrows38cc89063bSNico Weber   ~MoveThrows() { --alive; }
39cc89063bSNico Weber };
40cc89063bSNico Weber 
41cc89063bSNico Weber int MoveThrows::alive = 0;
42cc89063bSNico Weber 
43cc89063bSNico Weber struct MakeEmptyT {
44cc89063bSNico Weber   static int alive;
MakeEmptyTMakeEmptyT45cc89063bSNico Weber   MakeEmptyT() { ++alive; }
MakeEmptyTMakeEmptyT46cc89063bSNico Weber   MakeEmptyT(MakeEmptyT const&) {
47cc89063bSNico Weber       ++alive;
48cc89063bSNico Weber       // Don't throw from the copy constructor since variant's assignment
49cc89063bSNico Weber       // operator performs a copy before committing to the assignment.
50cc89063bSNico Weber   }
MakeEmptyTMakeEmptyT51cc89063bSNico Weber   MakeEmptyT(MakeEmptyT &&) {
52cc89063bSNico Weber       throw 42;
53cc89063bSNico Weber   }
54cc89063bSNico Weber   MakeEmptyT& operator=(MakeEmptyT const&) {
55cc89063bSNico Weber       throw 42;
56cc89063bSNico Weber   }
57cc89063bSNico Weber   MakeEmptyT& operator=(MakeEmptyT&&) {
58cc89063bSNico Weber       throw 42;
59cc89063bSNico Weber   }
~MakeEmptyTMakeEmptyT60cc89063bSNico Weber    ~MakeEmptyT() { --alive; }
61cc89063bSNico Weber };
62cc89063bSNico Weber static_assert(std::is_swappable_v<MakeEmptyT>, ""); // required for test
63cc89063bSNico Weber 
64cc89063bSNico Weber int MakeEmptyT::alive = 0;
65cc89063bSNico Weber 
66cc89063bSNico Weber template <class Variant>
makeEmpty(Variant & v)67cc89063bSNico Weber void makeEmpty(Variant& v) {
68cc89063bSNico Weber     Variant v2(std::in_place_type<MakeEmptyT>);
69cc89063bSNico Weber     try {
70cc89063bSNico Weber         v = std::move(v2);
71cc89063bSNico Weber         assert(false);
72cc89063bSNico Weber     } catch (...) {
73cc89063bSNico Weber         assert(v.valueless_by_exception());
74cc89063bSNico Weber     }
75cc89063bSNico Weber }
76cc89063bSNico Weber #endif // TEST_HAS_NO_EXCEPTIONS
77cc89063bSNico Weber 
7851faba35SRuslan Arutyunyan enum CallType : unsigned {
7951faba35SRuslan Arutyunyan   CT_None,
8051faba35SRuslan Arutyunyan   CT_NonConst = 1,
8151faba35SRuslan Arutyunyan   CT_Const = 2,
8251faba35SRuslan Arutyunyan   CT_LValue = 4,
8351faba35SRuslan Arutyunyan   CT_RValue = 8
8451faba35SRuslan Arutyunyan };
8551faba35SRuslan Arutyunyan 
8651faba35SRuslan Arutyunyan inline constexpr CallType operator|(CallType LHS, CallType RHS) {
8751faba35SRuslan Arutyunyan   return static_cast<CallType>(static_cast<unsigned>(LHS) |
8851faba35SRuslan Arutyunyan                                static_cast<unsigned>(RHS));
8951faba35SRuslan Arutyunyan }
9051faba35SRuslan Arutyunyan 
9151faba35SRuslan Arutyunyan struct ForwardingCallObject {
9251faba35SRuslan Arutyunyan 
9351faba35SRuslan Arutyunyan   template <class... Args>
operatorForwardingCallObject9451faba35SRuslan Arutyunyan   ForwardingCallObject& operator()(Args&&...) & {
9551faba35SRuslan Arutyunyan     set_call<Args &&...>(CT_NonConst | CT_LValue);
9651faba35SRuslan Arutyunyan     return *this;
9751faba35SRuslan Arutyunyan   }
9851faba35SRuslan Arutyunyan 
9951faba35SRuslan Arutyunyan   template <class... Args>
operatorForwardingCallObject10051faba35SRuslan Arutyunyan   const ForwardingCallObject& operator()(Args&&...) const & {
10151faba35SRuslan Arutyunyan     set_call<Args &&...>(CT_Const | CT_LValue);
10251faba35SRuslan Arutyunyan     return *this;
10351faba35SRuslan Arutyunyan   }
10451faba35SRuslan Arutyunyan 
10551faba35SRuslan Arutyunyan   template <class... Args>
operatorForwardingCallObject10651faba35SRuslan Arutyunyan   ForwardingCallObject&& operator()(Args&&...) && {
10751faba35SRuslan Arutyunyan     set_call<Args &&...>(CT_NonConst | CT_RValue);
10851faba35SRuslan Arutyunyan     return std::move(*this);
10951faba35SRuslan Arutyunyan   }
11051faba35SRuslan Arutyunyan 
11151faba35SRuslan Arutyunyan   template <class... Args>
operatorForwardingCallObject11251faba35SRuslan Arutyunyan   const ForwardingCallObject&& operator()(Args&&...) const && {
11351faba35SRuslan Arutyunyan     set_call<Args &&...>(CT_Const | CT_RValue);
11451faba35SRuslan Arutyunyan     return std::move(*this);
11551faba35SRuslan Arutyunyan   }
11651faba35SRuslan Arutyunyan 
set_callForwardingCallObject11751faba35SRuslan Arutyunyan   template <class... Args> static void set_call(CallType type) {
11851faba35SRuslan Arutyunyan     assert(last_call_type == CT_None);
11951faba35SRuslan Arutyunyan     assert(last_call_args == nullptr);
12051faba35SRuslan Arutyunyan     last_call_type = type;
12151faba35SRuslan Arutyunyan     last_call_args = std::addressof(makeArgumentID<Args...>());
12251faba35SRuslan Arutyunyan   }
12351faba35SRuslan Arutyunyan 
check_callForwardingCallObject12451faba35SRuslan Arutyunyan   template <class... Args> static bool check_call(CallType type) {
12551faba35SRuslan Arutyunyan     bool result = last_call_type == type && last_call_args &&
12651faba35SRuslan Arutyunyan                   *last_call_args == makeArgumentID<Args...>();
12751faba35SRuslan Arutyunyan     last_call_type = CT_None;
12851faba35SRuslan Arutyunyan     last_call_args = nullptr;
12951faba35SRuslan Arutyunyan     return result;
13051faba35SRuslan Arutyunyan   }
13151faba35SRuslan Arutyunyan 
13251faba35SRuslan Arutyunyan   // To check explicit return type for visit<R>
13351faba35SRuslan Arutyunyan   constexpr operator int() const
13451faba35SRuslan Arutyunyan   {
13551faba35SRuslan Arutyunyan     return 0;
13651faba35SRuslan Arutyunyan   }
13751faba35SRuslan Arutyunyan 
13851faba35SRuslan Arutyunyan   static CallType last_call_type;
13951faba35SRuslan Arutyunyan   static const TypeID *last_call_args;
14051faba35SRuslan Arutyunyan };
14151faba35SRuslan Arutyunyan 
14251faba35SRuslan Arutyunyan CallType ForwardingCallObject::last_call_type = CT_None;
14351faba35SRuslan Arutyunyan const TypeID *ForwardingCallObject::last_call_args = nullptr;
14451faba35SRuslan Arutyunyan 
14551faba35SRuslan Arutyunyan struct ReturnFirst {
operatorReturnFirst14651faba35SRuslan Arutyunyan   template <class... Args> constexpr int operator()(int f, Args &&...) const {
14751faba35SRuslan Arutyunyan     return f;
14851faba35SRuslan Arutyunyan   }
14951faba35SRuslan Arutyunyan };
15051faba35SRuslan Arutyunyan 
15151faba35SRuslan Arutyunyan struct ReturnArity {
operatorReturnArity15251faba35SRuslan Arutyunyan   template <class... Args> constexpr int operator()(Args &&...) const {
15351faba35SRuslan Arutyunyan     return sizeof...(Args);
15451faba35SRuslan Arutyunyan   }
15551faba35SRuslan Arutyunyan };
156cc89063bSNico Weber 
157cc89063bSNico Weber #endif // SUPPORT_VARIANT_TEST_HELPERS_H
158