summaryrefslogtreecommitdiff
path: root/graphics/asymptote/LspCpp/LibLsp/JsonRpc/traits.h
blob: ce8905a84057fe7365ea3fb15a1ffaae26a37bab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once


#include <tuple>
#include <type_traits>

namespace lsp {
namespace traits {

// NthTypeOf returns the `N`th type in `Types`
template <int N, typename... Types>
using NthTypeOf = typename std::tuple_element<N, std::tuple<Types...>>::type;

// `IsTypeOrDerived<BASE, T>::value` is true iff `T` is of type `BASE`, or
// derives from `BASE`.
template <typename BASE, typename T>
using IsTypeOrDerived = std::integral_constant<
    bool,
    std::is_base_of<BASE, typename std::decay<T>::type>::value ||
        std::is_same<BASE, typename std::decay<T>::type>::value>;

// `EachIsTypeOrDerived<N, BASES, TYPES>::value` is true iff all of the types in
// the std::tuple `TYPES` is of, or derives from the corresponding indexed type
// in the std::tuple `BASES`.
// `N` must be equal to the number of types in both the std::tuple `BASES` and
// `TYPES`.
template <int N, typename BASES, typename TYPES>
struct EachIsTypeOrDerived {
  using base = typename std::tuple_element<N - 1, BASES>::type;
  using type = typename std::tuple_element<N - 1, TYPES>::type;
  using last_matches = IsTypeOrDerived<base, type>;
  using others_match = EachIsTypeOrDerived<N - 1, BASES, TYPES>;
  static constexpr bool value = last_matches::value && others_match::value;
};

// EachIsTypeOrDerived specialization for N = 1
template <typename BASES, typename TYPES>
struct EachIsTypeOrDerived<1, BASES, TYPES> {
  using base = typename std::tuple_element<0, BASES>::type;
  using type = typename std::tuple_element<0, TYPES>::type;
  static constexpr bool value = IsTypeOrDerived<base, type>::value;
};

// EachIsTypeOrDerived specialization for N = 0
template <typename BASES, typename TYPES>
struct EachIsTypeOrDerived<0, BASES, TYPES> {
  static constexpr bool value = true;
};

// Signature describes the signature of a function.
template <typename RETURN, typename... PARAMETERS>
struct Signature {
  // The return type of the function signature
  using ret = RETURN;
  // The parameters of the function signature held in a std::tuple
  using parameters = std::tuple<PARAMETERS...>;
  // The type of the Nth parameter of function signature
  template <std::size_t N>
  using parameter = NthTypeOf<N, PARAMETERS...>;
  // The total number of parameters
  static constexpr std::size_t parameter_count = sizeof...(PARAMETERS);
};

// SignatureOf is a traits helper that infers the signature of the function,
// method, static method, lambda, or function-like object `F`.
template <typename F>
struct SignatureOf {
  // The signature of the function-like object `F`
  using type = typename SignatureOf<decltype(&F::operator())>::type;
};

// SignatureOf specialization for a regular function or static method.
template <typename R, typename... ARGS>
struct SignatureOf<R (*)(ARGS...)> {
  // The signature of the function-like object `F`
  using type = Signature<typename std::decay<R>::type,
                         typename std::decay<ARGS>::type...>;
};

// SignatureOf specialization for a non-static method.
template <typename R, typename C, typename... ARGS>
struct SignatureOf<R (C::*)(ARGS...)> {
  // The signature of the function-like object `F`
  using type = Signature<typename std::decay<R>::type,
                         typename std::decay<ARGS>::type...>;
};

// SignatureOf specialization for a non-static, const method.
template <typename R, typename C, typename... ARGS>
struct SignatureOf<R (C::*)(ARGS...) const> {
  // The signature of the function-like object `F`
  using type = Signature<typename std::decay<R>::type,
                         typename std::decay<ARGS>::type...>;
};

// SignatureOfT is an alias to `typename SignatureOf<F>::type`.
template <typename F>
using SignatureOfT = typename SignatureOf<F>::type;

// ParameterType is an alias to `typename SignatureOf<F>::type::parameter<N>`.
template <typename F, std::size_t N>
using ParameterType = typename SignatureOfT<F>::template parameter<N>;

// `HasSignature<F, S>::value` is true iff the function-like `F` has a matching
// signature to the function-like `S`.
template <typename F, typename S>
using HasSignature = std::integral_constant<
    bool,
    std::is_same<SignatureOfT<F>, SignatureOfT<S>>::value>;

// `Min<A, B>::value` resolves to the smaller value of A and B.
template <std::size_t A, std::size_t B>
using Min = std::integral_constant<std::size_t, (A < B ? A : B)>;

// `CompatibleWith<F, S>::value` is true iff the function-like `F`
// can be called with the argument types of the function-like `S`. Return type
// of the two functions are not considered.
template <typename F, typename S>
using CompatibleWith = std::integral_constant<
    bool,
    (SignatureOfT<S>::parameter_count == SignatureOfT<F>::parameter_count) &&
        EachIsTypeOrDerived<Min<SignatureOfT<S>::parameter_count,
                                SignatureOfT<F>::parameter_count>::value,
                            typename SignatureOfT<S>::parameters,
                            typename SignatureOfT<F>::parameters>::value>;

// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
// invalid type.
template <bool CONDITION, typename T = void>
using EnableIf = typename std::enable_if<CONDITION, T>::type;

// If `BASE` is a base of `T` then EnableIfIsType resolves to type `TRUE`,
// otherwise an invalid type.
template <typename BASE, typename T, typename TRUE_ = void>
using EnableIfIsType = EnableIf<IsTypeOrDerived<BASE, T>::value, TRUE_>;

// If the function-like `F` has a matching signature to the function-like `S`
// then EnableIfHasSignature resolves to type `TRUE`, otherwise an invalid type.
template <typename F, typename S, typename TRUE_ = void>
using EnableIfHasSignature = EnableIf<HasSignature<F, S>::value, TRUE_>;

}  // namespace traits
}  // namespace lsp