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