1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <stddef.h>
8 #include <utility>
9 
10 //
11 // Compile-time type info utility without RTTI.
12 //
13 
14 // Check for supported versions of Clang or GCC.
15 #if defined(__clang__)
16 #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30600
17 #error "Unsupported clang version!"
18 #endif
19 #elif defined(__GNUC__)
20 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 50400
21 #error "Unsupported gcc version!"
22 #endif
23 #else
24 #error "Unrecognized compiler!"
25 #endif
26 
27 namespace fbl {
28 
29 // TypeInfo provides a compile-time string name for the given type T without
30 // requiring RTTI to be enabled. The type string is derived from
31 // __PRETTY_FUNCTION__ using a constexpr expression that works with both GCC and
32 // Clang.
33 //
34 // TypeInfo may be used in a wide variety of contexts. Here is one example of
35 // logging the types used to invoke a template function:
36 //
37 //  template <typename T, typename U, typename V>
38 //  void Function(const T& t, const U& u, const V& v) {
39 //      log("Function<%s, %s, %s>(...) invoked!",  TypeInfo<T>::Name(),
40 //          TypeInfo<U>::Name(), TypeInfo<V>::Name());
41 //      // Function body...
42 //  }
43 //
44 template <typename T>
45 class TypeInfo {
46 public:
47     // Returns the string name for type T.
Name()48     static const char* Name() {
49         static constexpr TypeInfo type_info;
50         return type_info.name;
51     }
52 
53 private:
54     struct Info {
55         const char* const kName;
56         const size_t kOffset;
57         const size_t kSize;
58     };
59 
Get()60     static constexpr Info Get() {
61         const char* type_name = __PRETTY_FUNCTION__;
62         const size_t size = sizeof(__PRETTY_FUNCTION__);
63         size_t start = Find(type_name, '=', 0, Forward) + 2;
64         size_t end = Find(type_name, ']', size - 1, Reverse) + 1;
65         return {type_name, start, end - start};
66     }
67 
68     enum Direction { Forward,
69                      Reverse };
Find(const char * subject,char value,size_t index,Direction direction)70     static constexpr size_t Find(const char* subject, char value, size_t index,
71                                  Direction direction) {
72         while (subject[index] != value)
73             index += direction == Forward ? 1 : -1;
74         return index;
75     }
76 
77     static constexpr size_t Size = Get().kSize;
78     static constexpr size_t Offset = Get().kOffset;
79     static constexpr const char* BaseName = Get().kName;
80 
TypeInfo()81     constexpr TypeInfo()
82         : TypeInfo(std::make_index_sequence<Size>{}) {}
83     template <size_t... Is>
TypeInfo(std::index_sequence<Is...>)84     constexpr TypeInfo(std::index_sequence<Is...>)
85         : name{(Is < Size - 1 ? BaseName[Offset + Is] : '\0')...} {}
86 
87     const char name[Size];
88 };
89 
90 } // namespace fbl
91