2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_RUNTIME_VM_BLOB_HELPER_H_
18 #define incl_HPHP_RUNTIME_VM_BLOB_HELPER_H_
23 #include <type_traits>
24 #include <unordered_set>
27 #include <folly/Optional.h>
28 #include <folly/Varint.h>
30 #include "hphp/runtime/base/builtin-functions.h"
31 #include "hphp/runtime/base/tv-mutate.h"
32 #include "hphp/runtime/base/tv-variant.h"
33 #include "hphp/runtime/base/type-string.h"
34 #include "hphp/runtime/base/variable-serializer.h"
35 #include "hphp/runtime/vm/repo.h"
36 #include "hphp/runtime/vm/repo-global-data.h"
39 * This module contains helpers for serializing and deserializing
40 * metadata into blobs suitable for insertion into the hhbc repo.
42 * Types may provide their own serialization logic by implementing a
43 * single-argument member function template called `serde' (as in
44 * "serialization/deserialization"), and pushing data it wants to
45 * serialize into the parameter. Those members may in turn have
46 * customized serialization behavior, or they may "bottom out" to
47 * these helpers if they are basic-enough types.
51 * struct MyBlobableStuff {
53 * std::vector<const StringData*> m_strList;
54 * OtherBlobbableData m_other;
56 * template<class SerDe> void serde(SerDe& sd) {
57 * sd(m_foo)(m_strList)(m_other);
61 * The argument to SerDe will have a static const member called
62 * `deserializing' which can be used to do custom behavior depending
63 * on whether you're deserializing. But generally the goal here
64 * should be to eliminate a class of bugs by having the same (textual)
65 * code implement both serialization and deserialization.
70 //////////////////////////////////////////////////////////////////////
73 * Warning: some language abuse below.
75 * This defines a trait that determines whether or not a type T has a
76 * member function template called `serde' that specializes for the
77 * type `SerDe'. The point here is that calling one of the blob
78 * helpers on an object that knows how to do its own serialization
79 * will just reflect back to it.
81 * If you are unlucky enough to need to know how this works, look up
85 template<class T
, class SerDe
>
86 struct IsNontrivialSerializable
{
88 template<class U
, void (U::*)(SerDe
&)> struct Checker
;
89 template<class U
> static char test(Checker
<U
,&U::template serde
<SerDe
> >*);
90 template<class> static long test(...);
92 enum { value
= sizeof(test
<T
>(0)) == 1 };
95 //////////////////////////////////////////////////////////////////////
98 static const bool deserializing
= false;
101 * Currently the most basic encoder/decode only works for integral
102 * types. (We don't want this to accidentally get used for things
103 * like pointers or aggregates.)
105 * Floating point support could be added later if we need it ...
108 typename
std::enable_if
<
109 std::is_integral
<T
>::value
||
110 std::is_enum
<T
>::value
113 const size_t start
= m_blob
.size();
114 unsigned char buf
[folly::kMaxVarintLength64
];
115 uint64_t value
= uint64_t{
116 static_cast<typename
std::make_unsigned
<T
>::type
>(t
)};
117 size_t buf_size
= folly::encodeVarint(value
, buf
);
119 m_blob
.resize(start
+ buf_size
);
121 std::copy(buf
, buf
+ buf_size
, &m_blob
[start
]);
125 typename
std::enable_if
<
126 IsNontrivialSerializable
<T
,BlobEncoder
>::value
127 >::type
encode(const T
& t
) {
128 const_cast<T
&>(t
).serde(*this);
131 void encode(bool b
) {
135 void encode(DataType t
) {
136 // always encode DataType as int8 even if it's a bigger size.
137 assertx(DataType(int8_t(t
)) == t
);
141 void encode(const StringData
* sd
) {
142 if (!sd
) { return encode(uint32_t(0)); }
143 uint32_t sz
= sd
->size();
147 const size_t start
= m_blob
.size();
148 m_blob
.resize(start
+ sz
);
149 std::copy(sd
->data(), sd
->data() + sz
, &m_blob
[start
]);
152 void encode(const std::string
& s
) {
153 uint32_t sz
= s
.size();
157 const size_t start
= m_blob
.size();
158 m_blob
.resize(start
+ sz
);
159 std::copy(s
.data(), s
.data() + sz
, &m_blob
[start
]);
162 void encode(const TypedValue
& tv
) {
163 if (tv
.m_type
== KindOfUninit
) {
164 return encode(staticEmptyString());
166 auto s
= internal_serialize(tvAsCVarRef(&tv
));
170 void encode(const TypedValueAux
& tv
) = delete;
173 void encode(const folly::Optional
<T
>& opt
) {
174 const bool some
= opt
.hasValue();
176 if (some
) encode(*opt
);
179 template <size_t I
= 0, typename
... Ts
>
180 typename
std::enable_if
<I
== sizeof...(Ts
), void>::type
181 encode(const std::tuple
<Ts
...>& /*val*/) {}
183 template<size_t I
= 0, typename
...Ts
>
184 typename
std::enable_if
<I
< sizeof...(Ts
), void>::type
185 encode(const std::tuple
<Ts
...>& val
) {
186 encode(std::get
<I
>(val
));
187 encode
<I
+ 1, Ts
...>(val
);
190 template<class K
, class V
>
191 void encode(const std::pair
<K
,V
>& kv
) {
197 void encode(const std::vector
<T
>& vec
) {
198 encodeContainer(vec
, "vector");
202 typename
std::enable_if
<
203 std::is_same
<typename
T::value_type
,
204 std::pair
<typename
T::key_type
const,
205 typename
T::mapped_type
>>::value
&&
206 !IsNontrivialSerializable
<T
,BlobEncoder
>::value
207 >::type
encode(const T
& map
) {
208 encodeContainer(map
, "map");
212 typename
std::enable_if
<
213 std::is_same
<typename
T::key_type
,
214 typename
T::value_type
>::value
&&
215 !IsNontrivialSerializable
<T
,BlobEncoder
>::value
216 >::type
encode(const T
& set
) {
217 encodeContainer(set
, "set");
221 BlobEncoder
& operator()(const T
& t
) {
226 size_t size() const { return m_blob
.size(); }
227 const void* data() const { return &m_blob
[0]; }
231 void encodeContainer(Cont
& cont
, const char* desc
) {
232 if (cont
.size() >= 0xffffffffu
) {
233 throw std::runtime_error("maximum " + std::string(desc
) +
234 " size exceeded in BlobEncoder");
236 encode(uint32_t(cont
.size()));
237 typedef typename
Cont::const_iterator iter
;
238 for (iter it
= cont
.begin(); it
!= cont
.end(); ++it
) {
244 std::vector
<char> m_blob
;
247 //////////////////////////////////////////////////////////////////////
250 static const bool deserializing
= true;
252 explicit BlobDecoder(const void* vp
, size_t sz
)
253 : m_p(static_cast<const unsigned char*>(vp
))
258 assertx(m_p
>= m_last
);
261 // See encode() in BlobEncoder for why this only allows integral
264 typename
std::enable_if
<
265 std::is_integral
<T
>::value
||
266 std::is_enum
<T
>::value
269 folly::ByteRange
range(m_p
, m_last
);
270 t
= static_cast<T
>(folly::decodeVarint(range
));
275 typename
std::enable_if
<
276 IsNontrivialSerializable
<T
,BlobDecoder
>::value
277 >::type
decode(T
& t
) {
281 void decode(DataType
& t
) {
282 // always decode DataType as int8 even if it's a bigger size.
288 void decode(const StringData
*& sd
) {
289 String
s(decodeString());
290 sd
= s
.get() ? makeStaticString(s
) : 0;
293 void decode(LowStringPtr
& s
) {
294 const StringData
* sd
;
299 void decode(std::string
& s
) {
300 String
str(decodeString());
301 s
= str
.toCppString();
304 void decode(TypedValue
& tv
) {
307 String s
= decodeString();
309 if (s
.empty()) return;
312 unserialize_from_string(s
, VariableUnserializer::Type::Internal
);
313 tvAsVariant(&tv
).setEvalScalar();
316 void decode(TypedValueAux
& tv
) = delete;
319 void decode(folly::Optional
<T
>& opt
) {
332 template <size_t I
= 0, typename
... Ts
>
333 typename
std::enable_if
<I
== sizeof...(Ts
), void>::type
334 decode(std::tuple
<Ts
...>& /*val*/) {}
336 template<size_t I
= 0, typename
...Ts
>
337 typename
std::enable_if
<I
< sizeof...(Ts
), void>::type
338 decode(std::tuple
<Ts
...>& val
) {
339 decode(std::get
<I
>(val
));
340 decode
<I
+ 1, Ts
...>(val
);
343 template<class K
, class V
>
344 void decode(std::pair
<K
,V
>& val
) {
350 void decode(std::vector
<T
>& vec
) {
353 for (uint32_t i
= 0; i
< size
; ++i
) {
360 typename
std::enable_if
<
361 std::is_same
<typename
T::value_type
,
362 std::pair
<typename
T::key_type
const,
363 typename
T::mapped_type
>>::value
&&
364 !IsNontrivialSerializable
<T
,BlobDecoder
>::value
365 >::type
decode(T
& map
) {
368 for (uint32_t i
= 0; i
< size
; ++i
) {
369 typename
T::key_type key
;
371 typename
T::mapped_type val
;
373 map
.emplace(key
, val
);
378 typename
std::enable_if
<
379 std::is_same
<typename
T::key_type
,
380 typename
T::value_type
>::value
&&
381 !IsNontrivialSerializable
<T
,BlobDecoder
>::value
382 >::type
decode(T
& set
) {
385 for (uint32_t i
= 0; i
< size
; ++i
) {
386 typename
T::value_type val
;
393 BlobDecoder
& operator()(T
& t
) {
399 String
decodeString() {
402 if (sz
== 0) return String();
404 if (sz
== 0) return empty_string();
406 String s
= String(sz
, ReserveString
);
407 char* pch
= s
.mutableData();
408 assertx(m_last
- m_p
>= sz
);
409 std::copy(m_p
, m_p
+ sz
, pch
);
416 const unsigned char* m_p
;
417 const unsigned char* const m_last
;
420 //////////////////////////////////////////////////////////////////////