1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <algorithm> 20 #include <memory> 21 #include <type_traits> 22 23 #include <folly/Indestructible.h> 24 #include <folly/Portability.h> 25 #include <folly/Range.h> 26 #include <folly/Traits.h> 27 28 #include <thrift/lib/cpp/protocol/TType.h> 29 #include <thrift/lib/cpp2/Thrift.h> 30 31 namespace apache { 32 namespace thrift { 33 namespace detail { 34 35 namespace st { 36 37 // copy_field_fn 38 // copy_field 39 // 40 // Returns a copy of a field. Used by structure copy-cosntructors. 41 // 42 // Transitively copies through unique-ptr's, which are not copy-constructible. 43 template <typename TypeClass> 44 struct copy_field_fn; 45 template <typename TypeClass> 46 FOLLY_INLINE_VARIABLE constexpr copy_field_fn<TypeClass> copy_field{}; 47 48 template <typename> 49 struct copy_field_rec { 50 template <typename T> operatorcopy_field_rec51 T operator()(T const& t) const { 52 return t; 53 } 54 }; 55 56 template <typename ValueTypeClass> 57 struct copy_field_rec<type_class::list<ValueTypeClass>> { 58 template <typename T> 59 T operator()(T const& t) const { 60 T result; 61 for (auto const& e : t) { 62 result.push_back(copy_field<ValueTypeClass>(e)); 63 } 64 return result; 65 } 66 }; 67 68 template <typename ValueTypeClass> 69 struct copy_field_rec<type_class::set<ValueTypeClass>> { 70 template <typename T> 71 T operator()(T const& t) const { 72 T result; 73 for (auto const& e : t) { 74 result.emplace_hint(result.end(), copy_field<ValueTypeClass>(e)); 75 } 76 return result; 77 } 78 }; 79 80 template <typename KeyTypeClass, typename MappedTypeClass> 81 struct copy_field_rec<type_class::map<KeyTypeClass, MappedTypeClass>> { 82 template <typename T> 83 T operator()(T const& t) const { 84 T result; 85 for (auto const& pair : t) { 86 result.emplace_hint( 87 result.end(), 88 copy_field<KeyTypeClass>(pair.first), 89 copy_field<MappedTypeClass>(pair.second)); 90 } 91 return result; 92 } 93 }; 94 95 template <typename TypeClass> 96 struct copy_field_fn : copy_field_rec<TypeClass> { 97 using rec = copy_field_rec<TypeClass>; 98 99 using rec::operator(); 100 template <typename T> 101 std::unique_ptr<T> operator()(std::unique_ptr<T> const& t) const { 102 return !t ? nullptr : std::make_unique<T>((*this)(*t)); 103 } 104 }; 105 106 struct translate_field_name_table { 107 size_t size; 108 folly::StringPiece const* names; 109 int16_t const* ids; 110 protocol::TType const* types; 111 }; 112 113 void translate_field_name( 114 folly::StringPiece fname, 115 int16_t& fid, 116 protocol::TType& ftype, 117 translate_field_name_table const& table) noexcept; 118 119 namespace { 120 121 // gen_check_get_json 122 // gen_check_get_nimble 123 // 124 // Metafunctions for getting the member types named, respectively, 125 // * __fbthrift_cpp2_gen_json 126 // * __fbthrift_cpp2_gen_nimble 127 struct gen_check_get_json { 128 template <typename Type> 129 using apply = 130 decltype(struct_private_access::__fbthrift_cpp2_gen_json<Type>()); 131 }; 132 struct gen_check_get_nimble { 133 template <typename Type> 134 using apply = 135 decltype(struct_private_access::__fbthrift_cpp2_gen_nimble<Type>()); 136 }; 137 138 // gen_check_get 139 // 140 // Metafunction for applying Get over Type and for handling the case where 141 // Get fails to apply. 142 // 143 // Get is one of the getters above: 144 // * gen_check_get_json 145 // * gen_check_get_nimble 146 // 147 // When Get::apply<Type>: 148 // * fails to apply (because cpp.type is in use), treat as true 149 // * returns signed (extern template instances are generated), treat as true 150 // * returns unsigned (otherwise), treat as false 151 // 152 // The tag types signed and unsigned are used in the generated code to minimize 153 // the overhead of parsing the class body, shifting all overhead to the code 154 // which inspects these tags. 155 template <typename Void, typename Get, typename Type> 156 constexpr bool gen_check_get_ = true; 157 template <typename Get, typename Type> 158 constexpr bool gen_check_get_< 159 folly::void_t<typename Get::template apply<Type>>, 160 Get, 161 Type> = Get::template apply<Type>::value; 162 template <typename Get, typename Type> 163 constexpr bool gen_check_get = gen_check_get_<void, Get, Type>; 164 165 // gen_check_rec 166 // 167 // Metafunction for recursing through container types to apply the metafunction 168 // gen_check_get over struct/union types. 169 // 170 // Get is one of the getters above: 171 // * gen_check_get_json 172 // * gen_check_get_nimble 173 template <typename TypeClass> 174 struct gen_check_rec { 175 template <typename Get, typename Type> 176 static constexpr bool apply = true; 177 }; 178 template <typename ValueTypeClass> 179 struct gen_check_rec_list_set { 180 using ValueTraits = gen_check_rec<ValueTypeClass>; 181 template <typename Get, typename Type> 182 static constexpr bool apply = 183 ValueTraits::template apply<Get, typename Type::value_type>; 184 }; 185 template <typename ValueTypeClass> 186 struct gen_check_rec<type_class::list<ValueTypeClass>> 187 : gen_check_rec_list_set<ValueTypeClass> {}; 188 template <typename ValueTypeClass> 189 struct gen_check_rec<type_class::set<ValueTypeClass>> 190 : gen_check_rec_list_set<ValueTypeClass> {}; 191 template <typename KeyTypeClass, typename MappedTypeClass> 192 struct gen_check_rec<type_class::map<KeyTypeClass, MappedTypeClass>> { 193 using KeyTraits = gen_check_rec<KeyTypeClass>; 194 using MappedTraits = gen_check_rec<MappedTypeClass>; 195 template <typename Get, typename Type> 196 static constexpr bool apply = 197 KeyTraits::template apply<Get, typename Type::key_type>&& 198 MappedTraits::template apply<Get, typename Type::mapped_type>; 199 }; 200 struct gen_check_rec_structure_variant { 201 template <typename Get, typename Type> 202 static constexpr bool apply = gen_check_get<Get, Type>; 203 }; 204 template <> 205 struct gen_check_rec<type_class::structure> : gen_check_rec_structure_variant { 206 }; 207 template <> 208 struct gen_check_rec<type_class::variant> : gen_check_rec_structure_variant {}; 209 210 // gen_check 211 // 212 // Returns whether, if the property Get holds for the outer structure Type, 213 // that it also holds for each structure-typed field FieldType of the outer 214 // type, peering through containers. 215 // 216 // Get is one of the getters above: 217 // * gen_check_get_json 218 // * gen_check_get_nimble 219 template < 220 typename Get, 221 typename Type, 222 typename FieldTypeClass, 223 typename FieldType> 224 constexpr bool gen_check = !gen_check_get<Get, Type> || 225 gen_check_rec<FieldTypeClass>::template apply<Get, FieldType>; 226 227 // gen_check_json 228 // gen_check_nimble 229 // 230 // Aliases to gen_check partially instantiated with one of the getters above: 231 // * gen_check_get_json 232 // * gen_check_get_nimble 233 // 234 // Used by a generated static_assert to enforce consistency over transitive 235 // dependencies in the use of extern-template instantiations over json/nimble. 236 template <typename Type, typename FieldTypeClass, typename FieldType> 237 constexpr bool gen_check_json = 238 gen_check<gen_check_get_json, Type, FieldTypeClass, FieldType>; 239 template <typename Type, typename FieldTypeClass, typename FieldType> 240 constexpr bool gen_check_nimble = 241 gen_check<gen_check_get_nimble, Type, FieldTypeClass, FieldType>; 242 243 } // namespace 244 245 } // namespace st 246 247 template <class T> 248 bool pointer_equal(const T& lhs, const T& rhs) { 249 return lhs && rhs ? *lhs == *rhs : lhs == rhs; 250 } 251 252 template <class T> 253 bool pointer_less(const T& lhs, const T& rhs) { 254 return lhs && rhs ? *lhs < *rhs : lhs < rhs; 255 } 256 257 } // namespace detail 258 } // namespace thrift 259 } // namespace apache 260