1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef _LIBCPP___TYPE_TRAITS_PROMOTE_H
10 #define _LIBCPP___TYPE_TRAITS_PROMOTE_H
11 
12 #include <__config>
13 #include <__type_traits/integral_constant.h>
14 #include <__type_traits/is_same.h>
15 #include <__utility/declval.h>
16 
17 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
18 #  pragma GCC system_header
19 #endif
20 
21 _LIBCPP_BEGIN_NAMESPACE_STD
22 
23 template <class _Tp>
24 struct __numeric_type {
25   static void __test(...);
26   static float __test(float);
27   static double __test(char);
28   static double __test(int);
29   static double __test(unsigned);
30   static double __test(long);
31   static double __test(unsigned long);
32   static double __test(long long);
33   static double __test(unsigned long long);
34 #ifndef _LIBCPP_HAS_NO_INT128
35   static double __test(__int128_t);
36   static double __test(__uint128_t);
37 #endif
38   static double __test(double);
39   static long double __test(long double);
40 
41   typedef decltype(__test(std::declval<_Tp>())) type;
42   static const bool value = _IsNotSame<type, void>::value;
43 };
44 
45 template <>
46 struct __numeric_type<void> {
47   static const bool value = true;
48 };
49 
50 template <class _A1,
51           class _A2 = void,
52           class _A3 = void,
53           bool      = __numeric_type<_A1>::value&& __numeric_type<_A2>::value&& __numeric_type<_A3>::value>
54 class __promote_imp {
55 public:
56   static const bool value = false;
57 };
58 
59 template <class _A1, class _A2, class _A3>
60 class __promote_imp<_A1, _A2, _A3, true> {
61 private:
62   typedef typename __promote_imp<_A1>::type __type1;
63   typedef typename __promote_imp<_A2>::type __type2;
64   typedef typename __promote_imp<_A3>::type __type3;
65 
66 public:
67   typedef decltype(__type1() + __type2() + __type3()) type;
68   static const bool value = true;
69 };
70 
71 template <class _A1, class _A2>
72 class __promote_imp<_A1, _A2, void, true> {
73 private:
74   typedef typename __promote_imp<_A1>::type __type1;
75   typedef typename __promote_imp<_A2>::type __type2;
76 
77 public:
78   typedef decltype(__type1() + __type2()) type;
79   static const bool value = true;
80 };
81 
82 template <class _A1>
83 class __promote_imp<_A1, void, void, true> {
84 public:
85   typedef typename __numeric_type<_A1>::type type;
86   static const bool value = true;
87 };
88 
89 template <class _A1, class _A2 = void, class _A3 = void>
90 class __promote : public __promote_imp<_A1, _A2, _A3> {};
91 
92 _LIBCPP_END_NAMESPACE_STD
93 
94 #endif // _LIBCPP___TYPE_TRAITS_PROMOTE_H
95