Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][complex] P2819R2: Add tuple protocol to complex #79744

Merged

Conversation

@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P2819R1-Adding-tuple-protocol-to-complex branch from fd81353 to 0720d95 Compare January 28, 2024 13:21
Copy link

github-actions bot commented Jan 28, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P2819R1-Adding-tuple-protocol-to-complex branch 6 times, most recently from 2836b3e to 361d25b Compare January 28, 2024 14:59
@H-G-Hristov H-G-Hristov marked this pull request as ready for review January 28, 2024 16:36
@H-G-Hristov H-G-Hristov requested a review from a team as a code owner January 28, 2024 16:36
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jan 28, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 28, 2024

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

Changes

Implements: P2819R2 <https://wg21.link/P2819R2>


Patch is 26.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/79744.diff

17 Files Affected:

  • (modified) libcxx/docs/ReleaseNotes/19.rst (+1-1)
  • (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1)
  • (modified) libcxx/include/CMakeLists.txt (+1)
  • (added) libcxx/include/__fwd/complex.h (+25)
  • (modified) libcxx/include/__fwd/get.h (+17)
  • (modified) libcxx/include/__tuple/tuple_like.h (+8)
  • (modified) libcxx/include/complex (+142)
  • (modified) libcxx/include/libcxx.imp (+1)
  • (modified) libcxx/include/module.modulemap.in (+2)
  • (modified) libcxx/modules/std/complex.inc (+7)
  • (added) libcxx/test/libcxx/utilities/tuple/__tuple_like.compile.pass.cpp (+76)
  • (added) libcxx/test/std/numerics/complex.number/complex.tuple/get.pass.cpp (+87)
  • (added) libcxx/test/std/numerics/complex.number/complex.tuple/get.verify.cpp (+60)
  • (added) libcxx/test/std/numerics/complex.number/complex.tuple/tuple_element.compile.pass.cpp (+43)
  • (added) libcxx/test/std/numerics/complex.number/complex.tuple/tuple_element.verify.cpp (+31)
  • (added) libcxx/test/std/numerics/complex.number/complex.tuple/tuple_size.compile.pass.cpp (+39)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (+1-1)
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index e081bc26d08097..0b0671ae6c64d5 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -35,7 +35,7 @@ see the `releases page <https://llvm.org/releases/>`_.
 What's New in Libc++ 19.0.0?
 ==============================
 
-TODO
+P2819R2 - Add ``tuple`` protocol to ``complex``
 
 
 Implemented Papers
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index f80b1f6b663f04..4fc7a23c0902a0 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -39,7 +39,7 @@
 "`P2868R3 <https://wg21.link/P2868R3>`__","LWG","Remove Deprecated ``std::allocator`` Typedef From C++26","Kona November 2023","|Complete|","18.0",""
 "`P2870R3 <https://wg21.link/P2870R3>`__","LWG","Remove ``basic_string::reserve()`` From C++26","Kona November 2023","|Complete|","18.0",""
 "`P2871R3 <https://wg21.link/P2871R3>`__","LWG","Remove Deprecated Unicode Conversion Facets from C++26","Kona November 2023","|Complete|","18.0",""
-"`P2819R2 <https://wg21.link/P2819R2>`__","LWG","Add tuple protocol to complex","Kona November 2023","","",""
+"`P2819R2 <https://wg21.link/P2819R2>`__","LWG","Add tuple protocol to complex","Kona November 2023","|Complete|","19.0",""
 "`P2937R0 <https://wg21.link/P2937R0>`__","LWG","Freestanding: Remove ``strtok``","Kona November 2023","","",""
 "`P2833R2 <https://wg21.link/P2833R2>`__","LWG","Freestanding Library: inout expected span","Kona November 2023","","",""
 "`P2836R1 <https://wg21.link/P2836R1>`__","LWG","``std::basic_const_iterator`` should follow its underlying type's convertibility","Kona November 2023","","","|DR|"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index ed721d467e94f4..05332a3507d07a 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -426,6 +426,7 @@ set(files
   __functional/weak_result_type.h
   __fwd/array.h
   __fwd/bit_reference.h
+  __fwd/complex.h
   __fwd/fstream.h
   __fwd/get.h
   __fwd/hash.h
diff --git a/libcxx/include/__fwd/complex.h b/libcxx/include/__fwd/complex.h
new file mode 100644
index 00000000000000..1c7be5a5ff7502
--- /dev/null
+++ b/libcxx/include/__fwd/complex.h
@@ -0,0 +1,25 @@
+//===---------------------------------------------------------------------===//
+//
+// 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
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FWD_COMPLEX_H
+#define _LIBCPP___FWD_COMPLEX_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp>
+class _LIBCPP_TEMPLATE_VIS complex;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FWD_COMPLEX_H
diff --git a/libcxx/include/__fwd/get.h b/libcxx/include/__fwd/get.h
index e7261b826953d7..dfd2b5ae8d2bbd 100644
--- a/libcxx/include/__fwd/get.h
+++ b/libcxx/include/__fwd/get.h
@@ -12,6 +12,7 @@
 #include <__concepts/copyable.h>
 #include <__config>
 #include <__fwd/array.h>
+#include <__fwd/complex.h>
 #include <__fwd/pair.h>
 #include <__fwd/subrange.h>
 #include <__fwd/tuple.h>
@@ -76,6 +77,22 @@ template <size_t _Ip, class _Tp, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp&& get(const array<_Tp, _Size>&&) _NOEXCEPT;
 #endif
 
+#if _LIBCPP_STD_VER >= 26
+
+template <size_t _Ip, class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp& get(complex<_Tp>&) noexcept;
+
+template <size_t _Ip, class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& get(complex<_Tp>&&) noexcept;
+
+template <size_t _Ip, class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& get(const complex<_Tp>&) noexcept;
+
+template <size_t _Ip, class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& get(const complex<_Tp>&&) noexcept;
+
+#endif // _LIBCPP_STD_VER >= 26
+
 #if _LIBCPP_STD_VER >= 20
 
 namespace ranges {
diff --git a/libcxx/include/__tuple/tuple_like.h b/libcxx/include/__tuple/tuple_like.h
index dab395be616b7d..0a619e7c998666 100644
--- a/libcxx/include/__tuple/tuple_like.h
+++ b/libcxx/include/__tuple/tuple_like.h
@@ -11,6 +11,7 @@
 
 #include <__config>
 #include <__fwd/array.h>
+#include <__fwd/complex.h>
 #include <__fwd/pair.h>
 #include <__fwd/subrange.h>
 #include <__fwd/tuple.h>
@@ -41,6 +42,13 @@ struct __tuple_like_impl<array<_Tp, _Size> > : true_type {};
 template <class _Ip, class _Sp, ranges::subrange_kind _Kp>
 struct __tuple_like_impl<ranges::subrange<_Ip, _Sp, _Kp> > : true_type {};
 
+#  if _LIBCPP_STD_VER >= 26
+
+template <class _Tp>
+struct __tuple_like_impl<complex<_Tp>> : true_type {};
+
+#  endif
+
 template <class _Tp>
 concept __tuple_like = __tuple_like_impl<remove_cvref_t<_Tp>>::value;
 
diff --git a/libcxx/include/complex b/libcxx/include/complex
index 02b9db8c516db4..a77d18b1f052c6 100644
--- a/libcxx/include/complex
+++ b/libcxx/include/complex
@@ -227,6 +227,31 @@ template<class T> complex<T> sqrt (const complex<T>&);
 template<class T> complex<T> tan (const complex<T>&);
 template<class T> complex<T> tanh (const complex<T>&);
 
+  // [complex.tuple], tuple interface
+  template<class T> struct tuple_size;                             // Since C++26
+  template<size_t I, class T> struct tuple_element;                // Since C++26
+  template<class T> struct tuple_size<complex<T>>;                 // Since C++26
+  template<size_t I, class T> struct tuple_element<I, complex<T>>; // Since C++26
+  template<size_t I, class T>
+    constexpr T& get(complex<T>&) noexcept;                        // Since C++26
+  template<size_t I, class T>
+    constexpr T&& get(complex<T>&&) noexcept;                      // Since C++26
+  template<size_t I, class T>
+    constexpr const T& get(const complex<T>&) noexcept;            // Since C++26
+  template<size_t I, class T>
+    constexpr const T&& get(const complex<T>&&) noexcept;          // Since C++26
+
+  // [complex.literals], complex literals
+  inline namespace literals {
+  inline namespace complex_literals {
+    constexpr complex<long double> operator""il(long double);        // Since C++14
+    constexpr complex<long double> operator""il(unsigned long long); // Since C++14
+    constexpr complex<double> operator""i(long double);              // Since C++14
+    constexpr complex<double> operator""i(unsigned long long);       // Since C++14
+    constexpr complex<float> operator""if(long double);              // Since C++14
+    constexpr complex<float> operator""if(unsigned long long);       // Since C++14
+  }
+  }
 }  // std
 
 */
@@ -331,6 +356,20 @@ public:
     *this = *this / complex(__c.real(), __c.imag());
     return *this;
   }
+
+#if _LIBCPP_STD_VER >= 26
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr _Xp& get(complex<_Xp>&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr _Xp&& get(complex<_Xp>&&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr const _Xp& get(const complex<_Xp>&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr const _Xp&& get(const complex<_Xp>&&) noexcept;
+#endif
 };
 
 template <>
@@ -408,6 +447,20 @@ public:
     *this = *this / complex(__c.real(), __c.imag());
     return *this;
   }
+
+#if _LIBCPP_STD_VER >= 26
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr _Xp& get(complex<_Xp>&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr _Xp&& get(complex<_Xp>&&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr const _Xp& get(const complex<_Xp>&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr const _Xp&& get(const complex<_Xp>&&) noexcept;
+#endif
 };
 
 template <>
@@ -480,6 +533,20 @@ public:
     *this = *this / complex(__c.real(), __c.imag());
     return *this;
   }
+
+#if _LIBCPP_STD_VER >= 26
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr _Xp& get(complex<_Xp>&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr _Xp&& get(complex<_Xp>&&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr const _Xp& get(const complex<_Xp>&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr const _Xp&& get(const complex<_Xp>&&) noexcept;
+#endif
 };
 
 template <>
@@ -553,6 +620,20 @@ public:
     *this = *this / complex(__c.real(), __c.imag());
     return *this;
   }
+
+#if _LIBCPP_STD_VER >= 26
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr _Xp& get(complex<_Xp>&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr _Xp&& get(complex<_Xp>&&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr const _Xp& get(const complex<_Xp>&) noexcept;
+
+  template <size_t _Ip, class _Xp>
+  friend _LIBCPP_HIDE_FROM_ABI constexpr const _Xp&& get(const complex<_Xp>&&) noexcept;
+#endif
 };
 
 inline _LIBCPP_CONSTEXPR complex<float>::complex(const complex<double>& __c) : __re_(__c.real()), __im_(__c.imag()) {}
@@ -1352,6 +1433,67 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x) {
 }
 #endif // !_LIBCPP_HAS_NO_LOCALIZATION
 
+#if _LIBCPP_STD_VER >= 26
+
+// [complex.tuple], tuple interface
+
+template <class _Tp>
+struct tuple_size;
+
+template <class _Tp>
+struct tuple_size<complex<_Tp>> : integral_constant<size_t, 2> {};
+
+template <size_t _Ip, class _Tp>
+struct tuple_element;
+
+template <size_t _Ip, class _Tp>
+struct tuple_element<_Ip, complex<_Tp>> {
+  static_assert(_Ip < 2, "Index value is out of range.");
+  using type = _Tp;
+};
+
+template <size_t _Ip, class _Xp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Xp& get(complex<_Xp>& __z) noexcept {
+  static_assert(_Ip < 2, "Index value is out of range.");
+  if constexpr (_Ip == 0) {
+    return static_cast<_Xp&>(__z.__re_);
+  } else {
+    return static_cast<_Xp&>(__z.__im_);
+  }
+}
+
+template <size_t _Ip, class _Xp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Xp&& get(complex<_Xp>&& __z) noexcept {
+  static_assert(_Ip < 2, "Index value is out of range.");
+  if constexpr (_Ip == 0) {
+    return static_cast<_Xp&&>(__z.__re_);
+  } else {
+    return static_cast<_Xp&&>(__z.__im_);
+  }
+}
+
+template <size_t _Ip, class _Xp>
+_LIBCPP_HIDE_FROM_ABI constexpr const _Xp& get(const complex<_Xp>& __z) noexcept {
+  static_assert(_Ip < 2, "Index value is out of range.");
+  if constexpr (_Ip == 0) {
+    return static_cast<const _Xp&>(__z.__re_);
+  } else {
+    return static_cast<const _Xp&>(__z.__im_);
+  }
+}
+
+template <size_t _Ip, class _Xp>
+_LIBCPP_HIDE_FROM_ABI constexpr const _Xp&& get(const complex<_Xp>&& __z) noexcept {
+  static_assert(_Ip < 2, "Index value is out of range.");
+  if constexpr (_Ip == 0) {
+    return static_cast<const _Xp&&>(__z.__re_);
+  } else {
+    return static_cast<const _Xp&&>(__z.__im_);
+  }
+}
+
+#endif // _LIBCPP_STD_VER >= 26
+
 #if _LIBCPP_STD_VER >= 14
 // Literal suffix for complex number literals [complex.literals]
 inline namespace literals {
diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp
index 45fa4a9541917f..4a6ca1c330280f 100644
--- a/libcxx/include/libcxx.imp
+++ b/libcxx/include/libcxx.imp
@@ -421,6 +421,7 @@
   { include: [ "<__fwd/array.h>", "private", "<array>", "public" ] },
   { include: [ "<__fwd/bit_reference.h>", "private", "<bitset>", "public" ] },
   { include: [ "<__fwd/bit_reference.h>", "private", "<vector>", "public" ] },
+  { include: [ "<__fwd/complex.h>", "private", "<complex>", "public" ] },
   { include: [ "<__fwd/fstream.h>", "private", "<fstream>", "public" ] },
   { include: [ "<__fwd/hash.h>", "private", "<functional>", "public" ] },
   { include: [ "<__fwd/ios.h>", "private", "<ios>", "public" ] },
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 194a74a1e07b14..a5aae481cff54e 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1197,6 +1197,8 @@ module std_private_compare_synth_three_way                [system] { header "__c
 module std_private_compare_three_way_comparable           [system] { header "__compare/three_way_comparable.h" }
 module std_private_compare_weak_order                     [system] { header "__compare/weak_order.h" }
 
+module std_private_complex_complex_fwd [system] { header "__fwd/complex.h" }
+
 module std_private_concepts_arithmetic            [system] { header "__concepts/arithmetic.h" }
 module std_private_concepts_assignable            [system] { header "__concepts/assignable.h" }
 module std_private_concepts_boolean_testable      [system] { header "__concepts/boolean_testable.h" }
diff --git a/libcxx/modules/std/complex.inc b/libcxx/modules/std/complex.inc
index 3ccf44fa022443..47a44420b127a9 100644
--- a/libcxx/modules/std/complex.inc
+++ b/libcxx/modules/std/complex.inc
@@ -59,6 +59,13 @@ export namespace std {
   using std::tan;
   using std::tanh;
 
+#if _LIBCPP_STD_VER >= 26
+  // [complex.tuple], tuple interface
+  using std::get;
+  using std::tuple_element;
+  using std::tuple_size;
+#endif
+
   // [complex.literals], complex literals
   inline namespace literals {
     inline namespace complex_literals {
diff --git a/libcxx/test/libcxx/utilities/tuple/__tuple_like.compile.pass.cpp b/libcxx/test/libcxx/utilities/tuple/__tuple_like.compile.pass.cpp
new file mode 100644
index 00000000000000..9f04f2cc04304b
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/tuple/__tuple_like.compile.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <tuple>
+
+#include <array>
+#include <complex>
+#include <ranges>
+#include <tuple>
+
+#include "test_iterators.h"
+
+static_assert(!std::__tuple_like<int>);
+
+static_assert(std::__tuple_like<std::array<int, 0>>);
+static_assert(std::__tuple_like<std::array<int, 1>>);
+static_assert(std::__tuple_like<std::array<int, 2>>);
+static_assert(std::__tuple_like<std::array<int, 2728>>);
+
+#if _LIBCPP_STD_VER >= 26
+static_assert(std::__tuple_like<std::complex<float>>);
+static_assert(std::__tuple_like<std::complex<double>>);
+static_assert(std::__tuple_like<std::complex<long double>>);
+#endif
+
+static_assert(std::__tuple_like<std::pair<int, float>>);
+
+static_assert(std::__tuple_like<std::tuple<int>>);
+static_assert(std::__tuple_like<std::tuple<int, float>>);
+static_assert(std::__tuple_like<std::tuple<int, float, double>>);
+
+using FI = forward_iterator<int*>;
+static_assert(std::__tuple_like<std::ranges::subrange<FI, FI, std::ranges::subrange_kind::sized>>);
+static_assert(std::__tuple_like<std::ranges::subrange<FI, FI, std::ranges::subrange_kind::unsized>>);
+static_assert(std::__tuple_like<std::ranges::subrange<int*, int*, std::ranges::subrange_kind::sized>>);
+static_assert(std::__tuple_like<std::ranges::subrange<int*, std::nullptr_t, std::ranges::subrange_kind::unsized>>);
+
+template <typename Iter>
+void test_subrange_sized() {
+  static_assert(std::__tuple_like<std::ranges::subrange<Iter, Iter, std::ranges::subrange_kind::sized>>);
+}
+
+template <typename Iter>
+void test_subrange_unsized() {
+  static_assert(std::__tuple_like<std::ranges::subrange<Iter, Iter, std::ranges::subrange_kind::unsized>>);
+}
+
+void test() {
+  test_subrange_sized<forward_iterator<int*>>();
+  test_subrange_sized<bidirectional_iterator<int*>>();
+  test_subrange_sized<random_access_iterator<int*>>();
+  test_subrange_sized<contiguous_iterator<int*>>();
+  test_subrange_sized<int*>();
+
+  test_subrange_sized<forward_iterator<int const*>>();
+  test_subrange_sized<bidirectional_iterator<int const*>>();
+  test_subrange_sized<random_access_iterator<int const*>>();
+  test_subrange_sized<contiguous_iterator<int const*>>();
+  test_subrange_sized<int const*>();
+
+  test_subrange_unsized<forward_iterator<int*>>();
+  test_subrange_unsized<bidirectional_iterator<int*>>();
+  static_assert(std::__tuple_like<std::ranges::subrange<int*, std::nullptr_t, std::ranges::subrange_kind::unsized>>);
+
+  test_subrange_unsized<forward_iterator<int const*>>();
+  test_subrange_unsized<bidirectional_iterator<int const*>>();
+  static_assert(
+      std::__tuple_like<std::ranges::subrange<const int*, std::nullptr_t, std::ranges::subrange_kind::unsized>>);
+}
diff --git a/libcxx/test/std/numerics/complex.number/complex.tuple/get.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.tuple/get.pass.cpp
new file mode 100644
index 00000000000000..0ada5c71777a72
--- /dev/null
+++ b/libcxx/test/std/numerics/complex.number/complex.tuple/get.pass.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <complex>
+
+//   template<size_t I, class T>
+//     constexpr T& get(complex<T>&) noexcept;
+//   template<size_t I, class T>
+//     constexpr T&& get(complex<T>&&) noexcept;
+//   template<size_t I, class T>
+//     constexpr const T& get(const complex<T>&) noexcept;
+//   template<size_t I, class T>
+//     constexpr const T&& get(const complex<T>&&) noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <complex>
+#include <utility>
+
+template <typename T>
+constexpr void test() {
+  // &
+  {
+    std::complex<T> c{T{27}, T{28}};
+
+    std::same_as<T&> decltype(auto) r = get<0>(c);
+    static_assert(noexcept(get<0>(c)));
+    assert(r == T{27});
+    std::same_as<T&> decltype(auto) i = get<1>(c);
+    static_assert(noexcept(get<1>(c)));
+    assert(i == T{28});
+  }
+  //  &&
+  {
+    std::complex<T> c{T{27}, T{28}};
+
+    std::same_as<T&&> decltype(auto) r = get<0>(std::move(c));
+    static_assert(noexcept(get<0>(c)));
+    assert(r == T{27});
+    std::same_as<T&&> decltype(auto) i = get<1>(std::move(c));
+    assert(i == T{28});
+  }
+  // const &
+  {
+    const std::complex<T> c{T{27}, T{28}};
+
+    std::same_as<const T&> decltype(auto) r = get<0>(c);
+    static_assert(noexcept(get<0>(c)));
+    assert(r == T{27});
+    std::same_as<const T&> decltype(auto) i = get<1>(c);
+    static_assert(noexcept(get<1>(c)));
+    assert(i == T{28});
+  }
+  //  const &&
+  {
+    const std::complex<T> c{T{27}, T{28}};
+
+    std::same_as<const T&&> decltype(auto) r = get<0>(std::move(c));
+    static_assert(noexcept(get<0>(c)));
+    assert(r == T{27});
+    std::same_as<const T&&> decltype(auto) i = get<1>(std::move(c));
+    static_assert(noexcept(get<1>(c)));
+    assert(i == T{28});
+  }
+}
+
+constexpr bool test() {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/numerics/complex.number/complex.tuple/get.verify.cpp b/libcxx/test/std/numerics/complex.number/complex.tuple/get.verify.cpp
new file mode 100644
index 00000000000000..6a6e3a968d50f7
--- /dev/null
+++ b/libcxx/test/std/numerics/complex.number/complex.tuple/get.verify.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <co...
[truncated]

@H-G-Hristov H-G-Hristov changed the title [libc++][complex] P2819R2 - Add tuple protocol to complex [libc++][complex] P2819R2: Add tuple protocol to complex Jan 30, 2024
@mordante mordante self-assigned this Feb 12, 2024
Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. It looks quite good, but I have some comments.

libcxx/include/complex Outdated Show resolved Hide resolved
libcxx/include/complex Outdated Show resolved Hide resolved
libcxx/include/complex Show resolved Hide resolved
Comment on lines 18 to 24
#include <__config>
#include <__fwd/array.h>
#include <__fwd/complex.h>
#include <__fwd/pair.h>
#include <__fwd/subrange.h>
#include <__fwd/tuple.h>
#include <__iterator/concepts.h>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to commit these changes in a separate commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense. I'll add

#include <__fwd/array.h>
#include <__fwd/pair.h>
#include <__fwd/subrange.h>
#include <__fwd/tuple.h>

in another patch.

Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general happy. I'd like to have a quick look after addressing the last comments.

Comment on lines 18 to 24
#include <__config>
#include <__fwd/array.h>
#include <__fwd/complex.h>
#include <__fwd/pair.h>
#include <__fwd/subrange.h>
#include <__fwd/tuple.h>
#include <__iterator/concepts.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to commit these changes in a separate commit?

libcxx/include/module.modulemap.in Outdated Show resolved Hide resolved
Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM!
FYI I had a look at the failing CI job and it does not seem related to your changes. I just restarted the failed job.

@Zingam Zingam merged commit 2ea5d16 into llvm:main Feb 19, 2024
55 checks passed
@H-G-Hristov H-G-Hristov deleted the hgh/libcxx/P2819R1-Adding-tuple-protocol-to-complex branch March 11, 2024 06:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants