1 /* 2 * Copyright (c) 2016, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 */ 9 10 #ifndef FATAL_INCLUDE_fatal_type_registry_h 11 #define FATAL_INCLUDE_fatal_type_registry_h 12 13 #include <type_traits> 14 15 namespace fatal { 16 namespace detail { 17 namespace registry_impl { 18 template <typename, typename> class lookup; 19 struct abort_on_not_found; 20 } // namespace registry_impl { 21 } // namespace detail { 22 23 /** 24 * Associates a type pair `Tag`/`Key` with a type, so thay it can be looked up 25 * from any scope. 26 * 27 * NOTE: this macro must be called from the same namespace of either the `Tag` 28 * or `Key`, or some other namespace that respects the C++ rules for Argument 29 * Dependent Lookup (http://en.cppreference.com/w/cpp/language/adl). 30 * 31 * See `registry_lookup` and `try_registry_lookup` below for more information 32 * on how to query the registry. 33 * 34 * Example: 35 * 36 * struct algo { 37 * FATAL_STR(quick_sort, "quicksort"); 38 * FATAL_STR(merge_sort, "merge sort"); 39 * FATAL_STR(insertion_sort, "insertion sort"); 40 * }; 41 * 42 * struct prop { 43 * struct sorting {}; 44 * struct adaptive {}; 45 * struct stable {}; 46 * struct in_place {}; 47 * }; 48 * 49 * FATAL_REGISTER_TYPE(algo::quick_sort, prop::adaptive, std::false_type); 50 * FATAL_REGISTER_TYPE(algo::quick_sort, prop::stable, std::false_type); 51 * FATAL_REGISTER_TYPE(algo::quick_sort, prop::in_place, std::true_type); 52 * 53 * FATAL_REGISTER_TYPE(algo::merge_sort, prop::adaptive, std::false_type); 54 * FATAL_REGISTER_TYPE(algo::merge_sort, prop::stable, std::true_type); 55 * FATAL_REGISTER_TYPE(algo::merge_sort, prop::in_place, std::false_type); 56 * 57 * FATAL_REGISTER_TYPE(algo::insertion_sort, prop::adaptive, std::true_type); 58 * FATAL_REGISTER_TYPE(algo::insertion_sort, prop::stable, std::true_type); 59 * FATAL_REGISTER_TYPE(algo::insertion_sort, prop::in_place, std::true_type); 60 * 61 * FATAL_REGISTER_TYPE( 62 * algo, 63 * prop::sorting, 64 * type_list<algo::quick_sort, algo::merge_sort, algo::insertion_sort> 65 * ); 66 * 67 * struct print_info_visitor { 68 * template <typename Algorithm, std::size_t Index> 69 * void operator ()(indexed_type_tag<Algorithm, Index>) const { 70 * std::cout << Algorithm::z_data() << '{' 71 * << " adaptive:" << registry_lookup<Algorithm, prop::adaptive>::value 72 * << " stable:" << registry_lookup<Algorithm, prop::stable>::value 73 * << " in-place:" << registry_lookup<Algorithm, prop::in_place>::value 74 * << " }" << std::endl; 75 * } 76 * }; 77 * 78 * // prints ` 79 * // quicksort { adaptive:0 stable:0 in-place:1 } 80 * // merge sort { adaptive:0 stable:1 in-place:0 } 81 * // insertion sort { adaptive:1 stable:1 in-place:1 } 82 * // ` 83 * registry_lookup<algo, prop::sorting>::foreach(print_info_visitor()); 84 * 85 * @author: Marcelo Juchem <marcelo@fb.com> 86 */ 87 #define FATAL_REGISTER_TYPE(Tag, Key, ...) \ 88 __VA_ARGS__ operator <<(Tag, Key *) 89 90 /** 91 * Looks up a type previously associated by `FATAL_REGISTER_TYPE` with the type 92 * pair `Tag`/`Key`. 93 * 94 * If the type was not previosly associated then `Default` will be returned. 95 * 96 * Example: 97 * 98 * struct my_tag {}; 99 * struct my_key_1 {}; 100 * struct my_key_2 {}; 101 * struct my_metadata_1 {}; 102 * 103 * FATAL_REGISTER_TYPE(my_tag, my_key_1, my_metadata_1); 104 * 105 * // yields `my_metadata_1` 106 * using result1 = try_registry_lookup<my_tag, my_key_1, void>; 107 * 108 * // yields `void` 109 * using result2 = try_registry_lookup<my_tag, my_key_2, void>; 110 * 111 * @author: Marcelo Juchem <marcelo@fb.com> 112 */ 113 template <typename Tag, typename Key, typename Default> 114 using try_registry_lookup = typename detail::registry_impl::lookup<Tag, Default> 115 ::template key<Key>; 116 117 /** 118 * Looks up a type previously associated by `FATAL_REGISTER_TYPE` with the type 119 * pair `Tag`/`Key`. 120 * 121 * If the type was not previosly associated then the compilation will fail. 122 * 123 * Example: 124 * 125 * struct my_tag {}; 126 * struct my_key_1 {}; 127 * struct my_key_2 {}; 128 * struct my_metadata_1 {}; 129 * 130 * FATAL_REGISTER_TYPE(my_tag, my_key_1, my_metadata_1); 131 * 132 * // yields `my_metadata_1` 133 * using result1 = registry_lookup<my_tag, my_key_1>; 134 * 135 * // fails compilation 136 * using result2 = registry_lookup<my_tag, my_key_2>; 137 * 138 * @author: Marcelo Juchem <marcelo@fb.com> 139 */ 140 template <typename Tag, typename Key> 141 using registry_lookup = try_registry_lookup< 142 Tag, Key, detail::registry_impl::abort_on_not_found 143 >; 144 145 //////////////////////////// 146 // IMPLEMENTATION DETAILS // 147 //////////////////////////// 148 149 namespace detail { 150 namespace registry_impl { 151 152 template <typename Key> 153 struct registry_key { 154 using key = Key; 155 }; 156 157 template <typename Tag, typename Default> 158 class lookup { 159 struct impl { 160 template < 161 typename Key, 162 typename Metadata = decltype( 163 std::declval<Tag>() << static_cast<Key *>(nullptr) 164 ) 165 > 166 static Metadata sfinae(registry_key<Key> *); 167 168 template <typename... Args> 169 static Default sfinae(...); 170 }; 171 172 public: 173 template <typename Key> 174 using key = decltype( 175 impl::sfinae(static_cast<registry_key<Key> *>(nullptr)) 176 ); 177 }; 178 179 template <typename Tag> 180 class lookup<Tag, abort_on_not_found> { 181 public: 182 template <typename Key> 183 using key = decltype(std::declval<Tag>() << static_cast<Key *>(nullptr)); 184 }; 185 186 } // namespace registry_impl { 187 } // namespace detail { 188 } // namespace fatal { 189 190 #endif // FATAL_INCLUDE_fatal_type_registry_h 191