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 #include <cstddef>
17 
18 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19 #  pragma GCC system_header
20 #endif
21 
22 _LIBCPP_BEGIN_NAMESPACE_STD
23 
24 template <class _Tp>
25 struct __numeric_type
26 {
27    static void __test(...);
28    static float __test(float);
29    static double __test(char);
30    static double __test(int);
31    static double __test(unsigned);
32    static double __test(long);
33    static double __test(unsigned long);
34    static double __test(long long);
35    static double __test(unsigned long long);
36    static double __test(double);
37    static long double __test(long double);
38 
39    typedef decltype(__test(declval<_Tp>())) type;
40    static const bool value = _IsNotSame<type, void>::value;
41 };
42 
43 template <>
44 struct __numeric_type<void>
45 {
46    static const bool value = true;
47 };
48 
49 template <class _A1, class _A2 = void, class _A3 = void,
50           bool = __numeric_type<_A1>::value &&
51                  __numeric_type<_A2>::value &&
52                  __numeric_type<_A3>::value>
53 class __promote_imp
54 {
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 {
62 private:
63     typedef typename __promote_imp<_A1>::type __type1;
64     typedef typename __promote_imp<_A2>::type __type2;
65     typedef typename __promote_imp<_A3>::type __type3;
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 {
74 private:
75     typedef typename __promote_imp<_A1>::type __type1;
76     typedef typename __promote_imp<_A2>::type __type2;
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 {
85 public:
86     typedef typename __numeric_type<_A1>::type type;
87     static const bool value = true;
88 };
89 
90 template <class _A1, class _A2 = void, class _A3 = void>
91 class __promote : public __promote_imp<_A1, _A2, _A3> {};
92 
93 _LIBCPP_END_NAMESPACE_STD
94 
95 #endif // _LIBCPP___TYPE_TRAITS_PROMOTE_H
96