summaryrefslogtreecommitdiff
path: root/absl/types/internal/conformance_testing_helpers.h
blob: 00775f960c3682ab3a59a724d33f335395e9db63 (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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
// Copyright 2019 The Abseil Authors.
//
// 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.

#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
#define ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_

// Checks to determine whether or not we can use abi::__cxa_demangle
#if (defined(__ANDROID__) || defined(ANDROID)) && !defined(OS_ANDROID)
#define ABSL_INTERNAL_OS_ANDROID
#endif

// We support certain compilers only.  See demangle.h for details.
#if defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__))
#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0
#elif (__GNUC__ >= 4 || (__GNUC__ >= 3 && __GNUC_MINOR__ >= 4)) && \
    !defined(__mips__)
#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1
#elif defined(__clang__) && !defined(_MSC_VER)
#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1
#else
#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0
#endif

#include <tuple>
#include <type_traits>
#include <utility>

#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
#include "absl/utility/utility.h"

#if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE
#include <cxxabi.h>

#include <cstdlib>
#endif

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace types_internal {

// Return a readable name for type T.
template <class T>
absl::string_view NameOfImpl() {
// TODO(calabrese) Investigate using debugging:internal_demangle as a fallback.
#if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE
  int status = 0;
  char* demangled_name = nullptr;

  demangled_name =
      abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);

  if (status == 0 && demangled_name != nullptr) {
    return demangled_name;
  } else {
    return typeid(T).name();
  }
#else
  return typeid(T).name();
#endif
  // NOTE: We intentionally leak demangled_name so that it remains valid
  // throughout the remainder of the program.
}

// Given a type, returns as nice of a type name as we can produce (demangled).
//
// Note: This currently strips cv-qualifiers and references, but that is okay
// because we only use this internally with unqualified object types.
template <class T>
std::string NameOf() {
  static const absl::string_view result = NameOfImpl<T>();
  return std::string(result);
}

////////////////////////////////////////////////////////////////////////////////
//
// Metafunction to check if a type is callable with no explicit arguments
template <class Fun, class /*Enabler*/ = void>
struct IsNullaryCallableImpl : std::false_type {};

template <class Fun>
struct IsNullaryCallableImpl<
    Fun, absl::void_t<decltype(std::declval<const Fun&>()())>>
    : std::true_type {
  using result_type = decltype(std::declval<const Fun&>()());

  template <class ValueType>
  using for_type = std::is_same<ValueType, result_type>;

  using void_if_true = void;
};

template <class Fun>
struct IsNullaryCallable : IsNullaryCallableImpl<Fun> {};
//
////////////////////////////////////////////////////////////////////////////////

// A type that contains a function object that returns an instance of a type
// that is undergoing conformance testing. This function is required to always
// return the same value upon invocation.
template <class Fun>
struct GeneratorType;

// A type that contains a tuple of GeneratorType<Fun> where each Fun has the
// same return type. The result of each of the different generators should all
// be equal values, though the underlying object representation may differ (such
// as if one returns 0.0 and another return -0.0, or if one returns an empty
// vector and another returns an empty vector with a different capacity.
template <class... Funs>
struct EquivalenceClassType;

////////////////////////////////////////////////////////////////////////////////
//
// A metafunction to check if a type is a specialization of EquivalenceClassType
template <class T>
struct IsEquivalenceClass : std::false_type {};

template <>
struct IsEquivalenceClass<EquivalenceClassType<>> : std::true_type {
  using self = IsEquivalenceClass;

  // A metafunction to check if this EquivalenceClassType is a valid
  // EquivalenceClassType for a type `ValueType` that is undergoing testing
  template <class ValueType>
  using for_type = std::true_type;
};

template <class Head, class... Tail>
struct IsEquivalenceClass<EquivalenceClassType<Head, Tail...>>
    : std::true_type {
  using self = IsEquivalenceClass;

  // The type undergoing conformance testing that this EquivalenceClass
  // corresponds to
  using result_type = typename IsNullaryCallable<Head>::result_type;

  // A metafunction to check if this EquivalenceClassType is a valid
  // EquivalenceClassType for a type `ValueType` that is undergoing testing
  template <class ValueType>
  using for_type = std::is_same<ValueType, result_type>;
};
//
////////////////////////////////////////////////////////////////////////////////

// A type that contains an ordered series of EquivalenceClassTypes, where the
// the function object of each underlying GeneratorType has the same return type
//
// These equivalence classes are required to be in a logical ascending order
// that is consistent with comparison operators that are defined for the return
// type of each GeneratorType, if any.
template <class... EqClasses>
struct OrderedEquivalenceClasses;

////////////////////////////////////////////////////////////////////////////////
//
// A metafunction to determine the return type of the function object contained
// in a GeneratorType specialization.
template <class T>
struct ResultOfGenerator {};

template <class Fun>
struct ResultOfGenerator<GeneratorType<Fun>> {
  using type = decltype(std::declval<const Fun&>()());
};

template <class Fun>
using ResultOfGeneratorT = typename ResultOfGenerator<GeneratorType<Fun>>::type;
//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//
// A metafunction that yields true iff each of Funs is a GeneratorType
// specialization and they all contain functions with the same return type
template <class /*Enabler*/, class... Funs>
struct AreGeneratorsWithTheSameReturnTypeImpl : std::false_type {};

template <>
struct AreGeneratorsWithTheSameReturnTypeImpl<void> : std::true_type {};

template <class Head, class... Tail>
struct AreGeneratorsWithTheSameReturnTypeImpl<
    typename std::enable_if<absl::conjunction<std::is_same<
        ResultOfGeneratorT<Head>, ResultOfGeneratorT<Tail>>...>::value>::type,
    Head, Tail...> : std::true_type {};

template <class... Funs>
struct AreGeneratorsWithTheSameReturnType
    : AreGeneratorsWithTheSameReturnTypeImpl<void, Funs...>::type {};
//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//
// A metafunction that yields true iff each of Funs is an EquivalenceClassType
// specialization and they all contain GeneratorType specializations that have
// the same return type
template <class... EqClasses>
struct AreEquivalenceClassesOfTheSameType {
  static_assert(sizeof...(EqClasses) != sizeof...(EqClasses), "");
};

template <>
struct AreEquivalenceClassesOfTheSameType<> : std::true_type {
  using self = AreEquivalenceClassesOfTheSameType;

  // Metafunction to check that a type is the same as all of the equivalence
  // classes, if any.
  // Note: In this specialization there are no equivalence classes, so the
  // value type is always compatible.
  template <class /*ValueType*/>
  using for_type = std::true_type;
};

template <class... Funs>
struct AreEquivalenceClassesOfTheSameType<EquivalenceClassType<Funs...>>
    : std::true_type {
  using self = AreEquivalenceClassesOfTheSameType;

  // Metafunction to check that a type is the same as all of the equivalence
  // classes, if any.
  template <class ValueType>
  using for_type = typename IsEquivalenceClass<
      EquivalenceClassType<Funs...>>::template for_type<ValueType>;
};

template <class... TailEqClasses>
struct AreEquivalenceClassesOfTheSameType<
    EquivalenceClassType<>, EquivalenceClassType<>, TailEqClasses...>
    : AreEquivalenceClassesOfTheSameType<TailEqClasses...>::self {};

template <class HeadNextFun, class... TailNextFuns, class... TailEqClasses>
struct AreEquivalenceClassesOfTheSameType<
    EquivalenceClassType<>, EquivalenceClassType<HeadNextFun, TailNextFuns...>,
    TailEqClasses...>
    : AreEquivalenceClassesOfTheSameType<
          EquivalenceClassType<HeadNextFun, TailNextFuns...>,
          TailEqClasses...>::self {};

template <class HeadHeadFun, class... TailHeadFuns, class... TailEqClasses>
struct AreEquivalenceClassesOfTheSameType<
    EquivalenceClassType<HeadHeadFun, TailHeadFuns...>, EquivalenceClassType<>,
    TailEqClasses...>
    : AreEquivalenceClassesOfTheSameType<
          EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
          TailEqClasses...>::self {};

template <class HeadHeadFun, class... TailHeadFuns, class HeadNextFun,
          class... TailNextFuns, class... TailEqClasses>
struct AreEquivalenceClassesOfTheSameType<
    EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
    EquivalenceClassType<HeadNextFun, TailNextFuns...>, TailEqClasses...>
    : absl::conditional_t<
          IsNullaryCallable<HeadNextFun>::template for_type<
              typename IsNullaryCallable<HeadHeadFun>::result_type>::value,
          AreEquivalenceClassesOfTheSameType<
              EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
              TailEqClasses...>,
          std::false_type> {};
//
////////////////////////////////////////////////////////////////////////////////

// Execute a function for each passed-in parameter.
template <class Fun, class... Cases>
void ForEachParameter(const Fun& fun, const Cases&... cases) {
  const std::initializer_list<bool> results = {
      (static_cast<void>(fun(cases)), true)...};

  (void)results;
}

// Execute a function on each passed-in parameter (using a bound function).
template <class Fun>
struct ForEachParameterFun {
  template <class... T>
  void operator()(const T&... cases) const {
    (ForEachParameter)(fun, cases...);
  }

  Fun fun;
};

// Execute a function on each element of a tuple.
template <class Fun, class Tup>
void ForEachTupleElement(const Fun& fun, const Tup& tup) {
  absl::apply(ForEachParameterFun<Fun>{fun}, tup);
}

////////////////////////////////////////////////////////////////////////////////
//
// Execute a function for each combination of two elements of a tuple, including
// combinations of an element with itself.
template <class Fun, class... T>
struct ForEveryTwoImpl {
  template <class Lhs>
  struct WithBoundLhs {
    template <class Rhs>
    void operator()(const Rhs& rhs) const {
      fun(lhs, rhs);
    }

    Fun fun;
    Lhs lhs;
  };

  template <class Lhs>
  void operator()(const Lhs& lhs) const {
    (ForEachTupleElement)(WithBoundLhs<Lhs>{fun, lhs}, args);
  }

  Fun fun;
  std::tuple<T...> args;
};

template <class Fun, class... T>
void ForEveryTwo(const Fun& fun, std::tuple<T...> args) {
  (ForEachTupleElement)(ForEveryTwoImpl<Fun, T...>{fun, args}, args);
}
//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//
// Insert all values into an associative container
template<class Container>
void InsertEach(Container* cont) {
}

template<class Container, class H, class... T>
void InsertEach(Container* cont, H&& head, T&&... tail) {
  cont->insert(head);
  (InsertEach)(cont, tail...);
}
//
////////////////////////////////////////////////////////////////////////////////
// A template with a nested "Invoke" static-member-function that executes a
// passed-in Callable when `Condition` is true, otherwise it ignores the
// Callable. This is useful for executing a function object with a condition
// that corresponds to whether or not the Callable can be safely instantiated.
// It has some overlapping uses with C++17 `if constexpr`.
template <bool Condition>
struct If;

template <>
struct If</*Condition =*/false> {
  template <class Fun, class... P>
  static void Invoke(const Fun& /*fun*/, P&&... /*args*/) {}
};

template <>
struct If</*Condition =*/true> {
  template <class Fun, class... P>
  static void Invoke(const Fun& fun, P&&... args) {
    // TODO(calabrese) Use std::invoke equivalent instead of function-call.
    fun(absl::forward<P>(args)...);
  }
};

//
// ABSL_INTERNAL_STRINGIZE(...)
//
// This variadic macro transforms its arguments into a c-string literal after
// expansion.
//
// Example:
//
//   ABSL_INTERNAL_STRINGIZE(std::array<int, 10>)
//
// Results in:
//
//   "std::array<int, 10>"
#define ABSL_INTERNAL_STRINGIZE(...) ABSL_INTERNAL_STRINGIZE_IMPL((__VA_ARGS__))
#define ABSL_INTERNAL_STRINGIZE_IMPL(arg) ABSL_INTERNAL_STRINGIZE_IMPL2 arg
#define ABSL_INTERNAL_STRINGIZE_IMPL2(...) #__VA_ARGS__

}  // namespace types_internal
ABSL_NAMESPACE_END
}  // namespace absl

#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_