117cfc57dSNikolas Klauser //===----------------------------------------------------------------------===//
217cfc57dSNikolas Klauser //
317cfc57dSNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
417cfc57dSNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
517cfc57dSNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
617cfc57dSNikolas Klauser //
717cfc57dSNikolas Klauser //===----------------------------------------------------------------------===//
817cfc57dSNikolas Klauser 
917cfc57dSNikolas Klauser // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10*fd4cc870SLouis Dionne 
11*fd4cc870SLouis Dionne // Throwing bad_optional_access is supported starting in macosx10.13
12*fd4cc870SLouis Dionne // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions
13*fd4cc870SLouis Dionne 
1417cfc57dSNikolas Klauser // <optional>
1517cfc57dSNikolas Klauser 
1617cfc57dSNikolas Klauser // template<class F> constexpr auto transform(F&&) &;
1717cfc57dSNikolas Klauser // template<class F> constexpr auto transform(F&&) &&;
1817cfc57dSNikolas Klauser // template<class F> constexpr auto transform(F&&) const&;
1917cfc57dSNikolas Klauser // template<class F> constexpr auto transform(F&&) const&&;
2017cfc57dSNikolas Klauser 
2117cfc57dSNikolas Klauser #include "test_macros.h"
2217cfc57dSNikolas Klauser #include <cassert>
2317cfc57dSNikolas Klauser #include <optional>
2417cfc57dSNikolas Klauser #include <type_traits>
2517cfc57dSNikolas Klauser 
2617cfc57dSNikolas Klauser struct LVal {
operator ()LVal2717cfc57dSNikolas Klauser   constexpr int operator()(int&) { return 1; }
2817cfc57dSNikolas Klauser   int operator()(const int&) = delete;
2917cfc57dSNikolas Klauser   int operator()(int&&) = delete;
3017cfc57dSNikolas Klauser   int operator()(const int&&) = delete;
3117cfc57dSNikolas Klauser };
3217cfc57dSNikolas Klauser 
3317cfc57dSNikolas Klauser struct CLVal {
3417cfc57dSNikolas Klauser   int operator()(int&) = delete;
operator ()CLVal3517cfc57dSNikolas Klauser   constexpr int operator()(const int&) { return 1; }
3617cfc57dSNikolas Klauser   int operator()(int&&) = delete;
3717cfc57dSNikolas Klauser   int operator()(const int&&) = delete;
3817cfc57dSNikolas Klauser };
3917cfc57dSNikolas Klauser 
4017cfc57dSNikolas Klauser struct RVal {
4117cfc57dSNikolas Klauser   int operator()(int&) = delete;
4217cfc57dSNikolas Klauser   int operator()(const int&) = delete;
operator ()RVal4317cfc57dSNikolas Klauser   constexpr int operator()(int&&) { return 1; }
4417cfc57dSNikolas Klauser   int operator()(const int&&) = delete;
4517cfc57dSNikolas Klauser };
4617cfc57dSNikolas Klauser 
4717cfc57dSNikolas Klauser struct CRVal {
4817cfc57dSNikolas Klauser   int operator()(int&) = delete;
4917cfc57dSNikolas Klauser   int operator()(const int&) = delete;
5017cfc57dSNikolas Klauser   int operator()(int&&) = delete;
operator ()CRVal5117cfc57dSNikolas Klauser   constexpr int operator()(const int&&) { return 1; }
5217cfc57dSNikolas Klauser };
5317cfc57dSNikolas Klauser 
5417cfc57dSNikolas Klauser struct RefQual {
operator ()RefQual5517cfc57dSNikolas Klauser   constexpr int operator()(int) & { return 1; }
5617cfc57dSNikolas Klauser   int operator()(int) const& = delete;
5717cfc57dSNikolas Klauser   int operator()(int) && = delete;
5817cfc57dSNikolas Klauser   int operator()(int) const&& = delete;
5917cfc57dSNikolas Klauser };
6017cfc57dSNikolas Klauser 
6117cfc57dSNikolas Klauser struct CRefQual {
6217cfc57dSNikolas Klauser   int operator()(int) & = delete;
operator ()CRefQual6317cfc57dSNikolas Klauser   constexpr int operator()(int) const& { return 1; }
6417cfc57dSNikolas Klauser   int operator()(int) && = delete;
6517cfc57dSNikolas Klauser   int operator()(int) const&& = delete;
6617cfc57dSNikolas Klauser };
6717cfc57dSNikolas Klauser 
6817cfc57dSNikolas Klauser struct RVRefQual {
6917cfc57dSNikolas Klauser   int operator()(int) & = delete;
7017cfc57dSNikolas Klauser   int operator()(int) const& = delete;
operator ()RVRefQual7117cfc57dSNikolas Klauser   constexpr int operator()(int) && { return 1; }
7217cfc57dSNikolas Klauser   int operator()(int) const&& = delete;
7317cfc57dSNikolas Klauser };
7417cfc57dSNikolas Klauser 
7517cfc57dSNikolas Klauser struct RVCRefQual {
7617cfc57dSNikolas Klauser   int operator()(int) & = delete;
7717cfc57dSNikolas Klauser   int operator()(int) const& = delete;
7817cfc57dSNikolas Klauser   int operator()(int) && = delete;
operator ()RVCRefQual7917cfc57dSNikolas Klauser   constexpr int operator()(int) const&& { return 1; }
8017cfc57dSNikolas Klauser };
8117cfc57dSNikolas Klauser 
8217cfc57dSNikolas Klauser struct NoCopy {
8317cfc57dSNikolas Klauser   NoCopy() = default;
NoCopyNoCopy8417cfc57dSNikolas Klauser   NoCopy(const NoCopy&) { assert(false); }
operator ()NoCopy8517cfc57dSNikolas Klauser   int operator()(const NoCopy&&) { return 1; }
8617cfc57dSNikolas Klauser };
8717cfc57dSNikolas Klauser 
8817cfc57dSNikolas Klauser struct NoMove {
8917cfc57dSNikolas Klauser   NoMove() = default;
9017cfc57dSNikolas Klauser   NoMove(NoMove&&) = delete;
operator ()NoMove9117cfc57dSNikolas Klauser   NoMove operator()(const NoCopy&&) { return NoMove{}; }
9217cfc57dSNikolas Klauser };
9317cfc57dSNikolas Klauser 
test_val_types()9417cfc57dSNikolas Klauser constexpr void test_val_types() {
9517cfc57dSNikolas Klauser   // Test & overload
9617cfc57dSNikolas Klauser   {
9717cfc57dSNikolas Klauser     // Without & qualifier on F's operator()
9817cfc57dSNikolas Klauser     {
9917cfc57dSNikolas Klauser       std::optional<int> i{0};
10017cfc57dSNikolas Klauser       assert(i.transform(LVal{}) == 1);
10117cfc57dSNikolas Klauser       ASSERT_SAME_TYPE(decltype(i.transform(LVal{})), std::optional<int>);
10217cfc57dSNikolas Klauser     }
10317cfc57dSNikolas Klauser 
10417cfc57dSNikolas Klauser     //With & qualifier on F's operator()
10517cfc57dSNikolas Klauser     {
10617cfc57dSNikolas Klauser       std::optional<int> i{0};
10717cfc57dSNikolas Klauser       RefQual l{};
10817cfc57dSNikolas Klauser       assert(i.transform(l) == 1);
10917cfc57dSNikolas Klauser       ASSERT_SAME_TYPE(decltype(i.transform(l)), std::optional<int>);
11017cfc57dSNikolas Klauser     }
11117cfc57dSNikolas Klauser   }
11217cfc57dSNikolas Klauser 
11317cfc57dSNikolas Klauser   // Test const& overload
11417cfc57dSNikolas Klauser   {
11517cfc57dSNikolas Klauser     // Without & qualifier on F's operator()
11617cfc57dSNikolas Klauser     {
11717cfc57dSNikolas Klauser       const std::optional<int> i{0};
11817cfc57dSNikolas Klauser       assert(i.transform(CLVal{}) == 1);
11917cfc57dSNikolas Klauser       ASSERT_SAME_TYPE(decltype(i.transform(CLVal{})), std::optional<int>);
12017cfc57dSNikolas Klauser     }
12117cfc57dSNikolas Klauser 
12217cfc57dSNikolas Klauser     //With & qualifier on F's operator()
12317cfc57dSNikolas Klauser     {
12417cfc57dSNikolas Klauser       const std::optional<int> i{0};
12517cfc57dSNikolas Klauser       const CRefQual l{};
12617cfc57dSNikolas Klauser       assert(i.transform(l) == 1);
12717cfc57dSNikolas Klauser       ASSERT_SAME_TYPE(decltype(i.transform(l)), std::optional<int>);
12817cfc57dSNikolas Klauser     }
12917cfc57dSNikolas Klauser   }
13017cfc57dSNikolas Klauser 
13117cfc57dSNikolas Klauser   // Test && overload
13217cfc57dSNikolas Klauser   {
13317cfc57dSNikolas Klauser     // Without & qualifier on F's operator()
13417cfc57dSNikolas Klauser     {
13517cfc57dSNikolas Klauser       std::optional<int> i{0};
13617cfc57dSNikolas Klauser       assert(std::move(i).transform(RVal{}) == 1);
13717cfc57dSNikolas Klauser       ASSERT_SAME_TYPE(decltype(std::move(i).transform(RVal{})), std::optional<int>);
13817cfc57dSNikolas Klauser     }
13917cfc57dSNikolas Klauser 
14017cfc57dSNikolas Klauser     //With & qualifier on F's operator()
14117cfc57dSNikolas Klauser     {
14217cfc57dSNikolas Klauser       std::optional<int> i{0};
14317cfc57dSNikolas Klauser       assert(i.transform(RVRefQual{}) == 1);
14417cfc57dSNikolas Klauser       ASSERT_SAME_TYPE(decltype(i.transform(RVRefQual{})), std::optional<int>);
14517cfc57dSNikolas Klauser     }
14617cfc57dSNikolas Klauser   }
14717cfc57dSNikolas Klauser 
14817cfc57dSNikolas Klauser   // Test const&& overload
14917cfc57dSNikolas Klauser   {
15017cfc57dSNikolas Klauser     // Without & qualifier on F's operator()
15117cfc57dSNikolas Klauser     {
15217cfc57dSNikolas Klauser       const std::optional<int> i{0};
15317cfc57dSNikolas Klauser       assert(std::move(i).transform(CRVal{}) == 1);
15417cfc57dSNikolas Klauser       ASSERT_SAME_TYPE(decltype(std::move(i).transform(CRVal{})), std::optional<int>);
15517cfc57dSNikolas Klauser     }
15617cfc57dSNikolas Klauser 
15717cfc57dSNikolas Klauser     //With & qualifier on F's operator()
15817cfc57dSNikolas Klauser     {
15917cfc57dSNikolas Klauser       const std::optional<int> i{0};
16017cfc57dSNikolas Klauser       const RVCRefQual l{};
16117cfc57dSNikolas Klauser       assert(i.transform(std::move(l)) == 1);
16217cfc57dSNikolas Klauser       ASSERT_SAME_TYPE(decltype(i.transform(std::move(l))), std::optional<int>);
16317cfc57dSNikolas Klauser     }
16417cfc57dSNikolas Klauser   }
16517cfc57dSNikolas Klauser }
16617cfc57dSNikolas Klauser 
16717cfc57dSNikolas Klauser struct NonConst {
non_constNonConst16817cfc57dSNikolas Klauser   int non_const() { return 1; }
16917cfc57dSNikolas Klauser };
17017cfc57dSNikolas Klauser 
17117cfc57dSNikolas Klauser // check that the lambda body is not instantiated during overload resolution
test_sfinae()17217cfc57dSNikolas Klauser constexpr void test_sfinae() {
17317cfc57dSNikolas Klauser   std::optional<NonConst> opt{};
17417cfc57dSNikolas Klauser   auto l = [](auto&& x) { return x.non_const(); };
17517cfc57dSNikolas Klauser   opt.transform(l);
17617cfc57dSNikolas Klauser   std::move(opt).transform(l);
17717cfc57dSNikolas Klauser }
17817cfc57dSNikolas Klauser 
test()17917cfc57dSNikolas Klauser constexpr bool test() {
18017cfc57dSNikolas Klauser   test_sfinae();
18117cfc57dSNikolas Klauser   test_val_types();
18217cfc57dSNikolas Klauser   std::optional<int> opt;
18317cfc57dSNikolas Klauser   const auto& copt = opt;
18417cfc57dSNikolas Klauser 
18517cfc57dSNikolas Klauser   const auto never_called = [](int) {
18617cfc57dSNikolas Klauser     assert(false);
18717cfc57dSNikolas Klauser     return 0;
18817cfc57dSNikolas Klauser   };
18917cfc57dSNikolas Klauser 
19017cfc57dSNikolas Klauser   opt.transform(never_called);
19117cfc57dSNikolas Klauser   std::move(opt).transform(never_called);
19217cfc57dSNikolas Klauser   copt.transform(never_called);
19317cfc57dSNikolas Klauser   std::move(copt).transform(never_called);
19417cfc57dSNikolas Klauser 
19517cfc57dSNikolas Klauser   std::optional<NoCopy> nc;
19617cfc57dSNikolas Klauser   const auto& cnc = nc;
19717cfc57dSNikolas Klauser   std::move(nc).transform(NoCopy{});
19817cfc57dSNikolas Klauser   std::move(cnc).transform(NoCopy{});
19917cfc57dSNikolas Klauser 
20017cfc57dSNikolas Klauser   std::move(nc).transform(NoMove{});
20117cfc57dSNikolas Klauser   std::move(cnc).transform(NoMove{});
20217cfc57dSNikolas Klauser 
20317cfc57dSNikolas Klauser   return true;
20417cfc57dSNikolas Klauser }
20517cfc57dSNikolas Klauser 
main(int,char **)20617cfc57dSNikolas Klauser int main(int, char**) {
20717cfc57dSNikolas Klauser   test();
20817cfc57dSNikolas Klauser   static_assert(test());
209c31cf74cSLouis Dionne   return 0;
21017cfc57dSNikolas Klauser }
211